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