1 /* radare - LGPL - Copyright 2009-2018 - pancake */
2
3 #include <r_lang.h>
4 #include <r_util.h>
5
6 R_LIB_VERSION(r_lang);
7
8 #include "p/pipe.c" // hardcoded
9 #include "p/vala.c" // hardcoded
10 #include "p/rust.c" // hardcoded
11 #include "p/zig.c" // hardcoded
12 #include "p/spp.c" // hardcoded
13 #include "p/c.c" // hardcoded
14 #include "p/lib.c"
15 #if __UNIX__
16 #include "p/cpipe.c" // hardcoded
17 #endif
18
19 static RLang *__lang = NULL;
20
r_lang_plugin_free(RLangPlugin * p)21 R_API void r_lang_plugin_free (RLangPlugin *p) {
22 if (p && p->fini) {
23 p->fini (__lang);
24 }
25 }
26
r_lang_new(void)27 R_API RLang *r_lang_new(void) {
28 RLang *lang = R_NEW0 (RLang);
29 if (!lang) {
30 return NULL;
31 }
32 lang->user = NULL;
33 lang->langs = r_list_new ();
34 if (!lang->langs) {
35 r_lang_free (lang);
36 return NULL;
37 }
38 lang->langs->free = (RListFree)r_lang_plugin_free;
39 lang->defs = r_list_new ();
40 if (!lang->defs) {
41 r_lang_free (lang);
42 return NULL;
43 }
44 lang->defs->free = (RListFree)r_lang_def_free;
45 lang->cb_printf = (PrintfCallback)printf;
46 #if __UNIX__
47 r_lang_add (lang, &r_lang_plugin_c);
48 r_lang_add (lang, &r_lang_plugin_cpipe);
49 #endif
50 r_lang_add (lang, &r_lang_plugin_vala);
51 r_lang_add (lang, &r_lang_plugin_rust);
52 r_lang_add (lang, &r_lang_plugin_zig);
53 r_lang_add (lang, &r_lang_plugin_spp);
54 r_lang_add (lang, &r_lang_plugin_pipe);
55 r_lang_add (lang, &r_lang_plugin_lib);
56
57 return lang;
58 }
59
r_lang_free(RLang * lang)60 R_API void r_lang_free(RLang *lang) {
61 if (lang) {
62 __lang = NULL;
63 r_lang_undef (lang, NULL);
64 r_list_free (lang->langs);
65 r_list_free (lang->defs);
66 // TODO: remove langs plugins
67 free (lang);
68 }
69 }
70
71 // XXX: This is only used actually to pass 'core' structure
72 // TODO: when language bindings are done we will need an api to
73 // define symbols from C to the language namespace
74 // XXX: Depcreate!!
r_lang_set_user_ptr(RLang * lang,void * user)75 R_API void r_lang_set_user_ptr(RLang *lang, void *user) {
76 lang->user = user;
77 }
78
r_lang_define(RLang * lang,const char * type,const char * name,void * value)79 R_API bool r_lang_define(RLang *lang, const char *type, const char *name, void *value) {
80 RLangDef *def;
81 RListIter *iter;
82 r_list_foreach (lang->defs, iter, def) {
83 if (!r_str_casecmp (name, def->name)) {
84 def->value = value;
85 return true;
86 }
87 }
88 def = R_NEW0 (RLangDef);
89 if (!def) {
90 return false;
91 }
92 def->type = strdup (type);
93 def->name = strdup (name);
94 def->value = value;
95 r_list_append (lang->defs, def);
96 return true;
97 }
98
r_lang_def_free(RLangDef * def)99 R_API void r_lang_def_free (RLangDef *def) {
100 free (def->name);
101 free (def->type);
102 free (def);
103 }
104
r_lang_undef(RLang * lang,const char * name)105 R_API void r_lang_undef(RLang *lang, const char *name) {
106 if (name && *name) {
107 RLangDef *def;
108 RListIter *iter;
109 /* No _safe loop necessary because we return immediately after the delete. */
110 r_list_foreach (lang->defs, iter, def) {
111 if (!name || !r_str_casecmp (name, def->name)) {
112 r_list_delete (lang->defs, iter);
113 break;
114 }
115 }
116 } else {
117 r_list_free (lang->defs);
118 lang->defs = NULL;
119 }
120 }
121
r_lang_setup(RLang * lang)122 R_API bool r_lang_setup(RLang *lang) {
123 if (lang && lang->cur && lang->cur->setup) {
124 return lang->cur->setup (lang);
125 }
126 return false;
127 }
128
r_lang_add(RLang * lang,RLangPlugin * foo)129 R_API bool r_lang_add(RLang *lang, RLangPlugin *foo) {
130 if (foo && (!r_lang_get_by_name (lang, foo->name))) {
131 if (foo->init) {
132 foo->init (lang);
133 }
134 r_list_append (lang->langs, foo);
135 return true;
136 }
137 return false;
138 }
139
140 /* TODO: deprecate all list methods */
r_lang_list(RLang * lang)141 R_API bool r_lang_list(RLang *lang) {
142 RListIter *iter;
143 RLangPlugin *h;
144 if (!lang) {
145 return false;
146 }
147 r_list_foreach (lang->langs, iter, h) {
148 const char *license = h->license
149 ? h->license : "???";
150 lang->cb_printf ("%s: (%s) %s\n",
151 h->name, license, h->desc);
152 }
153 return true;
154 }
155
r_lang_get_by_extension(RLang * lang,const char * ext)156 R_API RLangPlugin *r_lang_get_by_extension (RLang *lang, const char *ext) {
157 RListIter *iter;
158 RLangPlugin *h;
159 const char *p = r_str_lchr (ext, '.');
160 if (p) {
161 ext = p + 1;
162 }
163 r_list_foreach (lang->langs, iter, h) {
164 if (!r_str_casecmp (h->ext, ext)) {
165 return h;
166 }
167 }
168 return NULL;
169 }
170
r_lang_get_by_name(RLang * lang,const char * name)171 R_API RLangPlugin *r_lang_get_by_name (RLang *lang, const char *name) {
172 RListIter *iter;
173 RLangPlugin *h;
174 r_list_foreach (lang->langs, iter, h) {
175 if (!r_str_casecmp (h->name, name)) {
176 return h;
177 }
178 if (h->alias && !r_str_casecmp (h->alias, name)) {
179 return h;
180 }
181 }
182 return NULL;
183 }
184
r_lang_use(RLang * lang,const char * name)185 R_API bool r_lang_use(RLang *lang, const char *name) {
186 RLangPlugin *h = r_lang_get_by_name (lang, name);
187 if (h) {
188 lang->cur = h;
189 return true;
190 }
191 return false;
192 }
193
194 // TODO: store in r_lang and use it from the plugin?
r_lang_set_argv(RLang * lang,int argc,char ** argv)195 R_API bool r_lang_set_argv(RLang *lang, int argc, char **argv) {
196 if (lang->cur && lang->cur->set_argv) {
197 return lang->cur->set_argv (lang, argc, argv);
198 }
199 return false;
200 }
201
r_lang_run(RLang * lang,const char * code,int len)202 R_API bool r_lang_run(RLang *lang, const char *code, int len) {
203 if (lang->cur && lang->cur->run) {
204 return lang->cur->run (lang, code, len);
205 }
206 return false;
207 }
208
r_lang_run_string(RLang * lang,const char * code)209 R_API bool r_lang_run_string(RLang *lang, const char *code) {
210 return r_lang_run (lang, code, strlen (code));
211 }
212
r_lang_run_file(RLang * lang,const char * file)213 R_API bool r_lang_run_file(RLang *lang, const char *file) {
214 bool ret = false;
215 if (lang->cur) {
216 if (!lang->cur->run_file) {
217 if (lang->cur->run) {
218 size_t len;
219 char *code = r_file_slurp (file, &len);
220 if (!code) {
221 eprintf ("Could not open '%s'.\n", file);
222 return 0;
223 }
224 ret = lang->cur->run (lang, code, (int)len);
225 free (code);
226 }
227 } else {
228 ret = lang->cur->run_file (lang, file);
229 }
230 }
231 return ret;
232 }
233
234 /* TODO: deprecate or make it more modular .. reading from stdin in a lib?!? wtf */
r_lang_prompt(RLang * lang)235 R_API bool r_lang_prompt(RLang *lang) {
236 char buf[1024];
237 const char *p;
238
239 if (!lang || !lang->cur) {
240 return false;
241 }
242
243 if (lang->cur->prompt) {
244 if (lang->cur->prompt (lang)) {
245 return true;
246 }
247 }
248 /* init line */
249 RLine *line = r_line_singleton ();
250 RLineHistory hist = line->history;
251 RLineHistory histnull = {0};
252 RLineCompletion oc = line->completion;
253 RLineCompletion ocnull = {0};
254 char *prompt = strdup (line->prompt);
255 line->completion = ocnull;
256 line->history = histnull;
257
258 /* foo */
259 for (;;) {
260 r_cons_flush ();
261 snprintf (buf, sizeof (buf)-1, "%s> ", lang->cur->name);
262 r_line_set_prompt (buf);
263 #if 0
264 printf ("%s> ", lang->cur->name);
265 fflush (stdout);
266 fgets (buf, sizeof (buf), stdin);
267 if (feof (stdin)) break;
268 r_str_trim_tail (buf);
269 #endif
270 p = r_line_readline ();
271 if (!p) {
272 break;
273 }
274 r_line_hist_add (p);
275 strncpy (buf, p, sizeof (buf) - 1);
276 if (*buf == '!') {
277 if (buf[1]) {
278 r_sandbox_system (buf + 1, 1);
279 } else {
280 char *foo, *code = NULL;
281 do {
282 foo = r_cons_editor (NULL, code);
283 r_lang_run (lang, foo, 0);
284 free (code);
285 code = foo;
286 } while (r_cons_yesno ('y', "Edit again? (Y/n)"));
287 free (foo);
288 }
289 continue;
290 }
291 if (!memcmp (buf, ". ", 2)) {
292 char *file = r_file_abspath (buf+2);
293 if (file) {
294 r_lang_run_file (lang, file);
295 free (file);
296 }
297 continue;
298 }
299 if (!strcmp (buf, "q")) {
300 free (prompt);
301 return true;
302 }
303 if (!strcmp (buf, "?")) {
304 RLangDef *def;
305 RListIter *iter;
306 eprintf(" ? - show this help message\n"
307 " ! - run $EDITOR\n"
308 " !command - run system command\n"
309 " . file - interpret file\n"
310 " q - quit prompt\n");
311 eprintf ("%s example:\n", lang->cur->name);
312 if (lang->cur->help) {
313 eprintf ("%s", *lang->cur->help);
314 }
315 if (!r_list_empty (lang->defs)) {
316 eprintf ("variables:\n");
317 }
318 r_list_foreach (lang->defs, iter, def) {
319 eprintf (" %s %s\n", def->type, def->name);
320 }
321 } else {
322 r_lang_run (lang, buf, strlen (buf));
323 }
324 }
325 // XXX: leaking history
326 r_line_set_prompt (prompt);
327 line->completion = oc;
328 line->history = hist;
329 clearerr (stdin);
330 printf ("\n");
331 free (prompt);
332 return true;
333 }
334