|
|
|
@ -9,15 +9,76 @@
|
|
|
|
|
#include "../js_require.c"
|
|
|
|
|
#include "../js_r2papi.c"
|
|
|
|
|
|
|
|
|
|
static R_TH_LOCAL JSContext *Gctx = NULL;
|
|
|
|
|
static R_TH_LOCAL JSValue Gfunc;
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
JSContext *ctx;
|
|
|
|
|
JSRuntime *r;
|
|
|
|
|
RCore *core;
|
|
|
|
|
char *name; // if name != NULL its a plugin reference
|
|
|
|
|
JSRuntime *r;
|
|
|
|
|
JSContext *ctx;
|
|
|
|
|
JSValue func;
|
|
|
|
|
} QjsContext;
|
|
|
|
|
|
|
|
|
|
// XXX remove globals
|
|
|
|
|
static R_TH_LOCAL RList *Glist = NULL;
|
|
|
|
|
static R_TH_LOCAL int Gplug = 0;
|
|
|
|
|
|
|
|
|
|
static void qjsctx_free_item(QjsContext *c) {
|
|
|
|
|
if (c) {
|
|
|
|
|
free (c->name);
|
|
|
|
|
free (c);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static QjsContext *qjsctx_find(RCore *core, const char *name) {
|
|
|
|
|
r_return_val_if_fail (core, NULL);
|
|
|
|
|
QjsContext *qc;
|
|
|
|
|
RListIter *iter;
|
|
|
|
|
r_list_foreach (Glist, iter, qc) {
|
|
|
|
|
if (name && core) {
|
|
|
|
|
if (qc->core == core && qc->name && !strcmp (qc->name, name)) {
|
|
|
|
|
return qc;
|
|
|
|
|
}
|
|
|
|
|
} else if (qc->core == core) {
|
|
|
|
|
return qc;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static QjsContext *qjsctx_add(RCore *core, const char *name, JSContext *ctx, JSValue func) {
|
|
|
|
|
QjsContext *qc = R_NEW0 (QjsContext);
|
|
|
|
|
if (qc) {
|
|
|
|
|
qc->name = name? strdup (name): NULL;
|
|
|
|
|
qc->core = core;
|
|
|
|
|
qc->ctx = ctx;
|
|
|
|
|
qc->func = func;
|
|
|
|
|
if (!Glist) {
|
|
|
|
|
Glist = r_list_newf ((RListFree)qjsctx_free_item);
|
|
|
|
|
}
|
|
|
|
|
r_list_append (Glist, qc);
|
|
|
|
|
}
|
|
|
|
|
return qc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool qjsctx_del(RCore *core, const char *name) {
|
|
|
|
|
r_return_val_if_fail (core && name, false);
|
|
|
|
|
QjsContext *qc;
|
|
|
|
|
RListIter *iter;
|
|
|
|
|
r_list_foreach (Glist, iter, qc) {
|
|
|
|
|
if (qc->core == core && name && qc->name && !strcmp (qc->name, name)) {
|
|
|
|
|
r_list_delete (Glist, iter);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void qjsctx_free(void) {
|
|
|
|
|
r_list_free (Glist);
|
|
|
|
|
Glist = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
static bool eval(JSContext *ctx, const char *code);
|
|
|
|
|
|
|
|
|
|
static void js_dump_obj(JSContext *ctx, FILE *f, JSValueConst val) {
|
|
|
|
@ -86,49 +147,82 @@ static JSValue b64(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// JS_FreeValue (ctx, argv[0]);
|
|
|
|
|
JSValue v = JS_NewString (ctx, r_str_get (ret));
|
|
|
|
|
free (ret);
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int r2plugin_core_call(void *_core, const char *input) {
|
|
|
|
|
static int r2plugin_core_call2(QjsContext *qc, RCore *core, const char *input) {
|
|
|
|
|
JSValueConst args[1] = {
|
|
|
|
|
JS_NewString (Gctx, input)
|
|
|
|
|
JS_NewString (qc->ctx, input)
|
|
|
|
|
};
|
|
|
|
|
JSValue res = JS_Call (Gctx, Gfunc, JS_UNDEFINED, countof (args), args);
|
|
|
|
|
return JS_ToBool (Gctx, res) == 1;
|
|
|
|
|
JSValue res = JS_Call (qc->ctx, qc->func, JS_UNDEFINED, countof (args), args);
|
|
|
|
|
return JS_ToBool (qc->ctx, res) == 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSValue r2plugin_core(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
|
|
|
|
|
if (Gctx) {
|
|
|
|
|
return JS_ThrowRangeError (ctx, "r2plugin core already registered (only one exists)");
|
|
|
|
|
// R2_590 - XXX this is a hack to not break the ABI
|
|
|
|
|
#define MAXPLUGS 5
|
|
|
|
|
static R_TH_LOCAL QjsContext *GcallsData[MAXPLUGS] = { NULL };
|
|
|
|
|
typedef int (*CallX)(void *, const char *);
|
|
|
|
|
static int call0(void *c, const char *i) { return r2plugin_core_call2 (GcallsData[0], c, i); }
|
|
|
|
|
static int call1(void *c, const char *i) { return r2plugin_core_call2 (GcallsData[1], c, i); }
|
|
|
|
|
static int call2(void *c, const char *i) { return r2plugin_core_call2 (GcallsData[2], c, i); }
|
|
|
|
|
static int call3(void *c, const char *i) { return r2plugin_core_call2 (GcallsData[3], c, i); }
|
|
|
|
|
static int call4(void *c, const char *i) { return r2plugin_core_call2 (GcallsData[4], c, i); }
|
|
|
|
|
static const CallX Gcalls[MAXPLUGS] = { &call0, &call1, &call2, &call3, &call4 };
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
static int r2plugin_core_call(void *_core, const char *input) {
|
|
|
|
|
return r2_plugin_core_call2 (NULL, _core, input);
|
|
|
|
|
#if 0
|
|
|
|
|
QjsContext *qc = qjsctx_find (_core, "qjs-example");
|
|
|
|
|
if (!qc) {
|
|
|
|
|
R_LOG_WARN ("Internal error, cannot find the qjs context");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (!qc->name) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
JSValueConst args[1] = {
|
|
|
|
|
JS_NewString (qc->ctx, input)
|
|
|
|
|
};
|
|
|
|
|
JSValue res = JS_Call (qc->ctx, qc->func, JS_UNDEFINED, countof (args), args);
|
|
|
|
|
return JS_ToBool (qc->ctx, res) == 1;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static JSValue r2plugin_core(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
|
|
|
|
|
JSRuntime *rt = JS_GetRuntime (ctx);
|
|
|
|
|
QjsContext *k = JS_GetRuntimeOpaque (rt);
|
|
|
|
|
RCore *core = k->core;
|
|
|
|
|
|
|
|
|
|
if (argc != 2) {
|
|
|
|
|
return JS_ThrowRangeError(ctx, "r2plugin expects two arguments");
|
|
|
|
|
return JS_ThrowRangeError (ctx, "r2.plugin expects two arguments");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSValueConst args[1] = {
|
|
|
|
|
JS_NewString (ctx, "POP"),
|
|
|
|
|
JS_NewString (ctx, ""),
|
|
|
|
|
};
|
|
|
|
|
JSValue res = JS_Call (ctx, argv[1], JS_UNDEFINED, countof (args), args);
|
|
|
|
|
|
|
|
|
|
// check if res is an object
|
|
|
|
|
if (!JS_IsObject (res)) {
|
|
|
|
|
return JS_ThrowRangeError(ctx, "r2plugin function must return an object");
|
|
|
|
|
return JS_ThrowRangeError (ctx, "r2.plugin function must return an object");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RCorePlugin *ap = R_NEW0 (RCorePlugin);
|
|
|
|
|
if (!ap) {
|
|
|
|
|
return JS_ThrowRangeError (ctx, "heap stuff");
|
|
|
|
|
}
|
|
|
|
|
JSValue name = JS_GetPropertyStr (ctx, res, "name");
|
|
|
|
|
size_t namelen;
|
|
|
|
|
const char *nameptr = JS_ToCStringLen2 (ctx, &namelen, name, false);
|
|
|
|
|
if (nameptr) {
|
|
|
|
|
ap->name = strdup (nameptr);
|
|
|
|
|
} else {
|
|
|
|
|
return JS_ThrowRangeError(ctx, "r2plugin requires the function to return an object with the `name` field");
|
|
|
|
|
R_LOG_WARN ("r2.plugin requires the function to return an object with the `name` field");
|
|
|
|
|
return JS_NewBool (ctx, false);
|
|
|
|
|
}
|
|
|
|
|
JSValue desc = JS_GetPropertyStr (ctx, res, "desc");
|
|
|
|
|
const char *descptr = JS_ToCStringLen2 (ctx, &namelen, desc, false);
|
|
|
|
@ -142,22 +236,37 @@ static JSValue r2plugin_core(JSContext *ctx, JSValueConst this_val, int argc, JS
|
|
|
|
|
}
|
|
|
|
|
JSValue func = JS_GetPropertyStr (ctx, res, "call");
|
|
|
|
|
if (!JS_IsFunction (ctx, func)) {
|
|
|
|
|
return JS_ThrowRangeError(ctx, "r2plugin requires the function to return an object with the `call` field to be a function");
|
|
|
|
|
R_LOG_WARN ("r2.plugin requires the function to return an object with the `call` field to be a function");
|
|
|
|
|
// return JS_ThrowRangeError (ctx, "r2.plugin requires the function to return an object with the `call` field to be a function");
|
|
|
|
|
return JS_NewBool (ctx, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// XXX dont do globals
|
|
|
|
|
Gctx = ctx;
|
|
|
|
|
Gfunc = func;
|
|
|
|
|
QjsContext *qc = qjsctx_find (core, ap->name);
|
|
|
|
|
if (qc) {
|
|
|
|
|
R_LOG_WARN ("r2.plugin with name %s is already registered", ap->name);
|
|
|
|
|
free ((char*)ap->name);
|
|
|
|
|
free (ap);
|
|
|
|
|
// return JS_ThrowRangeError (ctx, "r2.plugin core already registered (only one exists)");
|
|
|
|
|
return JS_NewBool (ctx, false);
|
|
|
|
|
}
|
|
|
|
|
eprintf ("ADDING LE PLUGIN BECAUSE WE DDIND FIND IT THE FUNC\n");
|
|
|
|
|
if (Gplug >= MAXPLUGS) {
|
|
|
|
|
R_LOG_WARN ("Maximum number of plugins loaded! this is a limitation induced by the");
|
|
|
|
|
return JS_NewBool (ctx, false);
|
|
|
|
|
}
|
|
|
|
|
qc = qjsctx_add (core, nameptr, ctx, func);
|
|
|
|
|
ap->call = Gcalls[Gplug];
|
|
|
|
|
eprintf ("%s = %p\n", ap->name, qc);
|
|
|
|
|
GcallsData[Gplug] = qc;
|
|
|
|
|
Gplug++;
|
|
|
|
|
|
|
|
|
|
ap->call = r2plugin_core_call;
|
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
|
|
RLibStruct *lib = R_NEW0 (RLibStruct);
|
|
|
|
|
if (lib) {
|
|
|
|
|
lib->type = R_LIB_TYPE_CORE;
|
|
|
|
|
lib->data = ap;
|
|
|
|
|
lib->version = R2_VERSION;
|
|
|
|
|
ret = r_lib_open_ptr (core->lib, "qjs", NULL, lib);
|
|
|
|
|
ret = r_lib_open_ptr (core->lib, nameptr, NULL, lib);
|
|
|
|
|
}
|
|
|
|
|
return JS_NewBool (ctx, ret == 0);
|
|
|
|
|
}
|
|
|
|
@ -179,10 +288,7 @@ static JSValue r2plugin(JSContext *ctx, JSValueConst this_val, int argc, JSValue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSValue r2plugin_unload(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
|
|
|
|
|
if (argc != 1) {
|
|
|
|
|
return JS_ThrowRangeError(ctx, "r2.unload takes only one string as argument");
|
|
|
|
|
}
|
|
|
|
|
if (!JS_IsString (argv[0])) {
|
|
|
|
|
if (argc != 1 || !JS_IsString (argv[0])) {
|
|
|
|
|
return JS_ThrowRangeError(ctx, "r2.unload takes only one string as argument");
|
|
|
|
|
}
|
|
|
|
|
JSRuntime *rt = JS_GetRuntime (ctx);
|
|
|
|
@ -190,10 +296,10 @@ static JSValue r2plugin_unload(JSContext *ctx, JSValueConst this_val, int argc,
|
|
|
|
|
size_t plen;
|
|
|
|
|
const char *name = JS_ToCStringLen2 (ctx, &plen, argv[0], false);
|
|
|
|
|
k->core->lang->cmdf (k->core, "L-%s", name);
|
|
|
|
|
Gctx = NULL;
|
|
|
|
|
bool res = qjsctx_del (k->core, name);
|
|
|
|
|
// invalid throw exception here
|
|
|
|
|
// return JS_ThrowRangeError(ctx, "invalid r2plugin type");
|
|
|
|
|
return JS_NewBool (ctx, true);
|
|
|
|
|
return JS_NewBool (ctx, res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSValue r2cmd(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
|
|
|
|
@ -303,7 +409,6 @@ static const JSCFunctionListEntry js_r2_funcs[] = {
|
|
|
|
|
JS_CFUNC_DEF ("cmd", 1, r2cmd),
|
|
|
|
|
JS_CFUNC_DEF ("plugin", 2, r2plugin),
|
|
|
|
|
JS_CFUNC_DEF ("unload", 1, r2plugin_unload),
|
|
|
|
|
// JS_SetPropertyStr (ctx, global_obj, "r2plugin", JS_NewCFunction (ctx, r2plugin, "r2plugin", 1));
|
|
|
|
|
// JS_CFUNC_DEF ("cmdj", 1, r2cmdj), // can be implemented in js
|
|
|
|
|
JS_CFUNC_DEF ("log", 1, r2log),
|
|
|
|
|
JS_CFUNC_DEF ("error", 1, r2error),
|
|
|
|
@ -391,11 +496,11 @@ static JSContext *JS_NewCustomContext(JSRuntime *rt) {
|
|
|
|
|
|
|
|
|
|
static void eval_jobs(JSContext *ctx) {
|
|
|
|
|
JSRuntime *rt = JS_GetRuntime (ctx);
|
|
|
|
|
JSContext * pctx = NULL;
|
|
|
|
|
JSContext *pctx = NULL;
|
|
|
|
|
do {
|
|
|
|
|
int res = JS_ExecutePendingJob (rt, &pctx);
|
|
|
|
|
if (res == -1) {
|
|
|
|
|
eprintf ("exception in job%c", 10);
|
|
|
|
|
eprintf ("exception in job\n");
|
|
|
|
|
}
|
|
|
|
|
} while (pctx);
|
|
|
|
|
}
|
|
|
|
@ -441,18 +546,20 @@ static bool lang_quickjs_file(RLangSession *s, const char *file) {
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void *init(RLangSession *s) {
|
|
|
|
|
QjsContext *k = R_NEW0 (QjsContext);
|
|
|
|
|
if (k) {
|
|
|
|
|
JSRuntime *rt = JS_NewRuntime ();
|
|
|
|
|
JS_SetRuntimeOpaque (rt, k);
|
|
|
|
|
k->r = rt;
|
|
|
|
|
k->ctx = JS_NewCustomContext (rt);
|
|
|
|
|
// already initialized by customcontext register_helpers (k->ctx);
|
|
|
|
|
k->core = s->lang->user;
|
|
|
|
|
static void *init(RLangSession *ls) {
|
|
|
|
|
RCore *core = (RCore *)ls->lang->user;
|
|
|
|
|
JSRuntime *rt = JS_NewRuntime ();
|
|
|
|
|
JSContext *ctx = JS_NewCustomContext (rt);
|
|
|
|
|
JSValue jv = JS_NewBool (ctx, false); // fake function
|
|
|
|
|
QjsContext *qc = qjsctx_add (core, NULL, ctx, jv);
|
|
|
|
|
if (qc) {
|
|
|
|
|
qc->r = rt;
|
|
|
|
|
qc->core = ls->lang->user;
|
|
|
|
|
JS_SetRuntimeOpaque (rt, qc);
|
|
|
|
|
// XXX we still have a global list of plugins.. we can probably use this pointer to hold everything
|
|
|
|
|
ls->plugin_data = qc; // implicit
|
|
|
|
|
}
|
|
|
|
|
s->plugin_data = k; // implicit
|
|
|
|
|
return k;
|
|
|
|
|
return qc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool fini(RLangSession *s) {
|
|
|
|
@ -461,7 +568,8 @@ static bool fini(RLangSession *s) {
|
|
|
|
|
JS_FreeContext (k->ctx);
|
|
|
|
|
k->ctx = NULL;
|
|
|
|
|
k->r = NULL;
|
|
|
|
|
free (k);
|
|
|
|
|
qjsctx_free ();
|
|
|
|
|
// free (k);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|