/* forward typedefs */ typedef struct MethSpec MethSpec; typedef struct PropSpec PropSpec; typedef struct ObjSpec ObjSpec; /* types and constants */ #define ReadOnly 1 struct MethSpec { Rune* name; Rune** args; }; #define IVundef 0 #define IVnull 1 #define IVtrue 2 #define IVfalse 3 #define IVnullstr 4 #define IVzero 5 #define IVzerostr 6 #define IVarray 7 struct PropSpec { Rune* name; int attr; int initval; }; struct ObjSpec { Rune* name; MethSpec* methods; PropSpec* props; Obj* prototype; }; struct Objpint_pair { Obj* t0; int t1; }; /* globals */ Modlink* E; Modlink* me; Modlink* sys; Modlink* CU; Modlink* D; Modlink* S; Modlink* T; Modlink* C; Modlink* U; Modlink* EV; ObjSpec objspecs[17]= {makeObjSpec(L"Anchor", nil, (PropSpec*)malloc(1 * sizeof(PropSpec))/* TODO initialize! */, nil), makeObjSpec(L"Applet", nil, nil, nil), makeObjSpec(L"Area", (MethSpec*)malloc(1 * sizeof(MethSpec))/* TODO initialize! */, (PropSpec*)malloc(10 * sizeof(PropSpec))/* TODO initialize! */, nil), makeObjSpec(L"document", (MethSpec*)malloc(9 * sizeof(MethSpec))/* TODO initialize! */, (PropSpec*)malloc(19 * sizeof(PropSpec))/* TODO initialize! */, nil), makeObjSpec(L"Event", nil, (PropSpec*)malloc(13 * sizeof(PropSpec))/* TODO initialize! */, nil), makeObjSpec(L"Form", (MethSpec*)malloc(3 * sizeof(MethSpec))/* TODO initialize! */, (PropSpec*)malloc(7 * sizeof(PropSpec))/* TODO initialize! */, nil), makeObjSpec(L"FormField", (MethSpec*)malloc(3 * sizeof(MethSpec))/* TODO initialize! */, (PropSpec*)malloc(10 * sizeof(PropSpec))/* TODO initialize! */, nil), makeObjSpec(L"History", (MethSpec*)malloc(3 * sizeof(MethSpec))/* TODO initialize! */, (PropSpec*)malloc(4 * sizeof(PropSpec))/* TODO initialize! */, nil), makeObjSpec(L"Image", (MethSpec*)malloc(1 * sizeof(MethSpec))/* TODO initialize! */, (PropSpec*)malloc(10 * sizeof(PropSpec))/* TODO initialize! */, nil), makeObjSpec(L"Link", (MethSpec*)malloc(1 * sizeof(MethSpec))/* TODO initialize! */, (PropSpec*)malloc(10 * sizeof(PropSpec))/* TODO initialize! */, nil), makeObjSpec(L"Location", (MethSpec*)malloc(2 * sizeof(MethSpec))/* TODO initialize! */, (PropSpec*)malloc(8 * sizeof(PropSpec))/* TODO initialize! */, nil), makeObjSpec(L"MimeType", nil, (PropSpec*)malloc(4 * sizeof(PropSpec))/* TODO initialize! */, nil), makeObjSpec(L"Option", nil, (PropSpec*)malloc(4 * sizeof(PropSpec))/* TODO initialize! */, nil), makeObjSpec(L"navigator", (MethSpec*)malloc(4 * sizeof(MethSpec))/* TODO initialize! */, (PropSpec*)malloc(8 * sizeof(PropSpec))/* TODO initialize! */, nil), makeObjSpec(L"Plugin", nil, (PropSpec*)malloc(4 * sizeof(PropSpec))/* TODO initialize! */, nil), makeObjSpec(L"screen", nil, (PropSpec*)malloc(6 * sizeof(PropSpec))/* TODO initialize! */, nil), makeObjSpec(L"Window", (MethSpec*)malloc(30 * sizeof(MethSpec))/* TODO initialize! */, (PropSpec*)malloc(26 * sizeof(PropSpec))/* TODO initialize! */, nil)}; int dbg; Docinfo* doc; Exec* mainex; Rune* docwriteout = L""; Val* nullstrval; Val* zeroval; Val* zerostrval; /* function forward declarations */ void init(Modlink* cu, Docinfo* d); RunepRunep_pair evalscript(Rune* s); void do_on(ScriptEvent* e); Val* get(Exec* ex, Obj* o, Rune* property); void put(Exec* ex, Obj* o, Rune* property, Val* val); Val* canput(Exec* ex, Obj* o, Rune* property); Val* hasproperty(Exec* ex, Obj* o, Rune* property); void delete(Exec* ex, Obj* o, Rune* property); Val* defaultval(Exec* ex, Obj* o, int tyhint); Ref* call(Exec* ex, Obj* func, Obj* this, Val** args); Obj* construct(Exec* UNKNOWN, Obj* UNKNOWN, Val** UNKNOWN); Obj* mkhostobj(Rune* class, Exec* ex); int specindex(Rune* class); Obj* fillinprototype(int ci, Exec* ex); Obj* getframeobj(int frameid); Obj* getdocobj(int frameid); Obj* getformobj(int frameid, int formid); Obj* getformfieldobj(int frameid, int formid, int fieldid); Obj* getobj(Obj* o, Rune* prop); Obj* getarrayelem(Obj* o, Rune* arrayname, int index); Rune* getstr(Obj* o, Rune* prop); int pind(Obj* o, Rune* prop); void reinitprop(Obj* o, Rune* prop, Val* v); Objpint_pair getarraywithlen(Exec* ex, Obj* o, Rune* aname); void arrayput(Exec* ex, Obj* oarray, int index, Rune* name, Val* v); void wininstant(Exec* ex, Obj* w); void winxfer(Exec* ex, Obj* w); Val* docinstant(Exec* ex, Docinfo* di); void docfill(Exec* ex, Obj* od, Docinfo* di); void docxfer(Exec* ex, Obj* od, Docinfo* di); Val* forminstant(Exec* ex, Form* form, int frameid); Val* fieldinstant(Exec* ex, Formfield* field, Obj* oform); void puthandler(Exec* ex, Obj* o, Rune* hname, Rune* hbody); Val* anchorinstant(Exec* ex, DestAnchor* dest); Val* linkinstant(Exec* ex, Anchor* anchor); Val* colorval(int v); int colorxfer(Exec* ex, Obj* o, Rune* name, int dflt); Rune* strxfer(Exec* ex, Obj* o, Rune* name, Rune* dflt); /* functions */ void init(Modlink* cu, Docinfo* d) { Obj* mainwinobj; CU = cu; sys = sys; D = D; S = S; T = T; U = U; C = C; EV = E; doc = d; E = /* TODO load PATH */; if(E == nil) raise(L"EXInternal: couldn't load Ecmascript"); init(); me = /* TODO load SELF */; if(me == nil) raise(L"EXInternal: can't load self as a ESHostobj"); dbg = (config).dbg[115]; if(dbg > 1) { debug[112] = 1; debug[101] = 1; debug[118] = 1; } nullstrval = strval(L""); zeroval = numval(0.0); zerostrval = strval(L"0"); mainwinobj = mkhostobj(L"Window", nil); mainex = mkexec(mainwinobj); mainwinobj->prototype = mainex->objproto; mainwinobj->prototype = fillinprototype(specindex(L"Window"), mainex); wininstant(mainex, mainwinobj); } RunepRunep_pair evalscript(Rune* s) { Exception* exc; Obj* od; docwriteout = L""; exc = copyException((Exception); if(rescue(L"ecmascript*", exc) == EXCEPTION) { return makeRunepRunep_pair(mainex->error, docwriteout); } od = getobj(mainex->global, L"document"); if(od != nil) docfill(mainex, od, doc); if(s != L"") { eval(mainex, s); winxfer(mainex, mainex->global); } return makeRunepRunep_pair(L"", docwriteout); } void do_on(ScriptEvent* e) { Obj* target; Obj* oscript; if(dbg) trace("do_on %d, frameid=%d, formid=%d, fieldid=%d, anchorid=%d, x=%d, y=%d, which=%d\n", e->kind, e->frameid, e->formid, e->fieldid, e->anchorid, e->x, e->y, e->which); target = nil; if(e->formid > 0) { if(e->fieldid > 0) target = getformfieldobj(e->frameid, e->formid, e->fieldid); else target = getformobj(e->frameid, e->formid); } ; if(target != nil) { switch(e->kind) { case Aonclick: oscript = getobj(target, L"onclick"); break; default: trace("got another script event to implement: %d\n", e->kind); break; } if(oscript != nil) { if(dbg) trace("calling script\n"); call(mainex, oscript, target, nil); } } } Val* get(Exec* ex, Obj* o, Rune* property) { return get(ex, o, property); } void put(Exec* ex, Obj* o, Rune* property, Val* val) { return put(ex, o, property, val); } Val* canput(Exec* ex, Obj* o, Rune* property) { return canput(ex, o, property); } Val* hasproperty(Exec* ex, Obj* o, Rune* property) { return hasproperty(ex, o, property); } void delete(Exec* ex, Obj* o, Rune* property) { return delete(ex, o, property); } Val* defaultval(Exec* ex, Obj* o, int tyhint) { return defaultval(ex, o, tyhint); } Ref* call(Exec* ex, Obj* func, Obj* this, Val** args) { int frameid; int formid; int ftype; Val* vframeid; Val* vformid; Channel* sync; // TODO: declare Rune* tmp_1 if(!Strcmp(tmp_1, L"document.prototype.write") { Strncat(docwriteout, toString(ex, biarg(args, 0)), FIXME); } else if(!Strcmp(tmp_1, L"document.prototype.writeln") { Strncat(docwriteout, newStr2(toString(ex, biarg(args, 0)), L"\n"), FIXME); } else if(!Strcmp(tmp_1, L"Form.prototype.reset" || !Strcmp(tmp_1, L"Form.prototype.submit") { vframeid = get(ex, this, L"PRIVframeid"); vformid = get(ex, this, L"PRIVformid"); if(isnum(vframeid) && isnum(vformid)) { frameid = toInt32(ex, vframeid); formid = toInt32(ex, vformid); ; if(!Strcmp(func->val->str, L"Form.prototype.reset")) ftype = EFreset; else ftype = EFsubmit; // TODO: declare tmp_2 tmp_2 = copyEform((Event.Eform(frameid, formid, ftype)); send(evchan, &tmp_2); } } else if(!Strcmp(tmp_1, L"Window.prototype.alert") { sync = newchan(sizeof(int), 0); // TODO: declare tmp_3 tmp_3 = copyEalert((Event.Ealert(toString(ex, biarg(args, 0)), sync)); send(evchan, &tmp_3); /* TODO: declare tmp_4*/ (recv(sync, &tmp_4), tmp_4); } else if(1 /* TODO: put this case at end */) { runtime(ex, newStr2(newStr2(L"unknown or unimplemented func ", func->val->str), L" in host call")); return nil; } return valref(true); } Obj* construct(Exec* UNKNOWN, Obj* UNKNOWN, Val** UNKNOWN) { return nil; } Obj* mkhostobj(Rune* class, Exec* ex) { int ci; Obj* ans; PropSpec* props; int i; Obj* ao; Val* v; ci = specindex(class); if(objspecs[ci].prototype == nil && ex != nil) fillinprototype(ci, ex); ans = mkobj(objspecs[ci].prototype, class); props = objspecs[ci].props; for(i = 0; i < arraylen(props); i++) { v = undefined; switch(props[i].initval) { case IVundef: v = undefined; break; case IVnull: v = null; break; case IVtrue: v = true; break; case IVfalse: v = false; break; case IVnullstr: v = nullstrval; break; case IVzero: v = zeroval; break; case IVzerostr: v = zerostrval; break; case IVarray: ao = mkobj(ex->arrayproto, L"Array"); varinstant(ao, DontEnum|DontDelete, L"length", newRefVal(numval(0.0))); v = objval(ao); break; default: assert(0); break; } varinstant(ans, props[i].attr|DontDelete, props[i].name, newRefVal(v)); } return ans; } int specindex(Rune* class) { int i; for(i = 0; i < arraylen(objspecs); i++) if(!Strcmp(objspecs[i].name, class)) break; ; if(i == arraylen(objspecs)) raise(newStr2(L"EXInternal: couldn't find host object class ", class)); return i; } Obj* fillinprototype(int ci, Exec* ex) { Rune* class; Obj* prototype; MethSpec* meths; int k; Rune* name; Rune* fullname; Rune** args; assert(ex != nil); class = objspecs[ci].name; prototype = mkobj(ex->objproto, class); meths = objspecs[ci].methods; for(k = 0; k < arraylen(meths); k++) { name = meths[k].name; fullname = newStr2(newStr2(class, L".prototype."), name); args = meths[k].args; biinst(prototype, makeBuiltin(name, fullname, args, arraylen(args)), ex->funcproto, me); } objspecs[ci].prototype = prototype; return prototype; } Obj* getframeobj(int frameid) { Val* vid; vid = get(mainex, mainex->global, L"PRIVframeid"); if(isnum(vid) && toInt32(mainex, vid) == frameid) return mainex->global; return nil; } Obj* getdocobj(int frameid) { return getobj(getframeobj(frameid), L"document"); } Obj* getformobj(int frameid, int formid) { return getarrayelem(getdocobj(frameid), L"forms", formid - 1); } Obj* getformfieldobj(int frameid, int formid, int fieldid) { return getarrayelem(getformobj(frameid, formid), L"elements", fieldid - 1); } Obj* getobj(Obj* o, Rune* prop) { Val* v; if(o != nil) { v = get(mainex, o, prop); if(isobj(v)) return toObject(mainex, v); } return nil; } Obj* getarrayelem(Obj* o, Rune* arrayname, int index) { Obj* oarr; Val* v; oarr = getobj(o, arrayname); if(oarr != nil) { v = get(mainex, oarr, ltoStr(index)); if(isobj(v)) return toObject(mainex, v); } return nil; } Rune* getstr(Obj* o, Rune* prop) { Val* v; if(o != nil) { v = get(mainex, o, prop); if(isstr(v)) return toString(mainex, v); } return L""; } int pind(Obj* o, Rune* prop) { Prop** props; int i; props = o->props; for(i = 0; i < arraylen(props); i++) { if(props[i] != nil && !Strcmp(props[i]->name, prop)) return i; } return -1; } void reinitprop(Obj* o, Rune* prop, Val* v) { int i; i = pind(o, prop); if(i < 0) runtime(mainex, newStr2(L"missing property ", prop)); assert(i >= 0); o->props[i]->val->val = v; } Objpint_pair getarraywithlen(Exec* ex, Obj* o, Rune* aname) { Val* varray; Obj* oarray; Val* vlen; varray = get(ex, o, aname); if(isobj(varray)) { oarray = toObject(ex, varray); vlen = get(ex, oarray, L"length"); if(vlen != undefined) return makeObjpint_pair(oarray, toInt32(ex, vlen)); } return makevoidpint_pair(nil, 0); } void arrayput(Exec* ex, Obj* oarray, int index, Rune* name, Val* v) { int c; int i; put(ex, oarray, ltoStr(index), v); if(name != L"" && name != L"length") { for(i = 0; i < arraylen(name); i++) { c = name[i]; if(c < 48 || c > 57) { put(ex, oarray, name, v); break; } } } } void wininstant(Exec* ex, Obj* w) { reinitprop(w, L"document", docinstant(ex, doc)); varinstant(w, DontEnum|DontDelete, L"PRIVframeid", newRefVal(numval((double)doc->frameid))); } void winxfer(Exec* ex, Obj* w) { Val* vd; vd = get(ex, w, L"document"); if(vd != undefined) docxfer(ex, toObject(ex, vd), doc); } Val* docinstant(Exec* ex, Docinfo* di) { Obj* od; od = mkhostobj(L"document", ex); docfill(ex, od, di); return objval(od); } void docfill(Exec* ex, Obj* od, Docinfo* di) { Form* form; Formp_list* fl; int i; int newformslen; Obj* oforms; int oldformslen; DestAnchor* dest; DestAnchorp_list* dl; int newdestslen; Obj* oanchors; int oldanchorslen; Anchor* a; Anchorp_list* al; int newanchorslen; Obj* olinks; int oldlinkslen; if(di->src != nil) { reinitprop(od, L"URL", strval(tostring(di->src))); reinitprop(od, L"domain", strval(di->src->host)); } if(di->doctitle != L"") reinitprop(od, L"title", strval(di->doctitle)); reinitprop(od, L"bgColor", colorval(di->background.color)); reinitprop(od, L"fgColor", colorval(di->text)); reinitprop(od, L"alinkColor", colorval(di->alink)); reinitprop(od, L"linkColor", colorval(di->link)); reinitprop(od, L"vlinkColor", colorval(di->vlink)); if(di->forms != nil) { newformslen = listlen((List*)di->forms); // TODO declare Objpint_pair tmp_5 tmp_5 = getarraywithlen(ex, od, L"forms"); oforms = tmp_5.t0; oldformslen = tmp_5.t1; if(oforms != nil) { fl = di->forms; for(i = newformslen - 1; i >= oldformslen; i--) { form = fl->hd; fl = fl->tl; arrayput(ex, oforms, i, form->name, forminstant(ex, form, di->frameid)); } } } if(di->dests != nil) { newdestslen = listlen((List*)di->dests); // TODO declare Objpint_pair tmp_6 tmp_6 = getarraywithlen(ex, od, L"anchors"); oanchors = tmp_6.t0; oldanchorslen = tmp_6.t1; if(oanchors != nil) { dl = di->dests; for(i = newdestslen - 1; i >= oldanchorslen; i--) { dest = dl->hd; dl = dl->tl; arrayput(ex, oanchors, i, dest->name, anchorinstant(ex, dest)); } } } if(di->anchors != nil) { newanchorslen = listlen((List*)di->anchors); // TODO declare Objpint_pair tmp_7 tmp_7 = getarraywithlen(ex, od, L"links"); olinks = tmp_7.t0; oldlinkslen = tmp_7.t1; if(olinks != nil) { al = di->anchors; for(i = newanchorslen - 1; i >= oldlinkslen; i--) { a = al->hd; al = al->tl; arrayput(ex, olinks, i, a->name, linkinstant(ex, a)); } } } varinstant(od, DontEnum|DontDelete, L"PRIVframeid", newRefVal(numval((double)di->frameid))); } void docxfer(Exec* ex, Obj* od, Docinfo* di) { di->doctitle = strxfer(ex, od, L"title", di->doctitle); di->background.color = colorxfer(ex, od, L"bgColor", di->background.color); di->text = colorxfer(ex, od, L"fgColor", di->text); di->alink = colorxfer(ex, od, L"alinkColor", di->alink); di->link = colorxfer(ex, od, L"linkColor", di->link); di->vlink = colorxfer(ex, od, L"vlinkColor", di->vlink); } Val* forminstant(Exec* ex, Form* form, int frameid) { Obj* oform; Formfieldp_list* ffl; Formfield* field; Obj* oelements; int i; Val* velements; oform = mkhostobj(L"Form", ex); reinitprop(oform, L"action", strval(tostring(form->action))); reinitprop(oform, L"encoding", strval(L"application/x-www-form-urlencoded")); reinitprop(oform, L"length", numval((double)form->nfields)); reinitprop(oform, L"method", strval(hmeth[form->method])); reinitprop(oform, L"name", strval(form->name)); reinitprop(oform, L"target", strval(form->target)); ffl = form->fields; if(ffl != nil) { velements = get(ex, oform, L"elements"); if(isobj(velements)) { oelements = toObject(ex, velements); for(i = 0; i < form->nfields; i++) { field = ffl->hd; ffl = ffl->tl; arrayput(ex, oelements, i, field->name, fieldinstant(ex, field, oform)); } } } varinstant(oform, DontEnum|DontDelete, L"PRIVformid", newRefVal(numval((double)form->formid))); varinstant(oform, DontEnum|DontDelete, L"PRIVframeid", newRefVal(numval((double)frameid))); return objval(oform); } Val* fieldinstant(Exec* ex, Formfield* field, Obj* oform) { Obj* ofield; Val* chkd; int nopts; Rune* ty; Attr_list* el; Option* opt; Obj* oopt; Obj* options; Optionp_list* optl; int i; Attr e; ofield = mkhostobj(L"FormField", ex); reinitprop(ofield, L"form", objval(oform)); reinitprop(ofield, L"name", strval(field->name)); reinitprop(ofield, L"value", strval(field->value)); reinitprop(ofield, L"defaultValue", strval(field->value)); chkd = false; if((field->flags&FFchecked) != (uchar)0) chkd = true; reinitprop(ofield, L"checked", chkd); reinitprop(ofield, L"defaultChecked", chkd); nopts = listlen((List*)field->options); reinitprop(ofield, L"length", numval((double)nopts)); reinitprop(ofield, L"selectedIndex", numval(-1.0)); ; switch(field->ftype) { case Ftext: ty = L"text"; break; case Fpassword: ty = L"password"; break; case Fcheckbox: ty = L"checkbox"; break; case Fradio: ty = L"radio"; break; case Fsubmit: ty = L"submit"; break; case Fhidden: ty = L"hidden"; break; case Fimage: ty = L"image"; break; case Freset: ty = L"reset"; break; case Ffile: ty = L"fileupload"; break; case Fbutton: ty = L"button"; break; case Fselect: ty = L"select"; options = mkobj(ex->arrayproto, L"Array"); varinstant(options, DontEnum|DontDelete, L"length", newRefVal(numval((double)nopts))); reinitprop(ofield, L"options", objval(options)); optl = field->options; for(i = 0; i < nopts; i++) { opt = optl->hd; optl = optl->tl; oopt = mkhostobj(L"Option", ex); reinitprop(oopt, L"value", strval(opt->value)); reinitprop(oopt, L"text", strval(opt->display)); if(opt->selected) { reinitprop(oopt, L"selected", true); reinitprop(oopt, L"defaultSelected", true); } put(ex, options, ltoStr(i), objval(oopt)); } break; case Ftextarea: ty = L"textarea"; break; } reinitprop(ofield, L"type", strval(ty)); for(el = field->events; el != nil; el = el->tl) { e = el->hd; switch(e.attid) { case Aonclick: puthandler(ex, ofield, L"onclick", e.value); break; } } return objval(ofield); } void puthandler(Exec* ex, Obj* o, Rune* hname, Rune* hbody) { Completion c; Obj* hobj; c = eval(mainex, newStr2(newStr2(L"function PRIVhandler() {", hbody), L"}")); hobj = getobj(mainex->global, L"PRIVhandler"); if(hobj != nil) { put(ex, o, hname, objval(hobj)); } } Val* anchorinstant(Exec* ex, DestAnchor* dest) { Obj* oanchor; oanchor = mkhostobj(L"Anchor", ex); reinitprop(oanchor, L"name", strval(dest->name)); return objval(oanchor); } Val* linkinstant(Exec* ex, Anchor* anchor) { Obj* olink; ParsedUrl* u; Rune* host; Rune* hostname; Rune* pathname; olink = mkhostobj(L"Link", ex); u = anchor->href; if(u != nil) { if(u->frag != L"") reinitprop(olink, L"hash", strval(newStr2(L"#", u->frag))); host = u->host; if(u->user != L"" || u->passwd != L"") { host = u->user; if(u->passwd != L"") Strncat(host, newStr2(L":", u->passwd), FIXME); Strncat(host, newStr2(L"@", u->host), FIXME); } reinitprop(olink, L"host", strval(host)); hostname = host; if(u->port != L"") Strncat(hostname, newStr2(L":", u->port), FIXME); reinitprop(olink, L"hostname", strval(hostname)); reinitprop(olink, L"href", strval(tostring(u))); pathname = newStr2(u->pstart, u->path); if(u->params != L"") Strncat(pathname, newStr2(L";", u->params), FIXME); reinitprop(olink, L"pathname", strval(pathname)); if(u->port != L"") reinitprop(olink, L"port", strval(u->port)); reinitprop(olink, L"protocol", strval(newStr2(schemes[u->scheme], L":"))); if(u->query != L"") reinitprop(olink, L"search", strval(newStr2(L"?", u->query))); } if(anchor->target != L"") reinitprop(olink, L"target", strval(anchor->target)); return objval(olink); } Val* colorval(int v) { return strval(sprint(L"%.6x", v)); } int colorxfer(Exec* ex, Obj* o, Rune* name, int dflt) { Val* v; v = get(ex, o, name); if(v == undefined) return dflt; return color(toString(ex, v), dflt); } Rune* strxfer(Exec* ex, Obj* o, Rune* name, Rune* dflt) { Val* v; v = get(ex, o, name); if(v == undefined) return dflt; return toString(ex, v); }