mirror of
https://github.com/radareorg/radare2.git
synced 2024-11-24 05:40:10 +00:00
UTF-8 support in canvas (panels, graph) (#10319)
This commit is contained in:
parent
f08603c6c7
commit
83e85ee07f
@ -10,157 +10,54 @@
|
||||
|
||||
R_API void r_cons_canvas_free(RConsCanvas *c) {
|
||||
if (c) {
|
||||
free (c->b);
|
||||
if (c->b) {
|
||||
int y;
|
||||
for (y = 0; y < c->h; y++) {
|
||||
free (c->b[y]);
|
||||
}
|
||||
free (c->b);
|
||||
}
|
||||
free (c->bsize);
|
||||
free (c->blen);
|
||||
free (c->attrs);
|
||||
free (c);
|
||||
}
|
||||
}
|
||||
|
||||
R_API void r_cons_canvas_clear(RConsCanvas *c) {
|
||||
int y;
|
||||
if (c && c->b) {
|
||||
memset (c->b, '\n', c->blen);
|
||||
c->b[c->blen] = 0;
|
||||
int y;
|
||||
for (y = 0; y < c->h; y++) {
|
||||
c->b[y * c->w] = '\n';
|
||||
memset (c->b[y], '\n', c->bsize[y]);
|
||||
}
|
||||
|
||||
/*//XXX tofix*/
|
||||
if (c->attrs) {
|
||||
c->attrslen = 0;
|
||||
memset (c->attrs, 0, sizeof (*c->attrs) * c->blen);
|
||||
memset (c->attrs, 0, sizeof (*c->attrs) * (c->w + 1) * c->h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
R_API RConsCanvas *r_cons_canvas_new(int w, int h) {
|
||||
if (w < 1 || h < 1) {
|
||||
return NULL;
|
||||
}
|
||||
RConsCanvas *c = R_NEW0 (RConsCanvas);
|
||||
if (!c) {
|
||||
return NULL;
|
||||
}
|
||||
c->color = 0;
|
||||
c->sx = 0;
|
||||
c->sy = 0;
|
||||
c->blen = (w + 1) * h;
|
||||
c->b = malloc (c->blen + 1);
|
||||
if (!c->b) {
|
||||
free (c);
|
||||
return NULL;
|
||||
}
|
||||
c->attrslen = 0;
|
||||
c->attrs = calloc (sizeof (*c->attrs), c->blen + 1);
|
||||
if (!c->attrs) {
|
||||
free (c->b);
|
||||
free (c);
|
||||
return NULL;
|
||||
}
|
||||
c->attr = Color_RESET;
|
||||
c->w = w;
|
||||
c->h = h;
|
||||
c->x = c->y = 0;
|
||||
r_cons_canvas_clear (c);
|
||||
return c;
|
||||
}
|
||||
|
||||
R_API bool r_cons_canvas_gotoxy(RConsCanvas *c, int x, int y) {
|
||||
bool ret = true;
|
||||
if (!c) {
|
||||
return 0;
|
||||
}
|
||||
x += c->sx;
|
||||
y += c->sy;
|
||||
if (x > c->w * 2) {
|
||||
return false;
|
||||
}
|
||||
if (y > c->h * 2) {
|
||||
return false;
|
||||
}
|
||||
if (x >= c->w) {
|
||||
c->x = c->w;
|
||||
ret = false;
|
||||
}
|
||||
if (y >= c->h) {
|
||||
c->y = c->h;
|
||||
ret = false;
|
||||
}
|
||||
if (x < 0) {
|
||||
//c->x = 0;
|
||||
ret = false;
|
||||
}
|
||||
if (y < 0) {
|
||||
c->y = 0;
|
||||
ret = false;
|
||||
}
|
||||
if (x < c->w && x >= 0) {
|
||||
c->x = x;
|
||||
}
|
||||
if (y < c->h && y >= 0) {
|
||||
c->y = y;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool is_ansi_seq(const char *s) {
|
||||
#if 0
|
||||
/* check utf8 length */
|
||||
if (((*s & 0xc0) == 0x80)) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
static bool _is_ansi_seq(const char *s) {
|
||||
return s && s[0] == 033 && s[1] == '[';
|
||||
}
|
||||
|
||||
static int get_piece(const char *p, char *chr) {
|
||||
static int _get_piece(const char *p, char *chr) {
|
||||
const char *q = p;
|
||||
if (!p) {
|
||||
return 0;
|
||||
}
|
||||
while (p && *p && *p != '\n' && !is_ansi_seq (p)) {
|
||||
while (p && *p && *p != '\n' && ! _is_ansi_seq (p)) {
|
||||
p++;
|
||||
}
|
||||
// XXX: this is wrong because is_ansi_seq requires skipping until JmH
|
||||
#if 0
|
||||
while (p && *p && *p != '\n') {
|
||||
if (is_ansi_seq (p)) {
|
||||
p += 2;
|
||||
while (*p && *p != 'J' && *p != 'm' && *p != 'H') {
|
||||
p++;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (chr) {
|
||||
*chr = *p;
|
||||
}
|
||||
return p - q;
|
||||
}
|
||||
|
||||
static char *prefixline(RConsCanvas *c, int *left) {
|
||||
if (!c) {
|
||||
return NULL;
|
||||
}
|
||||
int x, len;
|
||||
char *p;
|
||||
int b_len = c->w * c->h;
|
||||
int yxw = c->y * c->w;
|
||||
if (b_len < yxw) {
|
||||
return NULL;
|
||||
}
|
||||
p = c->b + yxw;
|
||||
len = b_len - yxw - 1;
|
||||
for (x = 0; (p[x] && x < c->x) && x < len; x++) {
|
||||
if (p[x] == '\n') {
|
||||
p[x] = ' ';
|
||||
}
|
||||
}
|
||||
if (left) {
|
||||
*left = c->w - c->x;
|
||||
}
|
||||
return p + x;
|
||||
}
|
||||
|
||||
//XXX todo
|
||||
static const char **attr_at(RConsCanvas *c, int loc) {
|
||||
int i, j, delta;
|
||||
if (!c->color || c->attrslen == 0) {
|
||||
@ -197,6 +94,7 @@ static const char **attr_at(RConsCanvas *c, int loc) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//XXX todo
|
||||
static void sort_attrs(RConsCanvas *c) {
|
||||
int i, j;
|
||||
RConsCanvasAttr value;
|
||||
@ -209,10 +107,10 @@ static void sort_attrs(RConsCanvas *c) {
|
||||
}
|
||||
}
|
||||
|
||||
static void stamp_attr(RConsCanvas *c, int length) {
|
||||
//XXX todo
|
||||
static void stamp_attr(RConsCanvas *c, int loc, int length) {
|
||||
int i;
|
||||
const char **s;
|
||||
const int loc = c->x + (c->y * c->w);
|
||||
s = attr_at (c, loc);
|
||||
|
||||
if (s) {
|
||||
@ -233,6 +131,7 @@ static void stamp_attr(RConsCanvas *c, int length) {
|
||||
}
|
||||
}
|
||||
|
||||
//XXX todo
|
||||
/* check for ANSI sequences and use them as attr */
|
||||
static const char *set_attr(RConsCanvas *c, const char *s) {
|
||||
if (!c || !s) {
|
||||
@ -240,7 +139,7 @@ static const char *set_attr(RConsCanvas *c, const char *s) {
|
||||
}
|
||||
const char *p = s;
|
||||
|
||||
while (is_ansi_seq (p)) {
|
||||
while (_is_ansi_seq (p)) {
|
||||
p += 2;
|
||||
while (*p && *p != 'J' && *p != 'm' && *p != 'H') {
|
||||
p++;
|
||||
@ -261,47 +160,210 @@ static const char *set_attr(RConsCanvas *c, const char *s) {
|
||||
return p;
|
||||
}
|
||||
|
||||
R_API void r_cons_canvas_write(RConsCanvas *c, const char *s) {
|
||||
char *p, ch;
|
||||
int orig_x, x;
|
||||
int left, slen, attr_len, piece_len;
|
||||
R_API bool r_cons_canvas_gotoxy(RConsCanvas *c, int x, int y) {
|
||||
bool ret = true;
|
||||
if (!c) {
|
||||
return 0;
|
||||
}
|
||||
y += c->sy;
|
||||
x += c->sx;
|
||||
|
||||
if (x > c->blen[y] * 2) {
|
||||
return false;
|
||||
}
|
||||
if (y > c->h * 2) {
|
||||
return false;
|
||||
}
|
||||
if (x >= c->blen[y]) {
|
||||
c->x = c->blen[y];
|
||||
ret = false;
|
||||
}
|
||||
if (y >= c->h) {
|
||||
c->y = c->h;
|
||||
ret = false;
|
||||
}
|
||||
if (x < 0) {
|
||||
//c->x = 0;
|
||||
ret = false;
|
||||
}
|
||||
if (y < 0) {
|
||||
c->y = 0;
|
||||
ret = false;
|
||||
}
|
||||
if (x < c->blen[y] && x >= 0) {
|
||||
c->x = x;
|
||||
}
|
||||
if (y < c->h && y >= 0) {
|
||||
c->y = y;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
R_API RConsCanvas *r_cons_canvas_new(int w, int h) {
|
||||
if (w < 1 || h < 1) {
|
||||
return NULL;
|
||||
}
|
||||
RConsCanvas *c = R_NEW0 (RConsCanvas);
|
||||
if (!c) {
|
||||
return NULL;
|
||||
}
|
||||
c->bsize = NULL;
|
||||
c->blen = NULL;
|
||||
int i = 0;
|
||||
c->color = 0;
|
||||
c->sx = 0;
|
||||
c->sy = 0;
|
||||
c->b = malloc (sizeof *c->b * h);
|
||||
if (!c->b) {
|
||||
goto beach;
|
||||
}
|
||||
c->blen = malloc (sizeof *c->blen * h);
|
||||
if (!c->blen) {
|
||||
goto beach;
|
||||
}
|
||||
c->bsize = malloc (sizeof *c->bsize * h);
|
||||
if (!c->bsize) {
|
||||
goto beach;
|
||||
}
|
||||
for (i = 0; i < h; i++) {
|
||||
c->b[i] = malloc (w + 1);
|
||||
c->blen[i] = w;
|
||||
c->bsize[i] = w + 1;
|
||||
if (!c->b[i]) {
|
||||
goto beach;
|
||||
}
|
||||
}
|
||||
c->w = w;
|
||||
c->h = h;
|
||||
c->x = c->y = 0;
|
||||
c->attrslen = 0;
|
||||
c->attrs = calloc (sizeof (*c->attrs), (c->w + 1) * c->h);
|
||||
if (!c->attrs) {
|
||||
goto beach;
|
||||
}
|
||||
c->attr = Color_RESET;
|
||||
r_cons_canvas_clear (c);
|
||||
return c;
|
||||
beach: {
|
||||
int j;
|
||||
for (j = 0; j < i; j++) {
|
||||
free (c->b[j]);
|
||||
}
|
||||
free (c->bsize);
|
||||
free (c->blen);
|
||||
free (c->b);
|
||||
free (c);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int utf8len_fixed(const char *s, int n) {
|
||||
int i = 0, j = 0;
|
||||
while (s[i] && n > 0) {
|
||||
if ((s[i] & 0xc0) != 0x80) {
|
||||
j++;
|
||||
}
|
||||
n--;
|
||||
i++;
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
static int bytes_utf8len(const char *s, int n) {
|
||||
int i = 0;
|
||||
while (s[i] && n > 0) {
|
||||
if ((s[i] & 0xc0) != 0x80) {
|
||||
n--;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int expand_line (RConsCanvas *c, int real_len, int utf8_len) {
|
||||
int buf_utf8_len = bytes_utf8len (c->b[c->y] + c->x, utf8_len);
|
||||
int goback = R_MAX (0, (buf_utf8_len - real_len));
|
||||
int padding = (real_len - utf8_len) - goback;
|
||||
|
||||
if (padding) {
|
||||
if (padding > 0 && c->blen[c->y] + padding > c->bsize[c->y]) {
|
||||
int newsize = R_MAX (c->bsize[c->y] * 1.5, c->blen[c->y] + padding);
|
||||
char * newline = realloc (c->b[c->y], sizeof (*c->b[c->y])*(newsize));
|
||||
if (!newline) {
|
||||
r_cons_canvas_free (c);
|
||||
return false;
|
||||
}
|
||||
memset (newline + c->bsize[c->y], 0, newsize - c->bsize[c->y]);
|
||||
c->b[c->y] = newline;
|
||||
c->bsize[c->y] = newsize;
|
||||
}
|
||||
int size = c->blen[c->y] - c->x - utf8_len;
|
||||
char *start = c->b[c->y] + c->x + utf8_len;
|
||||
char *tmp = malloc (size);
|
||||
if (!tmp) {
|
||||
return false;
|
||||
}
|
||||
memcpy (tmp, start, size);
|
||||
memcpy (start + padding, tmp, size);
|
||||
free (tmp);
|
||||
c->blen[c->y] += padding;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
R_API void r_cons_canvas_write(RConsCanvas *c, const char *s) {
|
||||
if (!c || !s || !*s) {
|
||||
return;
|
||||
}
|
||||
|
||||
char ch;
|
||||
int left, slen, attr_len, piece_len;
|
||||
int orig_x = c->x, attr_x = c->x;
|
||||
|
||||
int x_padding = c->x - utf8len_fixed (c->b[c->y], c->x);
|
||||
c->x += x_padding;
|
||||
|
||||
/* split the string into pieces of non-ANSI chars and print them normally,
|
||||
** using the ANSI chars to set the attr of the canvas */
|
||||
orig_x = c->x;
|
||||
r_cons_break_push (NULL, NULL);
|
||||
do {
|
||||
const char *s_part = set_attr (c, s);
|
||||
ch = 0;
|
||||
piece_len = get_piece (s_part, &ch);
|
||||
piece_len = _get_piece (s_part, &ch);
|
||||
if (piece_len == 0 && ch == '\0' && s_part == s) {
|
||||
break;
|
||||
}
|
||||
left = 0;
|
||||
p = prefixline (c, &left);
|
||||
left = c->blen[c->y] - c->x;
|
||||
slen = R_MIN (left, piece_len);
|
||||
attr_len = slen <= 0 && s_part != s? 1: slen;
|
||||
if (attr_len > 0) {
|
||||
stamp_attr (c, attr_len);
|
||||
if (attr_len > 0 && attr_x < c->blen[c->y]) {
|
||||
stamp_attr (c, c->y*c->w + attr_x, attr_len);
|
||||
}
|
||||
// XXX this is a bug if we scroll in the middle of \033
|
||||
x = c->x - c->sx;
|
||||
if (G (x, c->y - c->sy)) {
|
||||
memcpy (p, s_part, slen);
|
||||
|
||||
int real_len = r_str_nlen (s_part, slen);
|
||||
int utf8_len = utf8len_fixed (s_part, slen);
|
||||
|
||||
if (!expand_line (c, real_len, utf8_len)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (G (c->x - c->sx, c->y - c->sy)) {
|
||||
memcpy (c->b[c->y] + c->x, s_part, slen);
|
||||
}
|
||||
|
||||
s = s_part;
|
||||
if (ch == '\n') {
|
||||
c->y++;
|
||||
c->x = orig_x;
|
||||
s++;
|
||||
if (*s == '\0') {
|
||||
if (*s == '\0' || c->y >= c->h) {
|
||||
break;
|
||||
}
|
||||
x_padding = utf8len_fixed (c->b[c->y], orig_x);
|
||||
c->x = 2*orig_x - x_padding;
|
||||
attr_x = orig_x;
|
||||
} else {
|
||||
c->x += slen;
|
||||
attr_x += utf8_len;
|
||||
}
|
||||
s += piece_len;
|
||||
} while (*s && !r_cons_is_breaked ());
|
||||
@ -310,43 +372,55 @@ R_API void r_cons_canvas_write(RConsCanvas *c, const char *s) {
|
||||
}
|
||||
|
||||
R_API char *r_cons_canvas_to_string(RConsCanvas *c) {
|
||||
int x, y, olen = 0;
|
||||
int x, y, olen = 0, attr_x = 0;
|
||||
char *o;
|
||||
const char *b;
|
||||
const char **atr;
|
||||
int is_first = true;
|
||||
|
||||
if (!c) {
|
||||
return NULL;
|
||||
}
|
||||
b = c->b;
|
||||
o = calloc (1, (c->w * (c->h + 1)) * (CONS_MAX_ATTR_SZ));
|
||||
|
||||
for (y = 0; y < c->h; y++) {
|
||||
olen += c->blen[y] + 1;
|
||||
}
|
||||
o = calloc (1, olen * (CONS_MAX_ATTR_SZ));
|
||||
if (!o) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
olen = 0;
|
||||
for (y = 0; y < c->h; y++) {
|
||||
if (!is_first) {
|
||||
o[olen++] = '\n';
|
||||
}
|
||||
is_first = false;
|
||||
for (x = 0; x < c->w; x++) {
|
||||
const int p = x + (y * c->w);
|
||||
atr = attr_at (c, p);
|
||||
if (atr && *atr) {
|
||||
strcat (o, *atr);
|
||||
olen += strlen (*atr);
|
||||
attr_x = 0;
|
||||
for (x = 0; x < c->blen[y]; x++) {
|
||||
if ((c->b[y][x] & 0xc0) != 0x80) {
|
||||
atr = attr_at (c, y*c->w + attr_x);
|
||||
if (atr && *atr) {
|
||||
int len = strlen (*atr);
|
||||
memcpy (o + olen, *atr, len);
|
||||
olen += len;
|
||||
}
|
||||
attr_x++;
|
||||
}
|
||||
if (!b[p] || b[p] == '\n') {
|
||||
break;
|
||||
if (!c->b[y][x] || c->b[y][x] == '\n') {
|
||||
o[olen++] = ' ';
|
||||
continue;
|
||||
}
|
||||
const char *rune = r_cons_get_rune ((const ut8)b[p]);
|
||||
const char *rune = r_cons_get_rune ((const ut8)c->b[y][x]);
|
||||
if (rune) {
|
||||
strcpy (o + olen, rune);
|
||||
olen += strlen (rune);
|
||||
} else {
|
||||
o[olen++] = b[p];
|
||||
o[olen++] = c->b[y][x];
|
||||
}
|
||||
}
|
||||
while (o[olen - 1] == ' ') {
|
||||
o[--olen] = '\0';
|
||||
}
|
||||
}
|
||||
o[olen] = '\0';
|
||||
return o;
|
||||
@ -372,26 +446,59 @@ R_API void r_cons_canvas_print(RConsCanvas *c) {
|
||||
}
|
||||
|
||||
R_API int r_cons_canvas_resize(RConsCanvas *c, int w, int h) {
|
||||
void *newbuf = NULL;
|
||||
const int blen = (w + 1) * h;
|
||||
char *b = NULL;
|
||||
if (!c || w < 0) {
|
||||
return false;
|
||||
}
|
||||
b = realloc (c->b, blen + 1);
|
||||
if (!b) {
|
||||
void *newattrs = NULL;
|
||||
int *newblen = realloc (c->blen, sizeof *c->blen * h);
|
||||
if (!newblen) {
|
||||
r_cons_canvas_free (c);
|
||||
return false;
|
||||
}
|
||||
c->b = b;
|
||||
newbuf = realloc (c->attrs, sizeof (*c->attrs) * blen + 1);
|
||||
if (!newbuf) {
|
||||
free (c->b);
|
||||
free (c->attrs);
|
||||
c->blen = newblen;
|
||||
int *newbsize = realloc (c->bsize, sizeof *c->bsize * h);
|
||||
if (!newbsize) {
|
||||
r_cons_canvas_free (c);
|
||||
return false;
|
||||
}
|
||||
c->attrs = newbuf;
|
||||
c->blen = blen;
|
||||
c->b = b;
|
||||
c->bsize = newbsize;
|
||||
char **newb = realloc (c->b, sizeof *c->b * h);
|
||||
if (!newb) {
|
||||
r_cons_canvas_free (c);
|
||||
return false;
|
||||
}
|
||||
c->b = newb;
|
||||
int i;
|
||||
char *newline = NULL;
|
||||
for (i = 0; i < h; i++) {
|
||||
if (i < c->h) {
|
||||
newline = realloc (c->b[i], sizeof *c->b[i] * (w + 1));
|
||||
} else {
|
||||
newline = malloc ((w + 1));
|
||||
}
|
||||
c->blen[i] = w;
|
||||
c->bsize[i] = w + 1;
|
||||
if (!newline) {
|
||||
int j;
|
||||
for (j = 0; j <= i; j++) {
|
||||
free (c->b[i]);
|
||||
}
|
||||
free (c->bsize);
|
||||
free (c->attrs);
|
||||
free (c->blen);
|
||||
free (c->bsize);
|
||||
free (c->b);
|
||||
free (c);
|
||||
return false;
|
||||
}
|
||||
c->b[i] = newline;
|
||||
}
|
||||
newattrs = realloc (c->attrs, sizeof (*c->attrs) * (w + 1) * h);
|
||||
if (!newattrs) {
|
||||
r_cons_canvas_free (c);
|
||||
return false;
|
||||
}
|
||||
c->attrs = newattrs;
|
||||
c->w = w;
|
||||
c->h = h;
|
||||
c->x = 0;
|
||||
|
@ -33,7 +33,7 @@
|
||||
#define PANEL_CMD_STACK "px 256@r:SP"
|
||||
#define PANEL_CMD_REGISTERS "dr="
|
||||
#define PANEL_CMD_REGISTERREFS "drr"
|
||||
#define PANEL_CMD_DISASSEMBLY "pd $r @e:scr.utf8=0"
|
||||
#define PANEL_CMD_DISASSEMBLY "pd $r"
|
||||
|
||||
static const int layoutMaxCount = 2;
|
||||
|
||||
@ -1034,9 +1034,7 @@ R_API void r_panels_free(RPanels *panels) {
|
||||
}
|
||||
free (panels->panel);
|
||||
if (panels->can) {
|
||||
free (panels->can->b);
|
||||
free (panels->can->attrs);
|
||||
free (panels->can);
|
||||
r_cons_canvas_free (panels->can);
|
||||
}
|
||||
free (panels);
|
||||
}
|
||||
@ -1067,12 +1065,12 @@ R_API int r_core_visual_panels(RCore *core, RPanels *panels) {
|
||||
core->print->cur_enabled = false;
|
||||
core->print->col = 0;
|
||||
|
||||
have_utf8 = r_config_get_i (core->config, "scr.utf8");
|
||||
r_config_set_i (core->config, "asm.comments", 0);
|
||||
r_config_set_i (core->config, "asm.bytes", 1);
|
||||
r_config_set_i (core->config, "scr.utf8", 1);
|
||||
asm_comments = r_config_get_i (core->config, "asm.comments");
|
||||
asm_bytes = r_config_get_i (core->config, "asm.bytes");
|
||||
have_utf8 = r_config_get_i (core->config, "scr.utf8");
|
||||
|
||||
repeat:
|
||||
core->panels = panels;
|
||||
|
@ -305,8 +305,9 @@ typedef struct r_cons_canvas_t {
|
||||
int h;
|
||||
int x;
|
||||
int y;
|
||||
char *b;
|
||||
int blen;
|
||||
char **b;
|
||||
int *blen;
|
||||
int *bsize;
|
||||
const char * attr;//The current attr (inserted on each write)
|
||||
RConsCanvasAttr * attrs;// all the different attributes
|
||||
int attrslen;
|
||||
|
Loading…
Reference in New Issue
Block a user