static void visual_help() { r_cons_clear00 (); r_cons_less_str ( "Visual mode help:\n" " ? show this help or manpage in cursor mode\n" " & rotate asm.bits between supported 8, 16, 32, 64\n" " % in cursor mode finds matching pair, otherwise toggle autoblocksz\n" " @ set cmd.vprompt to run commands before the visual prompt\n" " ! enter into the visual panels mode\n" " _ enter the hud\n" " = set cmd.vprompt (top row)\n" " | set cmd.cprompt (right column)\n" " . seek to program counter\n" " / in cursor mode search in current block\n" " :cmd run radare command\n" " ;[-]cmt add/remove comment\n" " /*+-[] change block size, [] = resize hex.cols\n" " >||< seek aligned to block size\n" " a/A (a)ssemble code, visual (A)ssembler\n" " b toggle breakpoint\n" " c/C toggle (c)ursor and (C)olors\n" " d[f?] define function, data, code, ..\n" " D enter visual diff mode (set diff.from/to)\n" " e edit eval configuration variables\n" " f/F set/unset or browse flags. f- to unset, F to browse, ..\n" " gG go seek to begin and end of file (0-$s)\n" " hjkl move around (or HJKL) (left-down-up-right)\n" " i insert hex or string (in hexdump) use tab to toggle\n" " mK/'K mark/go to Key (any key)\n" " M walk the mounted filesystems\n" " n/N seek next/prev function/flag/hit (scr.nkey)\n" " o go/seek to given offset\n" " O toggle asm.esil\n" " p/P rotate print modes (hex, disasm, debug, words, buf)\n" " q back to radare shell\n" " r browse anal info and comments\n" " R randomize color palette (ecr)\n" " sS step / step over\n" " T enter textlog chat console (TT)\n" " uU undo/redo seek\n" " v visual code analysis menu\n" " V (V)iew graph using cmd.graph (agv?)\n" " wW seek cursor to next/prev word\n" " xX show xrefs/refs of current function from/to data/code\n" " yY copy and paste selection\n" " z fold/unfold comments in disassembly\n" " Z toggle zoom mode\n" " Enter follow address of jump/call\n" "Function Keys: (See 'e key.'), defaults to:\n" " F2 toggle breakpoint\n" " F7 single step\n" " F8 step over\n" " F9 continue\n" ); r_cons_flush (); r_cons_clear00 (); }
static void visual_help() { r_cons_clear00 (); r_cons_less_str ( "Visual mode help:\n" " ? show this help or manpage in cursor mode\n" " & rotate asm.bits between supported 8, 16, 32, 64\n" " ! run r2048 game\n" " _ enter the hud\n" " . seek to program counter\n" " / in cursor mode search in current block\n" " :cmd run radare command\n" " ;[-]cmt add/remove comment\n" " /*+-[] change block size, [] = resize hex.cols\n" " >||< seek aligned to block size\n" " i/a/A (i)nsert hex, (a)ssemble code, visual (A)ssembler\n" " b/B toggle breakpoint / automatic block size\n" " c/C toggle (c)ursor and (C)olors\n" " d[f?] define function, data, code, ..\n" " D enter visual diff mode (set diff.from/to)\n" " e edit eval configuration variables\n" " f/F set/unset flag\n" " gG go seek to begin and end of file (0-$s)\n" " hjkl move around (or HJKL) (left-down-up-right)\n" " mK/'K mark/go to Key (any key)\n" " M walk the mounted filesystems\n" " n/N seek next/prev function/flag/hit (scr.nkey)\n" " o go/seek to given offset\n" " p/P rotate print modes (hex, disasm, debug, words, buf)\n" " q back to radare shell\n" " R randomize color palette (ecr)\n" " sS step / step over\n" " t track flags (browse symbols, functions..)\n" " T browse anal info and comments\n" " v visual code analysis menu\n" " V/W (V)iew graph using cmd.graph (agv?), open (W)ebUI\n" " uU undo/redo seek\n" " xX show xrefs/refs of current function from/to data/code\n" " yY copy and paste selection\n" " z toggle zoom mode\n" " Enter follow address of jump/call\n" "Function Keys: (See 'e key.'), defaults to:\n" " F2 toggle breakpoint\n" " F7 single step\n" " F8 step over\n" " F9 continue\n" ); r_cons_flush (); r_cons_clear00 (); }
R_API int r_cons_grepbuf(char *buf, int len) { RCons *cons = r_cons_singleton (); char *tline, *tbuf, *p, *out, *in = buf; int ret, total_lines = 0, buffer_len = 0, l = 0, tl = 0; bool show = false; if (cons->filter) { cons->buffer_len = 0; R_FREE (cons->buffer); return 0; } if ((!len || !buf || buf[0] == '\0') && (cons->grep.json || cons->grep.less)) { cons->grep.json = 0; cons->grep.less = 0; return 0; } if (cons->grep.json) { if (cons->grep.json_path) { char *u = sdb_json_get_str (cons->buffer, cons->grep.json_path); if (u) { cons->buffer = u; cons->buffer_len = strlen (u); cons->buffer_sz = cons->buffer_len + 1; cons->grep.json = 0; r_cons_newline (); } R_FREE (cons->grep.json_path); } else { const char *palette[] = { cons->pal.graph_false, // f cons->pal.graph_true, // t cons->pal.num, // k cons->pal.comment, // v Color_RESET, NULL }; char *out = r_print_json_indent (buf, I (color), " ", palette); if (!out) { return 0; } free (cons->buffer); cons->buffer = out; cons->buffer_len = strlen (out); cons->buffer_sz = cons->buffer_len + 1; cons->grep.json = 0; if (cons->grep.less) { cons->grep.less = 0; r_cons_less_str (cons->buffer, NULL); } } return 3; } if (cons->grep.less) { int less = cons->grep.less; cons->grep.less = 0; if (less == 2) { char *res = r_cons_hud_string (buf); r_cons_println (res); free (res); } else { r_cons_less_str (buf, NULL); buf[0] = 0; cons->buffer_len = 0; if (cons->buffer) { cons->buffer[0] = 0; } R_FREE (cons->buffer); } return 0; } if (!cons->buffer) { cons->buffer_len = len + 20; cons->buffer = malloc (cons->buffer_len); cons->buffer[0] = 0; } out = tbuf = calloc (1, len); if (!out) { return 0; } tline = malloc (len); if (!tline) { free (out); return 0; } cons->lines = 0; // used to count lines and change negative grep.line values while ((int) (size_t) (in - buf) < len) { p = strchr (in, '\n'); if (!p) { break; } l = p - in; if (l > 0) { in += l + 1; } else { in++; } total_lines++; } if (!cons->grep.range_line && cons->grep.line < 0) { cons->grep.line = total_lines + cons->grep.line; } if (cons->grep.range_line == 1) { if (cons->grep.f_line < 0) { cons->grep.f_line = total_lines + cons->grep.f_line; } if (cons->grep.l_line < 0) { cons->grep.l_line = total_lines + cons->grep.l_line; } } in = buf; while ((int) (size_t) (in - buf) < len) { p = strchr (in, '\n'); if (!p) { free (tbuf); free (tline); return 0; } l = p - in; if (l > 0) { memcpy (tline, in, l); if (cons->grep_color) { tl = l; } else { tl = r_str_ansi_filter (tline, NULL, NULL, l); } if (tl < 0) { ret = -1; } else { ret = r_cons_grep_line (tline, tl); if (!cons->grep.range_line) { if (cons->grep.line == cons->lines) { show = true; } } else if (cons->grep.range_line == 1) { if (cons->grep.f_line == cons->lines) { show = true; } if (cons->grep.l_line == cons->lines) { show = false; } } else { show = true; } } if (ret > 0) { if (show) { memcpy (out, tline, ret); memcpy (out + ret, "\n", 1); out += ret + 1; buffer_len += ret + 1; } if (!cons->grep.range_line) { show = false; } cons->lines++; } else if (ret < 0) { free (tbuf); free (tline); return 0; } in += l + 1; } else { in++; } } memcpy (buf, tbuf, len); cons->buffer_len = buffer_len; free (tbuf); free (tline); if (cons->grep.counter) { int cnt = cons->grep.charCounter? strlen (cons->buffer): cons->lines; if (cons->buffer_len < 10) { cons->buffer_len = 10; // HACK } snprintf (cons->buffer, cons->buffer_len, "%d\n", cnt); cons->buffer_len = strlen (cons->buffer); cons->num->value = cons->lines; } if (cons->grep.sort != -1) { #define INSERT_LINES(list)\ do {\ r_list_foreach (list, iter, str) {\ int len = strlen (str);\ memcpy (ptr, str, len);\ memcpy (ptr + len, "\n", 2);\ ptr += len + 1;\ nl++;\ }\ }\ while (false) RListIter *iter; int nl = 0; char *ptr = cons->buffer; char *str; sorted_column = cons->grep.sort; r_list_sort (sorted_lines, cmp); if (cons->grep.sort_invert) { r_list_reverse (sorted_lines); } INSERT_LINES (unsorted_lines); INSERT_LINES (sorted_lines); cons->lines = nl; r_list_free (sorted_lines); sorted_lines = NULL; r_list_free (unsorted_lines); unsorted_lines = NULL; } return cons->lines; }
R_API int r_cons_grepbuf(char *buf, int len) { RCons *cons = r_cons_singleton (); char *tline, *tbuf, *p, *out, *in = buf; int ret, buffer_len = 0, l = 0, tl = 0; if ((len == 0 || buf == NULL || buf[0] == '\0') && (cons->grep.json || cons->grep.less)) { cons->grep.json = 0; cons->grep.less = 0; return 0; } if (cons->grep.json) { char *out = sdb_json_indent (buf); free (cons->buffer); cons->buffer = out; cons->buffer_len = strlen (out); cons->buffer_sz = cons->buffer_len + 1; cons->grep.json = 0; if (cons->grep.less) { cons->grep.less = 0; r_cons_less_str (cons->buffer, NULL); } return 3; } if (cons->grep.less) { cons->grep.less = 0; r_cons_less_str (buf, NULL); buf[0] = 0; cons->buffer_len = 0; if (cons->buffer) cons->buffer[0] = 0; free (cons->buffer); cons->buffer = NULL; return 0; } if (!cons->buffer) { cons->buffer_len = len + 20; cons->buffer = malloc (cons->buffer_len); cons->buffer[0] = 0; } out = tbuf = calloc (1, len); tline = malloc (len); cons->lines = 0; while ((int)(size_t)(in-buf) < len) { p = strchr (in, '\n'); if (!p) { free (tbuf); free (tline); return 0; } l = p - in; if (l > 0) { memcpy (tline, in, l); tl = r_str_ansi_filter (tline, NULL, NULL, l); if (tl < 0) ret = -1; else ret = r_cons_grep_line (tline, tl); if (ret > 0) { if (cons->grep.line == -1 || (cons->grep.line != -1 && cons->grep.line == cons->lines)) { memcpy (out, tline, ret); memcpy (out + ret, "\n", 1); out += ret + 1; buffer_len += ret + 1; } cons->lines++; } else if (ret < 0) { free (tbuf); free (tline); return 0; } in += l + 1; } else in++; } memcpy (buf, tbuf, len); cons->buffer_len = buffer_len; free (tbuf); free (tline); if (cons->grep.counter) { if (cons->buffer_len < 10) cons->buffer_len = 10; // HACK snprintf (cons->buffer, cons->buffer_len, "%d\n", cons->lines); cons->buffer_len = strlen (cons->buffer); } return cons->lines; }
R_API void r_cons_less() { r_cons_less_str (r_cons_singleton ()->buffer); }
R_API int r_cons_less_str(const char *str, const char *exitkeys) { static int in_help = false; static const char *r_cons_less_help = \ " u/space - page up/down\n" " jk - line down/up\n" " gG - begin/end buffer\n" " / - search in buffer\n" " _ - enter the hud mode\n" " n/p - next/prev search result\n" " q - quit\n" " ? - show this help\n" "\n"; int lines_count = 0; RRegex *rx = NULL; int w, h, ch, to, ui = 1, from = 0, i; const char *sreg; RList **mla; if (!str || !*str) { return 0; } // rcons kills str after flushing the buffer, so we must keep a copy char *ostr = strdup (str); if (!ostr) { return 0; } char *p = strdup (str); if (!p) { free (ostr); return 0; } int *lines = pager_splitlines (p, &lines_count); if (lines_count < 1) { mla = NULL; } else { mla = calloc (lines_count, sizeof (RList *)); if (!mla) { free (p); free (ostr); free (lines); return 0; } } for (i = 0; i < lines_count; i++) { mla[i] = r_list_new (); } r_cons_set_raw (true); r_cons_show_cursor (false); r_cons_reset (); h = 0; while (ui) { w = r_cons_get_size (&h); to = R_MIN (lines_count, from + h); if (from + 3 > lines_count) { from = lines_count - 3; } if (from < 0) { from = 0; } pager_printpage (p, lines, mla, from, to, w); ch = r_cons_readchar (); if (exitkeys && strchr (exitkeys, ch)) { for (i = 0; i < lines_count; i++) { r_list_free (mla[i]); } free (p); free (mla); free (ostr); free (lines); return ch; } ch = r_cons_arrow_to_hjkl (ch); switch (ch) { case '_': r_cons_hud_string (ostr); break; case '?': if (!in_help) { in_help = true; r_cons_less_str (r_cons_less_help, NULL); in_help = false; } break; case 'u': from -= h; if (from < 0) { from = 0; } break; case ' ': from += h; break; case 'g': from = 0; break; case 'G': from = lines_count-h; break; case -1: // EOF case '\x03': // ^C case 'q': ui = 0; break; case '\r': case '\n': case 'j': from++; break; case 'J': from+=h; break; case 'k': if (from > 0) { from--; } break; case 'K': from = (from>=h)? from-h: 0; break; case '/': /* search */ r_cons_reset_colors (); r_line_set_prompt ("/"); sreg = r_line_readline (); from = R_MIN (lines_count - 1, from); /* repeat last search if empty string is provided */ if (sreg[0]) { /* prepare for a new search */ if (rx) { r_regex_free (rx); } rx = r_regex_new (sreg, ""); } else { /* we got an empty string */ from = pager_next_match (from, mla, lines_count); break; } if (!rx) { break; } /* find all occurences */ if (pager_all_matches (p, rx, mla, lines, lines_count)) { from = pager_next_match (from, mla, lines_count); } break; case 'n': /* next match */ /* search already performed */ if (rx) { from = pager_next_match (from, mla, lines_count); } break; case 'N': case 'p': /* previous match */ if (rx) { from = pager_prev_match (from, mla); } break; } } for (i = 0; i < lines_count; i++) { r_list_free (mla[i]); } free (mla); r_regex_free (rx); free (lines); free (p); r_cons_reset_colors (); r_cons_set_raw (false); r_cons_show_cursor (true); free (ostr); return 0; }
R_API void r_cons_less() { r_cons_less_str (r_cons_singleton ()->context->buffer, NULL); }
static int cmd_log(void *data, const char *input) { RCore *core = (RCore *)data; const char *arg, *input2; int n, n2; if (!input) return 1; input2 = (input && *input) ? input+1 : ""; arg = strchr (input2, ' '); n = atoi (input2); n2 = arg ? atoi (arg+1) : 0; switch (*input) { case 'e': // shell: less { char *p = strchr (input, ' '); if (p) { char *b = r_file_slurp (p+1, NULL); if (b) { r_cons_less_str (b, NULL); free (b); } else eprintf ("File not found\n"); } else eprintf ("Usage: less [filename]\n"); } break; case 'l': r_cons_printf ("%d\n", core->log->last-1); break; case '-': r_core_log_del (core, n); break; case '?':{ const char* help_msg[] = { "Usage:", "T","[-][ num|msg]", "T", "", "List all Text log messages", "T", " new comment", "0x80480", "T", " 123", "List log from 123", "T", " 10 3", "List 3 log messages starting from 10", "T*", "", "List in radare commands", "T-", "", "Delete all logs", "T-", " 123", "Delete logs before 123", "Tl", "", "Get last log message id", "Tj", "", "List in json format", "Tm", " [idx]", "Display log messages without index", "Ts", "", "List files in current directory (see pwd, cd)", "Tp", "[-plug]", "Tist, load, unload plugins", "TT", "", "Enter into the text log chat console", NULL}; r_core_cmd_help (core, help_msg); } break; case 'T': if (r_config_get_i (core->config, "scr.interactive")) { textlog_chat (core); } else eprintf ("Only available when the screen is interactive\n"); break; case 'p': switch (input[1]) { case 0: r_lib_list (core->lib); break; case '-': r_lib_close (core->lib, input+2); break; case ' ': r_lib_open (core->lib, input+2); break; case '?': { const char* help_msg[] = { "Usage:", "Tp", "[-name][ file]", "Tp", "", "List all plugins loaded by RCore.lib", "Tp-", "duk", "Unload plugin matching in filename", "Tp", " blah."R_LIB_EXT, "Load plugin file", NULL}; r_core_cmd_help(core, help_msg); } break; } break; case ' ': if (n>0) { r_core_log_list (core, n, n2, *input); } else { r_core_log_add (core, input+1); } break; case 'm': if (n>0) { r_core_log_list (core, n, 1, 't'); } else { r_core_log_list (core, n, 0, 't'); } break; case 'j': case '*': case '\0': r_core_log_list (core, n, n2, *input); break; } return 0; }