Skip to content

Commit

Permalink
Extract histograms and bars into RzCons
Browse files Browse the repository at this point in the history
  • Loading branch information
XVilka committed Nov 16, 2022
1 parent 8226cc5 commit b514b6d
Show file tree
Hide file tree
Showing 13 changed files with 458 additions and 258 deletions.
66 changes: 66 additions & 0 deletions librz/cons/bar.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// SPDX-FileCopyrightText: 2022 Anton Kochkov <[email protected]>
// SPDX-License-Identifier: LGPL-3.0-only

#include <rz_cons.h>
#include <rz_util/rz_assert.h>

// TODO: add support for colors
RZ_API RZ_OWN RzStrBuf *rz_progressbar(RZ_NONNULL RzBarOptions *opts, int pc, int width) {
rz_return_val_if_fail(opts, NULL);
RzStrBuf *buf = rz_strbuf_new("");
if (!buf) {
return NULL;
}
int i, cols = (width == -1) ? 78 : width;
const char *h_line = opts->unicode ? RUNE_LONG_LINE_HORIZ : "-";
const char *block = opts->unicode ? UTF_BLOCK : "#";

pc = RZ_MAX(0, RZ_MIN(100, pc));
if (opts->legend) {
rz_strbuf_appendf(buf, "%4d%% ", pc);
}
cols -= 15;
rz_strbuf_append(buf, "[");
for (i = cols * pc / 100; i; i--) {
rz_strbuf_append(buf, block);
}
for (i = cols - (cols * pc / 100); i; i--) {
rz_strbuf_append(buf, h_line);
}
rz_strbuf_append(buf, "]");
return buf;
}

RZ_API RZ_OWN RzStrBuf *rz_rangebar(RZ_NONNULL RzBarOptions *opts, ut64 startA, ut64 endA, ut64 min,
ut64 max, int width) {
rz_return_val_if_fail(opts, NULL);
RzStrBuf *buf = rz_strbuf_new("|");
if (!buf) {
return NULL;
}
int cols = (width == -1) ? 78 : width;
const char *h_line = opts->unicode ? RUNE_LONG_LINE_HORIZ : "-";
const char *block = opts->unicode ? UTF_BLOCK : "#";
int mul = (max - min) / cols;
bool isFirst = true;
for (int j = 0; j < cols; j++) {
ut64 startB = min + (j * mul);
ut64 endB = min + ((j + 1) * mul);
if (startA <= endB && endA >= startB) {
if (opts->color & isFirst) {
rz_strbuf_append(buf, Color_GREEN);
isFirst = false;
}
rz_strbuf_append(buf, block);
} else {
if (!isFirst) {
rz_strbuf_append(buf, Color_RESET);
}
rz_strbuf_append(buf, h_line);
}
}
rz_strbuf_append(buf, "|");
return buf;
}


202 changes: 202 additions & 0 deletions librz/cons/histogram.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
// SPDX-FileCopyrightText: 2022 Anton Kochkov <[email protected]>
// SPDX-License-Identifier: LGPL-3.0-only

#include <rz_cons.h>
#include <rz_util/rz_assert.h>

/**
* \brief Create the string buffer with the horisontal histogram
*
* █ ██ █ █ █
* █ ██ █ █ ██
* █ █ ██ █ █ █ ██
* ██ █ ██ █ ███ █ █ █ ██ █
* ██ ██ ███ █ ███ █ █ █ █ █ █ █ █ ██ █
* ██ ██ ███ █ ███ █ █ █ █ █ █ ██ █ ███ ██ █
* ██ ██ ███ █ ███ █ █ █ █ █ █ █ ██ █ ███ ███ █ █
* ███ ██ ███ █ ███ █ █ █ █ █ █ █ ██ █ ███ █████ █
* ███████ ███ █ ███ █ █ █ █ █ ███ ██ █ ███ █████ █
* ███████ ███ █ ███ ██ ██ █ █ █ █ █ ███ ███ ██ ███ █████ █
* ███████ ████ █ ███ ██ ██ █ █ █ █ █ ███ ███ ██ ████ █████ █
* ███████ ████ █ ███ ██ ██ █ █ ██ █ ██ ███ ███ ██ ████ █████ █
* ███████__████_█_███__███__█_██_████__████___██__████___███___██__█████_█████_█
*
* \param opts Histogram options: color, style, legen and cursor position
* \param data A buffer with the numerical data in the format of one byte per value
* \param width Width of the histogram
* \param height Height of the histogram
*/
RZ_API RZ_OWN RzStrBuf *rz_histogram_horizontal(RZ_NONNULL RzHistogramOptions *opts, RZ_NONNULL const ut8 *data, ut32 width, ut32 height) {
rz_return_val_if_fail(opts && data, NULL);
RzStrBuf *buf = rz_strbuf_new("");
if (!buf) {
return NULL;
}

size_t i, j;
ut32 cols = 78;
ut32 rows = height > 0 ? height : 10;
const char *vline = opts->unicode ? RUNE_LINE_VERT : "|";
const char *block = opts->unicode ? UTF_BLOCK : "#";
const char *kol[5];
kol[0] = opts->pal->call;
kol[1] = opts->pal->jmp;
kol[2] = opts->pal->cjmp;
kol[3] = opts->pal->mov;
kol[4] = opts->pal->nop;
if (opts->color) {
for (i = 0; i < rows; i++) {
size_t threshold = i * (0xff / rows);
size_t koli = i * 5 / rows;
for (j = 0; j < cols; j++) {
int realJ = j * width / cols;
if (255 - data[realJ] < threshold || (i + 1 == rows)) {
if (opts->thinline) {
rz_strbuf_appendf(buf, "%s%s%s", kol[koli], vline, Color_RESET);
} else {
rz_strbuf_appendf(buf, "%s%s%s", kol[koli], block, Color_RESET);
}
} else {
rz_strbuf_append(buf, " ");
}
}
rz_strbuf_append(buf, "\n");
}
return buf;
}

for (i = 0; i < rows; i++) {
size_t threshold = i * (0xff / rows);
for (j = 0; j < cols; j++) {
size_t realJ = j * width / cols;
if (255 - data[realJ] < threshold) {
if (opts->thinline) {
rz_strbuf_append(buf, vline);
} else {
rz_strbuf_appendf(buf, "%s%s%s", Color_BGGRAY, block, Color_RESET);
}
} else if (i + 1 == rows) {
rz_strbuf_append(buf, "_");
} else {
rz_strbuf_append(buf, " ");
}
}
rz_strbuf_append(buf, "\n");
}
return buf;
}

static void histogram_block(RZ_NONNULL RzHistogramOptions *opts, RZ_NONNULL RzStrBuf *buf, int k, int cols) {
rz_return_if_fail(opts && buf);
const char *h_line = opts->unicode ? RUNE_LONG_LINE_HORIZ : "-";
const char *block = opts->unicode ? UTF_BLOCK : "#";
if (cols < 1) {
cols = 1;
}
if (opts->color) {
const char *kol[5];
kol[0] = opts->pal->nop;
kol[1] = opts->pal->mov;
kol[2] = opts->pal->cjmp;
kol[3] = opts->pal->jmp;
kol[4] = opts->pal->call;
int idx = (int)((k * 4) / cols);
if (idx < 5) {
const char *str = kol[idx];
if (opts->thinline) {
rz_strbuf_appendf(buf, "%s%s%s", str, h_line, Color_RESET);
} else {
rz_strbuf_appendf(buf, "%s%s%s", str, block, Color_RESET);
}
}
} else {
if (opts->thinline) {
rz_strbuf_append(buf, h_line);
} else {
rz_strbuf_append(buf, block);
}
}
}

/**
* \brief Create the string buffer with the vertical histogram
*
* \param opts Histogram options: color, style, legen and cursor position
* \param data A buffer with the numerical data in the format of one byte per value
* \param width Width of the histogram
* \param step Step for the new line
*/
RZ_API RZ_OWN RzStrBuf *rz_histogram_vertical(RZ_NONNULL RzHistogramOptions *opts, RZ_NONNULL const
ut8 *data, int width, int step) {
rz_return_val_if_fail(opts && data, NULL);
RzStrBuf *buf = rz_strbuf_new("");
if (!buf) {
return NULL;
}

const int increment = 5;
const char *v_line = opts->unicode ? RUNE_LINE_VERT : "|";
int i = 0, j;

// get the max of columns
int cols = 0;
for (i = 0; i < width; i++) {
cols = data[i] > cols ? data[i] : cols;
}
cols /= 5;
for (i = 0; i < width; i++) {
ut8 next = (i + 1 < width) ? data[i + 1] : 0;
int base = 0, k = 0;
if (step > 0) {
if (opts->offset) {
ut64 at = opts->offpos + (i * step);
if (opts->cursor) {
if (i == opts->curpos) {
rz_strbuf_appendf(buf, Color_INVERT "> 0x%08" PFMT64x " " Color_RESET, at);
} else {
rz_strbuf_appendf(buf, " 0x%08" PFMT64x " ", at);
}
} else {
rz_strbuf_appendf(buf, "0x%08" PFMT64x " ", at);
}
}
rz_strbuf_appendf(buf, "%03x %04x %s", i, data[i], v_line);
} else {
rz_strbuf_appendf(buf, "%s", v_line);
}
if (next < increment) {
base = 1;
}
if (next < data[i]) {
if (data[i] > increment) {
for (j = 0; j < next + base; j += increment) {
histogram_block(opts, buf, k, cols);
k++;
}
}
for (j = next + increment; j + base < data[i]; j += increment) {
histogram_block(opts, buf, k, cols);
k++;
}
} else {
histogram_block(opts, buf, k, cols);
k++;
}
if (i + 1 == width) {
for (j = data[i] + increment + base; j + base < next; j += increment) {
histogram_block(opts, buf, k, cols);
k++;
}
} else if (data[i + 1] > data[i]) {
for (j = data[i] + increment + base; j + base < next; j += increment) {
histogram_block(opts, buf, k, cols);
k++;
}
}
if (opts->color) {
rz_strbuf_append(buf, Color_RESET);
}
rz_strbuf_append(buf, "\n");
}
return buf;
}
2 changes: 2 additions & 0 deletions librz/cons/meson.build
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
rz_cons_sources = [
'bar.c',
'canvas.c',
'canvas_line.c',
'cons.c',
Expand All @@ -9,6 +10,7 @@ rz_cons_sources = [
'input.c',
'less.c',
'line.c',
'histogram.c',
'output.c',
'pager.c',
'pal.c',
Expand Down
2 changes: 1 addition & 1 deletion librz/core/agraph.c
Original file line number Diff line number Diff line change
Expand Up @@ -4416,7 +4416,7 @@ RZ_IPI int rz_core_visual_graph(RzCore *core, RzAGraph *g, RzAnalysisFunction *_
" Page-UP/DOWN - scroll canvas up/down\n"
" b - visual browse things\n"
" c - toggle graph cursor mode\n"
" C - toggle scr.colors\n"
" C - toggle scr.color\n"
" d - rename function\n"
" D - toggle the mixed graph+disasm mode\n"
" e - rotate graph.edges (show/hide edges)\n"
Expand Down
17 changes: 16 additions & 1 deletion librz/core/cmd/cmd_flag.c
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,22 @@ static bool flagbar_foreach(RzFlagItem *fi, void *user) {
max = m->itv.addr + m->itv.size;
}
rz_cons_printf("0x%08" PFMT64x " ", fi->offset);
rz_print_rangebar(u->core->print, fi->offset, fi->offset + fi->size, min, max, u->cols);
RzBarOptions opts = {
.unicode = false,
.thinline = false,
.legend = true,
.offset = false,
.offpos = 0,
.cursor = false,
.curpos = 0,
.color = false
};
RzStrBuf *strbuf = rz_rangebar(&opts, fi->offset, fi->offset + fi->size, min, max, u->cols);
if (!strbuf) {
RZ_LOG_ERROR("Cannot generate rangebar\n");
} else {
rz_cons_print(rz_strbuf_drain(strbuf));
}
rz_cons_printf(" %s\n", fi->name);
return true;
}
Expand Down
17 changes: 16 additions & 1 deletion librz/core/cmd/cmd_help.c
Original file line number Diff line number Diff line change
Expand Up @@ -923,7 +923,22 @@ RZ_IPI int rz_cmd_help(void *data, const char *input) {
break;
case '=': { // "?e="
ut64 pc = rz_num_math(core->num, input + 2);
rz_print_progressbar(core->print, pc, 80);
RzBarOptions opts = {
.unicode = rz_config_get_b(core->config, "scr.utf8"),
.thinline = !rz_config_get_b(core->config, "scr.hist.block"),
.legend = true,
.offset = rz_config_get_b(core->config, "hex.offset"),
.offpos = 0,
.cursor = false,
.curpos = 0,
.color = rz_config_get_i(core->config, "scr.color")
};
RzStrBuf *strbuf = rz_progressbar(&opts, pc, 80);
if (!strbuf) {
RZ_LOG_ERROR("Cannot generate progressbar\n");
} else {
rz_cons_print(rz_strbuf_drain(strbuf));
}
rz_cons_newline();
break;
}
Expand Down
24 changes: 19 additions & 5 deletions librz/core/cmd/cmd_open.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "../core_private.h"

struct open_list_ascii_data_t {
RzCore *core;
RzPrint *p;
int fdsz;
};
Expand Down Expand Up @@ -41,15 +42,27 @@ static bool init_desc_list_visual_cb(void *user, void *data, ut32 id) {

static bool desc_list_visual_cb(void *user, void *data, ut32 id) {
struct open_list_ascii_data_t *u = (struct open_list_ascii_data_t *)user;
RzPrint *p = u->p;
RzCore *core = u->core;
RzIODesc *desc = (RzIODesc *)data;
ut64 sz = rz_io_desc_size(desc);
rz_cons_printf("%2d %c %s 0x%08" PFMT64x " ", desc->fd,
(desc->io && (desc->io->desc == desc)) ? '*' : '-', rz_str_rwx_i(desc->perm), sz);
int flags = p->flags;
p->flags &= ~RZ_PRINT_FLAGS_HEADER;
rz_print_progressbar(p, sz * 100 / u->fdsz, rz_cons_get_size(NULL) - 40);
p->flags = flags;
RzBarOptions opts = {
.unicode = rz_config_get_b(core->config, "scr.utf8"),
.thinline = !rz_config_get_b(core->config, "scr.hist.block"),
.legend = true,
.offset = rz_config_get_b(core->config, "hex.offset"),
.offpos = 0,
.cursor = false,
.curpos = 0,
.color = rz_config_get_i(core->config, "scr.color")
};
RzStrBuf *strbuf = rz_progressbar(&opts, sz * 100 / u->fdsz , rz_cons_get_size(NULL) - 40);
if (!strbuf) {
RZ_LOG_ERROR("Cannot generate progressbar\n");
} else {
rz_cons_print(rz_strbuf_drain(strbuf));
}
rz_cons_printf(" %s\n", desc->uri);
return true;
}
Expand Down Expand Up @@ -121,6 +134,7 @@ RZ_IPI RzCmdStatus rz_open_close_all_handler(RzCore *core, int argc, const char
}
RZ_IPI RzCmdStatus rz_open_list_ascii_handler(RzCore *core, int argc, const char **argv) {
struct open_list_ascii_data_t data = { 0 };
data.core = core;
data.p = core->print;
data.fdsz = 0;
rz_id_storage_foreach(core->io->files, init_desc_list_visual_cb, &data);
Expand Down
Loading

0 comments on commit b514b6d

Please sign in to comment.