Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract histograms and bars into RzCons #3189

Merged
merged 1 commit into from
Nov 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions librz/cons/bar.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// 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
/**
* \brief Create the string buffer with the progressbar
*
* \param opts Progressbar options: color, style, legend
* \param pc How much percent is filled
* \param width Width of the histogram
*/
RZ_API RZ_OWN RzStrBuf *rz_progressbar(RZ_NONNULL RzBarOptions *opts, int pc, int width) {
rz_return_val_if_fail(opts, NULL);
wargio marked this conversation as resolved.
Show resolved Hide resolved
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--) {
wargio marked this conversation as resolved.
Show resolved Hide resolved
rz_strbuf_append(buf, h_line);
}
rz_strbuf_append(buf, "]");
return buf;
}

/**
* \brief Create the string buffer with the rangebar
*
* \param opts Rangebar options: color, style, legend
* \param startA Position of the range start
* \param endA Position of the range end
* \param min Minimum range value
* \param max Maximum range value
* \param width Width of the rangebar
*/
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;
}
201 changes: 201 additions & 0 deletions librz/cons/histogram.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
// 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, legend 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, legend 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
Loading