1 /* radare - LGPL - Copyright 2009-2020 - pancake */
2 
3 #include <stddef.h>
4 #include <math.h> // required for signbit
5 #include "r_cons.h"
6 #include "r_core.h"
7 #include "r_util.h"
8 
vernum(const char * s)9 static ut32 vernum(const char *s) {
10 	// XXX this is known to be buggy, only works for strings like "x.x.x"
11 	// XXX anything like "x.xx.x" will break the parsing
12 	// XXX -git is ignored, maybe we should shift for it
13 	char *a = strdup (s);
14 	a = r_str_replace (a, ".", "0", 1);
15 	char *dash = strchr (a, '-');
16 	if (dash) {
17 		*dash = 0;
18 	}
19 	ut32 res = atoi (a);
20 	free (a);
21 	return res;
22 }
23 
24 static const char *help_msg_percent[] = {
25 	"Usage:", "%[name[=value]]", "Set each NAME to VALUE in the environment",
26 	"%", "", "list all environment variables",
27 	"%", "SHELL", "prints SHELL value",
28 	"%", "TMPDIR=/tmp", "sets TMPDIR value to \"/tmp\"",
29 	NULL
30 };
31 
32 // NOTE: probably not all environment vars takes sesnse
33 // because they can be replaced by commands in the given
34 // command.. we should only expose the most essential and
35 // unidirectional ones.
36 static const char *help_msg_env[] = {
37 	"\nEnvironment:", "", "",
38 	"R2_FILE", "", "file name",
39 	"R2_OFFSET", "", "10base offset 64bit value",
40 	"R2_BYTES", "", "TODO: variable with bytes in curblock",
41 	"R2_XOFFSET", "", "same as above, but in 16 base",
42 	"R2_BSIZE", "", "block size",
43 	"R2_ENDIAN", "", "'big' or 'little'",
44 	"R2_IOVA", "", "is io.va true? virtual addressing (1,0)",
45 	"R2_DEBUG", "", "debug mode enabled? (1,0)",
46 	"R2_BLOCK", "", "TODO: dump current block to tmp file",
47 	"R2_SIZE", "","file size",
48 	"R2_ARCH", "", "value of asm.arch",
49 	"R2_BITS", "", "arch reg size (8, 16, 32, 64)",
50 	"RABIN2_LANG", "", "assume this lang to demangle",
51 	"RABIN2_DEMANGLE", "", "demangle or not",
52 	"RABIN2_PDBSERVER", "", "e pdb.server",
53 	NULL
54 };
55 
56 static const char *help_msg_exclamation[] = {
57 	"Usage:", "!<cmd>", "  Run given command as in system(3)",
58 	"!", "", "list all historic commands",
59 	"!", "ls", "execute 'ls' in shell",
60 	"!*", "r2p x", "run r2 command via r2pipe in current session",
61 	"!!", "", "save command history to hist file",
62 	"!!", "ls~txt", "print output of 'ls' and grep for 'txt'",
63 	"!!!", "cmd [args|$type]", "adds the autocomplete value",
64 	"!!!-", "cmd [args]", "removes the autocomplete value",
65 	".!", "rabin2 -rpsei ${FILE}", "run each output line as a r2 cmd",
66 	"!", "echo $R2_SIZE", "display file size",
67 	"!-", "", "clear history in current session",
68 	"!-*", "", "clear and save empty history log",
69 	"!=!", "", "enable remotecmd mode",
70 	"=!=", "", "disable remotecmd mode",
71 	NULL
72 };
73 
74 static const char *help_msg_root[] = {
75 	"%var", "=value", "alias for 'env' command",
76 	"*", "[?] off[=[0x]value]", "pointer read/write data/values (see ?v, wx, wv)",
77 	"(macro arg0 arg1)",  "", "manage scripting macros",
78 	".", "[?] [-|(m)|f|!sh|cmd]", "Define macro or load r2, cparse or rlang file",
79 	",", "[?] [/jhr]", "create a dummy table import from file and query it to filter/sort",
80 	"_", "[?]", "Print last output",
81 	"=","[?] [cmd]", "send/listen for remote commands (rap://, raps://, udp://, http://, <fd>)",
82 	"<","[...]", "push escaped string into the RCons.readChar buffer",
83 	"/","[?]", "search for bytes, regexps, patterns, ..",
84 	"!","[?] [cmd]", "run given command as in system(3)",
85 	"#","[?] !lang [..]", "Hashbang to run an rlang script",
86 	"a","[?]", "analysis commands",
87 	"b","[?]", "display or change the block size",
88 	"c","[?] [arg]", "compare block with given data",
89 	"C","[?]", "code metadata (comments, format, hints, ..)",
90 	"d","[?]", "debugger commands",
91 	"e","[?] [a[=b]]", "list/get/set config evaluable vars",
92 	"f","[?] [name][sz][at]", "add flag at current address",
93 	"g","[?] [arg]", "generate shellcodes with r_egg",
94 	"i","[?] [file]", "get info about opened file from r_bin",
95 	"k","[?] [sdb-query]", "run sdb-query. see k? for help, 'k *', 'k **' ...",
96 	"l"," [filepattern]", "list files and directories",
97 	"L","[?] [-] [plugin]", "list, unload load r2 plugins",
98 	"m","[?]", "mountpoints commands",
99 	"o","[?] [file] ([offset])", "open file at optional address",
100 	"p","[?] [len]", "print current block with format and length",
101 	"P","[?]", "project management utilities",
102 	"q","[?] [ret]", "quit program with a return value",
103 	"r","[?] [len]", "resize file",
104 	"s","[?] [addr]", "seek to address (also for '0x', '0x1' == 's 0x1')",
105 	"t","[?]", "types, noreturn, signatures, C parser and more",
106 	"T","[?] [-] [num|msg]", "Text log utility (used to chat, sync, log, ...)",
107 	"u","[?]", "uname/undo seek/write",
108 	"v","", "panels mode",
109 	"V", "", "visual mode (Vv = func/var anal, VV = graph mode, ...)",
110 	"w","[?] [str]", "multiple write operations",
111 	"x","[?] [len]", "alias for 'px' (print hexadecimal)",
112 	"y","[?] [len] [[[@]addr", "Yank/paste bytes from/to memory",
113 	"z", "[?]", "zignatures management",
114 	"?[??]","[expr]", "Help or evaluate math expression",
115 	"?$?", "", "show available '$' variables and aliases",
116 	"?@?", "", "misc help for '@' (seek), '~' (grep) (see ~?\"\"?)",
117 	"?>?", "", "output redirection",
118 	"?|?", "", "help for '|' (pipe)",
119 	NULL
120 };
121 
122 static const char *help_msg_question_e[] = {
123 	"Usage: ?e[=bdgnpst] arg", "print/echo things", "",
124 	"?e", "", "echo message with newline",
125 	"?e=", " 32", "progress bar at 32 percentage",
126 	"?eb", " 10 20 30", "proportional segments bar",
127 	"?ed", " 1", "draw a 3D ascii donut at the given animation frame",
128 	"?eg", " 10 20", "move cursor to column 10, row 20",
129 	"?en", " nonl", "echo message without ending newline",
130 	"?ep", " 10 20 30", "draw a pie char with given portion sizes",
131 	"?es", " msg", "speak message using the text-to-speech program (e cfg.tts)",
132 	"?et", " msg", "change terminal title",
133 	NULL
134 };
135 
136 static const char *help_msg_question[] = {
137 	"Usage: ?[?[?]] expression", "", "",
138 	"?!", " [cmd]", "run cmd if $? == 0",
139 	"?", " eip-0x804800", "show all representation result for this math expr",
140 	"?$", "", "show value all the variables ($)",
141 	"?+", " [cmd]", "run cmd if $? > 0",
142 	"?-", " [cmd]", "run cmd if $? < 0",
143 	"?:", "", "list core cmd plugins",
144 	"?=", " eip-0x804800", "hex and dec result for this math expr",
145 	"?==", " x86 `e asm.arch`", "strcmp two strings",
146 	"??", " [cmd]", "run cmd if $? != 0",
147 	"??", "", "show value of operation",
148 	"?a", "", "show ascii table",
149 	"?B", " [elem]", "show range boundaries like 'e?search.in",
150 	"?b", " [num]", "show binary value of number",
151 	"?b64[-]", " [str]", "encode/decode in base64",
152 	"?btw", " num|expr num|expr num|expr", "returns boolean value of a <= b <= c",
153 	"?e", "[=bdgnpst] arg", "echo messages, bars, pie charts and more (see ?e? for details)",
154 	"?f", " [num] [str]", "map each bit of the number as flag string index",
155 	"?F", "", "flush cons output",
156 	"?h", " [str]", "calculate hash for given string",
157 	"?i", "[ynmkp] arg", "prompt for number or Yes,No,Msg,Key,Path and store in $$?",
158 	"?ik", "", "press any key input dialog",
159 	"?im", " message", "show message centered in screen",
160 	"?in", " prompt", "noyes input prompt",
161 	"?ip", " prompt", "path input prompt",
162 	"?iy", " prompt", "yesno input prompt",
163 	"?j", " arg", "same as '? num' but in JSON",
164 	"?l", "[q] str", "returns the length of string ('q' for quiet, just set $?)",
165 	"?o", " num", "get octal value",
166 	"?P", " paddr", "get virtual address for given physical one",
167 	"?p", " vaddr", "get physical address for given virtual address",
168 	"?q", " eip-0x804800", "compute expression like ? or ?v but in quiet mode",
169 	"?r", " [from] [to]", "generate random number between from-to",
170 	"?s", " from to step", "sequence of numbers from to by steps",
171 	"?t", " cmd", "returns the time to run a command",
172 	"?T", "", "show loading times",
173 	"?u", " num", "get value in human units (KB, MB, GB, TB)",
174 	"?v", " eip-0x804800", "show hex value of math expr",
175 	"?V", "", "show library version of r_core",
176 	"?vi", " rsp-rbp", "show decimal value of math expr",
177 	"?w", " addr", "show what's in this address (like pxr/pxq does)",
178 	"?X", " num|expr", "returns the hexadecimal value numeric expr",
179 	"?x", " str", "returns the hexpair of number or string",
180 	"?x", "+num", "like ?v, but in hexpairs honoring cfg.bigendian",
181 	"?x", "-hexst", "convert hexpair into raw string with newline",
182 	"?_", " hudfile", "load hud menu with given file",
183 	"[cmd]?*", "", "recursive help for the given cmd",
184 	NULL
185 };
186 
187 static const char *help_msg_question_v[] = {
188 	"Usage: ?v [$.]","","",
189 	"flag", "", "offset of flag",
190 	"$", "{ev}", "get value of eval config variable",
191 	"$$", "", "here (current virtual seek)",
192 	"$$$", "", "current non-temporary virtual seek",
193 	"$?", "", "last comparison value",
194 	"$alias", "=value", "alias commands (simple macros)",
195 	"$B", "", "base address (aligned lowest map address)",
196 	"$b", "", "block size",
197 	"$c", "", "get terminal width in character columns",
198 	"$Cn", "", "get nth call of function",
199 	"$D", "", "current debug map base address ?v $D @ rsp",
200 	"$DB", "", "same as dbg.baddr, progam base address",
201 	"$DD", "", "current debug map size",
202 	"$Dn", "", "get nth data reference in function",
203 	"$e", "", "1 if end of block, else 0",
204 	"$e", "{flag}", "end of flag (flag->offset + flag->size)",
205 	"$f", "", "jump fail address (e.g. jz 0x10 => next instruction)",
206 	"$F", "", "Same as $FB",
207 	"$Fb", "", "begin of basic block",
208 	"$FB", "", "begin of function",
209 	"$Fe", "", "end of basic block",
210 	"$FE", "", "end of function",
211 	"$Ff", "", "function false destination",
212 	"$Fi", "", "basic block instructions",
213 	"$FI", "", "function instructions",
214 	"$Fj", "", "function jump destination",
215 	"$fl", "", "flag length (size) at current address (fla; pD $l @ entry0)",
216 	"$FS", "", "function size (linear length)",
217 	"$Fs", "", "size of the current basic block",
218 	"$FSS", "", "function size (sum bb sizes)",
219 	"$i", "{n}", "address of nth instruction forward",
220 	"$I", "{n}", "address of nth instruction backward (s $I1@$Fe) #last instr in bb",
221 	"$j", "", "jump address (e.g. jmp 0x10, jz 0x10 => 0x10)",
222 	"$Ja", "", "get nth jump of function",
223 	"$k", "{kv}", "get value of an sdb query value",
224 	"$l", "", "opcode length",
225 	"$M", "", "map address (lowest map address)",
226 	"$m", "", "opcode memory reference (e.g. mov eax,[0x10] => 0x10)",
227 	"$MM", "", "map size (lowest map address)",
228 	"$O", "", "cursor here (current offset pointed by the cursor)",
229 	"$o", "", "here (current disk io offset)",
230 	"$p", "", "getpid()",
231 	"$P", "", "pid of children (only in debug)",
232 	"$r", "", "get console height (in rows, see $c for columns)",
233 	"$r", "{reg}", "get value of named register",
234 	"$s", "", "file size",
235 	"$S", "", "section offset",
236 	"$SS", "", "section size",
237 	"$s", "{flag}", "get size of flag",
238 	"$v", "", "opcode immediate value (e.g. lui a0,0x8010 => 0x8010)",
239 	"$w", "", "get word size, 4 if asm.bits=32, 8 if 64, ...",
240 	"$Xn", "", "get nth xref of function",
241 	"RNum", "", "$variables usable in math expressions",
242 	NULL
243 };
244 
245 static const char *help_msg_question_V[] = {
246 	"Usage: ?V[jq]","","",
247 	"?V", "", "show version information",
248 	"?V0", "", "show major version",
249 	"?V1", "", "show minor version",
250 	"?V2", "", "show patch version",
251 	"?Vn", "", "show numeric version (2)",
252 	"?Vc", "", "show numeric version",
253 	"?Vj", "", "same as above but in JSON",
254 	"?Vq", "", "quiet mode, just show the version number",
255 	NULL
256 };
257 
258 static const char *help_msg_greater_sign[] = {
259 	"Usage:", "[cmd]>[file]", "redirects console from 'cmd' output to 'file'",
260 	"[cmd] > [file]", "", "redirect STDOUT of 'cmd' to 'file'",
261 	"[cmd] > $alias", "", "save the output of the command as an alias (see $?)",
262 	"[cmd] H> [file]", "", "redirect html output of 'cmd' to 'file'",
263 	"[cmd] 2> [file]", "", "redirect STDERR of 'cmd' to 'file'",
264 	"[cmd] 2> /dev/null", "", "omit the STDERR output of 'cmd'",
265 	NULL
266 };
267 
268 static const char *help_msg_intro[] = {
269 	"Usage: [.][times][cmd][~grep][@[@iter]addr!size][|>pipe] ; ...", "", "",
270 	"Append '?' to any char command to get detailed help", "", "",
271 	"Prefix with number to repeat command N times (f.ex: 3x)", "", "",
272 	NULL
273 };
274 
cmd_help_exclamation(RCore * core)275 static void cmd_help_exclamation(RCore *core) {
276 	r_core_cmd_help (core, help_msg_exclamation);
277 	r_core_cmd_help (core, help_msg_env);
278 }
279 
cmd_help_percent(RCore * core)280 static void cmd_help_percent(RCore *core) {
281 	r_core_cmd_help (core, help_msg_percent);
282 	r_core_cmd_help (core, help_msg_env);
283 }
284 
cmd_help_init(RCore * core,RCmdDesc * parent)285 static void cmd_help_init(RCore *core, RCmdDesc *parent) {
286 	DEFINE_CMD_DESCRIPTOR_SPECIAL (core, ?, question);
287 	DEFINE_CMD_DESCRIPTOR_SPECIAL (core, ?v, question_v);
288 	DEFINE_CMD_DESCRIPTOR_SPECIAL (core, ?V, question_V);
289 }
290 
findBreakChar(const char * s)291 static const char* findBreakChar(const char *s) {
292 	while (*s) {
293 		if (!r_name_validate_char (*s)) {
294 			break;
295 		}
296 		s++;
297 	}
298 	return s;
299 }
300 
filterFlags(RCore * core,const char * msg)301 static char *filterFlags(RCore *core, const char *msg) {
302 	const char *dollar, *end;
303 	char *word, *buf = NULL;
304 	for (;;) {
305 		dollar = strchr (msg, '$');
306 		if (!dollar) {
307 			break;
308 		}
309 		buf = r_str_appendlen (buf, msg, dollar-msg);
310 		if (dollar[1]=='{') {
311 			// find }
312 			end = strchr (dollar+2, '}');
313 			if (end) {
314 				word = r_str_newlen (dollar+2, end-dollar-2);
315 				end++;
316 			} else {
317 				msg = dollar+1;
318 				buf = r_str_append (buf, "$");
319 				continue;
320 			}
321 		} else {
322 			end = findBreakChar (dollar+1);
323 			if (!end) {
324 				end = dollar + strlen (dollar);
325 			}
326 			word = r_str_newlen (dollar+1, end-dollar-1);
327 		}
328 		if (end && word) {
329 			ut64 val = r_num_math (core->num, word);
330 			char num[32];
331 			snprintf (num, sizeof (num), "0x%"PFMT64x, val);
332 			buf = r_str_append (buf, num);
333 			msg = end;
334 		} else {
335 			break;
336 		}
337 		free (word);
338 	}
339 	buf = r_str_append (buf, msg);
340 	return buf;
341 }
342 
343 static const char *avatar_orangg[] = {
344 	"      _______\n"
345 	"     /       \\      .-%s-.\n"
346 	"   _| ( o) (o)\\_    | %s |\n"
347 	"  / _     .\\. | \\  <| %s |\n"
348 	"  \\| \\   ____ / 7`  | %s |\n"
349 	"  '|\\|  `---'/      `-%s-'\n"
350 	"     | /----. \\\n"
351 	"     | \\___/  |___\n"
352 	"     `-----'`-----'\n"
353 };
354 
355 static const char *avatar_clippy[] = {
356 	" .--.     .-%s-.\n"
357 	" | _|     | %s |\n"
358 	" | O O   <  %s |\n"
359 	" |  |  |  | %s |\n"
360 	" || | /   `-%s-'\n"
361 	" |`-'|\n"
362 	" `---'\n",
363 	" .--.     .-%s-.\n"
364 	" |   \\    | %s |\n"
365 	" | O o   <  %s |\n"
366 	" |   | /  | %s |\n"
367 	" |  ( /   `-%s-'\n"
368 	" |   / \n"
369 	" `--'\n",
370 	" .--.     .-%s-.\n"
371 	" | _|_    | %s |\n"
372 	" | O O   <  %s |\n"
373 	" |  ||    | %s |\n"
374 	" | _:|    `-%s-'\n"
375 	" |   |\n"
376 	" `---'\n",
377 };
378 
379 static const char *avatar_clippy_utf8[] = {
380 	" ╭──╮    ╭─%s─╮\n"
381 	" │ _│    │ %s │\n"
382 	" │ O O  <  %s │\n"
383 	" │  │╭   │ %s │\n"
384 	" ││ ││   ╰─%s─╯\n"
385 	" │└─┘│\n"
386 	" ╰───╯\n",
387 	" ╭──╮    ╭─%s─╮\n"
388 	" │ ╶│╶   │ %s │\n"
389 	" │ O o  <  %s │\n"
390 	" │  │  ╱ │ %s │\n"
391 	" │ ╭┘ ╱  ╰─%s─╯\n"
392 	" │ ╰ ╱\n"
393 	" ╰──'\n",
394 	" ╭──╮    ╭─%s─╮\n"
395 	" │ _│_   │ %s │\n"
396 	" │ O O  <  %s │\n"
397 	" │  │╷   │ %s │\n"
398 	" │  ││   ╰─%s─╯\n"
399 	" │ ─╯│\n"
400 	" ╰───╯\n",
401 };
402 
403 static const char *avatar_cybcat[] = {
404 "     /\\.---./\\       .-%s-.\n"
405 " '--           --'   | %s |\n"
406 "----   ^   ^   ---- <  %s |\n"
407 "  _.-    Y    -._    | %s |\n"
408 "                     `-%s-'\n",
409 "     /\\.---./\\       .-%s-.\n"
410 " '--   @   @   --'   | %s |\n"
411 "----     Y     ---- <  %s |\n"
412 "  _.-    O    -._    | %s |\n"
413 "                     `-%s-'\n",
414 "     /\\.---./\\       .-%s-.\n"
415 " '--   =   =   --'   | %s |\n"
416 "----     Y     ---- <  %s |\n"
417 "  _.-    U    -._    | %s |\n"
418 "                     `-%s-'\n",
419 };
420 
421 enum {
422 	R_AVATAR_ORANGG,
423 	R_AVATAR_CYBCAT,
424 	R_AVATAR_CLIPPY,
425 };
426 
r_core_clippy(RCore * core,const char * msg)427 R_API void r_core_clippy(RCore *core, const char *msg) {
428 	int type = R_AVATAR_CLIPPY;
429 	if (*msg == '+' || *msg == '3') {
430 		char *space = strchr (msg, ' ');
431 		if (!space) {
432 			return;
433 		}
434 		type = (*msg == '+')? R_AVATAR_ORANGG: R_AVATAR_CYBCAT;
435 		msg = space + 1;
436 	}
437 	const char *f;
438 	int msglen = r_str_len_utf8 (msg);
439 	char *s = strdup (r_str_pad (' ', msglen));
440 	char *l;
441 
442 	if (type == R_AVATAR_ORANGG) {
443 		l = strdup (r_str_pad ('-', msglen));
444 		f = avatar_orangg[0];
445 	} else if (type == R_AVATAR_CYBCAT) {
446 		l = strdup (r_str_pad ('-', msglen));
447 		f = avatar_cybcat[r_num_rand (R_ARRAY_SIZE (avatar_cybcat))];
448 	} else if (r_config_get_i (core->config, "scr.utf8")) {
449 		l = (char *)r_str_repeat ("─", msglen);
450 		f = avatar_clippy_utf8[r_num_rand (R_ARRAY_SIZE (avatar_clippy_utf8))];
451 	} else {
452 		l = strdup (r_str_pad ('-', msglen));
453 		f = avatar_clippy[r_num_rand (R_ARRAY_SIZE (avatar_clippy))];
454 	}
455 
456 	r_cons_printf (f, l, s, msg, s, l);
457 	free (l);
458 	free (s);
459 }
460 
cmd_help(void * data,const char * input)461 static int cmd_help(void *data, const char *input) {
462 	RCore *core = (RCore *)data;
463 	RIOMap *map;
464 	const char *k;
465 	RListIter *iter;
466 	char *p, out[128] = R_EMPTY;
467 	ut64 n;
468 	int i;
469 	RList *tmp;
470 
471 	switch (input[0]) {
472 	case 't': { // "?t"
473 		switch (input[1]) {
474 		case '0':
475 			core->curtab = 0;
476 			break;
477 		case '1':
478 			if (core->curtab < 0) {
479 				core->curtab = 0;
480 			}
481 			core->curtab ++;
482 			break;
483 		case ' ':
484 			{
485 				struct r_prof_t prof;
486 				r_prof_start (&prof);
487 				r_core_cmd (core, input + 1, 0);
488 				r_prof_end (&prof);
489 				core->num->value = (ut64)(int)prof.result;
490 				eprintf ("%lf\n", prof.result);
491 				break;
492 			}
493 		default:
494 			eprintf ("Usage: ?t[0,1] [cmd]\n");
495 			eprintf ("?t pd 32 # show time needed to run 'pd 32'\n");
496 			eprintf ("?t0 # select first visual tab\n");
497 			eprintf ("?t1 # select next visual tab\n");
498 			break;
499 		}
500 		break;
501 		}
502 	case 'r': // "?r"
503 		{ // TODO : Add support for 64bit random numbers
504 		ut64 b = 0;
505 		ut32 r = UT32_MAX;
506 		if (input[1]) {
507 			strncpy (out, input+(input[1]==' '? 2: 1), sizeof (out)-1);
508 			p = strchr (out + 1, ' ');
509 			if (p) {
510 				*p = 0;
511 				b = (ut32)r_num_math (core->num, out);
512 				r = (ut32)r_num_math (core->num, p+1)-b;
513 			} else {
514 				r = (ut32)r_num_math (core->num, out);
515 			}
516 		} else {
517 			r = 0LL;
518 		}
519 		if (!r) {
520 			r = UT32_MAX >> 1;
521 		}
522 		core->num->value = (ut64) (b + r_num_rand (r));
523 		r_cons_printf ("0x%"PFMT64x"\n", core->num->value);
524 		}
525 		break;
526 	case 'a': // "?a"
527 		r_cons_printf ("%s", ret_ascii_table());
528 		break;
529 	case 'b': // "?b"
530 		if (input[1] == '6' && input[2] == '4') {
531 			//b64 decoding takes at most strlen(str) * 4
532 			const int buflen = (strlen (input+3) * 4) + 1;
533 			char* buf = calloc (buflen, sizeof(char));
534 			if (!buf) {
535 				return false;
536 			}
537 			if (input[3] == '-') {
538 				r_base64_decode ((ut8*)buf, input + 4, -1);
539 			} else if (input[3] == ' ') {
540 				r_base64_encode (buf, (const ut8*)input + 4, -1);
541 			}
542 			r_cons_println (buf);
543 			free (buf);
544 		} else if (input[1] == 't' && input[2] == 'w') { // "?btw"
545 			if (r_num_between (core->num, input + 3) == -1) {
546 				eprintf ("Usage: ?btw num|(expr) num|(expr) num|(expr)\n");
547 			}
548 		} else {
549 			n = r_num_get (core->num, input+1);
550 			r_num_to_bits (out, n);
551 			r_cons_printf ("%sb\n", out);
552 		}
553 		break;
554 	case 'B': // "?B"
555 		k = r_str_trim_head_ro (input + 1);
556 		tmp = r_core_get_boundaries_prot (core, -1, k, "search");
557 		if (!tmp) {
558 			return false;
559 		}
560 		r_list_foreach (tmp, iter, map) {
561 			r_cons_printf ("0x%"PFMT64x" 0x%"PFMT64x"\n", r_io_map_begin (map), r_io_map_end (map));
562 		}
563 		r_list_free (tmp);
564 		break;
565 	case 'h': // "?h"
566 		if (input[1] == ' ') {
567 			r_cons_printf ("0x%08x\n", (ut32)r_str_hash (input + 2));
568 		} else {
569 			eprintf ("Usage: ?h [string-to-hash]\n");
570 		}
571 		break;
572 	case 'F': // "?F"
573 		r_cons_flush ();
574 		break;
575 	case 'f': // "?f"
576 		if (input[1] == ' ') {
577 			char *q, *p = strdup (input + 2);
578 			if (!p) {
579 				eprintf ("Cannot strdup\n");
580 				return 0;
581 			}
582 			q = strchr (p, ' ');
583 			if (q) {
584 				*q = 0;
585 				n = r_num_get (core->num, p);
586 				r_str_bits (out, (const ut8*)&n, sizeof (n) * 8, q + 1);
587 				r_cons_println (out);
588 			} else {
589 				eprintf ("Usage: \"?b value bitstring\"\n");
590 			}
591 			free (p);
592 		} else {
593 			eprintf ("Whitespace expected after '?f'\n");
594 		}
595 		break;
596 	case 'o': // "?o"
597 		n = r_num_math (core->num, input+1);
598 		r_cons_printf ("0%"PFMT64o"\n", n);
599 		break;
600 	case 'T': // "?T"
601 		r_cons_printf("plug.init = %"PFMT64d"\n"
602 			"plug.load = %"PFMT64d"\n"
603 			"file.load = %"PFMT64d"\n",
604 			core->times->loadlibs_init_time,
605 			core->times->loadlibs_time,
606 			core->times->file_open_time);
607 		break;
608 	case 'u': // "?u"
609 		{
610 			char unit[8];
611 			n = r_num_math (core->num, input+1);
612 			r_num_units (unit, sizeof (unit), n);
613 			r_cons_println (unit);
614 		}
615 		break;
616 	case 'j': // "?j"
617 	case ' ': // "? "
618 		{
619 			char *asnum, unit[8];
620 			ut32 s, a;
621 			double d;
622 			float f;
623 			char * const inputs = strdup (input + 1);
624 			RList *list = r_num_str_split_list (inputs);
625 			const int list_len = r_list_length (list);
626 			PJ *pj = NULL;
627 			if (*input ==  'j') {
628 				pj = pj_new ();
629 				pj_o (pj);
630 			}
631 			for (i = 0; i < list_len; i++) {
632 				const char *str = r_list_pop_head (list);
633 				if (!*str) {
634 					continue;
635 				}
636 				n = r_num_math (core->num, str);
637 				if (core->num->dbz) {
638 					eprintf ("RNum ERROR: Division by Zero\n");
639 				}
640 				asnum  = r_num_as_string (NULL, n, false);
641 				/* decimal, hexa, octal */
642 				s = n >> 16 << 12;
643 				a = n & 0x0fff;
644 				r_num_units (unit, sizeof (unit), n);
645 				if (*input ==  'j') {
646 					pj_ks (pj, "int32", sdb_fmt ("%d", (st32)(n & UT32_MAX)));
647 					pj_ks (pj, "uint32", sdb_fmt ("%u", (ut32)n));
648 					pj_ks (pj, "int64", sdb_fmt ("%"PFMT64d, (st64)n));
649 					pj_ks (pj, "uint64", sdb_fmt ("%"PFMT64u, (ut64)n));
650 					pj_ks (pj, "hex", sdb_fmt ("0x%08"PFMT64x, n));
651 					pj_ks (pj, "octal", sdb_fmt ("0%"PFMT64o, n));
652 					pj_ks (pj, "unit", unit);
653 					pj_ks (pj, "segment", sdb_fmt ("%04x:%04x", s, a));
654 
655 				} else {
656 					if (n >> 32) {
657 						r_cons_printf ("int64   %"PFMT64d"\n", (st64)n);
658 						r_cons_printf ("uint64  %"PFMT64u"\n", (ut64)n);
659 					} else {
660 						r_cons_printf ("int32   %d\n", (st32)n);
661 						r_cons_printf ("uint32  %u\n", (ut32)n);
662 					}
663 					r_cons_printf ("hex     0x%"PFMT64x"\n", n);
664 					r_cons_printf ("octal   0%"PFMT64o"\n", n);
665 					r_cons_printf ("unit    %s\n", unit);
666 					r_cons_printf ("segment %04x:%04x\n", s, a);
667 
668 					if (asnum) {
669 						r_cons_printf ("string  \"%s\"\n", asnum);
670 						free (asnum);
671 					}
672 				}
673 				/* binary and floating point */
674 				r_str_bits64 (out, n);
675 				f = d = core->num->fvalue;
676 				memcpy (&f, &n, sizeof (f));
677 				memcpy (&d, &n, sizeof (d));
678 				/* adjust sign for nan floats, different libcs are confused */
679 				if (isnan (f) && signbit (f)) {
680 					f = -f;
681 				}
682 				if (isnan (d) && signbit (d)) {
683 					d = -d;
684 				}
685 				if (*input ==  'j') {
686 					pj_ks (pj, "fvalue", sdb_fmt ("%.1lf", core->num->fvalue));
687 					pj_ks (pj, "float", sdb_fmt ("%ff", f));
688 					pj_ks (pj, "double", sdb_fmt ("%lf", d));
689 					pj_ks (pj, "binary", sdb_fmt ("0b%s", out));
690 					r_num_to_ternary (out, n);
691 					pj_ks (pj, "ternary", sdb_fmt ("0t%s", out));
692 				} else {
693 					r_cons_printf ("fvalue: %.1lf\n", core->num->fvalue);
694 					r_cons_printf ("float:  %ff\n", f);
695 					r_cons_printf ("double: %lf\n", d);
696 					r_cons_printf ("binary  0b%s\n", out);
697 					r_num_to_ternary (out, n);
698 					r_cons_printf ("ternary 0t%s\n", out);
699 				}
700 			}
701 			if (*input ==  'j') {
702 				pj_end (pj);
703 			}
704 			free (inputs);
705 			r_list_free (list);
706 			if (pj) {
707 				r_cons_printf ("%s\n", pj_string (pj));
708 				pj_free (pj);
709 			}
710 		}
711 		break;
712 	case 'q': // "?q"
713 		if (core->num->dbz) {
714 			eprintf ("RNum ERROR: Division by Zero\n");
715 		}
716 		if (input[1] == '?') {
717 			r_cons_printf ("|Usage: ?q [num]  # Update $? without printing anything\n"
718 				"|?q 123; ?? x    # hexdump if 123 != 0");
719 		} else {
720 			const char *space = strchr (input, ' ');
721 			if (space) {
722 				n = r_num_math (core->num, space + 1);
723 			} else {
724 				n = r_num_math (core->num, "$?");
725 			}
726 			core->num->value = n; // redundant
727 		}
728 		break;
729 	case 'v': // "?v"
730 		{
731 			const char *space = strchr (input, ' ');
732 			if (space) {
733 				n = r_num_math (core->num, space + 1);
734 			} else {
735 				n = r_num_math (core->num, "$?");
736 			}
737 		}
738 		if (core->num->dbz) {
739 			eprintf ("RNum ERROR: Division by Zero\n");
740 		}
741 		switch (input[1]) {
742 		case '?':
743 			r_cons_printf ("|Usage: ?v[id][ num]  # Show value\n"
744 				"|?vx number  -> show 8 digit padding in hex\n"
745 				"|?vi1 200    -> 1 byte size value (char)\n"
746 				"|?vi2 0xffff -> 2 byte size value (short)\n"
747 				"|?vi4 0xffff -> 4 byte size value (int)\n"
748 				"|?vi8 0xffff -> 8 byte size value (st64)\n"
749 				"| No argument shows $? value\n"
750 				"|?vi will show in decimal instead of hex\n");
751 			break;
752 		case '\0':
753 			r_cons_printf ("%d\n", (st32)n);
754 			break;
755 		case 'x': // "?vx"
756 			r_cons_printf ("0x%08"PFMT64x"\n", n);
757 			break;
758 		case 'i': // "?vi"
759 			switch (input[2]) {
760 			case '1': // byte
761 				r_cons_printf ("%d\n", (st8)(n & UT8_MAX));
762 				break;
763 			case '2': // word
764 				r_cons_printf ("%d\n", (st16)(n & UT16_MAX));
765 				break;
766 			case '4': // dword
767 				r_cons_printf ("%d\n", (st32)(n & UT32_MAX));
768 				break;
769 			case '8': // qword
770 				r_cons_printf ("%"PFMT64d"\n", (st64)(n & UT64_MAX));
771 				break;
772 			default:
773 				r_cons_printf ("%"PFMT64d"\n", n);
774 				break;
775 			}
776 			break;
777 		case 'd':
778 			r_cons_printf ("%"PFMT64d"\n", n);
779 			break;
780 		default:
781 			r_cons_printf ("0x%"PFMT64x"\n", n);
782 		}
783 		core->num->value = n; // redundant
784 		break;
785 	case '=': // "?=" set num->value
786 		if (input[1] == '=') { // ?==
787 			if (input[2] == ' ') {
788 				char *s = strdup (input + 3);
789 				char *e = strchr (s, ' ');
790 				if (e) {
791 					*e++ = 0;
792 					core->num->value = strcmp (s, e);
793 				} else {
794 					eprintf ("Missing secondary word in expression to compare\n");
795 				}
796 				free (s);
797 			} else {
798 				eprintf ("Usage: ?== str1 str2\n");
799 			}
800 		} else {
801 			if (input[1]) { // ?=
802 				r_num_math (core->num, input+1);
803 			} else {
804 				r_cons_printf ("0x%"PFMT64x"\n", core->num->value);
805 			}
806 		}
807 		break;
808 	case '+': // "?+"
809 		if (input[1]) {
810 			st64 n = (st64)core->num->value;
811 			if (n > 0) {
812 				r_core_cmd (core, input + 1, 0);
813 			}
814 		} else {
815 			r_cons_printf ("0x%"PFMT64x"\n", core->num->value);
816 		}
817 		break;
818 	case '-': // "?-"
819 		if (input[1]) {
820 			st64 n = (st64)core->num->value;
821 			if (n < 0) {
822 				r_core_cmd (core, input + 1, 0);
823 			}
824 		} else {
825 			r_cons_printf ("0x%"PFMT64x"\n", core->num->value);
826 		}
827 		break;
828 	case '!': // "?!"
829 		if (input[1]) {
830 			if (!core->num->value) {
831 				if (input[1] == '?') {
832 					cmd_help_exclamation (core);
833 					return 0;
834 				}
835 				return core->num->value = r_core_cmd (core, input+1, 0);
836 			}
837 		} else {
838 			r_cons_printf ("0x%"PFMT64x"\n", core->num->value);
839 		}
840 		break;
841 	case '@': // "?@"
842 		if (input[1] == '@') {
843 			if (input[2] == '@') {
844 				r_core_cmd_help (core, help_msg_at_at_at);
845 			} else {
846 				r_core_cmd_help (core, help_msg_at_at);
847 			}
848 		} else {
849 			r_core_cmd_help (core, help_msg_at);
850 		}
851 		break;
852 	case '&': // "?&"
853 		helpCmdTasks (core);
854 		break;
855 	case '%': // "?%"
856 		if (input[1] == '?') {
857 			cmd_help_percent (core);
858 		}
859 		break;
860 	case '$': // "?$"
861 		if (input[1] == '?') {
862 			r_core_cmd_help (core, help_msg_question_v);
863 		} else {
864 			int i = 0;
865 			const char *vars[] = {
866 				"$$", "$$$", "$?", "$B", "$b", "$c", "$Cn", "$D", "$DB", "$DD", "$Dn",
867 				"$e", "$f", "$F", "$Fb", "$FB", "$Fe", "$FE", "$Ff", "$Fi", "$FI", "$Fj",
868 				"$fl", "$FS", "$Fs", "$FSS", "$i", "$j", "$Ja", "$l", "$M", "$m", "$MM", "$O",
869 				"$o", "$p", "$P", "$r", "$s", "$S", "$SS", "$v", "$w", "$Xn", NULL
870 			};
871 			const bool wideOffsets = r_config_get_i (core->config, "scr.wideoff");
872 			while (vars[i]) {
873 				const char *pad = r_str_pad (' ', 6 - strlen (vars[i]));
874 				if (wideOffsets) {
875 					eprintf ("%s %s 0x%016"PFMT64x"\n", vars[i], pad, r_num_math (core->num, vars[i]));
876 				} else {
877 					eprintf ("%s %s 0x%08"PFMT64x"\n", vars[i], pad, r_num_math (core->num, vars[i]));
878 				}
879 				i++;
880 			}
881 		}
882 		return true;
883 	case 'V': // "?V"
884 		switch (input[1]) {
885 		case '?': // "?V?"
886 			r_core_cmd_help (core, help_msg_question_V);
887 			break;
888 		case 0: // "?V"
889 #if R2_VERSION_COMMIT == 0
890 			r_cons_printf ("%s release\n", R2_VERSION);
891 #else
892 			if (!strcmp (R2_VERSION, R2_GITTAP)) {
893 				r_cons_printf ("%s %d\n", R2_VERSION, R2_VERSION_COMMIT);
894 			} else {
895 				r_cons_printf ("%s aka %s commit %d\n", R2_VERSION, R2_GITTAP, R2_VERSION_COMMIT);
896 			}
897 #endif
898 			break;
899 		case 'c': // "?Vc"
900 			r_cons_printf ("%d\n", vernum (R2_VERSION));
901 			break;
902 		case 'j': // "?Vj"
903 			{
904 				PJ *pj = pj_new ();
905 				pj_o (pj);
906 				pj_ks (pj, "arch", R_SYS_ARCH);
907 				pj_ks (pj, "os", R_SYS_OS);
908 				pj_ki (pj, "bits", R_SYS_BITS);
909 				pj_ki (pj, "commit", R2_VERSION_COMMIT);
910 				pj_ks (pj, "tap", R2_GITTAP);
911 				pj_ki (pj, "major", R2_VERSION_MAJOR);
912 				pj_ki (pj, "minor", R2_VERSION_MINOR);
913 				pj_ki (pj, "patch", R2_VERSION_PATCH);
914 				pj_ki (pj, "number", R2_VERSION_NUMBER);
915 				pj_ki (pj, "nversion", vernum (R2_VERSION));
916 				pj_ks (pj, "version", R2_VERSION);
917 				pj_end (pj);
918 				r_cons_printf ("%s\n", pj_string (pj));
919 				pj_free (pj);
920 			}
921 			break;
922 		case 'n': // "?Vn"
923 			r_cons_printf ("%d\n", R2_VERSION_NUMBER);
924 			break;
925 		case 'q': // "?Vq"
926 			r_cons_println (R2_VERSION);
927 			break;
928 		case '0':
929 			r_cons_printf ("%d\n", R2_VERSION_MAJOR);
930 			break;
931 		case '1':
932 			r_cons_printf ("%d\n", R2_VERSION_MINOR);
933 			break;
934 		case '2':
935 			r_cons_printf ("%d\n", R2_VERSION_PATCH);
936 			break;
937 		}
938 		break;
939 	case 'l': // "?l"
940 		if (input[1] == 'q') {
941 			for (input += 2; input[0] == ' '; input++);
942 			core->num->value = strlen (input);
943 		} else {
944 			for (input++; input[0] == ' '; input++);
945 			core->num->value = strlen (input);
946 			r_cons_printf ("%" PFMT64d "\n", core->num->value);
947 		}
948 		break;
949 	case 'X': // "?X"
950 		for (input++; input[0] == ' '; input++);
951 		n = r_num_math (core->num, input);
952 		r_cons_printf ("%"PFMT64x"\n", n);
953 		break;
954 	case 'x': // "?x"
955 		for (input++; input[0] == ' '; input++);
956 		if (*input == '-') {
957 			ut8 *out = malloc (strlen (input) + 1);
958 			if (out) {
959 				int len = r_hex_str2bin (input + 1, out);
960 				if (len >= 0) {
961 					out[len] = 0;
962 					r_cons_println ((const char*)out);
963 				} else {
964 					eprintf ("Error parsing the hexpair string\n");
965 				}
966 				free (out);
967 			}
968 		} else if (*input == '+') {
969 			ut64 n = r_num_math (core->num, input);
970 			int bits = r_num_to_bits (NULL, n) / 8;
971 			for (i = 0; i < bits; i++) {
972 				r_cons_printf ("%02x", (ut8)((n >> (i * 8)) &0xff));
973 			}
974 			r_cons_newline ();
975 		} else {
976 			if (*input == ' ') {
977 				input++;
978 			}
979 			for (i = 0; input[i]; i++) {
980 				r_cons_printf ("%02x", input[i]);
981 			}
982 			r_cons_newline ();
983 		}
984 		break;
985 	case 'E': // "?E" clippy echo
986 		r_core_clippy (core, r_str_trim_head_ro (input + 1));
987 		break;
988 	case 'e': // "?e" echo
989 		switch (input[1]) {
990 		case 't': // "?e=t newtitle"
991 			r_cons_set_title (r_str_trim_head_ro (input + 2));
992 			break;
993 		case '=': { // "?e="
994 			ut64 pc = r_num_math (core->num, input + 2);
995 			r_print_progressbar (core->print, pc, 80);
996 			r_cons_newline ();
997 			break;
998 		}
999 		case 'b': { // "?eb"
1000 			char *arg = strdup (r_str_trim_head_ro (input + 2));
1001 			int n = r_str_split (arg, ' ');
1002 			ut64 *portions = calloc (n, sizeof (ut64));
1003 			for (i = 0; i < n; i++) {
1004 				portions[i] = r_num_math (core->num, r_str_word_get0 (arg, i));
1005 			}
1006 			r_print_portionbar (core->print, portions, n);
1007 			free (arg);
1008 			break;
1009 		}
1010 		case 's': { // "?es"
1011 			char *msg = strdup (input + 2);
1012 			r_str_trim (msg);
1013 			char *p = strchr (msg, '&');
1014 			if (p) *p = 0;
1015 			r_sys_tts (msg, p != NULL);
1016 			free (msg);
1017 			break;
1018 		}
1019 		case 'c': // "?ec" column
1020 			r_cons_column (r_num_math (core->num, input + 2));
1021 			break;
1022 		case 'g': { // "?eg" gotoxy
1023 			int x = atoi (input + 2);
1024 			char *arg = strchr (input + 2, ' ');
1025 			int y = arg? atoi (arg + 1): 0;
1026 			r_cons_gotoxy (x, y);
1027 			}
1028 			break;
1029 		case 'n': { // "?en" echo -n
1030 			const char *msg = r_str_trim_head_ro (input + 2);
1031 			// TODO: replace all ${flagname} by its value in hexa
1032 			char *newmsg = filterFlags (core, msg);
1033 			r_str_unescape (newmsg);
1034 			r_cons_print (newmsg);
1035 			free (newmsg);
1036 			break;
1037 		}
1038 		case 'd': // "?ed"
1039 			  if (input[2] == 'd') {
1040 				  int i,j;
1041 				  r_cons_show_cursor (0);
1042 				  r_cons_clear00 ();
1043 				  for (i = 1; i < 100; i++) {
1044 					  if (r_cons_is_breaked ()) {
1045 						  break;
1046 					  }
1047 					  for (j = 0; j < 20; j++) {
1048 						  char *d = r_str_donut (i);
1049 						  r_cons_gotoxy (0,0);
1050 						  r_str_trim_tail (d);
1051 						  r_cons_clear_line (0);
1052 						  r_cons_printf ("Downloading the Gibson...\n\n");
1053 						  r_core_cmdf (core, "?e=%d", i);
1054 						  r_cons_strcat (d);
1055 						  r_cons_clear_line (0);
1056 						  r_cons_newline ();
1057 						  free (d);
1058 						  r_cons_flush ();
1059 						  r_sys_usleep (2000);
1060 					  }
1061 				  }
1062 				  r_cons_clear00();
1063 				  r_cons_printf ("\nPayload installed. Thanks for your patience.\n\n");
1064 			} else {
1065 				  char *d = r_str_donut (r_num_math (core->num, input + 2));
1066 				  r_str_trim_tail (d);
1067 				  const char *color = (core->cons && core->cons->context->pal.flag)? core->cons->context->pal.flag: "";
1068 				  r_cons_printf ("%s%s", color, d);
1069 				  r_cons_newline ();
1070 				  free (d);
1071 			}
1072 			break;
1073 		case 'p':
1074 			  {
1075 			char *word, *str = strdup (input + 2);
1076 				  RList *list = r_str_split_list (str, " ", 0);
1077 				  ut64 *nums = calloc (sizeof (ut64), r_list_length (list));
1078 				  int i = 0;
1079 				  r_list_foreach (list, iter, word) {
1080 					nums[i] = r_num_math (core->num, word);;
1081 					i++;
1082 				  }
1083 				  int size = r_config_get_i (core->config, "hex.cols");
1084 				  r_print_pie (core->print, nums, r_list_length (list), size);
1085 				  r_list_free (list);
1086 			  }
1087 			break;
1088 		case ' ': {
1089 			const char *msg = r_str_trim_head_ro (input+1);
1090 			// TODO: replace all ${flagname} by its value in hexa
1091 			char *newmsg = filterFlags (core, msg);
1092 			r_str_unescape (newmsg);
1093 			r_cons_println (newmsg);
1094 			free (newmsg);
1095 			}
1096 			break;
1097 		case 0:
1098 			r_cons_newline ();
1099 			break;
1100 		default:
1101 			r_core_cmd_help (core, help_msg_question_e);
1102 			break;
1103 		}
1104 		break;
1105 	case 's': { // "?s" sequence from to step
1106 		ut64 from, to, step;
1107 		char *p, *p2;
1108 		for (input++; *input==' '; input++);
1109 		p = strchr (input, ' ');
1110 		if (p) {
1111 			*p = '\0';
1112 			from = r_num_math (core->num, input);
1113 			p2 = strchr (p+1, ' ');
1114 			if (p2) {
1115 				*p2 = '\0';
1116 				step = r_num_math (core->num, p2 + 1);
1117 			} else {
1118 				step = 1;
1119 			}
1120 			to = r_num_math (core->num, p + 1);
1121 			for (;from <= to; from += step)
1122 				r_cons_printf ("%"PFMT64d" ", from);
1123 			r_cons_newline ();
1124 		}
1125 		break;
1126 	}
1127 	case 'P': // "?P"
1128 		if (core->io->va) {
1129 			ut64 o, n = (input[0] && input[1])?
1130 				r_num_math (core->num, input+2): core->offset;
1131 			RIOMap *map = r_io_map_get_paddr (core->io, n);
1132 			if (map) {
1133 				o = n + r_io_map_begin (map) - map->delta;
1134 				r_cons_printf ("0x%08"PFMT64x"\n", o);
1135 			} else {
1136 				r_cons_printf ("no map at 0x%08"PFMT64x"\n", n);
1137 			}
1138 		} else {
1139 			r_cons_printf ("0x%08"PFMT64x"\n", core->offset);
1140 		}
1141 		break;
1142 	case 'p': // "?p"
1143 		if (core->io->va) {
1144 			// physical address
1145 			ut64 o, n = (input[0] && input[1])?
1146 				r_num_math (core->num, input + 2): core->offset;
1147 			RIOMap *map = r_io_map_get (core->io, n);
1148 			if (map) {
1149 				o = n - r_io_map_begin (map) + map->delta;
1150 				r_cons_printf ("0x%08"PFMT64x"\n", o);
1151 			} else {
1152 				r_cons_printf ("no map at 0x%08"PFMT64x"\n", n);
1153 			}
1154 		} else {
1155 			r_cons_printf ("0x%08"PFMT64x"\n", core->offset);
1156 		}
1157 		break;
1158 	case '_': // "?_" hud input
1159 		r_core_yank_hud_file (core, input+1);
1160 		break;
1161 	case 'i': // "?i" input num
1162 		r_cons_set_raw(0);
1163 		if (!r_cons_is_interactive ()) {
1164 			eprintf ("Not running in interactive mode\n");
1165 		} else {
1166 			switch (input[1]) {
1167 			case 'f': // "?if"
1168 				core->num->value = !r_num_conditional (core->num, input + 2);
1169 				eprintf ("%s\n", r_str_bool (!core->num->value));
1170 				break;
1171 			case 'm': // "?im"
1172 				r_cons_message (input + 2);
1173 				break;
1174 			case 'p': // "?ip"
1175 				core->num->value = r_core_yank_hud_path (core, input + 2, 0) == true;
1176 				break;
1177 			case 'k': // "?ik"
1178 				 r_cons_any_key (NULL);
1179 				 break;
1180 			case 'y': // "?iy"
1181 				 for (input += 2; *input==' '; input++);
1182 				 core->num->value = r_cons_yesno (1, "%s? (Y/n)", input);
1183 				 break;
1184 			case 'n': // "?in"
1185 				 for (input += 2; *input==' '; input++);
1186 				 core->num->value = r_cons_yesno (0, "%s? (y/N)", input);
1187 				 break;
1188 			default: {
1189 				char foo[1024];
1190 				r_cons_flush ();
1191 				for (input++; *input == ' '; input++);
1192 				// TODO: r_cons_input()
1193 				snprintf (foo, sizeof (foo) - 1, "%s: ", input);
1194 				r_line_set_prompt (foo);
1195 				r_cons_fgets (foo, sizeof (foo), 0, NULL);
1196 				foo[sizeof (foo) - 1] = 0;
1197 				r_core_yank_set_str (core, R_CORE_FOREIGN_ADDR, foo, strlen (foo) + 1);
1198 				core->num->value = r_num_math (core->num, foo);
1199 				}
1200 				break;
1201 			}
1202 		}
1203 		r_cons_set_raw (0);
1204 		break;
1205 	case 'w': { // "?w"
1206 		ut64 addr = r_num_math (core->num, input + 1);
1207 		char *rstr = core->print->hasrefs (core->print->user, addr, true);
1208 		if (!rstr) {
1209 			eprintf ("Cannot get refs\n");
1210 			break;
1211 		}
1212 		r_cons_println (rstr);
1213 		free (rstr);
1214 		break;
1215 	}
1216 	case '?': // "??"
1217 		if (input[1] == '?') {
1218 			if (input[2] == '?') { // "???"
1219 				r_core_clippy (core, "What are you doing?");
1220 				return 0;
1221 			}
1222 			if (input[2]) {
1223 				if (core->num->value) {
1224 					r_core_cmd (core, input + 1, 0);
1225 				}
1226 				break;
1227 			}
1228 			r_core_cmd_help (core, help_msg_question);
1229 			return 0;
1230 		} else if (input[1]) {
1231 			if (core->num->value) {
1232 				core->num->value = r_core_cmd (core, input+1, 0);
1233 			}
1234 		} else {
1235 			if (core->num->dbz) {
1236 				eprintf ("RNum ERROR: Division by Zero\n");
1237 			}
1238 			r_cons_printf ("%"PFMT64d"\n", core->num->value);
1239 		}
1240 		break;
1241 	case '\0': // "?"
1242 	default:
1243 		// TODO #7967 help refactor
1244 		r_core_cmd_help (core, help_msg_intro);
1245 		r_core_cmd_help (core, help_msg_root);
1246 		break;
1247 	}
1248 	return 0;
1249 }
1250