radare2/libr/cons/output.c

461 lines
9.8 KiB
C
Raw Normal View History

/* radare - LGPL - Copyright 2009-2022 - pancake */
#include <r_cons.h>
#include <r_th.h>
#include <r_util/r_assert.h>
#define I r_cons_singleton ()
#if R2__WINDOWS__
2019-06-09 16:50:36 +00:00
static void __fill_tail(int cols, int lines) {
2016-06-29 10:33:31 +00:00
lines++;
if (lines > 0) {
char white[1024];
2016-06-29 10:33:31 +00:00
cols = R_MIN (cols, sizeof (white));
2019-06-09 16:50:36 +00:00
memset (white, ' ', cols - 1);
lines--;
2019-06-09 16:50:36 +00:00
white[cols] = '\n';
2016-06-29 10:33:31 +00:00
while (lines-- > 0) {
write (1, white, cols);
2016-06-29 10:33:31 +00:00
}
}
}
static R_TH_LOCAL HANDLE hStdout = NULL;
static R_TH_LOCAL HANDLE hStderr = NULL;
static R_TH_LOCAL CONSOLE_SCREEN_BUFFER_INFO csbi;
R_API void r_cons_w32_clear(void) {
COORD startCoords;
DWORD dummy;
if (I->vtmode) {
2023-07-05 12:02:35 +00:00
r_cons_print (Color_RESET R_CONS_CLEAR_SCREEN);
return;
}
2016-06-29 10:33:31 +00:00
if (I->is_wine == 1) {
2018-01-02 18:31:02 +00:00
write (1, "\033[0;0H\033[0m\033[2J", 6 + 4 + 4);
}
if (!hStdout) {
hStdout = GetStdHandle (STD_OUTPUT_HANDLE);
}
GetConsoleScreenBufferInfo (hStdout, &csbi);
startCoords = (COORD) {
csbi.srWindow.Left,
csbi.srWindow.Top
};
DWORD nLength = csbi.dwSize.X * (csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
FillConsoleOutputCharacter (hStdout, ' ',
nLength, startCoords, &dummy);
FillConsoleOutputAttribute (hStdout,
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
nLength, startCoords, &dummy);
}
2019-05-22 07:25:22 +00:00
R_API void r_cons_w32_gotoxy(int fd, int x, int y) {
HANDLE *hConsole = (fd == 1)? &hStdout : &hStderr;
COORD coord;
coord.X = x;
coord.Y = y;
if (I->vtmode) {
r_cons_printf ("\x1b[%d;%dH", y, x);
return;
}
2016-06-29 10:33:31 +00:00
if (I->is_wine == 1) {
2019-05-22 07:25:22 +00:00
write (fd, "\x1b[0;0H", 6);
}
2019-05-22 07:25:22 +00:00
if (!*hConsole) {
*hConsole = GetStdHandle ((fd == 1)?
STD_OUTPUT_HANDLE: STD_ERROR_HANDLE);
2016-06-29 10:33:31 +00:00
}
CONSOLE_SCREEN_BUFFER_INFO info;
GetConsoleScreenBufferInfo (*hConsole, &info);
coord.X += info.srWindow.Left;
coord.Y += info.srWindow.Top;
2019-05-22 07:25:22 +00:00
SetConsoleCursorPosition (*hConsole, coord);
}
static int wrapline(const char *s, int len) {
2019-06-09 16:50:36 +00:00
int l = 0, n = 0;
2016-06-29 10:33:31 +00:00
for (; n < len; ) {
l = r_str_len_utf8char (s+n, (len-n));
n += l;
}
2019-12-08 11:49:58 +00:00
return n - ((n > len) ? l : 1);
}
// Dupe from canvas.c
static int utf8len_fixed(const char *s, int n) {
int i = 0, j = 0, fullwidths = 0;
while (s[i] && n > 0) {
if ((s[i] & 0xc0) != 0x80) {
j++;
if (r_str_char_fullwidth (s + i, n)) {
fullwidths++;
}
}
n--;
i++;
}
return j + fullwidths;
}
static int bytes_utf8len(const char *s, int n) {
int ret = 0;
while (n > 0) {
int sz = r_str_utf8_charsize (s);
ret += sz;
s += sz;
n--;
}
return ret;
}
2019-12-08 11:49:58 +00:00
static int r_cons_w32_hprint(DWORD hdl, const char *ptr, int len, bool vmode) {
2019-06-30 10:32:56 +00:00
HANDLE hConsole = GetStdHandle (hdl);
int fd = hdl == STD_OUTPUT_HANDLE ? 1 : 2;
int esc = 0;
int bg = 0, fg = 1|2|4|8;
2019-12-08 11:49:58 +00:00
const char *ptr_end, *str = ptr;
int ret = 0;
int inv = 0;
int linelen = 0;
int ll = 0;
int raw_ll = 0;
int lines, cols = r_cons_get_size (&lines);
2020-03-04 01:10:07 +00:00
if (I->is_wine == -1) {
I->is_wine = r_file_is_directory ("/proc")? 1: 0;
}
2016-06-29 10:33:31 +00:00
if (len < 0) {
len = strlen ((const char *)ptr);
2016-06-29 10:33:31 +00:00
}
ptr_end = ptr + len;
2010-06-27 22:36:47 +00:00
if (ptr && hConsole)
2016-06-29 10:33:31 +00:00
for (; *ptr && ptr < ptr_end; ptr++) {
if (ptr[0] == 0xa) {
raw_ll = (size_t)(ptr - str);
ll = utf8len_fixed (str, raw_ll);
lines--;
if (vmode && lines < 1) {
2016-06-29 10:33:31 +00:00
break;
}
if (raw_ll < 1) {
continue;
2016-06-29 10:33:31 +00:00
}
if (vmode) {
/* only chop columns if necessary */
if (ll + linelen >= cols) {
// chop line if too long
ll = (cols - linelen) - 1;
if (ll < 0) {
continue;
2016-06-29 10:33:31 +00:00
}
}
}
if (ll > 0) {
2019-08-16 04:10:00 +00:00
raw_ll = bytes_utf8len (str, ll);
2019-06-30 10:32:56 +00:00
write (fd, str, raw_ll);
linelen += ll;
}
esc = 0;
str = ptr + 1;
if (vmode) {
2016-06-29 10:33:31 +00:00
int wlen = cols - linelen;
char white[1024];
if (wlen > 0 && wlen < sizeof (white)) {
memset (white, ' ', sizeof (white));
2019-06-30 10:32:56 +00:00
write (fd, white, wlen-1);
}
}
2019-06-30 10:32:56 +00:00
write (fd, "\n\r", 2);
// reset colors for next line
SetConsoleTextAttribute (hConsole, 1 | 2 | 4 | 8);
linelen = 0;
continue;
}
if (ptr[0] == 0x1b) {
raw_ll = (size_t)(ptr - str);
ll = utf8len_fixed (str, raw_ll);
if (str[0] == '\n') {
str++;
ll--;
if (vmode) {
int wlen = cols - linelen - 1;
char white[1024];
//wlen = 5;
if (wlen > 0) {
memset (white, ' ', sizeof (white));
2019-06-30 10:32:56 +00:00
write (fd, white, wlen);
}
}
2019-06-30 10:32:56 +00:00
write (fd, "\n\r", 2);
//write (fd, "\r\n", 2);
//lines--;
linelen = 0;
}
2015-11-01 04:10:49 +00:00
if (vmode) {
if (linelen + ll >= cols) {
2015-11-01 04:10:49 +00:00
// chop line if too long
ll = (cols - linelen) - 1;
if (ll > 0) {
// fix utf8 len here
ll = wrapline ((const char*)str, cols - linelen - 1);
}
2015-11-01 04:10:49 +00:00
}
}
if (ll > 0) {
2019-08-16 04:10:00 +00:00
raw_ll = bytes_utf8len (str, ll);
2019-06-30 10:32:56 +00:00
write (fd, str, raw_ll);
linelen += ll;
}
esc = 1;
str = ptr + 1;
continue;
}
if (esc == 1) {
// \x1b[2J
if (ptr[0] != '[') {
2022-04-24 23:12:44 +00:00
R_LOG_ERROR ("Oops invalid escape char");
esc = 0;
str = ptr + 1;
continue;
}
esc = 2;
continue;
2016-06-29 10:33:31 +00:00
} else if (esc == 2) {
const char *ptr2 = NULL;
2016-06-29 10:33:31 +00:00
int x, y, i, state = 0;
for (i = 0; ptr[i] && state >= 0; i++) {
switch (state) {
case 0:
2016-06-29 10:33:31 +00:00
if (ptr[i] == ';') {
y = atoi ((const char *)ptr);
state = 1;
ptr2 = (const char *)ptr+i+1;
2016-06-29 10:33:31 +00:00
} else if (ptr[i] >='0' && ptr[i]<='9') {
// ok
2016-06-29 10:33:31 +00:00
} else {
state = -1; // END FAIL
}
break;
case 1:
if (ptr[i] == 'H') {
x = atoi (ptr2);
state = -2; // END OK
2016-06-29 10:33:31 +00:00
} else if (ptr[i] >='0' && ptr[i]<='9') {
// ok
2016-06-29 10:33:31 +00:00
} else {
state = -1; // END FAIL
}
break;
}
}
if (state == -2) {
2019-06-30 10:32:56 +00:00
r_cons_w32_gotoxy (fd, x, y);
ptr += i;
2018-11-25 00:47:11 +00:00
str = ptr; // + i-2;
continue;
}
bool bright = false;
if (ptr[0] == '0' && ptr[1] == ';' && ptr[2] == '0') {
// \x1b[0;0H
/** clear screen if gotoxy **/
if (vmode) {
// fill row here
2019-06-09 16:50:36 +00:00
__fill_tail (cols, lines);
}
2019-06-30 10:32:56 +00:00
r_cons_w32_gotoxy (fd, 0, 0);
lines = 0;
esc = 0;
ptr += 3;
str = ptr + 1;
continue;
} else if (ptr[0] == '2' && ptr[1] == 'J') {
r_cons_w32_clear ();
esc = 0;
ptr = ptr + 1;
str = ptr + 1;
continue;
} else if (ptr[0] == '0' && (ptr[1] == 'm' || ptr [1] == 'K')) {
2010-06-27 22:36:47 +00:00
SetConsoleTextAttribute (hConsole, 1|2|4|8);
fg = 1|2|4|8;
bg = 0;
inv = 0;
esc = 0;
ptr++;
str = ptr + 1;
continue;
// reset color
} else if (ptr[0] == '2' && ptr[1] == '7' && ptr[2] == 'm') {
SetConsoleTextAttribute (hConsole, bg|fg);
inv = 0;
esc = 0;
ptr = ptr + 2;
str = ptr + 1;
continue;
// invert off
} else if (ptr[0] == '7' && ptr[1] == 'm') {
SetConsoleTextAttribute (hConsole, bg|fg|COMMON_LVB_REVERSE_VIDEO);
inv = COMMON_LVB_REVERSE_VIDEO;
esc = 0;
ptr = ptr + 1;
str = ptr + 1;
continue;
// invert
} else if ((ptr[0] == '3' || (bright = ptr[0] == '9')) && (ptr[2] == 'm' || ptr[2] == ';')) {
switch (ptr[1]) {
case '0': // BLACK
fg = 0;
break;
case '1': // RED
fg = 4;
break;
case '2': // GREEN
fg = 2;
break;
case '3': // YELLOW
fg = 2|4;
break;
case '4': // BLUE
fg = 1;
break;
case '5': // MAGENTA
fg = 1|4;
break;
case '6': // CYAN
fg = 1|2;
break;
case '7': // WHITE
fg = 1|2|4;
break;
2019-05-18 09:48:33 +00:00
case '8': // ???
case '9':
break;
}
if (bright) {
fg |= 8;
}
SetConsoleTextAttribute (hConsole, bg|fg|inv);
esc = 0;
ptr = ptr + 2;
str = ptr + 1;
continue;
} else if ((ptr[0] == '4' && ptr[2] == 'm')
|| (bright = ptr[0] == '1' && ptr[1] == '0' && ptr[3] == 'm')) {
/* background color */
ut8 col = bright ? ptr[2] : ptr[1];
switch (col) {
case '0': // BLACK
bg = 0x0;
break;
case '1': // RED
bg = 0x40;
break;
case '2': // GREEN
bg = 0x20;
break;
case '3': // YELLOW
bg = 0x20|0x40;
break;
case '4': // BLUE
bg = 0x10;
break;
case '5': // MAGENTA
bg = 0x10|0x40;
break;
case '6': // CYAN
bg = 0x10|0x20;
break;
case '7': // WHITE
bg = 0x10|0x20|0x40;
break;
case '8': // ???
case '9':
break;
}
if (bright) {
bg |= 0x80;
}
SetConsoleTextAttribute (hConsole, bg|fg|inv);
esc = 0;
ptr = ptr + (bright ? 3 : 2);
2019-05-18 09:48:33 +00:00
str = ptr + 1;
continue;
}
}
ret++;
}
if (vmode) {
/* fill partial line */
2019-06-09 16:50:36 +00:00
int wlen = cols - linelen - 1;
2016-06-29 10:33:31 +00:00
if (wlen > 0) {
2017-04-28 21:01:37 +00:00
char white[1024];
memset (white, ' ', sizeof (white));
2019-06-30 10:32:56 +00:00
write (fd, white, wlen);
}
/* fill tail */
2019-06-09 16:50:36 +00:00
__fill_tail (cols, lines);
2016-06-29 10:33:31 +00:00
} else {
2017-04-28 21:01:37 +00:00
int ll = (size_t)(ptr - str);
2016-06-29 10:33:31 +00:00
if (ll > 0) {
2019-06-30 10:32:56 +00:00
write (fd, str, ll);
2015-11-01 04:10:49 +00:00
linelen += ll;
}
}
return ret;
}
2019-12-08 11:49:58 +00:00
R_API int r_cons_w32_print(const char *ptr, int len, bool vmode) {
2019-06-30 10:32:56 +00:00
return r_cons_w32_hprint (STD_OUTPUT_HANDLE, ptr, len, vmode);
}
2019-06-30 12:02:55 +00:00
R_API int r_cons_win_vhprintf(DWORD hdl, bool vmode, const char *fmt, va_list ap) {
2019-06-30 10:32:56 +00:00
va_list ap2;
int ret = -1;
FILE *con = hdl == STD_OUTPUT_HANDLE ? stdout : stderr;
if (!strchr (fmt, '%')) {
size_t len = strlen (fmt);
if (I->vtmode) {
2019-06-30 10:32:56 +00:00
return fwrite (fmt, 1, len, con);
}
2019-06-30 10:32:56 +00:00
return r_cons_w32_hprint (hdl, fmt, len, vmode);
}
va_copy (ap2, ap);
int num_chars = vsnprintf (NULL, 0, fmt, ap2);
num_chars++;
char *buf = calloc (1, num_chars);
if (buf) {
(void)vsnprintf (buf, num_chars, fmt, ap);
if (I->vtmode) {
2019-06-30 10:32:56 +00:00
ret = fwrite (buf, 1, num_chars - 1, con);
} else {
2019-06-30 10:32:56 +00:00
ret = r_cons_w32_hprint (hdl, buf, num_chars - 1, vmode);
}
free (buf);
}
va_end (ap2);
2019-06-30 10:32:56 +00:00
return ret;
}
R_API int r_cons_win_printf(bool vmode, const char *fmt, ...) {
va_list ap;
int ret;
r_return_val_if_fail (fmt, -1);
va_start (ap, fmt);
2019-06-30 12:02:55 +00:00
ret = r_cons_win_vhprintf (STD_OUTPUT_HANDLE, vmode, fmt, ap);
2019-06-30 10:32:56 +00:00
va_end (ap);
return ret;
}
R_API int r_cons_win_eprintf(bool vmode, const char *fmt, ...) {
va_list ap;
int ret;
r_return_val_if_fail (fmt, -1);
va_start (ap, fmt);
2019-06-30 12:02:55 +00:00
ret = r_cons_win_vhprintf (STD_ERROR_HANDLE, vmode, fmt, ap);
va_end (ap);
return ret;
}
#endif