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