edbrowse-dev - development list for edbrowse
 help / color / mirror / Atom feed
* [Edbrowse-dev] [PATCH] Initial version of jsdom.cpp (built agains mozjs 1.85) This compiles under g++
@ 2013-12-24 17:57 Adam Thompson
  0 siblings, 0 replies; only message in thread
From: Adam Thompson @ 2013-12-24 17:57 UTC (permalink / raw)
  To: edbrowse-dev

---
 src/jsdom.cpp | 1259 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 1259 insertions(+)
 create mode 100644 src/jsdom.cpp

diff --git a/src/jsdom.cpp b/src/jsdom.cpp
new file mode 100644
index 0000000..b2ff51a
--- /dev/null
+++ b/src/jsdom.cpp
@@ -0,0 +1,1259 @@
+/* jsdom.cpp
+* Javascript support, the connection to spider monkey JS.
+* Copyright (c) Karl Dahlke, 2008
+* This file is part of the edbrowse project, released under GPL.
+* This file contains the basics of the document object model.
+ * The Spider Monkey Javascript compiler/engine is released by Mozilla,
+ * under the MPL.  Install and build that package under /usr/local.
+ * ftp://ftp.mozilla.org/pub/mozilla.org/js/js-1.5.tar.gz
+*/
+
+#include <string>
+#include "eb.h"
+
+#include "js.h"
+using namespace std;
+
+/* jsprf.h is not publically visible on some systems,
+so I can't #include it here.
+Instead, I'll declare the needed prototype myself, and hope it is consistent
+with whatever smjs you are using. */
+extern
+JS_PUBLIC_API(char *)
+JS_smprintf(const char *fmt, ...);
+
+#define PROP_FIXED (JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT)
+
+
+JSContext *jcx;			/* really JSContext */
+void *jwin;			/* window object, really JSObject */
+void *jdoc;			/* window.document, really JSObject */
+JSObject *jwloc;		/* window.location, really JSObject */
+JSObject *jdloc;		/* document.location, really JSObject */
+static size_t gStackChunkSize = 8192;
+static FILE *gOutFile, *gErrFile;
+static const char *emptyParms[] = { 0 };
+static jsval emptyArgs[] = { 0 };
+
+static void
+my_ErrorReporter(JSContext * cx, const char *message, JSErrorReport * report)
+{
+    char *prefix, *tmp;
+
+    if(debugLevel < 2)
+	goto done;
+    if(ismc)
+	goto done;
+
+    if(!report) {
+	fprintf(gErrFile, "%s\n", message);
+	goto done;
+    }
+
+/* Conditionally ignore reported warnings. */
+    if(JSREPORT_IS_WARNING(report->flags)) {
+	if(browseLocal)
+	    goto done;
+    }
+
+    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);
+	if(tmp)
+	    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 " : "");
+	if(tmp)
+	    JS_free(cx, tmp);
+    }
+
+    if(prefix)
+	fputs(prefix, gErrFile);
+    fprintf(gErrFile, "%s\n", message);
+
+    if(prefix)
+	JS_free(cx, prefix);
+
+  done:
+    report->flags = 0;
+}				/* my_ErrorReporter */
+
+JSString *
+our_JS_NewStringCopyN(JSContext * cx, const char *s, size_t n)
+{
+    char *converted = NULL;
+    int converted_l = 0;
+    const char *outbytes = s;
+    int outbytes_l = n;
+    JSString *forSpidermonkey = NULL;
+
+    if(!JS_CStringsAreUTF8())
+/* Fixme this is too simple.  We need to decode UTF8 to JSCHAR, for proper
+ * unicode handling.  E.G., JS C strings are not UTF8, but the user has
+ * a UTF8 locale. */
+	return JS_NewStringCopyN(jcx, s, n);
+
+    if(!cons_utf8) {
+/* The string should not be UTF8, because of edbrowse's conversion. */
+	iso2utf(s, n, &converted, &converted_l);
+	outbytes = converted;
+	outbytes_l = converted_l;
+    }
+
+    forSpidermonkey = JS_NewStringCopyN(jcx, outbytes, outbytes_l);
+    nzFree(converted);
+
+    return forSpidermonkey;
+}				/* our_JS_NewStringCopyN */
+JSString *
+our_JS_NewStringCopyZ(JSContext * cx, const char *s)
+{
+    size_t len = strlen(s);
+    return our_JS_NewStringCopyN(jcx, s, len);
+}				/* our_JS_NewStringCopyZ */
+
+char *
+our_JSEncodeString(JSString * str)
+{
+    size_t encodedLength = JS_GetStringEncodingLength(jcx, str);
+    char *buffer = (char *) allocMem(encodedLength + 1);
+    buffer[encodedLength] = '\0';
+    size_t result = JS_EncodeStringToBuffer(str, buffer, encodedLength);
+    if(result == (size_t) - 1)
+	i_printfExit(MSG_JSFailure);
+    return buffer;
+}				/* our_JSEncodeString */
+
+static char *
+transcode_get_js_bytes(JSString * s)
+{
+    char *converted = NULL;
+    int converted_l = 0;
+    char *origbytes = our_JSEncodeString(s);
+
+    if(!JS_CStringsAreUTF8())
+	return origbytes;
+
+    if(cons_utf8)
+	return origbytes;
+
+    utf2iso(origbytes, strlen(origbytes), &converted, &converted_l);
+    nzFree(origbytes);
+    return converted;
+}				/* our_JS_GetTranscodedBytes */
+
+/*********************************************************************
+When an element is created without a name, it is not linked to its
+owner (via that name), and can be cleared via garbage collection.
+This is a disaster!
+Create a fake name, so we can attach the element.
+*********************************************************************/
+
+static const char *
+fakePropName(void)
+{
+    static char fakebuf[20];
+    static int idx = 0;
+    ++idx;
+    sprintf(fakebuf, "gc$away%d", idx);
+    return fakebuf;
+}				/*fakePropName */
+
+
+/*********************************************************************
+Here come the classes, and their inbuilt methods, for the document object model.
+Start with window and document.
+*********************************************************************/
+
+static JSClass window_class = {
+    "Window",
+    JSCLASS_HAS_PRIVATE | JSCLASS_GLOBAL_FLAGS,
+    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+};
+
+static JSBool
+window_ctor(JSContext * cx, uintN argc, jsval * vp)
+{
+    char *newloc = 0;
+    const char *winname = 0;
+    JSString *str;
+    jsval *argv = JS_ARGV(cx, vp);
+    JSObject *newwin = JS_NewObjectForConstructor(cx, vp);
+    if(argc > 0 && (str = JS_ValueToString(jcx, argv[0]))) {
+	newloc = our_JSEncodeString(str);
+    }
+    if(argc > 1 && (str = JS_ValueToString(jcx, argv[1]))) {
+	winname = transcode_get_js_bytes(str);
+    }
+/* third argument is attributes, like window size and location, that we don't care about. */
+    javaOpensWindow(newloc, winname);
+    if(newloc)
+	nzFree(newloc);
+
+    if(!parsePage)
+	return JS_FALSE;
+    establish_property_object(newwin, "opener", (JSObject *) jwin);
+    JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(newwin));
+    return JS_TRUE;
+}				/* window_ctor */
+
+/* window.open() instantiates a new window object */
+static JSBool
+win_open(JSContext * cx, uintN argc, jsval * vp)
+{
+    jsval *argv = JS_ARGV(cx, vp);
+    JSObject *newwin = JS_ConstructObjectWithArguments(jcx,
+       &window_class, 0, (JSObject *) jwin, argc, argv);
+    JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(newwin));
+    return JS_TRUE;
+}				/* win_open */
+
+/* for window.focus etc */
+static JSBool
+nullFunction(JSContext * cx, uintN argc, jsval * vp)
+{
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    return JS_TRUE;
+}				/* nullFunction */
+
+static JSBool
+falseFunction(JSContext * cx, uintN argc, jsval * vp)
+{
+    JS_SET_RVAL(cx, vp, JSVAL_FALSE);
+    return JS_TRUE;
+}				/* falseFunction */
+
+static JSBool
+trueFunction(JSContext * cx, uintN argc, jsval * vp)
+{
+    JS_SET_RVAL(cx, vp, JSVAL_TRUE);
+    return JS_TRUE;
+}				/* trueFunction */
+
+static JSBool
+setAttribute(JSContext * cx, uintN argc, jsval * vp)
+{
+    JSObject *obj = JS_THIS_OBJECT(cx, vp);
+    jsval *argv = JS_ARGV(cx, vp);
+    if(argc != 2 || !JSVAL_IS_STRING(argv[0])) {
+	JS_ReportError(jcx, "unexpected arguments to setAttribute()");
+    } else {
+	const char *prop = stringize(argv[0]);
+	JS_DefineProperty(jcx, obj, prop, argv[1], NULL, NULL, PROP_FIXED);
+    }
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    return JS_TRUE;
+}				/* setAttribute */
+
+static JSBool
+appendChild(JSContext * cx, uintN argc, jsval * vp)
+{
+    JSObject *elar;		/* elements array */
+    jsuint length;
+    jsval v;
+    jsval *argv = JS_ARGV(cx, vp);
+    JSObject *obj = JS_THIS_OBJECT(cx, vp);
+    JS_GetProperty(jcx, obj, "elements", &v);
+    elar = JSVAL_TO_OBJECT(v);
+    JS_GetArrayLength(jcx, elar, &length);
+    JS_DefineElement(jcx, elar, length,
+       (argc > 0 ? argv[0] : JSVAL_NULL), NULL, NULL, JSPROP_ENUMERATE);
+    return JS_TRUE;
+}				/* appendChild */
+
+static JSBool
+win_close(JSContext * cx, uintN argc, jsval * vp)
+{
+/* It's too confusing to just close the window */
+    i_puts(MSG_PageDone);
+    cw->jsdead = eb_true;
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    return JS_TRUE;
+}				/* win_close */
+
+static JSBool
+win_alert(JSContext * cx, uintN argc, jsval * vp)
+{
+    jsval *argv = JS_ARGV(cx, vp);
+    char *msg = NULL;
+    JSString *str;
+    if(argc > 0 && (str = JS_ValueToString(jcx, argv[0]))) {
+	msg = transcode_get_js_bytes(str);
+    }
+    if(msg) {
+	puts(msg);
+	nzFree(msg);
+    }
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    return JS_TRUE;
+}				/* win_alert */
+
+static JSBool
+win_prompt(JSContext * cx, uintN argc, jsval * vp)
+{
+    jsval *argv = JS_ARGV(cx, vp);
+    char *msg = EMPTYSTRING;
+    char *answer = EMPTYSTRING;
+    JSString *str;
+    char inbuf[80];
+    char *s;
+    char c;
+
+    if(argc > 0 && (str = JS_ValueToString(jcx, argv[0]))) {
+	msg = transcode_get_js_bytes(str);
+    }
+    if(argc > 1 && (str = JS_ValueToString(jcx, argv[1]))) {
+	answer = transcode_get_js_bytes(str);
+    }
+
+    printf("%s", msg);
+/* If it doesn't end in space or question mark, print a colon */
+    c = 'x';
+    if(*msg)
+	c = msg[strlen(msg) - 1];
+    if(!isspaceByte(c)) {
+	if(!ispunctByte(c))
+	    printf(":");
+	printf(" ");
+    }
+    if(answer)
+	printf("[%s] ", answer);
+    fflush(stdout);
+    if(!fgets(inbuf, sizeof (inbuf), stdin))
+	exit(1);
+    s = inbuf + strlen(inbuf);
+    if(s > inbuf && s[-1] == '\n')
+	*--s = 0;
+    if(inbuf[0]) {
+	nzFree(answer);		/* Don't need the default answer anymore. */
+	answer = inbuf;
+    }
+    JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(our_JS_NewStringCopyZ(jcx, answer)));
+    return JS_TRUE;
+}				/* win_prompt */
+
+static JSBool
+win_confirm(JSContext * cx, uintN argc, jsval * vp)
+{
+    jsval *argv = JS_ARGV(cx, vp);
+    char *msg = EMPTYSTRING;
+    JSString *str;
+    char inbuf[80];
+    char c;
+    eb_bool first = eb_true;
+
+    if(argc > 0 && (str = JS_ValueToString(jcx, argv[0]))) {
+	msg = transcode_get_js_bytes(str);
+    }
+
+    while(eb_true) {
+	printf("%s", msg);
+	c = 'x';
+	if(*msg)
+	    c = msg[strlen(msg) - 1];
+	if(!isspaceByte(c)) {
+	    if(!ispunctByte(c))
+		printf(":");
+	    printf(" ");
+	}
+	if(!first)
+	    printf("[y|n] ");
+	first = eb_false;
+	fflush(stdout);
+	if(!fgets(inbuf, sizeof (inbuf), stdin))
+	    exit(1);
+	c = *inbuf;
+	if(c && strchr("nNyY", c))
+	    break;
+    }
+
+    c = tolower(c);
+    if(c == 'y')
+	JS_SET_RVAL(cx, vp, JSVAL_TRUE);
+    else
+	JS_SET_RVAL(cx, vp, JSVAL_FALSE);
+    nzFree(msg);
+    return JS_TRUE;
+}				/* win_confirm */
+
+static JSClass timer_class = {
+    "Timer",
+    JSCLASS_HAS_PRIVATE,
+    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+};
+
+/* Set a timer or an interval */
+static JSObject *
+setTimeout(uintN argc, jsval * argv, eb_bool isInterval)
+{
+    jsval v0, v1;
+    JSObject *fo = 0;		/* function object */
+    JSObject *to;		/* tag object */
+    int n;			/* number of milliseconds */
+    char fname[48];		/* function name */
+    const char *fstr;		/* function string */
+    const char *methname = (isInterval ? "setInterval" : "setTimeout");
+    char *allocatedName = NULL;
+    char *s = NULL;
+
+    if(!parsePage) {
+	JS_ReportError(jcx,
+	   "cannot use %s() to delay the execution of a function", methname);
+	return NULL;
+    }
+
+    if(argc != 2 || !JSVAL_IS_INT(argv[1]))
+	goto badarg;
+
+    v0 = argv[0];
+    v1 = argv[1];
+    n = JSVAL_TO_INT(v1);
+
+    if(JSVAL_IS_STRING(v0) ||
+       JSVAL_IS_OBJECT(v0) &&
+       JS_ValueToObject(jcx, v0, &fo) && JS_ObjectIsFunction(jcx, fo)) {
+
+/* build the tag object and link it to window */
+	to = JS_NewObject(jcx, &timer_class, NULL, (JSObject *) jwin);
+	v1 = OBJECT_TO_JSVAL(to);
+	JS_DefineProperty(jcx, (JSObject *) jwin, fakePropName(), v1,
+	   NULL, NULL, JSPROP_READONLY | JSPROP_PERMANENT);
+
+	if(fo) {
+/* Extract the function name, which requires several steps */
+	    JSFunction *f = JS_ValueToFunction(jcx, OBJECT_TO_JSVAL(fo));
+	    JSString *jss = JS_GetFunctionId(f);
+	    if(jss)
+		allocatedName = our_JSEncodeString(jss);
+	    s = allocatedName;
+/* Remember that unnamed functions are named anonymous. */
+	    if(!s || !*s || stringEqual(s, "anonymous"))
+/* avoid compiler warning about string conversion */
+		s = (char *) string("javascript").c_str();
+	    int len = strlen(s);
+	    if(len > sizeof (fname) - 4)
+		len = sizeof (fname) - 4;
+	    strncpy(fname, s, len);
+	    nzFree(allocatedName);
+	    fname[len] = 0;
+	    strcat(fname, "()");
+	    fstr = fname;
+	    establish_property_object(to, "onclick", fo);
+	} else {
+/* compile the function from the string */
+	    fstr = stringize(v0);
+	    JS_CompileFunction(jcx, to, "onclick", 0, emptyParms,	/* no named parameters */
+	       fstr, strlen(fstr), "onclick", 1);
+	}
+
+	javaSetsTimeout(n, fstr, to, isInterval);
+	return to;
+    }
+
+  badarg:
+    JS_ReportError(jcx, "invalid arguments to %s()", methname);
+    return NULL;
+}				/* setTimeout */
+
+static JSBool
+win_sto(JSContext * cx, uintN argc, jsval * vp)
+{
+    jsval *argv = JS_ARGV(cx, vp);
+    JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(setTimeout(argc, argv, eb_false)));
+    return JS_TRUE;
+}				/* win_sto */
+
+static JSBool
+win_intv(JSContext * cx, uintN argc, jsval * vp)
+{
+    jsval *argv = JS_ARGV(cx, vp);
+    JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(setTimeout(argc, argv, eb_true)));
+    return JS_TRUE;
+}				/* win_intv */
+
+static JSFunctionSpec window_methods[] = {
+    {"alert", win_alert, 1, 0},
+    {"prompt", win_prompt, 2, 0},
+    {"confirm", win_confirm, 1, 0},
+    {"setTimeout", win_sto, 2, 0},
+    {"setInterval", win_intv, 2, 0},
+    {"open", win_open, 3, 0},
+    {"close", win_close, 0, 0},
+    {"focus", nullFunction, 0, 0},
+    {"blur", nullFunction, 0, 0},
+    {"scroll", nullFunction, 0, 0},
+    {0}
+};
+
+static JSClass doc_class = {
+    "Document",
+    JSCLASS_HAS_PRIVATE,
+    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+};
+
+static void
+dwrite2(const char *s)
+{
+    if(!cw->dw) {
+	cw->dw = initString(&cw->dw_l);
+	stringAndString(&cw->dw, &cw->dw_l, "<docwrite>");
+    }
+    stringAndString(&cw->dw, &cw->dw_l, s);
+}				/* dwrite2 */
+
+static void
+dwrite1(uintN argc, jsval * argv, eb_bool newline)
+{
+    int i;
+    char *msg;
+    JSString *str;
+    for(i = 0; i < argc; ++i) {
+	if((str = JS_ValueToString(jcx, argv[i])) &&
+	   (msg = transcode_get_js_bytes(str))) {
+	    dwrite2(msg);
+	    nzFree(msg);
+	}
+    }
+    if(newline)
+	dwrite2("\n");
+}				/* dwrite1 */
+
+static JSBool
+doc_write(JSContext * cx, uintN argc, jsval * vp)
+{
+    jsval *argv = JS_ARGV(cx, vp);
+    dwrite1(argc, argv, eb_false);
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    return JS_TRUE;
+}				/* doc_write */
+
+static JSBool
+setter_innerHTML(JSContext * cx, JSObject * obj, jsid id, JSBool strict,
+   jsval * vp)
+{
+    const char *s = stringize(*vp);
+    if(s && strlen(s)) {
+	dwrite2(parsePage ? "<hr>\n" : "<html>\n");
+	dwrite2(s);
+	if(s[strlen(s) - 1] != '\n')
+	    dwrite2("\n");
+    }
+/* The string has already been updated in the object. */
+    return JS_TRUE;
+}				/* setter_innerHTML */
+
+static JSBool
+setter_innerText(JSContext * cx, JSObject * obj, jsid id, JSBool strict,
+   jsval * vp)
+{
+    jsval v = *vp;
+    char *s;
+    if(!JSVAL_IS_STRING(v))
+	return JS_FALSE;
+    s = our_JSEncodeString(JSVAL_TO_STRING(v));
+    nzFree(s);
+    i_puts(MSG_InnerText);
+/* The string has already been updated in the object. */
+    return JS_TRUE;
+}				/* setter_innerText */
+
+static JSBool
+doc_writeln(JSContext * cx, uintN argc, jsval * vp)
+{
+    jsval *argv = JS_ARGV(cx, vp);
+    dwrite1(argc, argv, eb_true);
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    return JS_TRUE;
+}				/* doc_writeln */
+
+static JSFunctionSpec doc_methods[] = {
+    {"focus", nullFunction, 0, 0},
+    {"blur", nullFunction, 0, 0},
+    {"open", nullFunction, 0, 0},
+    {"close", nullFunction, 0, 0},
+    {"write", doc_write, 0, 0},
+    {"writeln", doc_writeln, 0, 0},
+    {0}
+};
+
+static JSClass element_class = {
+    "Element",
+    JSCLASS_HAS_PRIVATE,
+    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+};
+
+static JSFunctionSpec element_methods[] = {
+    {"focus", nullFunction, 0, 0},
+    {"blur", nullFunction, 0, 0},
+    {0}
+};
+
+static JSClass form_class = {
+    "Form",
+    JSCLASS_HAS_PRIVATE,
+    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+};
+
+static JSBool
+form_submit(JSContext * cx, uintN argc, jsval * vp)
+{
+    JSObject *obj = JS_THIS_OBJECT(cx, vp);
+    javaSubmitsForm(obj, eb_false);
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    return JS_TRUE;
+}				/* form_submit */
+
+static JSBool
+form_reset(JSContext * cx, uintN argc, jsval * vp)
+{
+    JSObject *obj = JS_THIS_OBJECT(cx, vp);
+    javaSubmitsForm(obj, eb_true);
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    return JS_TRUE;
+}				/* form_reset */
+
+static JSFunctionSpec form_methods[] = {
+    {"submit", form_submit, 0, 0},
+    {"reset", form_reset, 0, 0},
+    {0}
+};
+
+static JSClass body_class = {
+    "Body",
+    JSCLASS_HAS_PRIVATE,
+    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+};
+
+static JSFunctionSpec body_methods[] = {
+    {"setAttribute", setAttribute, 2, 0},
+    {"appendChild", appendChild, 1, 0},
+    {0}
+};
+
+static JSClass head_class = {
+    "Head",
+    JSCLASS_HAS_PRIVATE,
+    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+};
+
+static JSFunctionSpec head_methods[] = {
+    {"setAttribute", setAttribute, 2, 0},
+    {"appendChild", appendChild, 1, 0},
+    {0}
+};
+
+static JSClass meta_class = {
+    "Meta",
+    JSCLASS_HAS_PRIVATE,
+    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+};
+
+/* Don't be confused; this is for <link>, not <a> */
+static JSClass link_class = {
+    "Link",
+    JSCLASS_HAS_PRIVATE,
+    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+};
+
+static JSFunctionSpec link_methods[] = {
+    {"setAttribute", setAttribute, 2, 0},
+    {0}
+};
+
+static JSClass image_class = {
+    "Image",
+    JSCLASS_HAS_PRIVATE,
+    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+};
+
+static JSClass frame_class = {
+    "Frame",
+    JSCLASS_HAS_PRIVATE,
+    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+};
+
+static JSClass anchor_class = {
+    "Anchor",
+    JSCLASS_HAS_PRIVATE,
+    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+};
+
+static JSClass table_class = {
+    "Table",
+    JSCLASS_HAS_PRIVATE,
+    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+};
+
+static JSClass trow_class = {
+    "Trow",
+    JSCLASS_HAS_PRIVATE,
+    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+};
+
+static JSClass cell_class = {
+    "Cell",
+    JSCLASS_HAS_PRIVATE,
+    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+};
+
+static JSClass div_class = {
+    "Div",
+    JSCLASS_HAS_PRIVATE,
+    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+};
+
+static JSClass span_class = {
+    "Span",
+    JSCLASS_HAS_PRIVATE,
+    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+};
+
+static JSClass area_class = {
+    "Area",
+    JSCLASS_HAS_PRIVATE,
+    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+};
+
+static JSClass option_class = {
+    "Option",
+    JSCLASS_HAS_PRIVATE,
+    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+};
+
+struct DOMCLASS {
+    JSClass *objClass;
+    JSFunctionSpec *methods;
+    JSNative constructor;
+    int nargs;
+};
+
+static struct DOMCLASS domClasses[] = {
+    {&element_class, element_methods, nullFunction, 0},
+    {&form_class, form_methods},
+    {&body_class, body_methods},
+    {&head_class, head_methods},
+    {&meta_class},
+    {&link_class, link_methods, nullFunction, 0},
+    {&image_class, 0, nullFunction, 1},
+    {&frame_class},
+    {&anchor_class, 0, nullFunction, 1},
+    {&table_class},
+    {&div_class},
+    {&area_class},
+    {&span_class},
+    {&trow_class},
+    {&cell_class},
+    {&option_class},
+    {0}
+};
+
+static const char *docarrays[] = {
+    "heads", "bodies", "links", "tables", "divs", "spans",
+    "forms", "images", "areas", "metas", 0
+};
+
+
+/* Some things are just easier in javascript */
+static const char initScript[] = "document.all.tags = function(s) { \n\
+switch(s.toLowerCase()) { \n\
+case 'form': return document.forms; \n\
+case 'table': return document.tables; \n\
+case 'div': return document.divs; \n\
+case 'a': return document.links; \n\
+case 'img': case 'image': return document.images; \n\
+case 'span': return document.spans; \n\
+case 'head': return document.heads; \n\
+case 'meta': return document.metas; \n\
+case 'body': return document.bodies; \n\
+default: /* alert('all.tags default ' + s); */ return new Array(); }} \n\
+\n\
+document.getElementById = function(s) { \n\
+return document.idMaster[s]; } \n\
+\n\
+document.getElementsByTagName = function(s) { \n\
+return document.all.tags(s); }\n\
+\n\
+document.createElement = function(s) { \n\
+switch(s.toLowerCase()) { \n\
+case 'link': return new Link();\n\
+case 'image': case 'img': return new Image();\n\
+default: /* alert('createElement default ' + s); */ return new Object(); }} \n\
+\n\
+URL.prototype.indexOf = function(s) { \n\
+return this.toString().indexOf(s); }\n\
+URL.prototype.lastIndexOf = function(s) { \n\
+return this.toString().lastIndexOf(s); }\n\
+URL.prototype.substring = function(from, to) { \n\
+return this.toString().substring(from, to); }\n\
+URL.prototype.toLowerCase = function() { \n\
+return this.toString().toLowerCase(); }\n\
+URL.prototype.toUpperCase = function() { \n\
+return this.toString().toUpperCase(); }\n\
+URL.prototype.match = function(s) { \n\
+return this.toString().match(s); }\n\
+\n\
+history.toString = function() { \n\
+return 'Sorry, edbrowse does not maintain a browsing history.'; } \
+";
+
+void *
+createJavaContext(void)
+{
+    static JSRuntime *jrt;
+    JSObject *o, *nav, *screen, *hist, *del;
+/* navigator mime types and plugins */
+    JSObject *navmt, *navpi;
+    const char *itemname;
+    int i;
+    char verx11[20];
+    jsval rval;
+    struct MIMETYPE *mt;
+
+    if(!jrt) {
+/* 4 meg js space - should this be configurable? */
+	jrt = JS_NewRuntime(4L * 1024L * 1024L);
+	if(!jrt)
+	    i_printfExit(MSG_JavaMemError);
+	gOutFile = stdout;
+	gErrFile = stderr;
+    }
+
+    jcx = JS_NewContext(jrt, gStackChunkSize);
+    if(!jcx)
+	i_printfExit(MSG_JavaContextError);
+    JS_SetErrorReporter(jcx, my_ErrorReporter);
+    JS_SetOptions(jcx, JSOPTION_VAROBJFIX);
+
+/* Create the Window object, which is the global object in DOM. */
+//    jwin = JS_NewObject(jcx, &window_class, NULL, NULL);
+    jwin = JS_NewCompartmentAndGlobalObject(jcx, &window_class, NULL);
+    if(!jwin)
+	i_printfExit(MSG_JavaWindowError);
+    JS_InitClass(jcx, (JSObject *) jwin, 0, &window_class, window_ctor, 3,
+       NULL, window_methods, NULL, NULL);
+
+/* Ok, but the global object was created before the class,
+ * so it doesn't have its methods yet. */
+    JS_DefineFunctions(jcx, (JSObject *) jwin, window_methods);
+
+/* Math, Date, Number, String, etc */
+    if(!JS_InitStandardClasses(jcx, (JSObject *) jwin))
+	i_printfExit(MSG_JavaClassError);
+
+    establish_property_object((JSObject *) jwin, "window", (JSObject *) jwin);
+    establish_property_object((JSObject *) jwin, "self", (JSObject *) jwin);
+    establish_property_object((JSObject *) jwin, "parent", (JSObject *) jwin);
+    establish_property_object((JSObject *) jwin, "top", (JSObject *) jwin);
+
+/* Some visual attributes of the window.
+ * These are just guesses.
+ * Better to have something, than to leave them undefined. */
+    establish_property_number((JSObject *) jwin, "height", 768, eb_true);
+    establish_property_number((JSObject *) jwin, "width", 1024, eb_true);
+    establish_property_string((JSObject *) jwin, "status", 0, eb_false);
+    establish_property_string((JSObject *) jwin, "defaultStatus", 0, eb_false);
+    establish_property_bool((JSObject *) jwin, "returnValue", eb_true, eb_false);
+    establish_property_bool((JSObject *) jwin, "menubar", eb_true, eb_false);
+    establish_property_bool((JSObject *) jwin, "scrollbars", eb_true, eb_false);
+    establish_property_bool((JSObject *) jwin, "toolbar", eb_true, eb_false);
+    establish_property_bool((JSObject *) jwin, "resizable", eb_true, eb_false);
+    establish_property_bool((JSObject *) jwin, "directories", eb_false, eb_false);
+    establish_property_string((JSObject *) jwin, "name", "unspecifiedFrame", eb_false);
+
+/* Other classes that we'll need. */
+    for(i = 0; domClasses[i].objClass; ++i) {
+	JS_InitClass(jcx, (JSObject *) jwin, 0, domClasses[i].objClass,
+	   domClasses[i].constructor, domClasses[i].nargs,
+	   NULL, domClasses[i].methods, NULL, NULL);
+    }
+
+    initLocationClass();
+
+/* document under window */
+    JS_InitClass(jcx, (JSObject *) jwin, 0, &doc_class, NULL, 0,
+       NULL, doc_methods, NULL, NULL);
+    jdoc = JS_NewObject(jcx, &doc_class, NULL, (JSObject *) jwin);
+    if(!(JSObject *) jdoc)
+	i_printfExit(MSG_JavaObjError);
+    establish_property_object((JSObject *) jwin, "document", (JSObject *) jdoc);
+
+    establish_property_string((JSObject *) jdoc, "bgcolor", "white", eb_false);
+    establish_property_string((JSObject *) jdoc, "cookie", 0, eb_false);
+    establish_property_string((JSObject *) jdoc, "referrer", cw->referrer, eb_true);
+    establish_property_url((JSObject *) jdoc, "URL", cw->fileName, eb_true);
+    establish_property_url((JSObject *) jdoc, "location", cw->fileName, eb_false);
+    establish_property_url((JSObject *) jwin, "location", cw->firstURL, eb_false);
+    establish_property_string((JSObject *) jdoc, "domain", getHostURL(cw->fileName), eb_false);
+
+/* create arrays under document */
+    for(i = 0; itemname = docarrays[i]; ++i)
+	establish_property_array((JSObject *) jdoc, itemname);
+
+/* Some arrays are under window */
+    establish_property_array((JSObject *) jwin, "frames");
+
+    o = JS_NewObject(jcx, 0, 0, (JSObject *) jdoc);
+    establish_property_object((JSObject *) jdoc, "idMaster", o);
+    o = JS_NewObject(jcx, 0, 0, (JSObject *) jdoc);
+    establish_property_object((JSObject *) jdoc, "all", o);
+
+    nav = JS_NewObject(jcx, 0, 0, (JSObject *) jwin);
+    establish_property_object((JSObject *) jwin, "navigator", nav);
+
+/* attributes of the navigator */
+    establish_property_string(nav, "appName", "edbrowse", eb_true);
+    establish_property_string(nav, "appCode Name", "edbrowse C/SMJS", eb_true);
+/* Use X11 to indicate unix/linux.  Sort of a standard */
+    sprintf(verx11, "%s%s", version, "-X11");
+    establish_property_string(nav, "appVersion", version, eb_true);
+    establish_property_string(nav, "userAgent", currentAgent, eb_true);
+    establish_property_string(nav, "oscpu", currentOS(), eb_true);
+    establish_property_string(nav, "platform", currentMachine(), eb_true);
+    establish_property_string(nav, "product", "smjs", eb_true);
+    establish_property_string(nav, "productSub", "1.5", eb_true);
+    establish_property_string(nav, "vendor", "eklhad", eb_true);
+    establish_property_string(nav, "vendorSub", version, eb_true);
+/* We need to locale-ize the next one */
+    establish_property_string(nav, "userLanguage", "english", eb_true);
+    establish_property_string(nav, "language", "english", eb_true);
+    JS_DefineFunction(jcx, nav, "javaEnabled", falseFunction, 0, PROP_FIXED);
+    JS_DefineFunction(jcx, nav, "taintEnabled", falseFunction, 0, PROP_FIXED);
+    establish_property_bool(nav, "cookieEnabled", eb_true, eb_true);
+    establish_property_bool(nav, "onLine", eb_true, eb_true);
+
+/* Build the array of mime types and plugins,
+ * according to the entries in the config file. */
+    navpi = (JSObject *) establish_property_array(nav, "plugins");
+    navmt = (JSObject *) establish_property_array(nav, "mimeTypes");
+    mt = mimetypes;
+    for(i = 0; i < maxMime; ++i, ++mt) {
+/* po is the plugin object and mo is the mime object */
+	JSObject *mo, *po;
+	jsval mov, pov;
+	int len;
+
+	po = JS_NewObject(jcx, 0, 0, nav);
+	pov = OBJECT_TO_JSVAL(po);
+	JS_DefineElement(jcx, navpi, i, pov, NULL, NULL, PROP_FIXED);
+	mo = JS_NewObject(jcx, 0, 0, nav);
+	mov = OBJECT_TO_JSVAL(mo);
+	JS_DefineElement(jcx, navmt, i, mov, NULL, NULL, PROP_FIXED);
+	establish_property_object(mo, "enabledPlugin", po);
+	establish_property_string(mo, "type", mt->type, eb_true);
+	establish_property_object(navmt, mt->type, mo);
+	establish_property_string(mo, "description", mt->desc, eb_true);
+	establish_property_string(mo, "suffixes", mt->suffix, eb_true);
+/* I don't really have enough information, from the config file, to fill
+ * in the attributes of the plugin object.
+ * I'm just going to fake it.
+ * Description will be the same as that of the mime type,
+ * and the filename will be the program to run.
+ * No idea if this is right or not. */
+	establish_property_string(po, "description", mt->desc, eb_true);
+	establish_property_string(po, "filename", mt->program, eb_true);
+/* For the name, how about the program without its options? */
+	len = strcspn(mt->program, " \t");
+	JS_DefineProperty(jcx, po, "name",
+	   STRING_TO_JSVAL(our_JS_NewStringCopyN(jcx, mt->program, len)),
+	   0, 0, PROP_FIXED);
+    }
+
+    screen = JS_NewObject(jcx, 0, 0, (JSObject *) jwin);
+    establish_property_object((JSObject *) jwin, "screen", screen);
+    establish_property_number(screen, "height", 768, eb_true);
+    establish_property_number(screen, "width", 1024, eb_true);
+    establish_property_number(screen, "availHeight", 768, eb_true);
+    establish_property_number(screen, "availWidth", 1024, eb_true);
+    establish_property_number(screen, "availTop", 0, eb_true);
+    establish_property_number(screen, "availLeft", 0, eb_true);
+
+    del = JS_NewObject(jcx, 0, 0, (JSObject *) jdoc);
+    establish_property_object((JSObject *) jdoc, "body", del);
+    establish_property_object((JSObject *) jdoc, "documentElement", del);
+    establish_property_number(del, "clientHeight", 768, eb_true);
+    establish_property_number(del, "clientWidth", 1024, eb_true);
+    establish_property_number(del, "offsetHeight", 768, eb_true);
+    establish_property_number(del, "offsetWidth", 1024, eb_true);
+    establish_property_number(del, "scrollHeight", 768, eb_true);
+    establish_property_number(del, "scrollWidth", 1024, eb_true);
+    establish_property_number(del, "scrollTop", 0, eb_true);
+    establish_property_number(del, "scrollLeft", 0, eb_true);
+
+    hist = JS_NewObject(jcx, 0, 0, (JSObject *) jwin);
+    establish_property_object((JSObject *) jwin, "history", hist);
+
+/* attributes of history */
+    establish_property_string(hist, "current", cw->fileName, eb_true);
+/* There's no history in edbrowse. */
+/* Only the current file is known, hence length is 1. */
+    establish_property_number(hist, "length", 1, eb_true);
+    establish_property_string(hist, "next", 0, eb_true);
+    establish_property_string(hist, "previous", 0, eb_true);
+    JS_DefineFunction(jcx, hist, "back", nullFunction, 0, PROP_FIXED);
+    JS_DefineFunction(jcx, hist, "forward", nullFunction, 0, PROP_FIXED);
+    JS_DefineFunction(jcx, hist, "go", nullFunction, 0, PROP_FIXED);
+
+/* Set up some things in javascript */
+    JS_EvaluateScript(jcx, (JSObject *) jwin, initScript, strlen(initScript),
+       "initScript", 1, &rval);
+
+    return jcx;
+}				/* createJavaContext */
+
+void
+freeJavaContext(void *jsc)
+{
+    if(jsc)
+	JS_DestroyContext((JSContext *) jsc);
+}				/* freeJavaContext */
+
+void
+establish_innerHTML(void *jv, const char *start, const char *end, eb_bool is_ta)
+{
+    JSObject *obj = (JSObject *) jv, *o;
+    jsval v;
+
+    if(!obj)
+	return;
+
+/* null start means the pointer has been corrupted by a document.write() call */
+    if(!start)
+	start = end = EMPTYSTRING;
+    JS_DefineProperty(jcx, obj, "innerHTML",
+       STRING_TO_JSVAL(our_JS_NewStringCopyN(jcx, start, end - start)),
+       NULL, (is_ta ? setter_innerText : setter_innerHTML),
+       JSPROP_ENUMERATE | JSPROP_PERMANENT);
+    if(is_ta) {
+	JS_DefineProperty(jcx, obj, "innerText",
+	   STRING_TO_JSVAL(our_JS_NewStringCopyN(jcx, start, end - start)),
+	   NULL, setter_innerText, JSPROP_ENUMERATE | JSPROP_PERMANENT);
+    }
+
+/* Anything with an innerHTML might also have a style. */
+    o = JS_NewObject(jcx, 0, 0, obj);
+    v = OBJECT_TO_JSVAL(o);
+    JS_DefineProperty(jcx, obj, "style", v, NULL, NULL, JSPROP_ENUMERATE);
+}				/* establish_innerHTML */
+
+void
+jMyContext(void)
+{
+    jsval oval;
+    jcx = (JSContext *) cw->jsc;
+    if(jcx) {
+	jwin = JS_GetGlobalObject(jcx);
+	JS_GetProperty(jcx, (JSObject *) jwin, "document", &oval);
+	jdoc = JSVAL_TO_OBJECT(oval);
+	JS_GetProperty(jcx, (JSObject *) jwin, "location", &oval);
+	jwloc = JSVAL_TO_OBJECT(oval);
+	JS_GetProperty(jcx, (JSObject *) jdoc, "location", &oval);
+	jdloc = JSVAL_TO_OBJECT(oval);
+    } else
+	jwin = jdoc = jwloc = jdloc = 0;
+}				/* jMyContext */
+
+eb_bool
+javaParseExecute(void *obj, const char *str, const char *filename, int lineno)
+{
+    JSBool ok;
+    eb_bool rc;
+    jsval rval;
+
+/* Sometimes Mac puts these three chars at the start of a text file. */
+    if(!strncmp(str, "\xef\xbb\xbf", 3))
+	str += 3;
+
+    debugPrint(6, "javascript:\n%s", str);
+    ok = JS_EvaluateScript(jcx, (JSObject *) obj, str, strlen(str),
+       filename, lineno, &rval);
+    rc = eb_true;
+    if(JSVAL_IS_BOOLEAN(rval))
+	rc = JSVAL_TO_BOOLEAN(rval);
+    JS_GC(jcx);
+    return rc;
+}				/* javaParseExecute */
+
+/* link a frame, span, anchor, etc to the document object model */
+void *
+domLink(const char *classname,	/* instantiate this class */
+   const char *symname, const char *idname, const char *href, const char *href_url, const char *list,	/* next member of this array */
+   void *owner, int radiosel)
+{
+    JSObject *v = 0, *w, *alist = 0, *master;
+    jsval vv, listv;
+    jsuint length, attr = PROP_FIXED;
+    JSClass *cp;
+    eb_bool dupname = eb_false;
+    int i;
+
+    if(cw->jsdead)
+	return 0;
+
+/* find the class */
+    for(i = 0; cp = domClasses[i].objClass; ++i)
+	if(stringEqual(cp->name, classname))
+	    break;
+
+    if(symname) {
+	JSBool found;
+	JS_HasProperty(jcx, (JSObject *) owner, symname, &found);
+	if(found) {
+
+/*********************************************************************
+This could be a duplicate name.
+Yes, that really happens.
+Link to the first tag having this name,
+and link the second tag under a fake name, so gc won't throw it away.
+Or - it could be a duplicate name because multiple radio buttons
+all share the same name.
+The first time we create the array, and thereafter we just link
+under that array.
+Or - and this really does happen -
+an input tag could have the name action, colliding with form.action.
+I have no idea what to do here.
+I will assume the tag displaces the action.
+That means javascript cannot change the action of the form,
+which it rarely does anyways.
+When it refers to form.action, that will be the input tag.
+I'll check for that one first.
+Ok???
+Yeah, it makes my head spin too.
+*********************************************************************/
+
+	    if(stringEqual(symname, "action")) {
+		JSObject *ao;	/* action object */
+		JS_GetProperty(jcx, (JSObject *) owner, symname, &vv);
+		ao = JSVAL_TO_OBJECT(vv);
+/* actioncrash tells me if we've already had this collision */
+		JS_HasProperty(jcx, ao, "actioncrash", &found);
+		if(!found) {
+		    JS_DeleteProperty(jcx, (JSObject *) owner, symname);
+/* gc will clean this up later */
+/* advance, as though this were not found */
+		    goto afterfound;
+		}
+	    }
+
+	    if(radiosel == 1) {
+		JS_GetProperty(jcx, (JSObject *) owner, symname, &vv);
+		v = JSVAL_TO_OBJECT(vv);
+	    } else {
+		dupname = eb_true;
+	    }
+	}
+    }
+
+  afterfound:
+    if(!v) {
+	if(radiosel) {
+	    v = JS_NewArrayObject(jcx, 0, NULL);
+	    if(radiosel == 1) {
+		establish_property_string(v, "type", "radio", eb_true);
+	    } else {
+/* self-referencing - hope this is ok */
+		establish_property_object(v, "options", v);
+		establish_property_number(v, "selectedIndex", -1, eb_false);
+// not the normal pathway; we have to create our own element methods here.
+		JS_DefineFunction(jcx, v, "focus", nullFunction, 0, PROP_FIXED);
+		JS_DefineFunction(jcx, v, "blur", nullFunction, 0, PROP_FIXED);
+	    }
+	} else {
+	    v = JS_NewObject(jcx, cp, NULL, (JSObject *) owner);
+	}
+	vv = OBJECT_TO_JSVAL(v);
+
+/* if no name, then use id as name */
+	if(!symname && idname) {
+	    JS_DefineProperty(jcx, (JSObject *) owner, idname, vv, NULL, NULL, attr);
+	} else if(symname && !dupname) {
+	    JS_DefineProperty(jcx, (JSObject *) owner, symname, vv, NULL, NULL, attr);
+	    if(stringEqual(symname, "action"))
+		establish_property_bool(v, "actioncrash", eb_true, eb_true);
+
+/* link to document.all */
+	    JS_GetProperty(jcx, (JSObject *) jdoc, "all", &listv);
+	    master = JSVAL_TO_OBJECT(listv);
+	    establish_property_object(master, symname, v);
+	} else {
+/* tie this to something, to protect it from gc */
+	    JS_DefineProperty(jcx, (JSObject *) owner, fakePropName(), vv,
+	       NULL, NULL, JSPROP_READONLY | JSPROP_PERMANENT);
+	}
+
+	if(list) {
+	    JS_GetProperty(jcx, (JSObject *) owner, list, &listv);
+	    alist = JSVAL_TO_OBJECT(listv);
+	}
+	if(alist) {
+	    JS_GetArrayLength(jcx, alist, &length);
+	    JS_DefineElement(jcx, alist, length, vv, NULL, NULL, attr);
+	    if(symname && !dupname)
+		establish_property_object(alist, symname, v);
+	    if(idname && (!symname || !stringEqual(symname, idname)))
+		establish_property_object(alist, idname, v);
+	}			/* list indicated */
+    }
+
+    if(radiosel == 1) {
+/* drop down to the element within the radio array, and return that element */
+/* w becomes the object associated with this radio button */
+/* v is, by assumption, an array */
+	JS_GetArrayLength(jcx, v, &length);
+	w = JS_NewObject(jcx, &element_class, NULL, (JSObject *) owner);
+	vv = OBJECT_TO_JSVAL(w);
+	JS_DefineElement(jcx, v, length, vv, NULL, NULL, attr);
+	v = w;
+    }
+
+    if(symname)
+	establish_property_string(v, "name", symname, eb_true);
+    if(idname) {
+/* v.id becomes idname, and idMaster.idname becomes v
+ * In case of forms, v.id should remain undefined.  So we can have
+ * a form field named "id". */
+	if(strcmp(classname, "Form") != 0)
+	    establish_property_string(v, "id", idname, eb_true);
+	JS_GetProperty(jcx, (JSObject *) jdoc, "idMaster", &listv);
+	master = JSVAL_TO_OBJECT(listv);
+	establish_property_object(master, idname, v);
+    } else {
+	if(strcmp(classname, "Form") != 0)
+	    establish_property_string(v, "id", EMPTYSTRING, eb_true);
+    }
+
+    if(href && href_url) {
+	establish_property_url(v, href, href_url, eb_false);
+    }
+
+    if(cp == &element_class) {
+/* link back to the form that owns the element */
+	establish_property_object(v, "form", (JSObject *) owner);
+    }
+
+    return v;
+}				/* domLink */
-- 
1.8.5.2.297.g3e57c29


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2013-12-24 17:58 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-12-24 17:57 [Edbrowse-dev] [PATCH] Initial version of jsdom.cpp (built agains mozjs 1.85) This compiles under g++ Adam Thompson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).