R_API void r_cons_visual_flush() { if (I.noflush) return; r_cons_highlight (I.highlight); if (!I.null) { /* TODO: this ifdef must go in the function body */ #if __WINDOWS__ && !__CYGWIN__ r_cons_w32_print ((const ut8*)I.buffer, I.buffer_len, 1); #else r_cons_visual_write (I.buffer); #endif } r_cons_reset (); if (I.fps) { int w = r_cons_get_size (NULL); int fps = 0; static ut64 prev = 0LL; //r_sys_now (); fps = 0; if (prev) { ut64 now = r_sys_now (); ut64 diff = now-prev; fps = (diff<1000000)? (1000000/diff): 0; prev = now; } else prev = r_sys_now (); eprintf ("\x1b[0;%dH[%d FPS] \n", w-10, fps); } }
static void cmd_fz(RCore *core, const char *input) { switch (*input) { case '?': r_core_cmd_help (core, help_msg_fz); break; case '.': { const char *a = NULL, *b = NULL; r_flag_zone_around (core->flags, core->offset, &a, &b); r_cons_printf ("%s %s\n", a?a:"~", b?b:"~"); } break; case ':': { const char *a, *b; int a_len = 0; int w = r_cons_get_size (NULL); r_flag_zone_around (core->flags, core->offset, &a, &b); if (a) { r_cons_printf ("[<< %s]", a); a_len = strlen (a) + 4; } int padsize = (w / 2) - a_len; int title_size = 12; if (a || b) { char *title = r_str_newf ("[ 0x%08"PFMT64x" ]", core->offset); title_size = strlen (title); padsize -= strlen (title) / 2; const char *halfpad = r_str_pad (' ', padsize); r_cons_printf ("%s%s", halfpad, title); free (title); } if (b) { padsize = (w / 2) - title_size - strlen (b) - 4; const char *halfpad = padsize > 1? r_str_pad (' ', padsize): ""; r_cons_printf ("%s[%s >>]", halfpad, b); } if (a || b) { r_cons_newline(); } } break; case ' ': r_flag_zone_add (core->flags, r_str_trim_ro (input + 1), core->offset); break; case '-': if (input[1] == '*') { r_flag_zone_reset (core->flags); } else { r_flag_zone_del (core->flags, input + 1); } break; case '*': r_flag_zone_list (core->flags, '*'); break; case 0: r_flag_zone_list (core->flags, 0); break; } }
R_API void r_cons_less_str(const char *str) { int lines_count; int w, h, ch, to, ui = 1, from = 0; char *p = strdup (str); int *lines = splitlines (p, &lines_count); r_cons_set_raw (R_TRUE); r_cons_show_cursor (R_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; printpage (p, lines, from, to); ch = r_cons_readchar (); ch = r_cons_arrow_to_hjkl (ch); switch (ch) { case ' ': from += h; break; case 'g': from = 0; break; case 'G': from = lines_count-1-h; break; 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; } } free (lines); r_cons_set_raw (R_FALSE); r_cons_show_cursor (R_TRUE); }
R_API RCons *r_cons_new () { I.refcnt++; if (I.refcnt != 1) return &I; I.line = r_line_new (); I.highlight = NULL; I.event_interrupt = NULL; I.is_wine = -1; I.fps = 0; I.blankline = R_TRUE; I.teefile = NULL; I.fix_columns = 0; I.fix_rows = 0; I.mouse_event = 0; I.force_rows = 0; I.force_columns = 0; I.event_resize = NULL; I.data = NULL; I.event_data = NULL; I.is_interactive = R_TRUE; I.noflush = R_FALSE; I.fdin = stdin; I.fdout = 1; I.breaked = R_FALSE; //I.lines = 0; I.buffer = NULL; I.buffer_sz = 0; I.buffer_len = 0; r_cons_get_size (NULL); I.num = NULL; I.null = 0; #if EMSCRIPTEN /* do nothing here :? */ #elif __UNIX__ || __CYGWIN__ tcgetattr (0, &I.term_buf); memcpy (&I.term_raw, &I.term_buf, sizeof (I.term_raw)); I.term_raw.c_iflag &= ~(BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); I.term_raw.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); I.term_raw.c_cflag &= ~(CSIZE|PARENB); I.term_raw.c_cflag |= CS8; I.term_raw.c_cc[VMIN] = 1; // Solaris stuff hehe signal (SIGWINCH, resize); #elif __WINDOWS__ h = GetStdHandle (STD_INPUT_HANDLE); GetConsoleMode (h, (PDWORD) &I.term_buf); I.term_raw = 0; if (!SetConsoleCtrlHandler ((PHANDLER_ROUTINE)__w32_control, TRUE)) eprintf ("r_cons: Cannot set control console handler\n"); #endif I.pager = NULL; /* no pager by default */ I.truecolor = 0; I.mouse = 0; I.newline = R_TRUE; r_cons_pal_null (); r_cons_pal_init (NULL); r_cons_rgb_init (); r_cons_reset (); return &I; }
static void flagbars(RCore *core, const char *glob) { int cols = r_cons_get_size (NULL); cols -= 80; if (cols < 0) { cols += 80; } struct flagbar_t u = { .core = core, .cols = cols }; r_flag_foreach_glob (core->flags, glob, flagbar_foreach, &u); }
// TODO: Add fmt support R_API char *r_cons_message(const char *msg) { int cols, rows; int len = strlen (msg); cols = r_cons_get_size (&rows); r_cons_clear (); r_cons_gotoxy ((cols-len)/2, rows/2); // XXX /// TODO: add square, or talking clip here r_cons_printf ("%s\n", msg); r_cons_flush (); r_cons_gotoxy (0, rows-2); // XXX r_cons_any_key (); return NULL; }
static void Layout_run(Panel *panels) { int h, w = r_cons_get_size (&h); int i, j; int colpos = w-COLW; can->sx = 0; can->sy = 0; n_panels = 0; for (i=0; panels[i].text; i++) { if (panels[i].type == PANEL_TYPE_FRAME) n_panels++; } for (i=j=0; panels[i].text; i++) { switch (panels[i].type) { case PANEL_TYPE_FLOAT: panels[i].w = r_str_bounds ( panels[i].text, &panels[i].h); panels[i].h += 4; break; case PANEL_TYPE_FRAME: if (j == 0) { panels[i].x = 0; panels[i].y = 1; if (panels[j+1].text) { panels[i].w = colpos; } else { panels[i].w = w; } panels[i].h = h-1; } else { int ph = ((h-1)/(n_panels-1)); panels[i].x = colpos; panels[i].y = 1 + (ph*(j-1)); panels[i].w = w-colpos; if (panels[i].w<0) panels[i].w = 0; panels[i].h = ph; if (!panels[i+1].text) { panels[i].h = h - panels[i].y; } } j++; } } }
R_API void r_core_visual_prompt_input (RCore *core) { int ret; ut64 addr = core->offset; ut64 bsze = core->blocksize; int h; (void)r_cons_get_size (&h); r_cons_gotoxy (0, h-2); r_cons_reset_colors(); r_cons_printf("\nPress <enter> to return to Visual mode.\n"); r_cons_show_cursor (true); core->vmode = false; ut64 newaddr = addr; if (curset) { if (ocursor != -1) { newaddr = core->offset + ocursor; r_core_block_size (core, cursor-ocursor); } else newaddr = core->offset + cursor; r_core_seek (core, newaddr, 1); } do { ret = r_core_visual_prompt (core); if (core->offset != newaddr) { // do not restore seek anymore newaddr = addr; } } while (ret); if (curset) { if (addr != newaddr) { r_core_seek (core, addr, 1); r_core_block_size (core, bsze); } } r_cons_show_cursor (false); core->vmode = true; }
// damn singletons.. there should be only one screen and therefor // only one visual instance of the graph view. refactoring this // into a struct makes the code to reference pointers unnecesarily // we can look for a non-global solution here in the future if // necessary static void r_core_panels_refresh (RCore *core) { char title[128]; int i, j, h, w = r_cons_get_size (&h); if (instep && core->io->debug) { r_core_cmd0 (core, "sr pc"); } r_cons_clear00 (); if (!can) { return; } r_cons_canvas_resize (can, w, h); r_cons_canvas_clear (can); if (panels) { if (menu_y>0) { panels[menu_pos].x = menu_x * 6; } else { panels[menu_pos].x = w; } panels[menu_pos].y = 1; free (panels[menu_pos].text); panels[menu_pos].text = malloc(1024); //r_str_newf ("%d", menu_y); panels[menu_pos].text[0] = 0; int maxsub = 0; for (i=0; menus_sub[i]; i++) { maxsub = i; } if (menu_x >= 0 && menu_x <maxsub && menus_sub[menu_x]) { for (j = 0; menus_sub[menu_x][j]; j++) { if (menu_y-1 == j) { strcat (panels[menu_pos].text, "> "); } else { strcat (panels[menu_pos].text, " "); } strcat (panels[menu_pos].text, menus_sub[menu_x][j]); strcat (panels[menu_pos].text, " \n"); } } for (i=0; panels[i].text; i++) { if (i != curnode) { Panel_print (can, &panels[i], i==curnode); } } } if (menu_y) { curnode = menu_pos; } // redraw current node to make it appear on top if (curnode >= 0) { Panel_print (can, &panels[curnode], 1); } Panel_print (can, &panels[menu_pos], menu_y); (void)G (-can->sx, -can->sy); char str[128]; title[0] = 0; for (i=0; menus[i]; i++) { if (menu_x == i) { snprintf (str, sizeof (title)-1, "[%s]", menus[i]); } else { snprintf (str, sizeof (title)-1, " %s ", menus[i]); } strcat (title, str); } W (title); snprintf (title, sizeof (title)-1, "[0x%08"PFMT64x"]", core->offset); (void)G (-can->sx + w-strlen (title), -can->sy); W (title); r_cons_canvas_print (can); r_cons_flush_nonewline (); }
R_API int r_core_visual_panels(RCore *core) { #define OS_INIT() ostack.size = 0; ostack.panels[0] = 0; #define OS_PUSH(x) if (ostack.size<LIMIT) {ostack.panels[++ostack.size]=x;} #define OS_POP() ((ostack.size>0)? ostack.panels[--ostack.size]:0) int okey, key, wheel; int w, h; int asm_comments = 0; int asm_bytes = 0; n_panels = 0; panels = NULL; callgraph = 0; _core = core; OS_INIT(); w = r_cons_get_size (&h); can = r_cons_canvas_new (w, h); can->linemode = 1; can->color = r_config_get_i (core->config, "scr.color"); // disable colors in disasm because canvas doesnt supports ansi text yet r_config_set_i (core->config, "scr.color", 0); //can->color = 0; if (!can) { eprintf ("Cannot create RCons.canvas context\n"); return R_FALSE; } n_panels = bbPanels (core, &panels); if (!panels) { r_config_set_i (core->config, "scr.color", can->color); free (can); return R_FALSE; } reloadPanels (core); asm_comments = r_config_get_i (core->config, "asm.comments"); r_config_set_i (core->config, "asm.comments", 0); asm_bytes = r_config_get_i (core->config, "asm.bytes"); r_config_set_i (core->config, "asm.bytes", 0); repeat: core->cons->event_data = core; core->cons->event_resize = \ (RConsEvent)r_core_panels_refresh; w = r_cons_get_size (&h); Layout_run (panels); r_core_panels_refresh (core); wheel = r_config_get_i (core->config, "scr.wheel"); if (wheel) r_cons_enable_mouse (R_TRUE); // r_core_graph_inputhandle() okey = r_cons_readchar (); key = r_cons_arrow_to_hjkl (okey); switch (key) { case ' ': case '\n': if (menu_y) { const char *action = menus_sub[menu_x][menu_y-1]; eprintf ("ACTION %s\n", action); if (strstr (action, "New")) { int i; // add new panel for testing for (i=0; panels[i].text; i++) { // find last panel } panels[i].text = strdup ("Test"); panels[i].cmd = r_str_newf ("pxW $r-2"); panels[i].addr = core->offset; panels[i].type = PANEL_TYPE_FRAME; i++; n_panels++; panels[i].text = NULL; } if (strstr (action, "Quit")) { goto beach; } } break; case '?': r_cons_clear00 (); r_cons_printf ("Visual Ascii Art Panels:\n" " ! run r2048 game\n" " . - center graph to the current node\n" " : - run r2 command in prompt\n" " hl - toggle scr.color\n" " HL - move vertical column split\n" " JK - select prev/next panels\n" " jk - scroll/select menu\n" " q - quit, back to visual mode\n" ); r_cons_flush (); r_cons_any_key (NULL); break; case ':': core->vmode = R_FALSE; r_core_visual_prompt_input (core); core->vmode = R_TRUE; break; case 'C': can->color = !!!can->color; //WTF //r_config_swap (core->config, "scr.color"); // refresh graph // reloadPanels (core); break; case '!': r_cons_2048 (); break; case 'j': if (panels[curnode].type == PANEL_TYPE_FLOAT) { if (menus_sub[menu_x][menu_y]) menu_y ++; } break; case 'k': if (panels[curnode].type == PANEL_TYPE_FLOAT) { menu_y --; if (menu_y<0) menu_y = 0; } break; case 'J': curnode++; if (!panels[curnode].text) { curnode--; } break; case 'K': curnode--; if (curnode<0) curnode = 0; break; case 'H': COLW += 4; break; case 'L': COLW -= 4; if (COLW<0) COLW=0; break; case 'h': if (menu_x) { menu_x --; menu_y = menu_y?1:0; } break; case 'l': if (menus[menu_x + 1]) { menu_x ++; menu_y = menu_y?1:0; } break; case 'q': case -1: // EOF goto beach; case 27: // ESC if (r_cons_readchar () == 91) { if (r_cons_readchar () == 90) { } } break; default: //eprintf ("Key %d\n", key); //sleep (1); break; } goto repeat; beach: free (panels); r_config_set_i (core->config, "scr.color", can->color); free (can); r_config_set_i (core->config, "asm.comments", asm_comments); r_config_set_i (core->config, "asm.bytes", asm_bytes); return R_TRUE; }
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_str(const char *str) { int lines_count; RRegex *rx = NULL; int w, h, ch, to, ui = 1, from = 0, i; const char *sreg; if(str == NULL || str[0] == '\0') return; char *p = strdup (str); int *lines = splitlines (p, &lines_count); RRegexMatch **ms = malloc(lines_count * sizeof(void *)); for(i = 0; i < lines_count; i++) ms[i] = calloc(NMATCHES, sizeof(RRegexMatch)); r_cons_set_raw (R_TRUE); r_cons_show_cursor (R_FALSE); r_cons_reset (); w = 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; printpage (p, lines, ms, from, to, w); ch = r_cons_readchar (); ch = r_cons_arrow_to_hjkl (ch); switch (ch) { case ' ': from += h; break; case 'g': from = 0; break; case 'G': from = lines_count-1-h; break; case -1: // EOF 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 = next_match(from, ms, lines_count); break; } if(!rx) break; /* find all occurences */ if(all_matches(p, rx, ms, lines, lines_count)) from = next_match(from, ms, lines_count); break; case 'n': /* next match */ /* search already performed */ if(rx) from = next_match(from, ms, lines_count); break; case 'p': /* previous match */ if(rx) from = prev_match(from, ms); break; } } for(i = 0; i < lines_count; i++) free(ms[i]); free(ms); if(rx) r_regex_free(rx); free (lines); free (p); r_cons_reset_colors(); r_cons_set_raw (R_FALSE); r_cons_show_cursor (R_TRUE); }
static void print_debug_maps_ascii_art(RDebug *dbg, RList *maps, ut64 addr, int colors) { ut64 mul; // The amount of address space a single console column will represent in bar graph ut64 min = -1, max = 0; int width = r_cons_get_size (NULL) - 90; RListIter *iter; RDebugMap *map; if (width < 1) { width = 30; } r_list_sort (maps, cmp); mul = findMinMax (maps, &min, &max, 0, width); ut64 last = min; if (min != -1 && mul != 0) { const char *color_prefix = ""; // Color escape code prefixed to string (address coloring) const char *color_suffix = ""; // Color escape code appended to end of string const char *fmtstr; char size_buf[56]; // Holds the human formatted size string [124K] int skip = 0; // Number of maps to skip when re-calculating the minmax r_list_foreach (maps, iter, map) { r_num_units (size_buf, map->size); // Convert map size to human readable string if (colors) { color_suffix = Color_RESET; if (map->perm & 2) { // Writable maps are red color_prefix = Color_RED; } else if (map->perm & 1) { // Executable maps are green color_prefix = Color_GREEN; } else { color_prefix = ""; color_suffix = ""; } } else { color_prefix = ""; color_suffix = ""; } if ((map->addr - last) > UT32_MAX) { // TODO: Comment what this is for mul = findMinMax (maps, &min, &max, skip, width); // Recalculate minmax } skip++; fmtstr = dbg->bits & R_SYS_BITS_64 ? // Prefix formatting string (before bar) "map %4.8s %c %s0x%016"PFMT64x"%s |" : "map %4.8s %c %s0x%08"PFMT64x"%s |"; dbg->cb_printf (fmtstr, size_buf, (addr >= map->addr && \ addr < map->addr_end) ? '*' : '-', color_prefix, map->addr, color_suffix); // * indicates map is within our current seeked offset int col; for (col = 0; col < width; col++) { // Iterate over the available width/columns for bar graph ut64 pos = min + (col * mul); // Current address space to check ut64 npos = min + ((col + 1) * mul); // Next address space to check if (map->addr < npos && map->addr_end > pos) { dbg->cb_printf ("#"); // TODO: Comment what a # represents } else { dbg->cb_printf ("-"); } } fmtstr = dbg->bits & R_SYS_BITS_64 ? // Suffix formatting string (after bar) "| %s0x%016"PFMT64x"%s %s %s\n" : "| %s0x%08"PFMT64x"%s %s %s\n"; dbg->cb_printf (fmtstr, color_prefix, map->addr_end, color_suffix, r_str_rwx_i (map->perm), map->name); last = map->addr; } }
// Display a list of entries in the hud, filtered and emphasized based // on the user input. R_API char *r_cons_hud(RList *list, const char *prompt) { const int buf_size = 128; int ch, nch, first_line, current_entry_n, j, i = 0; char *p, *x, user_input[buf_size], mask[buf_size]; int last_color_change, top_entry_n = 0; char *selected_entry = NULL; char tmp, last_mask = 0; void *current_entry; RListIter *iter; user_input[0] = 0; r_cons_clear (); // Repeat until the user exits the hud for (;;) { first_line = 1; r_cons_gotoxy (0, 0); current_entry_n = 0; if (top_entry_n < 0) { top_entry_n = 0; } selected_entry = NULL; if (prompt && *prompt) { r_cons_print (">> "); r_cons_println (prompt); } r_cons_printf ("%d> %s|\n", top_entry_n, user_input); int counter = 0; int rows; (void)r_cons_get_size (&rows); // Iterate over each entry in the list r_list_foreach (list, iter, current_entry) { memset (mask, 0, buf_size); if (!user_input[0] || strmatch (current_entry, user_input, mask, buf_size)) { counter++; if (counter == rows + top_entry_n) { break; } // if the user scrolled down the list, do not print the first entries if (!top_entry_n || current_entry_n >= top_entry_n) { // remove everything after a tab (in ??, it contains the commands) x = strchr (current_entry, '\t'); if (x) { *x = 0; } p = strdup (current_entry); // if the filter is empty, print the entry and move on if (!user_input[0]) { r_cons_printf (" %c %s\n", first_line? '-': ' ', current_entry); } else { // otherwise we need to emphasize the matching part if (I(use_color)) { last_color_change = 0; last_mask = 0; r_cons_printf (" %c ", first_line? '-': ' '); // Instead of printing one char at the time // (which would be slow), we group substrings of the same color for (j = 0; p[j] && j < buf_size; j++) { if (mask[j] != last_mask) { tmp = p[j]; p[j] = 0; if (mask[j]) { r_cons_printf (Color_RESET"%s", p + last_color_change); } else { r_cons_printf (Color_GREEN"%s", p + last_color_change); } p[j] = tmp; last_color_change = j; last_mask = mask[j]; } } if (last_mask) { r_cons_printf (Color_GREEN"%s\n"Color_RESET, p + last_color_change); } else { r_cons_printf (Color_RESET"%s\n", p + last_color_change); } } else { // Otherwise we print the matching characters uppercase for (j = 0; p[j]; j++) { if (mask[j]) p[j] = toupper ((unsigned char)p[j]); } r_cons_printf (" %c %s\n", first_line? '-': ' ', p); } } // Clean up and restore the tab character (if any) free (p); if (x) { *x = '\t'; } if (first_line) { selected_entry = current_entry; } first_line = 0; } current_entry_n++; } } r_cons_visual_flush (); ch = r_cons_readchar (); nch = r_cons_arrow_to_hjkl (ch); (void)r_cons_get_size (&rows); if (nch == 'J' && ch != 'J') { top_entry_n += (rows - 1); if (top_entry_n + 1 >= current_entry_n) { top_entry_n = current_entry_n; } } else if (nch == 'K' && ch != 'K') { top_entry_n -= (rows - 1); if (top_entry_n < 0) { top_entry_n = 0; } } else if (nch == 'j' && ch != 'j') { if (top_entry_n + 1 < current_entry_n) { top_entry_n++; } } else if (nch == 'k' && ch != 'k') { if (top_entry_n >= 0) { top_entry_n--; } } else { switch (ch) { case 9: // \t if (top_entry_n + 1 < current_entry_n) { top_entry_n++; } else { top_entry_n = 0; } break; case 10: // \n case 13: // \r top_entry_n = 0; // if (!*buf) // return NULL; if (current_entry_n >= 1) { //eprintf ("%s\n", buf); //i = buf[0] = 0; return strdup (selected_entry); } // no match! break; case 23: // ^w top_entry_n = 0; i = user_input[0] = 0; break; case 0x1b: // ESC return NULL; case 8: // bs case 127: // bs top_entry_n = 0; if (i < 1) return NULL; user_input[--i] = 0; break; default: if (IS_PRINTABLE (ch)) { if (i >= buf_size) { break; } top_entry_n = 0; if (i + 1 >= buf_size) { // too many break; } user_input[i++] = ch; user_input[i] = 0; } break; } } }
R_API int r_cons_w32_print(const ut8 *ptr, int len, int vmode) { HANDLE hConsole = GetStdHandle (STD_OUTPUT_HANDLE); int esc = 0; int bg = 0, fg = 1|2|4|8; const ut8 *ptr_end, *str = ptr; int ret = 0; int inv = 0; int linelen = 0; int ll = 0; int lines, cols = r_cons_get_size (&lines); if (I->is_wine==-1) { I->is_wine = r_file_is_directory ("/proc")? 1: 0; } if (len < 0) { len = strlen ((const char *)ptr); } ptr_end = ptr + len; if (ptr && hConsole) for (; *ptr && ptr < ptr_end; ptr++) { if (ptr[0] == 0xa) { ll = (size_t)(ptr - str); lines--; if (vmode && lines < 0) { break; } if (ll < 1) { continue; } if (vmode) { // TODO: Fix utf8 chop /* only chop columns if necessary */ if (ll + linelen >= cols) { // chop line if too long ll = (cols - linelen) - 1; if (ll < 0) { continue; } } } if (ll > 0) { write (1, str, ll); linelen += ll; } esc = 0; str = ptr + 1; if (vmode) { int wlen = cols - linelen; char white[1024]; if (wlen > 0 && wlen < sizeof (white)) { memset (white, ' ', sizeof (white)); write (1, white, wlen-1); } } write (1, "\n\r", 2); // reset colors for next line SetConsoleTextAttribute (hConsole, 1 | 2 | 4 | 8); linelen = 0; continue; } if (ptr[0] == 0x1b) { ll = (size_t)(ptr-str); if (str[0] == '\n') { str++; ll--; if (vmode) { int wlen = cols - linelen - 1; char white[1024]; //wlen = 5; if (wlen > 0) { memset (white, ' ', sizeof (white)); write (1, white, wlen); } } write (1, "\n\r", 2); //write (1, "\r\n", 2); //lines--; linelen = 0; } if (vmode) { if (linelen + ll >= cols) { // chop line if too long ll = (cols-linelen) - 1; if (ll > 0) { // fix utf8 len here ll = wrapline ((const char*)str, cols - linelen - 1); } } } if (ll > 0) { write (1, str, ll); linelen += ll; } esc = 1; str = ptr + 1; continue; } if (esc == 1) { // \x1b[2J if (ptr[0] != '[') { eprintf ("Oops invalid escape char\n"); esc = 0; str = ptr + 1; continue; } esc = 2; continue; } else if (esc == 2) { const char *ptr2 = NULL; int x, y, i, state = 0; for (i = 0; ptr[i] && state >= 0; i++) { switch (state) { case 0: if (ptr[i] == ';') { y = atoi ((const char *)ptr); state = 1; ptr2 = (const char *)ptr+i+1; } else if (ptr[i] >='0' && ptr[i]<='9') { // ok } else { state = -1; // END FAIL } break; case 1: if (ptr[i]=='H') { x = atoi (ptr2); state = -2; // END OK } else if (ptr[i] >='0' && ptr[i]<='9') { // ok } else { state = -1; // END FAIL } break; } } if (state == -2) { w32_gotoxy (x, y); ptr += i; str = ptr + 1;// + i-2; continue; } if (ptr[0]=='0' && ptr[1] == ';' && ptr[2]=='0') { // \x1b[0;0H /** clear screen if gotoxy **/ if (vmode) { // fill row here fill_tail (cols, lines); } w32_gotoxy (0, 0); lines = 0; esc = 0; ptr += 3; str = ptr + 1; continue; } else if (ptr[0]=='2'&&ptr[1]=='J') { //fill_tail(cols, lines); w32_clear (); //r_cons_clear (); esc = 0; ptr = ptr + 1; str = ptr + 1; continue; } else if (ptr[0]=='0'&&(ptr[1]=='m' || ptr [1]=='K')) { SetConsoleTextAttribute (hConsole, 1|2|4|8); fg = 1|2|4|8; bg = 0; inv = 0; esc = 0; ptr++; str = ptr + 1; continue; // reset color } else if (ptr[0]=='2'&&ptr[1]=='7'&&ptr[2]=='m') { SetConsoleTextAttribute (hConsole, bg|fg); inv = 0; esc = 0; ptr = ptr + 2; str = ptr + 1; continue; // invert off } else if (ptr[0]=='7'&&ptr[1]=='m') { SetConsoleTextAttribute (hConsole, bg|fg|128); inv = 128; esc = 0; ptr = ptr + 1; str = ptr + 1; continue; // invert } else if (ptr[0]=='3' && (ptr[2]=='m' || ptr[2] == ';')) { // http://www.betarun.com/Pages/ConsoleColor/ switch (ptr[1]) { case '0': // BLACK fg = 0; break; case '1': // RED fg = 4; break; case '2': // GREEN fg = 2; break; case '3': // YELLOW fg = 2|4; break; case '4': // BLUE fg = 1; break; case '5': // MAGENTA fg = 1|4; break; case '6': // TURQOISE fg = 1|2|8; break; case '7': // WHITE fg = 1|2|4; break; case '8': // GRAY fg = 8; break; case '9': // ??? break; } SetConsoleTextAttribute (hConsole, bg|fg|inv); esc = 0; ptr = ptr + 2; str = ptr + 1; continue; } else if (ptr[0]=='4' && ptr[2]=='m') { /* background color */ switch (ptr[1]) { case '0': // BLACK bg = 0; break; case '1': // RED bg = 40; break; case '2': // GREEN bg = 20; break; case '3': // YELLOW bg = 20|40; break; case '4': // BLUE bg = 10; break; case '5': // MAGENTA bg = 10|40; break; case '6': // TURQOISE bg = 10|20|80; break; case '7': // WHITE bg = 10|20|40; break; case '8': // GRAY bg = 80; break; case '9': // ??? break; } esc = 0; ptr = ptr + 2; str = ptr + 1; continue; } } ret++; } if (vmode) { /* fill partial line */ int wlen = cols-linelen - 1; if (wlen > 0) { char white[1024]; memset (white, ' ', sizeof (white)); write (1, white, wlen); } /* fill tail */ fill_tail (cols, lines); } else { int ll = (size_t)(ptr - str); if (ll > 0) { write (1, str, ll); linelen += ll; } } return ret; }
int main(int argc, char **argv) { const char *addr = NULL; RCore *c, *c2; RDiff *d; const char *arch = NULL; int bits = 0; char *file, *file2; ut8 *bufa, *bufb; int o, sza, szb, /*diffmode = 0,*/ delta = 0; int mode = MODE_DIFF; int diffops = 0; int threshold = -1; int gdiff_mode = 0; double sim; while ((o = getopt (argc, argv, "a:b:Cnpg:Ojrhcdsvxt:")) != -1) { switch (o) { case 'a': arch = optarg; break; case 'b': bits = atoi (optarg); break; case 'p': useva = R_FALSE; break; case 'r': diffmode = 'r'; break; case 'g': mode = MODE_GRAPH; addr = optarg; break; case 'c': showcount = 1; break; case 'C': mode = MODE_CODE; gdiff_mode++; break; case 'n': showbare = R_TRUE; break; case 'O': diffops = 1; break; case 't': threshold = atoi (optarg); printf ("%s\n", optarg); break; case 'd': delta = 1; break; case 'h': return show_help (1); case 's': mode = MODE_DIST; break; case 'x': mode = MODE_COLS; break; case 'v': printf ("radiff2 v"R2_VERSION"\n"); return 0; case 'j': diffmode = 'j'; break; default: return show_help (0); } } if (argc<3 || optind+2>argc) return show_help (0); if (optind<argc) { file = argv[optind]; } else { file = NULL; } if (optind+1<argc) { file2 = argv[optind+1]; } else { file2 = NULL; } switch (mode) { case MODE_GRAPH: case MODE_CODE: c = opencore (file); if (!c) eprintf ("Cannot open '%s'\n", r_str_get (file)); c2 = opencore (file2); if (!c || !c2) { eprintf ("Cannot open '%s'\n", r_str_get (file2)); return 1; } if (arch) { r_config_set (c->config, "asm.arch", arch); r_config_set (c2->config, "asm.arch", arch); } if (bits) { r_config_set_i (c->config, "asm.bits", bits); r_config_set_i (c2->config, "asm.bits", bits); } r_config_set_i (c->config, "diff.bare", showbare); r_config_set_i (c2->config, "diff.bare", showbare); r_anal_diff_setup_i (c->anal, diffops, threshold, threshold); r_anal_diff_setup_i (c2->anal, diffops, threshold, threshold); if (mode == MODE_GRAPH) { char *words = strdup (addr); char *second = strstr (words, ","); if (second) { ut64 off; *second++ = 0; off = r_num_math (c->num, words); // define the same function at each offset r_core_anal_fcn (c, off, UT64_MAX, R_ANAL_REF_TYPE_NULL, 0); r_core_anal_fcn (c2, r_num_math (c2->num, second), UT64_MAX, R_ANAL_REF_TYPE_NULL, 0); r_core_gdiff (c, c2, R_FALSE); // compute the diff r_core_anal_graph (c, off, R_CORE_ANAL_GRAPHBODY | R_CORE_ANAL_GRAPHDIFF); } else { r_core_anal_fcn (c, r_num_math (c->num, words), UT64_MAX, R_ANAL_REF_TYPE_NULL, 0); r_core_anal_fcn (c2, r_num_math (c2->num, words), UT64_MAX, R_ANAL_REF_TYPE_NULL, 0); r_core_gdiff (c, c2, gdiff_mode); r_core_anal_graph (c, r_num_math (c->num, addr), R_CORE_ANAL_GRAPHBODY | R_CORE_ANAL_GRAPHDIFF); } free (words); } else { r_core_gdiff (c, c2, gdiff_mode); r_core_diff_show (c, c2); } r_cons_flush (); return 0; } bufa = (ut8*)r_file_slurp (file, &sza); if (!bufa) { eprintf ("radiff2: Cannot open %s\n", r_str_get (file)); return 1; } bufb = (ut8*)r_file_slurp (file2, &szb); if (!bufb) { eprintf ("radiff2: Cannot open: %s\n", r_str_get (file2)); free (bufa); return 1; } switch (mode) { case MODE_COLS: { int cols = (r_cons_get_size (NULL)>112)?16:8; dump_cols (bufa, sza, bufb, szb, cols); } break; case MODE_DIFF: d = r_diff_new (0LL, 0LL); r_diff_set_delta (d, delta); if (diffmode == 'j') { printf("{\"files\":[{\"filename\":\"%s\", \"size\":%d, \"sha256\":\"", file, sza); handle_sha256 (bufa, sza); printf("\"},\n{\"filename\":\"%s\", \"size\":%d, \"sha256\":\"", file2, szb); handle_sha256 (bufb, szb); printf("\"}],\n"); printf("\"changes\":["); } r_diff_set_callback (d, &cb, 0);//(void *)(size_t)diffmode); r_diff_buffers (d, bufa, sza, bufb, szb); if (diffmode == 'j') printf("]\n"); r_diff_free (d); break; case MODE_DIST: r_diff_buffers_distance (NULL, bufa, sza, bufb, szb, &count, &sim); printf ("similarity: %.2f\n", sim); printf ("distance: %d\n", count); break; } if (diffmode == 'j' && showcount) printf (",\"count\":%d}\n",count); else if (showcount && diffmode != 'j') printf ("%d\n", count); else if (!showcount && diffmode == 'j') printf ("}\n"); free (bufa); free (bufb); return 0; }
int main(int argc, char **argv) { const char *addr = NULL; RCore *c, *c2; RDiff *d; const char *arch = NULL; int bits = 0; char *file, *file2; ut8 *bufa, *bufb; int o, sza, szb, rad = 0, delta = 0; int mode = MODE_DIFF; int diffops = 0; int threshold = -1; double sim; while ((o = getopt (argc, argv, "a:b:Cnpg:Orhcdsvxt:")) != -1) { switch (o) { case 'a': arch = optarg; break; case 'b': bits = atoi (optarg); break; case 'p': useva = R_FALSE; break; case 'r': rad = 1; break; case 'g': mode = MODE_GRAPH; addr = optarg; break; case 'c': showcount = 1; break; case 'C': mode = MODE_CODE; break; case 'n': showbare = R_TRUE; break; case 'O': diffops = 1; break; case 't': threshold = atoi (optarg); break; case 'd': delta = 1; break; case 'h': return show_help (1); case 's': mode = MODE_DIST; break; case 'x': mode = MODE_COLS; break; case 'v': printf ("radiff2 v"R2_VERSION"\n"); return 0; default: return show_help (0); } } if (argc<3 || optind+2>argc) return show_help (0); file = argv[optind]; file2 = argv[optind+1]; switch (mode) { case MODE_GRAPH: case MODE_CODE: c = opencore (file); if (!c) eprintf ("Cannot open '%s'\n", file); c2 = opencore (file2); if (!c || !c2) { eprintf ("Cannot open '%s'\n", file2); return 1; } if (arch) { r_config_set (c->config, "asm.arch", arch); r_config_set (c2->config, "asm.arch", arch); } if (bits) { r_config_set_i (c->config, "asm.bits", bits); r_config_set_i (c2->config, "asm.bits", bits); } r_config_set_i (c->config, "diff.bare", showbare); r_config_set_i (c2->config, "diff.bare", showbare); r_anal_diff_setup_i (c->anal, diffops, threshold, threshold); r_anal_diff_setup_i (c2->anal, diffops, threshold, threshold); if (mode == MODE_GRAPH) { const char* second = strstr (addr, ","); if (!second) { r_core_gdiff (c, c2, R_TRUE); r_core_anal_graph (c, r_num_math (c->num, addr), R_CORE_ANAL_GRAPHBODY|R_CORE_ANAL_GRAPHDIFF); } else { const ut64 off = strtoull(addr, 0, 16); // define the same function at each offset r_core_anal_fcn (c, off, UT64_MAX, R_ANAL_REF_TYPE_NULL, 0); r_core_anal_fcn (c2, strtoull (second+1, 0, 16), UT64_MAX, R_ANAL_REF_TYPE_NULL, 0); r_core_gdiff (c, c2, R_FALSE); // compute the diff r_core_anal_graph (c, off, R_CORE_ANAL_GRAPHBODY|R_CORE_ANAL_GRAPHDIFF); } } else { r_core_gdiff (c, c2, R_TRUE); r_core_diff_show (c, c2); } return 0; } bufa = (ut8*)r_file_slurp (file, &sza); if (!bufa) { eprintf ("radiff2: Can not open %s\n", bufa); return 1; } bufb = (ut8*)r_file_slurp (file2, &szb); if (!bufb) { eprintf ("radiff2: Cannot open: %s\n", bufb); free (bufa); return 1; } switch (mode) { case MODE_COLS: { int cols = (r_cons_get_size (NULL)>112)?16:8; dump_cols (bufa, sza, bufb, szb, cols); } break; case MODE_DIFF: d = r_diff_new (0LL, 0LL); r_diff_set_delta (d, delta); r_diff_set_callback (d, &cb, (void *)(size_t)rad); r_diff_buffers (d, bufa, sza, bufb, szb); r_diff_free (d); break; case MODE_DIST: r_diff_buffers_distance (NULL, bufa, sza, bufb, szb, &count, &sim); printf ("similarity: %.2f\n", sim); printf ("distance: %d\n", count); break; } if (showcount) printf ("%d\n", count); free (bufa); free (bufb); return 0; }
static ut64 num_callback(RNum *userptr, const char *str, int *ok) { RCore *core = (RCore *)userptr; // XXX ? RAnalFunction *fcn; char *ptr, *bptr, *out; RFlagItem *flag; RIOSection *s; RAnalOp op; ut64 ret = 0; if (ok) *ok = R_FALSE; switch (*str) { case '[': { ut64 n = 0LL; int refsz = (core->assembler->bits & R_SYS_BITS_64)? 8: 4; const char *p = NULL; if (strlen (str)>5) p = strchr (str+5, ':'); // TODO: honor LE if (p) { refsz = atoi (str+1); str = p; } // push state { if (str[0] && str[1]) { const char *q; char *o = strdup (str+1); if (o) { q = r_num_calc_index (core->num, NULL); if (q) { if (r_str_replace_char (o, ']', 0)>0) { n = r_num_math (core->num, o); r_num_calc_index (core->num, q); } } free (o); } } } // pop state if (ok) *ok = 1; ut32 num = 0; switch (refsz) { case 8: case 4: case 2: case 1: (void)r_io_read_at (core->io, n, (ut8*)&num, refsz); r_mem_copyendian ((ut8*)&num, (ut8*)&num, refsz, !core->assembler->big_endian); return num; default: eprintf ("Invalid reference size: %d (%s)\n", refsz, str); return 0LL; } } break; case '$': if (ok) *ok = 1; // TODO: group analop-dependant vars after a char, so i can filter r_anal_op (core->anal, &op, core->offset, core->block, core->blocksize); switch (str[1]) { case '.': // can use pc, sp, a0, a1, ... return r_debug_reg_get (core->dbg, str+2); case 'k': if (str[2]!='{') { eprintf ("Expected '{' after 'k'.\n"); break; } bptr = strdup (str+3); ptr = strchr (bptr, '}'); if (ptr == NULL) { // invalid json free (bptr); break; } *ptr = '\0'; ret = 0LL; out = sdb_querys (core->sdb, NULL, 0, bptr); if (out && *out) { if (strstr (out, "$k{")) { eprintf ("Recursivity is not permitted here\n"); } else { ret = r_num_math (core->num, out); } } free (bptr); free (out); return ret; break; case '{': bptr = strdup (str+2); ptr = strchr (bptr, '}'); if (ptr != NULL) { ut64 ret; ptr[0] = '\0'; ret = r_config_get_i (core->config, bptr); free (bptr); return ret; } free (bptr); break; case 'c': return r_cons_get_size (NULL); case 'r': { int rows; r_cons_get_size (&rows); return rows; } case 'e': return r_anal_op_is_eob (&op); case 'j': return op.jump; case 'p': return r_sys_getpid (); case 'P': return (core->dbg->pid>0)? core->dbg->pid: 0; case 'f': return op.fail; case 'm': return op.ptr; // memref case 'v': return op.val; // immediate value case 'l': return op.size; case 'b': return core->blocksize; case 's': if (core->file) { return r_io_desc_size (core->io, core->file->desc); } return 0LL; case 'w': return r_config_get_i (core->config, "asm.bits") / 8; case 'S': s = r_io_section_vget (core->io, core->offset); return s? (str[2]=='S'? s->size: s->vaddr): 3; case '?': return core->num->value; case '$': return core->offset; case 'o': return r_io_section_vaddr_to_offset (core->io, core->offset); case 'C': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_CALL); case 'J': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_CODE); case 'D': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_DATA); case 'X': return getref (core, atoi (str+2), 'x', R_ANAL_REF_TYPE_CALL); case 'I': fcn = r_anal_get_fcn_in (core->anal, core->offset, 0); return fcn? fcn->ninstr: 0; case 'F': fcn = r_anal_get_fcn_in (core->anal, core->offset, 0); return fcn? fcn->size: 0; } break; default: if (*str>'A') { // NOTE: functions override flags RAnalFunction *fcn = r_anal_fcn_find_name (core->anal, str); if (fcn) { if (ok) *ok = R_TRUE; return fcn->addr; } #if 0 ut64 addr = r_anal_fcn_label_get (core->anal, core->offset, str); if (addr != 0) { ret = addr; } else { ... } #endif if ((flag = r_flag_get (core->flags, str))) { ret = flag->offset; if (ok) *ok = R_TRUE; } } break; }
static ut64 num_callback(RNum *userptr, const char *str, int *ok) { RCore *core = (RCore *)userptr; // XXX ? RAnalFunction *fcn; char *ptr, *bptr; RFlagItem *flag; RIOSection *s; RAnalOp op; ut64 ret = 0; if (ok) *ok = R_FALSE; if (*str=='[') { int refsz = (core->assembler->bits & R_SYS_BITS_64)? 8: 4; const char *p = strchr (str+5, ':'); ut64 n; // TODO: honor endian if (p) { refsz = atoi (str+1); str = p; } // push state { char *o = strdup (str+1); const char *q = r_num_calc_index (core->num, NULL); r_str_replace_char (o, ']', 0); n = r_num_math (core->num, o); r_num_calc_index (core->num, q); free (o); } // pop state switch (refsz) { case 8: { ut64 num = 0; r_io_read_at (core->io, n, (ut8*)&num, sizeof (num)); return num; } case 4: { ut32 num = 0; r_io_read_at (core->io, n, (ut8*)&num, sizeof (num)); return num; } case 2: { ut16 num = 0; r_io_read_at (core->io, n, (ut8*)&num, sizeof (num)); return num; } case 1: { ut8 num = 0; r_io_read_at (core->io, n, (ut8*)&num, sizeof (num)); return num; } default: eprintf ("Invalid reference size: %d (%s)\n", refsz, str); break; } } else if (str[0]=='$') { if (ok) *ok = 1; // TODO: group analop-dependant vars after a char, so i can filter r_anal_op (core->anal, &op, core->offset, core->block, core->blocksize); switch (str[1]) { case '.': // can use pc, sp, a0, a1, ... return r_debug_reg_get (core->dbg, str+2); case '{': bptr = strdup (str+2); ptr = strchr (bptr, '}'); if (ptr != NULL) { ut64 ret; ptr[0] = '\0'; ret = r_config_get_i (core->config, bptr); free (bptr); return ret; } break; case 'h': { int rows; r_cons_get_size (&rows); return rows; } case 'e': return op.eob; case 'j': return op.jump; case 'f': return op.fail; case 'r': return op.ref; case 'l': return op.length; case 'b': return core->blocksize; case 's': return core->file->size; case 'w': return r_config_get_i (core->config, "asm.bits") / 8; case 'S': s = r_io_section_get (core->io, r_io_section_vaddr_to_offset (core->io, core->offset)); return s? (str[2]=='S'? s->size: s->offset): 0; case '?': return core->num->value; case '$': return core->offset; case 'o': return core->io->off; case 'C': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_CALL); case 'J': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_CODE); case 'D': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_DATA); case 'X': return getref (core, atoi (str+2), 'x', R_ANAL_REF_TYPE_CALL); case 'I': fcn = r_anal_fcn_find (core->anal, core->offset, 0); return fcn? fcn->ninstr: 0; case 'F': fcn = r_anal_fcn_find (core->anal, core->offset, 0); return fcn? fcn->size: 0; } } else if (*str>'A') { if ((flag = r_flag_get (core->flags, str))) { ret = flag->offset; if (ok) *ok = R_TRUE; } } return ret; }
R_API int r_cons_w32_print(ut8 *ptr, int empty) { HANDLE hConsole = GetStdHandle (STD_OUTPUT_HANDLE); int esc = 0; int bg = 0, fg = 1|2|4|8; ut8 *str = ptr; int len = 0; int inv = 0; int linelen = 0; int lines, cols = r_cons_get_size (&lines); if (ptr && hConsole) for (; *ptr; ptr++) { if (ptr[0] == 0xa) { int ll = (size_t)(ptr-str); lines--; if (lines<0) break; //return 0; if (ll<1) continue; if (empty) { // TODO: Fix utf8 chop /* only chop columns if necessary */ if (linelen+ll>cols) { // chop line if too long ll = (cols-linelen)-1; } } write (1, str, ll); linelen += ll; esc = 0; str = ptr+1; if (empty) { int wlen = cols-linelen; char white[1024]; //wlen = 5; if (wlen>0 && wlen<sizeof (white)) { memset (white, ' ', sizeof (white)); write (1, white, wlen-1); } } write (1, "\n\r", 2); linelen = 0; continue; } if (ptr[0] == 0x1b) { int ll = (size_t)(ptr-str); if (str[0]=='\n') { str++; ll--; if (empty) { int wlen = cols-linelen-1; char white[1024]; //wlen = 5; if (wlen>0) { memset (white, ' ', sizeof (white)); write (1, white, wlen); } } write (1, "\n\r", 2); //write (1, "\r\n", 2); //lines--; linelen = 0; } if (linelen+ll>cols) { // chop line if too long ll = (cols-linelen)-1; // fix utf8 len here ll = wrapline (str, cols-linelen-1); } if (ll>0) { write (1, str, ll); linelen += ll; } esc = 1; str = ptr + 1; continue; } if (esc == 1) { // \x1b[2J if (ptr[0] != '[') { eprintf ("Oops invalid escape char\n"); esc = 0; str = ptr + 1; continue; } esc = 2; continue; } else if (esc == 2) { if (ptr[0]=='2'&&ptr[1]=='J') { //fill_tail(cols, lines); w32_clear (); //r_cons_clear (); esc = 0; ptr = ptr + 1; str = ptr + 1; continue; } else if (ptr[0]=='0'&&ptr[1]==';'&&ptr[2]=='0') { // \x1b[0;0H /** clear screen if gotoxy **/ if (empty) { // fill row here fill_tail(cols, lines); } w32_gotoxy (0, 0); lines = 0; esc = 0; ptr += 3; str = ptr + 1; continue; } else if (ptr[0]=='0'&&(ptr[1]=='m' || ptr [1]=='K')) { SetConsoleTextAttribute (hConsole, 1|2|4|8); fg = 1|2|4|8; bg = 0; inv = 0; esc = 0; ptr++; str = ptr + 1; continue; // reset color } else if (ptr[0]=='2'&&ptr[1]=='7'&&ptr[2]=='m') { SetConsoleTextAttribute (hConsole, bg|fg); inv = 0; esc = 0; ptr = ptr + 2; str = ptr + 1; continue; // invert off } else if (ptr[0]=='7'&&ptr[1]=='m') { SetConsoleTextAttribute (hConsole, bg|fg|128); inv = 128; esc = 0; ptr = ptr + 1; str = ptr + 1; continue; // invert } else if (ptr[0]=='3' && ptr[2]=='m') { // http://www.betarun.com/Pages/ConsoleColor/ switch (ptr[1]) { case '0': // BLACK fg = 0; break; case '1': // RED fg = 4; break; case '2': // GREEN fg = 2; break; case '3': // YELLOW fg = 2|4; break; case '4': // BLUE fg = 1; break; case '5': // MAGENTA fg = 1|4; break; case '6': // TURQOISE fg = 1|2|8; break; case '7': // WHITE fg = 1|2|4; break; case '8': // GRAY fg = 8; break; case '9': // ??? break; } SetConsoleTextAttribute (hConsole, bg|fg|inv); esc = 0; ptr = ptr + 2; str = ptr + 1; continue; } else if (ptr[0]=='4' && ptr[2]=='m') { /* background color */ switch (ptr[1]) { case '0': // BLACK bg = 0; break; case '1': // RED bg = 40; break; case '2': // GREEN bg = 20; break; case '3': // YELLOW bg = 20|40; break; case '4': // BLUE bg = 10; break; case '5': // MAGENTA bg = 10|40; break; case '6': // TURQOISE bg = 10|20|80; break; case '7': // WHITE bg = 10|20|40; break; case '8': // GRAY bg = 80; break; case '9': // ??? break; } esc = 0; ptr = ptr + 2; str = ptr + 1; continue; } } len++; } /* the ending padding */ { int ll = (size_t)(ptr-str); if (ll>0) { write (1, str, ll); linelen += ll; } } if (empty) { /* fill partial line */ int wlen = cols-linelen-1; char white[1024]; //wlen = 5; if (wlen>0) { memset (white, ' ', sizeof (white)); write (1, white, wlen); } /* fill tail */ fill_tail(cols, lines); } return len; }
static RList *hud_filter(RList *list, char *user_input, int top_entry_n, int *current_entry_n, char **selected_entry) { RListIter *iter; char *current_entry; char mask[HUD_BUF_SIZE]; char *p, *x; int j, rows; (void) r_cons_get_size (&rows); int counter = 0; bool first_line = true; RList *res = r_list_newf (free); r_list_foreach (list, iter, current_entry) { memset (mask, 0, HUD_BUF_SIZE); if (*user_input && !strmatch (current_entry, user_input, mask, HUD_BUF_SIZE)) { continue; } if (++counter == rows + top_entry_n) { break; } // if the user scrolled down the list, do not print the first entries if (!top_entry_n || *current_entry_n >= top_entry_n) { // remove everything after a tab (in ??, it contains the commands) x = strchr (current_entry, '\t'); if (x) { *x = 0; } p = strdup (current_entry); // if the filter is empty, print the entry and move on if (!user_input[0]) { r_list_append (res, r_str_newf (" %c %s", first_line? '-': ' ', p)); } else { // otherwise we need to emphasize the matching part if (I (context->color)) { int last_color_change = 0; int last_mask = 0; char *str = r_str_newf (" %c ", first_line? '-': ' '); // Instead of printing one char at the time // (which would be slow), we group substrings of the same color for (j = 0; p[j] && j < HUD_BUF_SIZE; j++) { if (mask[j] != last_mask) { char tmp = p[j]; p[j] = 0; if (mask[j]) { str = r_str_appendf (str, Color_RESET "%s", p + last_color_change); } else { str = r_str_appendf (str, Color_GREEN "%s", p + last_color_change); } p[j] = tmp; last_color_change = j; last_mask = mask[j]; } } if (last_mask) { str = r_str_appendf (str, Color_GREEN "%s"Color_RESET, p + last_color_change); } else { str = r_str_appendf (str, Color_RESET "%s", p + last_color_change); } r_list_append (res, str); } else { // Otherwise we print the matching characters uppercase for (j = 0; p[j]; j++) { if (mask[j]) { p[j] = toupper ((unsigned char) p[j]); } } r_list_append (res, r_str_newf (" %c %s", first_line? '-': ' ', p)); } } // Clean up and restore the tab character (if any) free (p); if (x) { *x = '\t'; } if (first_line) { *selected_entry = current_entry; } first_line = false; } (*current_entry_n)++; }