mirror of
https://github.com/radareorg/radare2.git
synced 2025-02-04 20:46:20 +00:00
Implement findNextWord in the interactive Visual Graph ##graph
This commit is contained in:
parent
311ad81894
commit
4b0e25caeb
@ -1,4 +1,4 @@
|
||||
/* radare - LGPL - Copyright 2013-2019 - pancake */
|
||||
/* radare - LGPL - Copyright 2013-2020 - pancake */
|
||||
|
||||
#include <r_cons.h>
|
||||
#include <r_util/r_assert.h>
|
||||
@ -218,6 +218,49 @@ R_API bool r_cons_canvas_gotoxy(RConsCanvas *c, int x, int y) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *canvas_string(RConsCanvas *c, size_t pos) {
|
||||
int x, y;
|
||||
char *s = calloc (c->w, c->h);
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
char *p = s;
|
||||
int ox = c->x;
|
||||
int oy = c->y;
|
||||
for (y = oy; y < c->h; y ++) {
|
||||
for (x = (y == oy)? ox: 0; x < c->w; x ++) {
|
||||
char ch = c->b[y][x];
|
||||
const char *rune = r_cons_get_rune ((const ut8)ch);
|
||||
if (rune) {
|
||||
size_t rune_len = strlen (rune);
|
||||
memcpy (p, rune, rune_len + 1);
|
||||
p += rune_len;
|
||||
} else {
|
||||
*p = c->b[y][x];
|
||||
}
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static int count_newlines(char *s, size_t len, size_t *col) {
|
||||
size_t nl = 0;
|
||||
size_t nc = 0;
|
||||
size_t i;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (s[i] == '\n') {
|
||||
nl++;
|
||||
nc = 0;
|
||||
} else {
|
||||
nc ++;
|
||||
}
|
||||
}
|
||||
if (col) {
|
||||
*col = nc;
|
||||
}
|
||||
return nl;
|
||||
}
|
||||
|
||||
R_API RConsCanvas *r_cons_canvas_new(int w, int h) {
|
||||
if (w < 1 || h < 1) {
|
||||
return NULL;
|
||||
@ -265,7 +308,7 @@ R_API RConsCanvas *r_cons_canvas_new(int w, int h) {
|
||||
c->attr = Color_RESET;
|
||||
r_cons_canvas_clear (c);
|
||||
return c;
|
||||
beach: {
|
||||
beach:
|
||||
r_str_constpool_fini (&c->constpool);
|
||||
int j;
|
||||
for (j = 0; j < i; j++) {
|
||||
@ -276,7 +319,6 @@ beach: {
|
||||
free (c->b);
|
||||
free (c);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
R_API void r_cons_canvas_write(RConsCanvas *c, const char *s) {
|
||||
@ -323,13 +365,13 @@ R_API void r_cons_canvas_write(RConsCanvas *c, const char *s) {
|
||||
|
||||
attr_len = slen <= 0 && s_part != s? 1: utf8_len;
|
||||
if (attr_len > 0 && attr_x < c->blen[c->y]) {
|
||||
__stampAttribute (c, c->y*c->w + attr_x, attr_len);
|
||||
__stampAttribute (c, c->y * c->w + attr_x, attr_len);
|
||||
}
|
||||
|
||||
s = s_part;
|
||||
if (ch == '\n') {
|
||||
c->attr = Color_RESET;
|
||||
__stampAttribute (c, c->y*c->w + attr_x, 0);
|
||||
__stampAttribute (c, c->y * c->w + attr_x, 0);
|
||||
c->y++;
|
||||
s++;
|
||||
if (*s == '\0' || c->y >= c->h) {
|
||||
@ -351,7 +393,7 @@ R_API char *r_cons_canvas_to_string(RConsCanvas *c) {
|
||||
r_return_val_if_fail (c, NULL);
|
||||
|
||||
int x, y, olen = 0, attr_x = 0;
|
||||
int is_first = true;
|
||||
bool is_first = true;
|
||||
|
||||
for (y = 0; y < c->h; y++) {
|
||||
olen += c->blen[y] + 1;
|
||||
@ -376,7 +418,7 @@ R_API char *r_cons_canvas_to_string(RConsCanvas *c) {
|
||||
if ((c->b[y][x] & 0xc0) != 0x80) {
|
||||
const char *atr = __attributeAt (c, y * c->w + attr_x);
|
||||
if (atr) {
|
||||
int len = strlen (atr);
|
||||
size_t len = strlen (atr);
|
||||
memcpy (o + olen, atr, len);
|
||||
olen += len;
|
||||
}
|
||||
@ -391,8 +433,9 @@ R_API char *r_cons_canvas_to_string(RConsCanvas *c) {
|
||||
}
|
||||
const char *rune = r_cons_get_rune ((const ut8)c->b[y][x]);
|
||||
if (rune) {
|
||||
strcpy (o + olen, rune);
|
||||
olen += strlen (rune);
|
||||
size_t rune_len = strlen (rune);
|
||||
memcpy (o + olen, rune, rune_len + 1);
|
||||
olen += rune_len;
|
||||
} else {
|
||||
o[olen++] = c->b[y][x];
|
||||
}
|
||||
@ -452,12 +495,12 @@ R_API int r_cons_canvas_resize(RConsCanvas *c, int w, int h) {
|
||||
if (i < c->h) {
|
||||
newline = realloc (c->b[i], sizeof *c->b[i] * (w + 1));
|
||||
} else {
|
||||
newline = malloc ((w + 1));
|
||||
newline = malloc (w + 1);
|
||||
}
|
||||
c->blen[i] = w;
|
||||
c->bsize[i] = w + 1;
|
||||
if (!newline) {
|
||||
int j;
|
||||
size_t j;
|
||||
for (j = 0; j <= i; j++) {
|
||||
free (c->b[i]);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright radare2 - 2014-2019 - pancake, ret2libc */
|
||||
/* Copyright radare2 - 2014-2020 - pancake, ret2libc */
|
||||
|
||||
#include <r_core.h>
|
||||
#include <r_cons.h>
|
||||
@ -2058,13 +2058,11 @@ static void set_layout(RAGraph *g) {
|
||||
|
||||
backedge_info (g);
|
||||
|
||||
//restore_original_edges (g);
|
||||
//remove_dummy_nodes (g);
|
||||
|
||||
/* free all temporary structures used during layout */
|
||||
for (i = 0; i < g->n_layers; i++) {
|
||||
free (g->layers[i].nodes);
|
||||
}
|
||||
|
||||
free (g->layers);
|
||||
r_list_free (g->long_edges);
|
||||
r_list_free (g->back_edges);
|
||||
@ -2413,7 +2411,7 @@ cleanup:
|
||||
|
||||
/* build the RGraph inside the RAGraph g, starting from the Call Graph
|
||||
* information */
|
||||
static int get_cgnodes(RAGraph *g, RCore *core, RAnalFunction *fcn) {
|
||||
static bool get_cgnodes(RAGraph *g, RCore *core, RAnalFunction *fcn) {
|
||||
RAnalFunction *f = r_anal_get_fcn_in (core->anal, core->offset, 0);
|
||||
RANode *node, *fcn_anode;
|
||||
RListIter *iter;
|
||||
@ -2474,25 +2472,21 @@ static int get_cgnodes(RAGraph *g, RCore *core, RAnalFunction *fcn) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static int reload_nodes(RAGraph *g, RCore *core, RAnalFunction *fcn) {
|
||||
int is_c = g->is_callgraph;
|
||||
static bool reload_nodes(RAGraph *g, RCore *core, RAnalFunction *fcn) {
|
||||
const bool is_c = g->is_callgraph;
|
||||
return is_c? get_cgnodes (g, core, fcn): get_bbnodes (g, core, fcn);
|
||||
}
|
||||
|
||||
static void update_seek(RConsCanvas *can, RANode *n, int force) {
|
||||
int x, y, w, h;
|
||||
int doscroll = false;
|
||||
|
||||
if (!n) {
|
||||
return;
|
||||
}
|
||||
x = n->x + can->sx;
|
||||
y = n->y + can->sy;
|
||||
w = can->w;
|
||||
h = can->h;
|
||||
|
||||
doscroll = force || y < 0 || y + 5 > h || x + 5 > w || x + n->w + 5 < 0;
|
||||
int x = n->x + can->sx;
|
||||
int y = n->y + can->sy;
|
||||
int w = can->w;
|
||||
int h = can->h;
|
||||
|
||||
const bool doscroll = force || y < 0 || y + 5 > h || x + 5 > w || x + n->w + 5 < 0;
|
||||
if (doscroll) {
|
||||
if (n->w > w) { //too big for centering
|
||||
can->sx = -n->x;
|
||||
@ -2529,8 +2523,8 @@ static const RGraphNode *find_near_of(const RAGraph *g, const RGraphNode *cur, i
|
||||
const RGraphNode *gn, *resgn = NULL;
|
||||
const RANode *n, *acur = cur? get_anode (cur): NULL;
|
||||
const int default_v = is_next? INT_MIN: INT_MAX;
|
||||
const int start_y = acur? acur->y: default_v;
|
||||
const int start_x = acur? acur->x: default_v;
|
||||
const int start_y = acur? acur->y: default_v;
|
||||
|
||||
graph_foreach_anode (nodes, it, gn, n) {
|
||||
// tab in horizontal layout is not correct, lets force vertical nextnode for now (g->layout == 0)
|
||||
@ -3152,9 +3146,8 @@ static void agraph_set_zoom(RAGraph *g, int v) {
|
||||
/* reload all the info in the nodes, depending on the type of the graph
|
||||
* (callgraph, CFG, etc.), set the default layout for these nodes and center
|
||||
* the screen on the selected one */
|
||||
static int agraph_reload_nodes(RAGraph *g, RCore *core, RAnalFunction *fcn) {
|
||||
static bool agraph_reload_nodes(RAGraph *g, RCore *core, RAnalFunction *fcn) {
|
||||
r_agraph_reset (g);
|
||||
|
||||
return reload_nodes (g, core, fcn);
|
||||
}
|
||||
|
||||
@ -3178,7 +3171,6 @@ static void move_current_node(RAGraph *g, int xdiff, int ydiff) {
|
||||
xdiff = NORMALIZE_MOV (xdiff);
|
||||
ydiff = NORMALIZE_MOV (ydiff);
|
||||
}
|
||||
|
||||
n->x += xdiff;
|
||||
n->y += ydiff;
|
||||
}
|
||||
@ -3234,7 +3226,7 @@ static void agraph_toggle_mini(RAGraph *g) {
|
||||
agraph_set_layout ((RAGraph *) g);
|
||||
}
|
||||
|
||||
static void agraph_follow_innodes (RAGraph *g, bool in) {
|
||||
static void agraph_follow_innodes(RAGraph *g, bool in) {
|
||||
int count = 0;
|
||||
RListIter *iter;
|
||||
RANode *an = get_anode (g->curnode);
|
||||
@ -4046,6 +4038,114 @@ static bool toggle_bb(RCore *core, ut64 addr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
typedef struct r_canvas_location {
|
||||
int x;
|
||||
int y;
|
||||
} RPosition;
|
||||
|
||||
static const char *strstr_xy(const char *p, const char *s, int *x, int *y) {
|
||||
const char *d = strstr (p, s);
|
||||
if (!d) {
|
||||
return NULL;
|
||||
}
|
||||
const char *q;
|
||||
int nl = 0;
|
||||
int nc = *x;
|
||||
for (q = p; q < d; q++) {
|
||||
if (*q == '\n') {
|
||||
nl++;
|
||||
*x = 0;
|
||||
nc = 0;
|
||||
} else {
|
||||
nc++;
|
||||
}
|
||||
}
|
||||
*x += nc;
|
||||
*y += nl;
|
||||
return d;
|
||||
}
|
||||
|
||||
static char *get_graph_string(RCore *core) {
|
||||
int c = r_config_get_i (core->config, "scr.color");
|
||||
int u = r_config_get_i (core->config, "scr.utf8");
|
||||
r_config_set_i (core->config, "scr.color", 0);
|
||||
r_config_set_i (core->config, "scr.utf8", 0);
|
||||
r_core_visual_graph (core, NULL, NULL, false);
|
||||
char *s = strdup (r_cons_get_buffer ());
|
||||
r_cons_reset ();
|
||||
r_config_set_i (core->config, "scr.color", c);
|
||||
r_config_set_i (core->config, "scr.utf8", u);
|
||||
return s;
|
||||
}
|
||||
|
||||
static void nextword(RCore *core, RConsCanvas *can, const char *word) {
|
||||
r_return_if_fail (core && core->graph && can && word);
|
||||
if (R_STR_ISEMPTY (word)) {
|
||||
return;
|
||||
}
|
||||
RAGraphHits *gh = &core->graph->ghits;
|
||||
if (gh->word_list.v.len && gh->old_word && !strcmp (word, gh->old_word)) {
|
||||
RPosition *pos = r_pvector_at (&gh->word_list, gh->word_nth);
|
||||
if (pos) {
|
||||
gh->word_nth++;
|
||||
} else {
|
||||
gh->word_nth = 0;
|
||||
pos = r_pvector_at (&gh->word_list, gh->word_nth);
|
||||
}
|
||||
if (pos) {
|
||||
can->sx = pos->x;
|
||||
can->sy = pos->y;
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
r_pvector_fini (&gh->word_list);
|
||||
r_pvector_init (&gh->word_list, free);
|
||||
}
|
||||
char *s = get_graph_string (core);
|
||||
const char *p = s;
|
||||
r_cons_clear00 ();
|
||||
r_cons_flush ();
|
||||
int ox = 0;
|
||||
int oy = 0;
|
||||
size_t count = 0;
|
||||
const size_t MAX_COUNT = 4096;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
bool first_x = true;
|
||||
for (count = 0; count < MAX_COUNT; count++) {
|
||||
x = 0;
|
||||
const char *a = strstr_xy (p, word, &x, &y);
|
||||
if (!a) {
|
||||
break;
|
||||
}
|
||||
RPosition *pos = R_NEW0 (RPosition);
|
||||
if (!pos) {
|
||||
break;
|
||||
}
|
||||
if (first_x) {
|
||||
gh->x_origin = x;
|
||||
first_x = false;
|
||||
}
|
||||
const size_t yhalf = can->h / 6;
|
||||
pos->y = -y + yhalf;
|
||||
if (oy == pos->y) {
|
||||
const size_t xhalf = can->w / 2;
|
||||
pos->x = - (x - (ox * 2) - xhalf);
|
||||
} else {
|
||||
const size_t nhalf = can->w / 3;
|
||||
pos->x = gh->x_origin - x + nhalf;
|
||||
}
|
||||
oy = pos->y;
|
||||
ox = pos->x;
|
||||
r_pvector_push (&gh->word_list, pos);
|
||||
p = a + 1;
|
||||
}
|
||||
free (gh->old_word);
|
||||
gh->old_word = strdup (word);
|
||||
free (s);
|
||||
return nextword (core, can, word);
|
||||
}
|
||||
|
||||
R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int is_interactive) {
|
||||
int o_asmqjmps_letter = core->is_asmqjmps_letter;
|
||||
int o_scrinteractive = r_cons_is_interactive ();
|
||||
@ -4242,6 +4342,9 @@ R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int
|
||||
get_bbupdate (g, core, fcn);
|
||||
}
|
||||
break;
|
||||
case '\\':
|
||||
nextword (core, can, r_config_get (core->config, "scr.highlight"));
|
||||
break;
|
||||
case 'b':
|
||||
r_core_visual_browse (core, "");
|
||||
break;
|
||||
@ -4345,6 +4448,7 @@ R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int
|
||||
" \" - toggle graph.refs\n"
|
||||
" # - toggle graph.hints\n"
|
||||
" / - highlight text\n"
|
||||
" \\ - scroll the graph canvas to the next highlight location\n"
|
||||
" | - set cmd.gprompt\n"
|
||||
" _ - enter hud selector\n"
|
||||
" > - show function callgraph (see graph.refs)\n"
|
||||
@ -4838,6 +4942,8 @@ R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int
|
||||
break;
|
||||
}
|
||||
}
|
||||
RAGraphHits *gh = &core->graph->ghits;
|
||||
r_pvector_fini (&gh->word_list);
|
||||
r_cons_break_pop ();
|
||||
r_config_set (core->config, "asm.comments", r_str_bool (asm_comments));
|
||||
core->cons->event_resize = NULL;
|
||||
|
@ -26,6 +26,14 @@ typedef struct r_ascii_node_t {
|
||||
bool is_mini;
|
||||
} RANode;
|
||||
|
||||
typedef struct r_core_graph_hits_t {
|
||||
char *old_word ;
|
||||
RPVector word_list;
|
||||
int word_nth;
|
||||
int x_origin;
|
||||
} RAGraphHits;
|
||||
|
||||
|
||||
#define R_AGRAPH_MODE_NORMAL 0
|
||||
#define R_AGRAPH_MODE_OFFSET 1
|
||||
#define R_AGRAPH_MODE_MINI 2
|
||||
@ -81,6 +89,7 @@ typedef struct r_ascii_graph_t {
|
||||
int n_layers;
|
||||
RList *dists; /* RList<struct dist_t> */
|
||||
RList *edges; /* RList<AEdge> */
|
||||
RAGraphHits ghits;
|
||||
} RAGraph;
|
||||
|
||||
#ifdef R_API
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* radare - LGPL - Copyright 2009-2019 - pancake */
|
||||
/* radare - LGPL - Copyright 2009-2020 - pancake */
|
||||
|
||||
#ifndef R2_CORE_H
|
||||
#define R2_CORE_H
|
||||
|
@ -2468,7 +2468,7 @@ R_API int r_str_len_utf8_ansi(const char *str) {
|
||||
}
|
||||
|
||||
// XXX must find across the ansi tags, as well as support utf8
|
||||
R_API const char *r_strstr_ansi (const char *a, const char *b) {
|
||||
R_API const char *r_strstr_ansi(const char *a, const char *b) {
|
||||
const char *ch, *p = a;
|
||||
do {
|
||||
ch = strchr (p, '\x1b');
|
||||
|
@ -228,7 +228,6 @@ static void pvector_free_elem(void *e, void *user) {
|
||||
elem_free (p);
|
||||
}
|
||||
|
||||
|
||||
R_API void r_pvector_init(RPVector *vec, RPVectorFree free) {
|
||||
r_vector_init (&vec->v, sizeof (void *), free ? pvector_free_elem : NULL, free);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user