Add N key in graph to toggle mini nodes and graph.cmtright
This commit is contained in:
parent
224b3c3319
commit
e7e4c86910
6 changed files with 270 additions and 151 deletions
|
|
@ -2055,7 +2055,8 @@ R_API int r_core_config_init(RCore *core) {
|
|||
r_config_desc (cfg, "http.uproot", "Path where files are uploaded");
|
||||
|
||||
/* graph */
|
||||
SETPREF("graph.comments", "false", "Show disasm comments in graph");
|
||||
SETPREF("graph.comments", "true", "Show disasm comments in graph");
|
||||
SETPREF("graph.cmtright", "false", "Show comments at right");
|
||||
SETPREF("graph.format", "dot", "Specify output format for graphs (dot, gml, gmlfcn)");
|
||||
SETPREF("graph.refs", "false", "Graph references in callgraphs (.agc*;aggi)");
|
||||
SETPREF("graph.font", "Courier", "Font for dot graphs");
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ static const char *mousemodes[] = {
|
|||
#define HORIZONTAL_NODE_SPACING 6
|
||||
#define VERTICAL_NODE_SPACING 4
|
||||
#define MIN_NODE_WIDTH 22
|
||||
#define MIN_NODE_HEIGTH BORDER_HEIGHT
|
||||
#define MIN_NODE_HEIGHT BORDER_HEIGHT
|
||||
#define TITLE_LEN 128
|
||||
#define DEFAULT_SPEED 1
|
||||
#define PAGEKEY_SPEED (h/2)
|
||||
|
|
@ -43,7 +43,7 @@ static const char *mousemodes[] = {
|
|||
#define hash_get_rnode(sdb,k) ((RGraphNode *)(size_t)hash_get (sdb, k))
|
||||
#define hash_get_rlist(sdb,k) ((RList *)(size_t)hash_get (sdb, k))
|
||||
#define hash_get_int(sdb,k) ((int)hash_get (sdb, k))
|
||||
|
||||
/* dont use macros for this */
|
||||
#define get_anode(gn) (gn ? (RANode *)gn->data : NULL)
|
||||
|
||||
#define graph_foreach_anode(list, it, pos, anode) \
|
||||
|
|
@ -134,6 +134,8 @@ static char *get_title (ut64 addr) {
|
|||
return r_str_newf ("0x%"PFMT64x, addr);
|
||||
}
|
||||
|
||||
static int agraph_refresh(struct agraph_refresh_data *grd);
|
||||
|
||||
static void update_node_dimension(const RGraph *g, int is_small, int zoom) {
|
||||
const RList *nodes = r_graph_get_nodes (g);
|
||||
RGraphNode *gn;
|
||||
|
|
@ -148,13 +150,15 @@ static void update_node_dimension(const RGraph *g, int is_small, int zoom) {
|
|||
unsigned int len;
|
||||
n->w = r_str_bounds (n->body, (int *)&n->h);
|
||||
len = strlen (n->title) + MARGIN_TEXT_X;
|
||||
if (len > INT_MAX) len = INT_MAX;
|
||||
if (len > INT_MAX) {
|
||||
len = INT_MAX;
|
||||
}
|
||||
n->w = R_MAX (n->w, (int)len);
|
||||
n->w += BORDER_WIDTH;
|
||||
n->h += BORDER_HEIGHT;
|
||||
/* scale node by zoom */
|
||||
n->w = R_MAX (MIN_NODE_WIDTH, (n->w * zoom) / 100);
|
||||
n->h = R_MAX (MIN_NODE_HEIGTH, (n->h * zoom) / 100);
|
||||
n->h = R_MAX (MIN_NODE_HEIGHT, (n->h * zoom) / 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -196,6 +200,33 @@ static void small_RANode_print(const RAGraph *g, const RANode *n, int cur) {
|
|||
return;
|
||||
}
|
||||
|
||||
static void mini_RANode_print(const RAGraph *g, const RANode *n, int cur) {
|
||||
char title[TITLE_LEN];
|
||||
int x, delta_x = 0;
|
||||
|
||||
if (!G (n->x + SMALLNODE_CENTER_X, n->y) &&
|
||||
!G (n->x + SMALLNODE_CENTER_X + n->w, n->y)) return;
|
||||
|
||||
x = n->x + SMALLNODE_CENTER_X + g->can->sx;
|
||||
if (x < 0) {
|
||||
delta_x = -x;
|
||||
}
|
||||
G (n->x + SMALLNODE_CENTER_X + delta_x, n->y);
|
||||
|
||||
if (cur) {
|
||||
W(&SMALLNODE_TEXT_CUR[delta_x]);
|
||||
snprintf (title, sizeof (title) - 1,
|
||||
"[ %s ]", n->title);
|
||||
W (title);
|
||||
} else {
|
||||
W(&SMALLNODE_TEXT_CUR[delta_x]);
|
||||
snprintf (title, sizeof (title) - 1,
|
||||
" %s ", n->title);
|
||||
W (title);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void normal_RANode_print(const RAGraph *g, const RANode *n, int cur) {
|
||||
unsigned int center_x = 0, center_y = 0;
|
||||
unsigned int delta_x = 0, delta_txt_x = 0;
|
||||
|
|
@ -207,13 +238,15 @@ static void normal_RANode_print(const RAGraph *g, const RANode *n, int cur) {
|
|||
|
||||
x = n->x + g->can->sx;
|
||||
y = n->y + g->can->sy;
|
||||
if (x + MARGIN_TEXT_X < 0)
|
||||
if (x + MARGIN_TEXT_X < 0) {
|
||||
delta_x = -(x + MARGIN_TEXT_X);
|
||||
if (x + n->w < -MARGIN_TEXT_X)
|
||||
}
|
||||
if (x + n->w < -MARGIN_TEXT_X) {
|
||||
return;
|
||||
if (y < -1)
|
||||
}
|
||||
if (y < -1) {
|
||||
delta_y = R_MIN (n->h - BORDER_HEIGHT - 1, -y - MARGIN_TEXT_Y);
|
||||
|
||||
}
|
||||
shortcut = sdb_get (g->db, sdb_fmt (2, "agraph.nodes.%s.shortcut", n->title), 0);
|
||||
/* print the title */
|
||||
if (cur) {
|
||||
|
|
@ -225,7 +258,6 @@ static void normal_RANode_print(const RAGraph *g, const RANode *n, int cur) {
|
|||
strncat (title, sdb_fmt (2, " ;[%s]", shortcut), sizeof (title) - strlen (title) - 1);
|
||||
free (shortcut);
|
||||
}
|
||||
|
||||
if ((delta_x < strlen (title)) && G(n->x + MARGIN_TEXT_X + delta_x, n->y + 1)) {
|
||||
W(title + delta_x);
|
||||
}
|
||||
|
|
@ -252,7 +284,9 @@ static void normal_RANode_print(const RAGraph *g, const RANode *n, int cur) {
|
|||
body_h);
|
||||
if (body) {
|
||||
W (body);
|
||||
if (g->zoom < ZOOM_DEFAULT) W ("\n");
|
||||
if (g->zoom < ZOOM_DEFAULT) {
|
||||
W ("\n");
|
||||
}
|
||||
free (body);
|
||||
} else {
|
||||
W (n->body);
|
||||
|
|
@ -261,7 +295,7 @@ static void normal_RANode_print(const RAGraph *g, const RANode *n, int cur) {
|
|||
/* print some dots when the body is cropped because of zoom */
|
||||
if (body_y <= body_h && g->zoom < ZOOM_DEFAULT) {
|
||||
char *dots = "...";
|
||||
if (delta_x < strlen(dots)) {
|
||||
if (delta_x < strlen (dots)) {
|
||||
dots += delta_x;
|
||||
W (dots);
|
||||
}
|
||||
|
|
@ -281,24 +315,22 @@ static int **get_crossing_matrix (const RGraph *g,
|
|||
const struct layer_t layers[],
|
||||
int maxlayer, int i, int from_up,
|
||||
int *n_rows) {
|
||||
int len = layers[i].n_nodes;
|
||||
int **m;
|
||||
int j;
|
||||
int j, **m, len = layers[i].n_nodes;
|
||||
|
||||
m = R_NEWS0 (int *, len);
|
||||
if (!m)
|
||||
if (!m) {
|
||||
return NULL;
|
||||
|
||||
for (j = 0; j < len; ++j) {
|
||||
m[j] = R_NEWS0 (int, len);
|
||||
if (!m[j])
|
||||
goto err_row;
|
||||
}
|
||||
|
||||
for (j = 0; j < len; j++) {
|
||||
m[j] = R_NEWS0 (int, len);
|
||||
if (!m[j]) {
|
||||
goto err_row;
|
||||
}
|
||||
}
|
||||
/* calculate crossings between layer i and layer i-1 */
|
||||
/* consider the crossings generated by each pair of edges */
|
||||
if (i > 0 && from_up) {
|
||||
for (j = 0; j < layers[i - 1].n_nodes; ++j) {
|
||||
for (j = 0; j < layers[i - 1].n_nodes; j++) {
|
||||
const RGraphNode *gj = layers[i - 1].nodes[j];
|
||||
const RList *neigh = r_graph_get_neighbours (g, gj);
|
||||
RGraphNode *gk;
|
||||
|
|
@ -307,8 +339,9 @@ static int **get_crossing_matrix (const RGraph *g,
|
|||
r_list_foreach (neigh, itk, gk) {
|
||||
int s;
|
||||
// skip self-loop
|
||||
if (gj == gk) continue;
|
||||
|
||||
if (gj == gk) {
|
||||
continue;
|
||||
}
|
||||
for (s = 0; s < j; ++s) {
|
||||
const RGraphNode *gs = layers[i - 1].nodes[s];
|
||||
const RList *neigh_s = r_graph_get_neighbours (g, gs);
|
||||
|
|
@ -317,10 +350,9 @@ static int **get_crossing_matrix (const RGraph *g,
|
|||
|
||||
r_list_foreach (neigh_s, itt, gt) {
|
||||
const RANode *ak, *at; /* k and t should be "indexes" on layer i */
|
||||
|
||||
if (gt == gk) continue;
|
||||
// skip self-loop
|
||||
if (gt == gs) continue;
|
||||
if (gt == gk || gt == gs) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ak = get_anode (gk);
|
||||
at = get_anode (gt);
|
||||
|
|
@ -993,7 +1025,6 @@ static RGraphNode *get_right_dummy (const RAGraph *g, const RGraphNode *n) {
|
|||
if (ak->is_dummy)
|
||||
return gk;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -1002,8 +1033,9 @@ static void adjust_directions (const RAGraph *g, int i, int from_up, Sdb *D, Sdb
|
|||
const RANode *vma = NULL, *wma = NULL;
|
||||
int j, d = from_up ? 1 : -1;
|
||||
|
||||
if (i + d < 0 || i + d >= g->n_layers) return;
|
||||
|
||||
if (i + d < 0 || i + d >= g->n_layers) {
|
||||
return;
|
||||
}
|
||||
for (j = 0; j < g->layers[i + d].n_nodes; ++j) {
|
||||
const RGraphNode *wp, *vp = g->layers[i + d].nodes[j];
|
||||
const RANode *wpa, *vpa = get_anode (vp);
|
||||
|
|
@ -1030,13 +1062,12 @@ static void adjust_directions (const RAGraph *g, int i, int from_up, Sdb *D, Sdb
|
|||
for (k = vma->pos_in_layer + 1; k < vpa->pos_in_layer; ++k) {
|
||||
const RGraphNode *v = g->layers[vma->layer].nodes[k];
|
||||
const RANode *av = get_anode (v);
|
||||
|
||||
if (av->is_dummy)
|
||||
if (av->is_dummy) {
|
||||
hash_set (D, v, from_up);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vm = vp;
|
||||
wm = wp;
|
||||
vma = get_anode (vm);
|
||||
|
|
@ -1045,8 +1076,7 @@ static void adjust_directions (const RAGraph *g, int i, int from_up, Sdb *D, Sdb
|
|||
}
|
||||
|
||||
/* find a placement for a single node */
|
||||
static void place_single (const RAGraph *g, int l, const RGraphNode *bm,
|
||||
const RGraphNode *bp, int from_up, int va) {
|
||||
static void place_single (const RAGraph *g, int l, const RGraphNode *bm, const RGraphNode *bp, int from_up, int va) {
|
||||
const RGraphNode *gk, *v = g->layers[l].nodes[va];
|
||||
const RANode *ak;
|
||||
RANode *av = get_anode (v);
|
||||
|
|
@ -1054,14 +1084,14 @@ static void place_single (const RAGraph *g, int l, const RGraphNode *bm,
|
|||
const RListIter *itk;
|
||||
int len;
|
||||
|
||||
if (from_up)
|
||||
neigh = r_graph_innodes (g->graph, v);
|
||||
else
|
||||
neigh = r_graph_get_neighbours (g->graph, v);
|
||||
neigh = from_up
|
||||
? r_graph_innodes (g->graph, v)
|
||||
: r_graph_get_neighbours (g->graph, v);
|
||||
|
||||
len = r_list_length (neigh);
|
||||
if (len == 0)
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int sum_x = 0;
|
||||
graph_foreach_anode (neigh, itk, gk, ak) {
|
||||
|
|
@ -1069,13 +1099,12 @@ static void place_single (const RAGraph *g, int l, const RGraphNode *bm,
|
|||
len--;
|
||||
continue;
|
||||
}
|
||||
|
||||
sum_x += ak->x;
|
||||
}
|
||||
|
||||
if (len == 0)
|
||||
if (len == 0) {
|
||||
return;
|
||||
|
||||
}
|
||||
av->x = sum_x / len;
|
||||
if (bm) {
|
||||
const RANode *bma = get_anode (bm);
|
||||
|
|
@ -1105,18 +1134,20 @@ static void collect_changes(const RAGraph *g, int l, const RGraphNode *b, int fr
|
|||
lcmp = is_left ? (RListComparator)RM_listcmp : (RListComparator)RP_listcmp;
|
||||
|
||||
for (i = is_left ? s : e - 1;
|
||||
(is_left && i < e) || (!is_left && i >= s);
|
||||
i = is_left ? i + 1 : i - 1) {
|
||||
(is_left && i < e) || (!is_left && i >= s);
|
||||
i = is_left ? i + 1 : i - 1) {
|
||||
const RGraphNode *v, *vi = g->layers[l].nodes[i];
|
||||
const RANode *av, *avi = get_anode (vi);
|
||||
const RList *neigh;
|
||||
const RListIter *it;
|
||||
int c = 0;
|
||||
|
||||
if (!avi) continue;
|
||||
if (!avi) {
|
||||
continue;
|
||||
}
|
||||
neigh = from_up
|
||||
? r_graph_innodes (g->graph, vi)
|
||||
: r_graph_get_neighbours (g->graph, vi);
|
||||
? r_graph_innodes (g->graph, vi)
|
||||
: r_graph_get_neighbours (g->graph, vi);
|
||||
|
||||
graph_foreach_anode (neigh, it, v, av) {
|
||||
if ((is_left && av->x >= avi->x) || (!is_left && av->x <= avi->x)) {
|
||||
|
|
@ -1144,12 +1175,14 @@ static void collect_changes(const RAGraph *g, int l, const RGraphNode *b, int fr
|
|||
|
||||
if (b) {
|
||||
const RANode *ab = get_anode (b);
|
||||
|
||||
cx = R_NEW (struct len_pos_t);
|
||||
cx->len = is_left ? INT_MAX : INT_MIN;
|
||||
cx->pos = ab->x;
|
||||
if (is_left) cx->pos += dist_nodes (g, b, vt);
|
||||
else cx->pos -= dist_nodes (g, vtp, b);
|
||||
if (is_left) {
|
||||
cx->pos += dist_nodes (g, b, vt);
|
||||
} else {
|
||||
cx->pos -= dist_nodes (g, vtp, b);
|
||||
}
|
||||
r_list_add_sorted (list, cx, lcmp);
|
||||
}
|
||||
}
|
||||
|
|
@ -1252,7 +1285,6 @@ static void original_traverse_l (const RAGraph *g, Sdb *D, Sdb *P, int from_up)
|
|||
while (j < g->layers[i].n_nodes && !bm) {
|
||||
const RGraphNode *gn = g->layers[i].nodes[j];
|
||||
const RANode *an = get_anode (gn);
|
||||
|
||||
if (an->is_dummy) {
|
||||
va = 0;
|
||||
vr = j;
|
||||
|
|
@ -1261,19 +1293,17 @@ static void original_traverse_l (const RAGraph *g, Sdb *D, Sdb *P, int from_up)
|
|||
}
|
||||
j++;
|
||||
}
|
||||
|
||||
if (!bm) {
|
||||
va = 0;
|
||||
vr = g->layers[i].n_nodes;
|
||||
}
|
||||
|
||||
place_sequence (g, i, NULL, bm, from_up, va, vr);
|
||||
for (k = va; k < vr - 1; ++k)
|
||||
for (k = va; k < vr - 1; k++) {
|
||||
set_dist_nodes (g, i, k, k + 1);
|
||||
|
||||
if (is_valid_pos (g, i, vr - 1) && bm)
|
||||
}
|
||||
if (is_valid_pos (g, i, vr - 1) && bm) {
|
||||
set_dist_nodes (g, i, vr - 1, bma->pos_in_layer);
|
||||
|
||||
}
|
||||
while (bm) {
|
||||
const RGraphNode *bp = get_right_dummy (g, bm);
|
||||
const RANode *bpa = NULL;
|
||||
|
|
@ -1295,10 +1325,8 @@ static void original_traverse_l (const RAGraph *g, Sdb *D, Sdb *P, int from_up)
|
|||
place_sequence (g, i, bm, bp, from_up, va, vr);
|
||||
hash_set (P, bm, true);
|
||||
}
|
||||
|
||||
bm = bp;
|
||||
}
|
||||
|
||||
adjust_directions (g, i, from_up, D, P);
|
||||
}
|
||||
}
|
||||
|
|
@ -1328,11 +1356,12 @@ static void place_original (RAGraph *g) {
|
|||
}
|
||||
|
||||
graph_foreach_anode (nodes, itn, gn, an) {
|
||||
if (!an->is_dummy) continue;
|
||||
if (!an->is_dummy) {
|
||||
continue;
|
||||
}
|
||||
const RGraphNode *right_v = get_right_dummy (g, gn);
|
||||
if (right_v) {
|
||||
const RANode *right = get_anode (right_v);
|
||||
|
||||
const RANode *right = get_anode (right_v);
|
||||
if (right_v && right) {
|
||||
hash_set (D, gn, 0);
|
||||
int dt_eq = right->x - an->x == dist_nodes (g, gn, right_v);
|
||||
hash_set (P, gn, dt_eq);
|
||||
|
|
@ -1374,7 +1403,9 @@ static void create_edge_from_dummies (const RAGraph *g, RANode *an, RList *torem
|
|||
RANode *a_from = get_anode (from);
|
||||
RListIter *(*add_to_list)(RList *, void *) = NULL;
|
||||
AEdge *e = R_NEW0 (AEdge);
|
||||
if (!e) return;
|
||||
if (!e) {
|
||||
return;
|
||||
}
|
||||
e->x = r_list_new ();
|
||||
e->y = r_list_new ();
|
||||
e->is_reversed = an->is_reversed;
|
||||
|
|
@ -1426,9 +1457,13 @@ static void analyze_back_edges (const RAGraph *g, RANode *an) {
|
|||
AEdge *e;
|
||||
|
||||
i++;
|
||||
if (ak->layer > an->layer) continue;
|
||||
if (ak->layer > an->layer) {
|
||||
continue;
|
||||
}
|
||||
e = R_NEW0 (AEdge);
|
||||
if (!e) return;
|
||||
if (!e) {
|
||||
return;
|
||||
}
|
||||
e->is_reversed = true;
|
||||
e->from = an;
|
||||
e->to = ak;
|
||||
|
|
@ -1493,7 +1528,7 @@ static void remove_dummy_nodes (const RAGraph *g) {
|
|||
static void set_layout(RAGraph *g) {
|
||||
int i, j, k;
|
||||
|
||||
if (g->edges) r_list_free (g->edges);
|
||||
r_list_free (g->edges);
|
||||
g->edges = r_list_new ();
|
||||
|
||||
remove_cycles (g);
|
||||
|
|
@ -1507,8 +1542,9 @@ static void set_layout(RAGraph *g) {
|
|||
int rh = 0;
|
||||
for (j = 0; j < g->layers[i].n_nodes; ++j) {
|
||||
const RANode *n = get_anode (g->layers[i].nodes[j]);
|
||||
if (n->h > rh)
|
||||
if (n->h > rh) {
|
||||
rh = n->h;
|
||||
}
|
||||
}
|
||||
g->layers[i].height = rh;
|
||||
}
|
||||
|
|
@ -1542,8 +1578,9 @@ static void set_layout(RAGraph *g) {
|
|||
remove_dummy_nodes (g);
|
||||
|
||||
/* free all temporary structures used during layout */
|
||||
for (i = 0; i < g->n_layers; ++i)
|
||||
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);
|
||||
|
|
@ -1558,6 +1595,7 @@ static char *get_body(RCore *core, ut64 addr, int size, int opts) {
|
|||
r_config_save_num (hc, "asm.fcnlines", "asm.lines", "asm.bytes",
|
||||
"asm.cmtcol", "asm.marks", "asm.marks", "asm.offset", "asm.comments", NULL);
|
||||
const bool o_comments = r_config_get_i (core->config, "graph.comments");
|
||||
const bool o_cmtright = r_config_get_i (core->config, "graph.cmtright");
|
||||
int o_cursor = core->print->cur_enabled;
|
||||
|
||||
const char *cmd = (opts & BODY_SUMMARY) ? "pds" : "pD";
|
||||
|
|
@ -1567,6 +1605,7 @@ static char *get_body(RCore *core, ut64 addr, int size, int opts) {
|
|||
r_config_set_i (core->config, "asm.lines", false);
|
||||
r_config_set_i (core->config, "asm.cmtcol", 0);
|
||||
r_config_set_i (core->config, "asm.marks", false);
|
||||
r_config_set_i (core->config, "asm.cmtright", o_cmtright);
|
||||
r_config_set_i (core->config, "asm.comments", (opts & BODY_SUMMARY) || o_comments);
|
||||
core->print->cur_enabled = false;
|
||||
|
||||
|
|
@ -1821,8 +1860,9 @@ static void update_seek(RConsCanvas *can, RANode *n, int force) {
|
|||
int x, y, w, h;
|
||||
int doscroll = false;
|
||||
|
||||
if (!n) return;
|
||||
|
||||
if (!n) {
|
||||
return;
|
||||
}
|
||||
x = n->x + can->sx;
|
||||
y = n->y + can->sy;
|
||||
w = can->w;
|
||||
|
|
@ -2002,11 +2042,22 @@ static void agraph_update_seek(RAGraph *g, RANode *n, int force) {
|
|||
|
||||
static void agraph_print_node(const RAGraph *g, RANode *n) {
|
||||
const int cur = g->curnode && get_anode (g->curnode) == n;
|
||||
|
||||
if (is_mini (g)) {
|
||||
small_RANode_print (g, n, cur);
|
||||
} else {
|
||||
normal_RANode_print (g, n, cur);
|
||||
if (n->mini) {
|
||||
n->w = strlen (n->title) + 4;
|
||||
#if 1
|
||||
mini_RANode_print (g, n, cur);
|
||||
#else
|
||||
small_RANode_print (g, n, cur);
|
||||
#endif
|
||||
(void)r_str_bounds ("", (int *)&n->h);
|
||||
} else {
|
||||
n->w = r_str_bounds (n->body, (int *)&n->h);
|
||||
n->h += 3;
|
||||
normal_RANode_print (g, n, cur);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2023,7 +2074,9 @@ static void agraph_print_nodes(const RAGraph *g) {
|
|||
}
|
||||
|
||||
/* draw current node now to make it appear on top */
|
||||
if (g->curnode) agraph_print_node (g, get_anode (g->curnode));
|
||||
if (g->curnode) {
|
||||
agraph_print_node (g, get_anode (g->curnode));
|
||||
}
|
||||
}
|
||||
|
||||
static int find_ascii_edge (const AEdge *a, const AEdge *b) {
|
||||
|
|
@ -2140,7 +2193,45 @@ static int agraph_reload_nodes(RAGraph *g, RCore *core, RAnalFunction *fcn) {
|
|||
|
||||
static void follow_nth(RAGraph *g, int nth) {
|
||||
const RGraphNode *cn = r_graph_nth_neighbour (g->graph, g->curnode, nth);
|
||||
if (cn) r_agraph_set_curnode (g, get_anode (cn));
|
||||
if (cn) {
|
||||
r_agraph_set_curnode (g, get_anode (cn));
|
||||
}
|
||||
}
|
||||
|
||||
#define K_NEIGHBOURS(x) (sdb_fmt(2, "agraph.nodes.%s.neighbours", x->title))
|
||||
static void agraph_merge_child(RAGraph *g, int idx) {
|
||||
const RGraphNode *nn = r_graph_nth_neighbour (g->graph, g->curnode, idx);
|
||||
const RGraphNode *cn = g->curnode;
|
||||
if (cn && nn) {
|
||||
RANode *ann = get_anode (nn);
|
||||
RANode *acn = get_anode (cn);
|
||||
acn->body = r_str_concat (acn->body, ann->title);
|
||||
acn->body = r_str_concat (acn->body, "\n");
|
||||
acn->body = r_str_concat (acn->body, ann->body);
|
||||
/* remove node from the graph */
|
||||
acn->h += ann->h - 3;
|
||||
free (ann->body);
|
||||
// TODO: do not merge nodes if those have edges targeting them
|
||||
// TODO: Add children neighbours to current one
|
||||
//nn->body
|
||||
//r_agraph_set_curnode (g, get_anode (cn));
|
||||
//agraph_refresh (grd);
|
||||
//r_agraph_add_edge (g, from, to);
|
||||
|
||||
char *neis = sdb_get (g->db, K_NEIGHBOURS (ann), 0);
|
||||
sdb_set_owned (g->db, K_NEIGHBOURS (ann), neis, 0);
|
||||
r_agraph_del_node (g, ann->title);
|
||||
agraph_print_nodes (g);
|
||||
agraph_print_edges (g);
|
||||
}
|
||||
//agraph_update_seek (g, get_anode (g->curnode), false);
|
||||
}
|
||||
|
||||
static void agraph_toggle_mini(RAGraph *g) {
|
||||
RANode *n = get_anode (g->curnode);
|
||||
n->mini = !n->mini;
|
||||
agraph_refresh (r_cons_singleton ()->event_data);
|
||||
agraph_set_layout ((RAGraph *)g, r_cons_singleton() ->is_interactive);
|
||||
}
|
||||
|
||||
static void agraph_follow_true(RAGraph *g) {
|
||||
|
|
@ -2308,7 +2399,8 @@ static int agraph_refresh(struct agraph_refresh_data *grd) {
|
|||
if (!f) {
|
||||
r_cons_message ("Not in a function. Type 'df' to define it here");
|
||||
return 0;
|
||||
} else if (f && f != *fcn) {
|
||||
}
|
||||
if (f && f != *fcn) {
|
||||
*fcn = f;
|
||||
g->need_reload_nodes = true;
|
||||
g->force_update_seek = true;
|
||||
|
|
@ -2363,7 +2455,6 @@ static void sdb_set_enc (Sdb *db, const char *key, const char *v, ut32 cas) {
|
|||
|
||||
static void agraph_sdb_init (const RAGraph *g) {
|
||||
sdb_bool_set (g->db, "agraph.is_callgraph", g->is_callgraph, 0);
|
||||
|
||||
sdb_set_enc (g->db, "agraph.color_box", g->color_box, 0);
|
||||
sdb_set_enc (g->db, "agraph.color_box2", g->color_box2, 0);
|
||||
sdb_set_enc (g->db, "agraph.color_box3", g->color_box3, 0);
|
||||
|
|
@ -2380,8 +2471,9 @@ R_API Sdb *r_agraph_get_sdb (RAGraph *g) {
|
|||
|
||||
R_API void r_agraph_print (RAGraph *g) {
|
||||
agraph_print (g, false, NULL, NULL);
|
||||
if (g->graph->n_nodes > 0)
|
||||
if (g->graph->n_nodes > 0) {
|
||||
r_cons_newline ();
|
||||
}
|
||||
}
|
||||
|
||||
R_API void r_agraph_set_title (RAGraph *g, const char *title) {
|
||||
|
|
@ -2392,9 +2484,13 @@ R_API void r_agraph_set_title (RAGraph *g, const char *title) {
|
|||
|
||||
R_API RANode *r_agraph_add_node(const RAGraph *g, const char *title, const char *body) {
|
||||
RANode *res = r_agraph_get_node (g, title);
|
||||
if (res) return res;
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
res = R_NEW0 (RANode);
|
||||
if (!res) return NULL;
|
||||
if (!res) {
|
||||
return NULL;
|
||||
}
|
||||
res->title = title ? strdup(title) : strdup ("");
|
||||
res->body = body ? strdup(body) : strdup ("");
|
||||
res->layer = -1;
|
||||
|
|
@ -2428,7 +2524,9 @@ R_API bool r_agraph_del_node(const RAGraph *g, const char *title) {
|
|||
RGraphNode *gn;
|
||||
RListIter *it;
|
||||
|
||||
if (!res) return false;
|
||||
if (!res) {
|
||||
return false;
|
||||
}
|
||||
sdb_set (g->nodes, title, NULL, 0);
|
||||
sdb_array_remove (g->db, "agraph.nodes", res->title, 0);
|
||||
sdb_set (g->db, sdb_fmt (2, "agraph.nodes.%s", res->title), NULL, 0);
|
||||
|
|
@ -2437,8 +2535,7 @@ R_API bool r_agraph_del_node(const RAGraph *g, const char *title) {
|
|||
sdb_set (g->db, sdb_fmt (2, "agraph.nodes.%s.y", res->title), NULL, 0);
|
||||
sdb_set (g->db, sdb_fmt (2, "agraph.nodes.%s.w", res->title), NULL, 0);
|
||||
sdb_set (g->db, sdb_fmt (2, "agraph.nodes.%s.h", res->title), NULL, 0);
|
||||
sdb_set (g->db, sdb_fmt (2, "agraph.nodes.%s.neighbours", res->title),
|
||||
NULL, 0);
|
||||
sdb_set (g->db, sdb_fmt (2, "agraph.nodes.%s.neighbours", res->title), NULL, 0);
|
||||
|
||||
innodes = r_graph_innodes (g->graph, res->gnode);
|
||||
graph_foreach_anode (innodes, it, gn, an) {
|
||||
|
|
@ -2642,11 +2739,9 @@ R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int
|
|||
RConsCanvas *can, *o_can = NULL;
|
||||
bool graph_allocated = false;
|
||||
int movspeed;
|
||||
int w, h;
|
||||
int ret;
|
||||
int invscroll;
|
||||
int ret, invscroll;
|
||||
|
||||
w = r_cons_get_size (&h);
|
||||
int h, w = r_cons_get_size (&h);
|
||||
can = r_cons_canvas_new (w, h);
|
||||
if (!can) {
|
||||
eprintf ("Cannot create RCons.canvas context. Invalid screen size? See scr.columns + scr.rows\n");
|
||||
|
|
@ -2828,6 +2923,7 @@ R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int
|
|||
" hjkl - scroll canvas\n"
|
||||
" HJKL - move node\n"
|
||||
" m/M - change mouse modes\n"
|
||||
" N - toggle node folding/minification\n"
|
||||
" tab - select next node\n"
|
||||
" TAB - select previous node\n"
|
||||
" t/f - follow true/false edges\n"
|
||||
|
|
@ -2908,13 +3004,13 @@ R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int
|
|||
r_core_visual_panels (core);
|
||||
break;
|
||||
case '\'':
|
||||
if (!fcn) break;
|
||||
r_config_toggle (core->config, "graph.comments");
|
||||
g->need_reload_nodes = true;
|
||||
if (fcn) {
|
||||
r_config_toggle (core->config, "graph.comments");
|
||||
g->need_reload_nodes = true;
|
||||
}
|
||||
break;
|
||||
case ';':
|
||||
{
|
||||
if (!fcn) break;
|
||||
if (fcn) {
|
||||
char buf[256];
|
||||
r_line_set_prompt ("[comment]> ");
|
||||
if (r_cons_fgets (buf, sizeof (buf) - 1, 0, NULL) > 0) {
|
||||
|
|
@ -2971,15 +3067,6 @@ R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int
|
|||
get_anode (g->curnode)->y -= movspeed;
|
||||
}
|
||||
break;
|
||||
case 'F':
|
||||
if (okey == 27) {
|
||||
// handle end key
|
||||
const RGraphNode *gn = find_near_of (g, NULL, false);
|
||||
g->update_seek_on = get_anode (gn);
|
||||
} else {
|
||||
r_core_visual_trackflags (core);
|
||||
}
|
||||
break;
|
||||
case 'H':
|
||||
if (okey == 27) {
|
||||
// handle home key
|
||||
|
|
@ -2992,6 +3079,9 @@ R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int
|
|||
case 'v':
|
||||
r_core_visual_anal (core);
|
||||
break;
|
||||
case 'N':
|
||||
agraph_toggle_mini (g);
|
||||
break;
|
||||
case 'L': get_anode (g->curnode)->x += movspeed; break;
|
||||
case 'j': can->sy -= movspeed * (invscroll ? -1 : 1); break;
|
||||
case 'k': can->sy += movspeed * (invscroll ? -1 : 1); break;
|
||||
|
|
@ -3003,9 +3093,22 @@ R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int
|
|||
case 't':
|
||||
agraph_follow_true (g);
|
||||
break;
|
||||
case 'T':
|
||||
// XXX WIP agraph_merge_child (g, 0);
|
||||
break;
|
||||
case 'f':
|
||||
agraph_follow_false (g);
|
||||
break;
|
||||
case 'F':
|
||||
if (okey == 27) {
|
||||
// handle end key
|
||||
const RGraphNode *gn = find_near_of (g, NULL, false);
|
||||
g->update_seek_on = get_anode (gn);
|
||||
} else {
|
||||
// agraph_merge_child (g, 1);
|
||||
r_core_visual_trackflags (core);
|
||||
}
|
||||
break;
|
||||
case '/':
|
||||
r_config_set_i (core->config, "scr.interactive", true);
|
||||
r_core_cmd0 (core, "?i highlight;e scr.highlight=`?y`");
|
||||
|
|
@ -3025,7 +3128,7 @@ R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int
|
|||
case ' ':
|
||||
case 'q':
|
||||
if (g->is_callgraph) {
|
||||
agraph_toggle_callgraph(g);
|
||||
agraph_toggle_callgraph (g);
|
||||
} else {
|
||||
exit_graph = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -635,6 +635,7 @@ typedef struct r_ascii_node_t {
|
|||
int is_dummy;
|
||||
int is_reversed;
|
||||
int klass;
|
||||
bool mini;
|
||||
} RANode;
|
||||
|
||||
#define R_AGRAPH_MODE_NORMAL 0
|
||||
|
|
@ -661,8 +662,8 @@ typedef struct r_ascii_graph_t {
|
|||
int movspeed;
|
||||
|
||||
RANode *update_seek_on;
|
||||
int need_reload_nodes;
|
||||
int need_set_layout;
|
||||
bool need_reload_nodes;
|
||||
bool need_set_layout;
|
||||
int need_update_dim;
|
||||
int force_update_seek;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@ enum {
|
|||
|
||||
static RGraphNode *r_graph_node_new (void *data) {
|
||||
RGraphNode *p = R_NEW0 (RGraphNode);
|
||||
if (!p) return NULL;
|
||||
if (!p) {
|
||||
return NULL;
|
||||
}
|
||||
p->data = data;
|
||||
p->free = NULL;
|
||||
p->out_nodes = r_list_new ();
|
||||
|
|
@ -20,9 +22,12 @@ static RGraphNode *r_graph_node_new (void *data) {
|
|||
}
|
||||
|
||||
static void r_graph_node_free (RGraphNode *n) {
|
||||
if (!n) return;
|
||||
if (n->free)
|
||||
if (!n) {
|
||||
return;
|
||||
}
|
||||
if (n->free) {
|
||||
n->free (n->data);
|
||||
}
|
||||
r_list_free (n->out_nodes);
|
||||
r_list_free (n->in_nodes);
|
||||
r_list_free (n->all_neighbours);
|
||||
|
|
@ -34,11 +39,12 @@ static int node_cmp (unsigned int idx, RGraphNode *b) {
|
|||
}
|
||||
|
||||
static void dfs_node (RGraph *g, RGraphNode *n, RGraphVisitor *vis, int color[]) {
|
||||
RStack *s;
|
||||
RGraphEdge *edg;
|
||||
|
||||
s = r_stack_new (2 * g->n_edges + 1);
|
||||
if (!s) return;
|
||||
RStack *s = r_stack_new (2 * g->n_edges + 1);
|
||||
if (!s) {
|
||||
return;
|
||||
}
|
||||
edg = R_NEW0 (RGraphEdge);
|
||||
if (!edg) {
|
||||
r_stack_free (s);
|
||||
|
|
@ -67,12 +73,12 @@ static void dfs_node (RGraph *g, RGraphNode *n, RGraphVisitor *vis, int color[])
|
|||
color[from->idx] = BLACK_COLOR;
|
||||
}
|
||||
free (cur_edge);
|
||||
|
||||
if (!cur || color[cur->idx] != WHITE_COLOR)
|
||||
if (!cur || color[cur->idx] != WHITE_COLOR) {
|
||||
continue;
|
||||
|
||||
if (color[cur->idx] == WHITE_COLOR && vis->discover_node)
|
||||
}
|
||||
if (color[cur->idx] == WHITE_COLOR && vis->discover_node) {
|
||||
vis->discover_node (cur, vis);
|
||||
}
|
||||
color[cur->idx] = GRAY_COLOR;
|
||||
|
||||
edg = R_NEW0 (RGraphEdge);
|
||||
|
|
@ -113,9 +119,9 @@ R_API void r_graph_free (RGraph* t) {
|
|||
|
||||
R_API RGraphNode *r_graph_get_node (const RGraph *t, unsigned int idx) {
|
||||
RListIter *it = r_list_find (t->nodes, (void *)(size_t)idx, (RListComparator)node_cmp);
|
||||
if (!it)
|
||||
if (!it) {
|
||||
return NULL;
|
||||
|
||||
}
|
||||
return (RGraphNode *)it->data;
|
||||
}
|
||||
|
||||
|
|
@ -125,9 +131,10 @@ R_API RListIter *r_graph_node_iter (const RGraph *t, unsigned int idx) {
|
|||
|
||||
R_API void r_graph_reset (RGraph *t) {
|
||||
r_list_free (t->nodes);
|
||||
|
||||
t->nodes = r_list_new ();
|
||||
if (!t->nodes) return;
|
||||
if (!t->nodes) {
|
||||
return;
|
||||
}
|
||||
t->nodes->free = (RListFree)r_graph_node_free;
|
||||
t->n_nodes = 0;
|
||||
t->n_edges = 0;
|
||||
|
|
@ -136,7 +143,9 @@ R_API void r_graph_reset (RGraph *t) {
|
|||
|
||||
R_API RGraphNode *r_graph_add_node (RGraph *t, void *data) {
|
||||
RGraphNode *n = r_graph_node_new (data);
|
||||
if (!n) return NULL;
|
||||
if (!n) {
|
||||
return NULL;
|
||||
}
|
||||
n->idx = t->last_index++;
|
||||
r_list_append (t->nodes, n);
|
||||
t->n_nodes++;
|
||||
|
|
@ -148,8 +157,9 @@ R_API RGraphNode *r_graph_add_node (RGraph *t, void *data) {
|
|||
R_API void r_graph_del_node(RGraph *t, RGraphNode *n) {
|
||||
RGraphNode *gn;
|
||||
RListIter *it;
|
||||
|
||||
if (!n) return;
|
||||
if (!n) {
|
||||
return;
|
||||
}
|
||||
r_list_foreach (n->in_nodes, it, gn) {
|
||||
r_list_delete_data (gn->out_nodes, n);
|
||||
r_list_delete_data (gn->all_neighbours, n);
|
||||
|
|
@ -171,12 +181,13 @@ R_API void r_graph_add_edge (RGraph *t, RGraphNode *from, RGraphNode *to) {
|
|||
}
|
||||
|
||||
R_API void r_graph_add_edge_at (RGraph *t, RGraphNode *from, RGraphNode *to, int nth) {
|
||||
if (!from || !to) return;
|
||||
r_list_insert(from->out_nodes, nth, to);
|
||||
r_list_append(from->all_neighbours, to);
|
||||
r_list_append(to->in_nodes, from);
|
||||
r_list_append(to->all_neighbours, from);
|
||||
t->n_edges++;
|
||||
if (from && to) {
|
||||
r_list_insert (from->out_nodes, nth, to);
|
||||
r_list_append (from->all_neighbours, to);
|
||||
r_list_append (to->in_nodes, from);
|
||||
r_list_append (to->all_neighbours, from);
|
||||
t->n_edges++;
|
||||
}
|
||||
}
|
||||
|
||||
R_API void r_graph_del_edge (RGraph *t, RGraphNode *from, RGraphNode *to) {
|
||||
|
|
@ -203,19 +214,16 @@ R_API RGraphNode *r_graph_nth_neighbour (const RGraph *g, const RGraphNode *n, i
|
|||
|
||||
/* returns the list of nodes that can reach `n` */
|
||||
R_API const RList *r_graph_innodes (const RGraph *g, const RGraphNode *n) {
|
||||
if (!n) return NULL;
|
||||
return n->in_nodes;
|
||||
return n? n->in_nodes: NULL;
|
||||
}
|
||||
|
||||
/* returns the list of nodes reachable from `n` and that can reach `n`. */
|
||||
R_API const RList *r_graph_all_neighbours (const RGraph *g, const RGraphNode *n) {
|
||||
if (!n) return NULL;
|
||||
return n->all_neighbours;
|
||||
return n? n->all_neighbours: NULL;
|
||||
}
|
||||
|
||||
R_API const RList *r_graph_get_nodes (const RGraph *g) {
|
||||
if (!g) return NULL;
|
||||
return g->nodes;
|
||||
return g? g->nodes: NULL;
|
||||
}
|
||||
|
||||
/* true if there is an edge from the node `from` to the node `to` */
|
||||
|
|
@ -226,12 +234,14 @@ R_API int r_graph_adjacent (const RGraph *g, const RGraphNode *from, const RGrap
|
|||
|
||||
R_API void r_graph_dfs_node (RGraph *g, RGraphNode *n, RGraphVisitor *vis) {
|
||||
int *color;
|
||||
|
||||
if (!g || !n || !vis) return;
|
||||
if (!g || !n || !vis) {
|
||||
return;
|
||||
}
|
||||
color = R_NEWS0 (int, g->last_index);
|
||||
if (!color) return;
|
||||
dfs_node (g, n, vis, color);
|
||||
free (color);
|
||||
if (color) {
|
||||
dfs_node (g, n, vis, color);
|
||||
free (color);
|
||||
}
|
||||
}
|
||||
|
||||
R_API void r_graph_dfs (RGraph *g, RGraphVisitor *vis) {
|
||||
|
|
@ -239,12 +249,17 @@ R_API void r_graph_dfs (RGraph *g, RGraphVisitor *vis) {
|
|||
RListIter *it;
|
||||
int *color;
|
||||
|
||||
if (!g || !vis) return;
|
||||
if (!g || !vis) {
|
||||
return;
|
||||
}
|
||||
color = R_NEWS0 (int, g->last_index);
|
||||
if (!color) return;
|
||||
if (!color) {
|
||||
return;
|
||||
}
|
||||
r_list_foreach (g->nodes, it, n) {
|
||||
if (color[n->idx] == WHITE_COLOR)
|
||||
dfs_node (g, n, vis, color);
|
||||
if (color[n->idx] == WHITE_COLOR) {
|
||||
dfs_node (g, n, vis, color);
|
||||
}
|
||||
}
|
||||
free (color);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -911,8 +911,8 @@ R_API char *r_str_prefix(char *ptr, const char *string) {
|
|||
}
|
||||
|
||||
R_API char *r_str_concatlen(char *ptr, const char *string, int slen) {
|
||||
char *ret, *msg = r_str_newlen (string, slen);
|
||||
ret = r_str_concat (ptr, msg);
|
||||
char *msg = r_str_newlen (string, slen);
|
||||
char *ret = r_str_concat (ptr, msg);
|
||||
free (msg);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -921,7 +921,6 @@ R_API char *r_str_concatlen(char *ptr, const char *string, int slen) {
|
|||
* first argument must be allocated
|
||||
* return: the pointer ptr resized to string size.
|
||||
*/
|
||||
// TODO: use vararg here?
|
||||
R_API char *r_str_concat(char *ptr, const char *string) {
|
||||
int slen, plen;
|
||||
if (!string && !ptr) {
|
||||
|
|
@ -966,7 +965,7 @@ R_API char *r_str_concatf(char *ptr, const char *fmt, ...) {
|
|||
}
|
||||
|
||||
R_API char *r_str_concatch(char *x, char y) {
|
||||
char b[2] = {y, 0};
|
||||
char b[2] = { y, 0 };
|
||||
return r_str_concat (x,b);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"previousRelease": "0.10.6",
|
||||
"releaseVersion": "1.0.0",
|
||||
"previousRelease": "1.0.2",
|
||||
"releaseVersion": "1.1.0",
|
||||
"codeName": "potato"
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue