2017-05-09 08:42:51 +08:00
|
|
|
/* radare - LGPL - Copyright 2009-2017 - pancake */
|
2009-02-06 05:08:46 +08:00
|
|
|
|
|
|
|
#include <r_lang.h>
|
2009-02-11 07:56:20 +08:00
|
|
|
#include <r_util.h>
|
2009-02-06 05:08:46 +08:00
|
|
|
|
2013-06-14 08:51:33 +08:00
|
|
|
R_LIB_VERSION(r_lang);
|
|
|
|
|
2015-08-20 05:11:53 +08:00
|
|
|
#include "p/pipe.c" // hardcoded
|
|
|
|
#include "p/vala.c" // hardcoded
|
2016-03-28 06:19:21 +08:00
|
|
|
#include "p/rust.c" // hardcoded
|
2015-08-20 05:11:53 +08:00
|
|
|
#include "p/c.c" // hardcoded
|
2017-02-18 05:11:15 +08:00
|
|
|
#include "p/lib.c"
|
2015-08-20 05:11:53 +08:00
|
|
|
#if __UNIX__
|
|
|
|
#include "p/cpipe.c" // hardcoded
|
|
|
|
#endif
|
2017-05-11 04:12:49 +08:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
#define strcasecmp stricmp
|
|
|
|
#endif
|
2011-02-06 21:10:16 +08:00
|
|
|
|
2014-03-26 08:34:32 +08:00
|
|
|
static RLang *__lang = NULL;
|
|
|
|
|
2012-06-14 23:41:07 +08:00
|
|
|
R_API void r_lang_plugin_free (RLangPlugin *p) {
|
2016-05-31 16:39:34 +08:00
|
|
|
if (p && p->fini) {
|
2012-06-14 23:41:07 +08:00
|
|
|
p->fini (__lang);
|
2016-05-31 16:39:34 +08:00
|
|
|
}
|
2012-06-14 23:41:07 +08:00
|
|
|
}
|
|
|
|
|
2010-05-20 23:40:58 +08:00
|
|
|
R_API RLang *r_lang_new() {
|
2014-12-19 10:17:28 +08:00
|
|
|
RLang *lang = R_NEW0 (RLang);
|
2016-05-31 16:39:34 +08:00
|
|
|
if (!lang) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2016-05-25 04:22:15 +08:00
|
|
|
lang->user = NULL;
|
|
|
|
lang->langs = r_list_new ();
|
|
|
|
if (!lang->langs) {
|
|
|
|
r_lang_free (lang);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
lang->langs->free = (RListFree)r_lang_plugin_free;
|
|
|
|
lang->defs = r_list_new ();
|
|
|
|
if (!lang->defs) {
|
|
|
|
r_lang_free (lang);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
lang->defs->free = (RListFree)r_lang_def_free;
|
|
|
|
lang->cb_printf = (PrintfCallback)printf;
|
|
|
|
r_lang_add (lang, &r_lang_plugin_c);
|
2015-08-20 05:11:53 +08:00
|
|
|
#if __UNIX__
|
2016-05-25 04:22:15 +08:00
|
|
|
r_lang_add (lang, &r_lang_plugin_cpipe);
|
2015-08-20 05:11:53 +08:00
|
|
|
#endif
|
2016-05-25 04:22:15 +08:00
|
|
|
r_lang_add (lang, &r_lang_plugin_vala);
|
|
|
|
r_lang_add (lang, &r_lang_plugin_rust);
|
|
|
|
r_lang_add (lang, &r_lang_plugin_pipe);
|
2017-02-18 05:11:15 +08:00
|
|
|
r_lang_add (lang, &r_lang_plugin_lib);
|
2016-05-25 04:22:15 +08:00
|
|
|
|
2009-09-20 07:03:57 +08:00
|
|
|
return lang;
|
|
|
|
}
|
|
|
|
|
2010-04-09 21:57:22 +08:00
|
|
|
R_API void *r_lang_free(RLang *lang) {
|
2017-05-09 08:42:51 +08:00
|
|
|
if (!lang) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-06-14 23:41:07 +08:00
|
|
|
__lang = NULL;
|
2011-02-06 21:10:16 +08:00
|
|
|
r_lang_undef (lang, NULL);
|
|
|
|
r_list_free (lang->langs);
|
|
|
|
r_list_free (lang->defs);
|
2009-09-20 07:03:57 +08:00
|
|
|
// TODO: remove langs plugins
|
2010-04-07 00:21:41 +08:00
|
|
|
free (lang);
|
2009-09-20 07:03:57 +08:00
|
|
|
return NULL;
|
2009-02-06 05:08:46 +08:00
|
|
|
}
|
|
|
|
|
2009-09-17 17:48:36 +08:00
|
|
|
// XXX: This is only used actually to pass 'core' structure
|
|
|
|
// TODO: when language bindings are done we will need an api to
|
|
|
|
// define symbols from C to the language namespace
|
2009-09-20 07:03:57 +08:00
|
|
|
// XXX: Depcreate!!
|
2010-04-09 21:57:22 +08:00
|
|
|
R_API void r_lang_set_user_ptr(RLang *lang, void *user) {
|
2009-02-12 07:04:30 +08:00
|
|
|
lang->user = user;
|
|
|
|
}
|
|
|
|
|
2017-05-09 08:42:51 +08:00
|
|
|
R_API bool r_lang_define(RLang *lang, const char *type, const char *name, void *value) {
|
2011-02-06 21:10:16 +08:00
|
|
|
RLangDef *def;
|
|
|
|
RListIter *iter;
|
|
|
|
r_list_foreach (lang->defs, iter, def) {
|
2013-12-14 09:35:14 +08:00
|
|
|
if (!strcasecmp (name, def->name)) {
|
2009-09-20 07:03:57 +08:00
|
|
|
def->value = value;
|
2015-09-14 08:08:31 +08:00
|
|
|
return true;
|
2009-09-20 07:03:57 +08:00
|
|
|
}
|
|
|
|
}
|
2016-05-31 16:39:34 +08:00
|
|
|
def = R_NEW0 (RLangDef);
|
|
|
|
if (!def) {
|
|
|
|
return false;
|
2009-09-20 07:03:57 +08:00
|
|
|
}
|
2016-05-31 16:39:34 +08:00
|
|
|
def->type = strdup (type);
|
|
|
|
def->name = strdup (name);
|
|
|
|
def->value = value;
|
|
|
|
r_list_append (lang->defs, def);
|
|
|
|
return true;
|
2009-09-20 07:03:57 +08:00
|
|
|
}
|
|
|
|
|
2011-02-06 21:10:16 +08:00
|
|
|
R_API void r_lang_def_free (RLangDef *def) {
|
|
|
|
free (def->name);
|
|
|
|
free (def->type);
|
|
|
|
free (def);
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API void r_lang_undef(RLang *lang, const char *name) {
|
2014-08-29 22:26:43 +08:00
|
|
|
if (name && *name) {
|
2011-02-06 21:10:16 +08:00
|
|
|
RLangDef *def;
|
|
|
|
RListIter *iter;
|
2012-02-15 01:10:52 +08:00
|
|
|
/* No _safe loop necessary because we return immediately after the delete. */
|
2011-02-06 21:10:16 +08:00
|
|
|
r_list_foreach (lang->defs, iter, def) {
|
2014-08-29 22:26:43 +08:00
|
|
|
if (!name || !strcasecmp (name, def->name)) {
|
2011-02-06 21:10:16 +08:00
|
|
|
r_list_delete (lang->defs, iter);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-08-29 22:26:43 +08:00
|
|
|
} else {
|
2015-08-29 15:58:57 +08:00
|
|
|
r_list_free (lang->defs);
|
2014-08-29 22:26:43 +08:00
|
|
|
lang->defs = NULL;
|
|
|
|
}
|
2009-09-17 17:48:36 +08:00
|
|
|
}
|
|
|
|
|
2017-05-09 08:42:51 +08:00
|
|
|
R_API bool r_lang_setup(RLang *lang) {
|
|
|
|
if (lang && lang->cur && lang->cur->setup) {
|
2011-02-06 21:10:16 +08:00
|
|
|
return lang->cur->setup (lang);
|
2016-05-31 16:39:34 +08:00
|
|
|
}
|
2015-09-14 08:08:31 +08:00
|
|
|
return false;
|
2011-02-06 21:10:16 +08:00
|
|
|
}
|
|
|
|
|
2017-05-09 08:42:51 +08:00
|
|
|
R_API bool r_lang_add(RLang *lang, RLangPlugin *foo) {
|
2013-08-18 01:53:04 +08:00
|
|
|
if (foo && (!r_lang_get_by_name (lang, foo->name))) {
|
2016-05-31 16:39:34 +08:00
|
|
|
if (foo->init) {
|
2011-11-01 11:37:13 +08:00
|
|
|
foo->init (lang);
|
2016-05-31 16:39:34 +08:00
|
|
|
}
|
2011-02-06 21:10:16 +08:00
|
|
|
r_list_append (lang->langs, foo);
|
2017-05-09 08:42:51 +08:00
|
|
|
return true;
|
2011-02-06 21:10:16 +08:00
|
|
|
}
|
2017-05-09 08:42:51 +08:00
|
|
|
return false;
|
2009-02-06 05:08:46 +08:00
|
|
|
}
|
|
|
|
|
2009-09-20 07:03:57 +08:00
|
|
|
/* TODO: deprecate all list methods */
|
2017-05-09 08:42:51 +08:00
|
|
|
R_API bool r_lang_list(RLang *lang) {
|
2011-02-06 21:10:16 +08:00
|
|
|
RListIter *iter;
|
|
|
|
RLangPlugin *h;
|
2016-05-31 16:39:34 +08:00
|
|
|
if (!lang) {
|
2015-09-14 08:08:31 +08:00
|
|
|
return false;
|
2016-05-31 16:39:34 +08:00
|
|
|
}
|
2011-02-06 21:10:16 +08:00
|
|
|
r_list_foreach (lang->langs, iter, h) {
|
2016-05-31 16:39:34 +08:00
|
|
|
const char *license = h->license
|
|
|
|
? h->license : "???";
|
|
|
|
lang->cb_printf ("%s: (%s) %s\n",
|
|
|
|
h->name, license, h->desc);
|
2009-02-06 05:08:46 +08:00
|
|
|
}
|
2015-09-14 08:08:31 +08:00
|
|
|
return true;
|
2009-02-06 05:08:46 +08:00
|
|
|
}
|
|
|
|
|
2013-08-18 01:53:04 +08:00
|
|
|
R_API RLangPlugin *r_lang_get_by_extension (RLang *lang, const char *ext) {
|
|
|
|
RListIter *iter;
|
|
|
|
RLangPlugin *h;
|
2013-09-04 05:47:18 +08:00
|
|
|
const char *p = r_str_lchr (ext, '.');
|
2016-05-31 16:39:34 +08:00
|
|
|
if (p) ext = p + 1;
|
2013-08-18 01:53:04 +08:00
|
|
|
r_list_foreach (lang->langs, iter, h) {
|
2016-05-31 16:39:34 +08:00
|
|
|
if (!strcasecmp (h->ext, ext)) {
|
2013-08-18 01:53:04 +08:00
|
|
|
return h;
|
2016-05-31 16:39:34 +08:00
|
|
|
}
|
2013-08-18 01:53:04 +08:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API RLangPlugin *r_lang_get_by_name (RLang *lang, const char *name) {
|
2011-02-06 21:10:16 +08:00
|
|
|
RListIter *iter;
|
|
|
|
RLangPlugin *h;
|
|
|
|
r_list_foreach (lang->langs, iter, h) {
|
2016-05-31 16:39:34 +08:00
|
|
|
if (!strcasecmp (h->name, name)) {
|
2011-02-07 01:44:56 +08:00
|
|
|
return h;
|
2016-05-31 16:39:34 +08:00
|
|
|
}
|
2009-02-06 05:08:46 +08:00
|
|
|
}
|
2011-02-07 01:44:56 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-05-09 08:42:51 +08:00
|
|
|
R_API bool r_lang_use(RLang *lang, const char *name) {
|
2013-08-18 01:53:04 +08:00
|
|
|
RLangPlugin *h = r_lang_get_by_name (lang, name);
|
2011-02-07 01:44:56 +08:00
|
|
|
if (h) {
|
|
|
|
lang->cur = h;
|
2015-09-14 08:08:31 +08:00
|
|
|
return true;
|
2011-02-07 01:44:56 +08:00
|
|
|
}
|
2015-09-14 08:08:31 +08:00
|
|
|
return false;
|
2009-02-06 05:08:46 +08:00
|
|
|
}
|
|
|
|
|
2009-09-20 07:03:57 +08:00
|
|
|
// TODO: store in r_lang and use it from the plugin?
|
2017-05-09 08:42:51 +08:00
|
|
|
R_API bool r_lang_set_argv(RLang *lang, int argc, char **argv) {
|
2016-05-31 16:39:34 +08:00
|
|
|
if (lang->cur && lang->cur->set_argv) {
|
2010-04-07 00:21:41 +08:00
|
|
|
return lang->cur->set_argv (lang, argc, argv);
|
2016-05-31 16:39:34 +08:00
|
|
|
}
|
2015-09-14 08:08:31 +08:00
|
|
|
return false;
|
2009-02-11 07:56:20 +08:00
|
|
|
}
|
|
|
|
|
2010-04-09 21:57:22 +08:00
|
|
|
R_API int r_lang_run(RLang *lang, const char *code, int len) {
|
2016-05-31 16:39:34 +08:00
|
|
|
if (lang->cur && lang->cur->run) {
|
2010-04-07 00:21:41 +08:00
|
|
|
return lang->cur->run (lang, code, len);
|
2016-05-31 16:39:34 +08:00
|
|
|
}
|
2015-09-14 08:08:31 +08:00
|
|
|
return false;
|
2009-02-11 07:56:20 +08:00
|
|
|
}
|
|
|
|
|
2010-04-09 21:57:22 +08:00
|
|
|
R_API int r_lang_run_string(RLang *lang, const char *code) {
|
|
|
|
return r_lang_run (lang, code, strlen (code));
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API int r_lang_run_file(RLang *lang, const char *file) {
|
2015-09-14 08:08:31 +08:00
|
|
|
int len, ret = false;
|
2009-02-06 05:08:46 +08:00
|
|
|
if (lang->cur) {
|
2016-05-31 16:39:34 +08:00
|
|
|
if (!lang->cur->run_file) {
|
|
|
|
if (lang->cur->run) {
|
2011-02-06 21:10:16 +08:00
|
|
|
char *code = r_file_slurp (file, &len);
|
|
|
|
ret = lang->cur->run (lang, code, len);
|
|
|
|
free (code);
|
2009-02-11 07:56:20 +08:00
|
|
|
}
|
2011-02-06 21:10:16 +08:00
|
|
|
} else ret = lang->cur->run_file (lang, file);
|
2009-02-06 05:08:46 +08:00
|
|
|
}
|
2009-02-11 07:56:20 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-09-20 07:03:57 +08:00
|
|
|
/* TODO: deprecate or make it more modular .. reading from stdin in a lib?!? wtf */
|
2010-04-09 21:57:22 +08:00
|
|
|
R_API int r_lang_prompt(RLang *lang) {
|
2009-02-11 07:56:20 +08:00
|
|
|
char buf[1024];
|
2015-02-03 07:51:20 +08:00
|
|
|
const char *p;
|
2009-02-11 20:31:26 +08:00
|
|
|
|
2016-05-31 16:39:34 +08:00
|
|
|
if (!lang || !lang->cur) {
|
2015-09-14 08:08:31 +08:00
|
|
|
return false;
|
2016-05-31 16:39:34 +08:00
|
|
|
}
|
2009-02-11 20:31:26 +08:00
|
|
|
|
2016-05-31 16:39:34 +08:00
|
|
|
if (lang->cur->prompt) {
|
|
|
|
if (lang->cur->prompt (lang)) {
|
2015-09-14 08:08:31 +08:00
|
|
|
return true;
|
2016-05-31 16:39:34 +08:00
|
|
|
}
|
|
|
|
}
|
2011-11-01 11:37:13 +08:00
|
|
|
/* init line */
|
|
|
|
RLine *line = r_line_singleton ();
|
|
|
|
RLineHistory hist = line->history;
|
|
|
|
RLineHistory histnull = {0};
|
|
|
|
RLineCompletion oc = line->completion;
|
|
|
|
RLineCompletion ocnull = {0};
|
|
|
|
char *prompt = strdup (line->prompt);
|
|
|
|
line->completion = ocnull;
|
|
|
|
line->history = histnull;
|
2016-05-31 16:39:34 +08:00
|
|
|
|
2011-11-01 11:37:13 +08:00
|
|
|
/* foo */
|
2010-04-07 00:21:41 +08:00
|
|
|
for (;;) {
|
2016-03-30 21:50:16 +08:00
|
|
|
snprintf (buf, sizeof (buf)-1, "%s> ", lang->cur->name);
|
2015-02-03 07:51:20 +08:00
|
|
|
r_line_set_prompt (buf);
|
2011-11-01 11:37:13 +08:00
|
|
|
#if 0
|
2010-04-07 00:21:41 +08:00
|
|
|
printf ("%s> ", lang->cur->name);
|
|
|
|
fflush (stdout);
|
2010-10-27 22:31:51 +08:00
|
|
|
fgets (buf, sizeof (buf)-1, stdin);
|
2010-04-07 00:21:41 +08:00
|
|
|
if (feof (stdin)) break;
|
2011-11-01 11:37:13 +08:00
|
|
|
if (*buf) buf[strlen (buf)-1]='\0';
|
|
|
|
#endif
|
2015-02-03 07:51:20 +08:00
|
|
|
p = r_line_readline ();
|
2016-05-31 16:39:34 +08:00
|
|
|
if (!p) {
|
|
|
|
break;
|
|
|
|
}
|
2011-11-01 11:37:13 +08:00
|
|
|
r_line_hist_add (p);
|
2014-12-19 10:17:28 +08:00
|
|
|
strncpy (buf, p, sizeof (buf) - 1);
|
2013-08-18 07:30:03 +08:00
|
|
|
if (*buf == '!') {
|
2014-12-19 10:17:28 +08:00
|
|
|
if (buf[1]) {
|
2016-05-31 16:39:34 +08:00
|
|
|
r_sandbox_system (buf + 1, 1);
|
2014-12-19 10:17:28 +08:00
|
|
|
} else {
|
|
|
|
char *foo, *code = NULL;
|
|
|
|
do {
|
|
|
|
foo = r_cons_editor (NULL, code);
|
|
|
|
r_lang_run (lang, foo, 0);
|
|
|
|
free (code);
|
|
|
|
code = foo;
|
|
|
|
} while (r_cons_yesno ('y', "Edit again? (Y/n)"));
|
|
|
|
free (foo);
|
|
|
|
}
|
2013-06-25 08:57:57 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!memcmp (buf, ". ", 2)) {
|
|
|
|
char *file = r_file_abspath (buf+2);
|
|
|
|
if (file) {
|
|
|
|
r_lang_run_file (lang, file);
|
|
|
|
free (file);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2014-07-29 03:58:44 +08:00
|
|
|
if (!strcmp (buf, "q")) {
|
|
|
|
free (prompt);
|
2015-09-14 08:08:31 +08:00
|
|
|
return true;
|
2014-07-29 03:58:44 +08:00
|
|
|
}
|
2010-04-07 00:21:41 +08:00
|
|
|
if (!strcmp (buf, "?")) {
|
2011-11-01 11:37:13 +08:00
|
|
|
RLangDef *def;
|
|
|
|
RListIter *iter;
|
2013-06-25 08:57:57 +08:00
|
|
|
eprintf(" ? - show this help message\n"
|
2014-12-19 10:17:28 +08:00
|
|
|
" ! - run $EDITOR\n"
|
2013-06-25 08:57:57 +08:00
|
|
|
" !command - run system command\n"
|
|
|
|
" . file - interpret file\n"
|
|
|
|
" q - quit prompt\n");
|
2014-07-31 04:13:55 +08:00
|
|
|
eprintf ("%s example:\n", lang->cur->name);
|
|
|
|
if (lang->cur->help)
|
|
|
|
eprintf ("%s", *lang->cur->help);
|
2011-11-01 11:37:13 +08:00
|
|
|
if (!r_list_empty (lang->defs))
|
|
|
|
eprintf ("variables:\n");
|
|
|
|
r_list_foreach (lang->defs, iter, def) {
|
|
|
|
eprintf (" %s %s\n", def->type, def->name);
|
|
|
|
}
|
2011-02-06 21:10:16 +08:00
|
|
|
} else r_lang_run (lang, buf, strlen (buf));
|
2009-02-11 07:56:20 +08:00
|
|
|
}
|
2011-11-01 11:37:13 +08:00
|
|
|
// XXX: leaking history
|
|
|
|
r_line_set_prompt (prompt);
|
|
|
|
line->completion = oc;
|
|
|
|
line->history = hist;
|
2010-04-09 21:57:22 +08:00
|
|
|
clearerr (stdin);
|
|
|
|
printf ("\n");
|
2015-09-14 08:08:31 +08:00
|
|
|
free (prompt);
|
|
|
|
return true;
|
2009-02-06 05:08:46 +08:00
|
|
|
}
|