Rizin
unix-like reverse engineering framework and cli tools
output.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2009-2019 pancake <pancake@nopcode.org>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_cons.h>
5 #include <rz_util/rz_assert.h>
6 #define I rz_cons_singleton()
7 
8 #if __WINDOWS__
9 #include <rz_windows.h>
10 static void __fill_tail(int cols, int lines) {
11  lines++;
12  if (lines > 0) {
13  char white[1024];
14  cols = RZ_MIN(cols, sizeof(white));
15  memset(white, ' ', cols - 1);
16  lines--;
17  white[cols] = '\n';
18  while (lines-- > 0) {
19  rz_xwrite(1, white, cols);
20  }
21  }
22 }
23 
24 RZ_API void rz_cons_w32_clear(void) {
25  static HANDLE hStdout = NULL;
26  static CONSOLE_SCREEN_BUFFER_INFO csbi;
27  COORD startCoords;
28  DWORD dummy;
29  if (I->vtmode != RZ_VIRT_TERM_MODE_DISABLE) {
31  return;
32  }
33  if (I->is_wine == 1) {
34  rz_xwrite(1, "\033[0;0H\033[0m\033[2J", 6 + 4 + 4);
35  }
36  if (!hStdout) {
37  hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
38  }
39  GetConsoleScreenBufferInfo(hStdout, &csbi);
40  startCoords = (COORD){
41  csbi.srWindow.Left,
42  csbi.srWindow.Top
43  };
44  DWORD nLength = csbi.dwSize.X * (csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
45  FillConsoleOutputCharacter(hStdout, ' ',
46  nLength, startCoords, &dummy);
47  FillConsoleOutputAttribute(hStdout,
48  FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
49  nLength, startCoords, &dummy);
50 }
51 
52 RZ_API void rz_cons_w32_gotoxy(int fd, int x, int y) {
53  static HANDLE hStdout = NULL;
54  static HANDLE hStderr = NULL;
55  HANDLE *hConsole = fd == 1 ? &hStdout : &hStderr;
56  COORD coord;
57  coord.X = x;
58  coord.Y = y;
59  if (I->vtmode != RZ_VIRT_TERM_MODE_DISABLE) {
60  rz_cons_printf("\x1b[%d;%dH", y, x);
61  return;
62  }
63  if (I->is_wine == 1) {
64  rz_xwrite(fd, "\x1b[0;0H", 6);
65  }
66  if (!*hConsole) {
67  *hConsole = GetStdHandle(fd == 1 ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
68  }
69  CONSOLE_SCREEN_BUFFER_INFO info;
70  GetConsoleScreenBufferInfo(*hConsole, &info);
71  coord.X += info.srWindow.Left;
72  coord.Y += info.srWindow.Top;
73  SetConsoleCursorPosition(*hConsole, coord);
74 }
75 
76 static int wrapline(const char *s, int len) {
77  int l = 0, n = 0;
78  for (; n < len;) {
79  l = rz_str_len_utf8char(s + n, (len - n));
80  n += l;
81  }
82  return n - ((n > len) ? l : 1);
83 }
84 
85 // Dupe from canvas.c
86 static int utf8len_fixed(const char *s, int n) {
87  int i = 0, j = 0, fullwidths = 0;
88  while (s[i] && n > 0) {
89  if ((s[i] & 0xc0) != 0x80) {
90  j++;
91  if (rz_str_char_fullwidth(s + i, n)) {
92  fullwidths++;
93  }
94  }
95  n--;
96  i++;
97  }
98  return j + fullwidths;
99 }
100 
101 static int bytes_utf8len(const char *s, int n) {
102  int ret = 0;
103  while (n > 0) {
104  int sz = rz_str_utf8_charsize(s);
105  ret += sz;
106  s += sz;
107  n--;
108  }
109  return ret;
110 }
111 
112 static int rz_cons_w32_hprint(DWORD hdl, const char *ptr, int len, bool vmode) {
113  HANDLE hConsole = GetStdHandle(hdl);
114  int fd = hdl == STD_OUTPUT_HANDLE ? 1 : 2;
115  int esc = 0;
116  int bg = 0, fg = 1 | 2 | 4 | 8;
117  const char *ptr_end, *str = ptr;
118  int ret = 0;
119  int inv = 0;
120  int linelen = 0;
121  int ll = 0;
122  int raw_ll = 0;
123  int lines, cols = rz_cons_get_size(&lines);
124  if (I->is_wine == -1) {
125  I->is_wine = rz_file_is_directory("/proc") ? 1 : 0;
126  }
127  if (len < 0) {
128  len = strlen((const char *)ptr);
129  }
130  ptr_end = ptr + len;
131  if (ptr && hConsole)
132  for (; *ptr && ptr < ptr_end; ptr++) {
133  if (ptr[0] == 0xa) {
134  raw_ll = (size_t)(ptr - str);
135  ll = utf8len_fixed(str, raw_ll);
136  lines--;
137  if (vmode && lines < 1) {
138  break;
139  }
140  if (raw_ll < 1) {
141  continue;
142  }
143  if (vmode) {
144  /* only chop columns if necessary */
145  if (ll + linelen >= cols) {
146  // chop line if too long
147  ll = (cols - linelen) - 1;
148  if (ll < 0) {
149  continue;
150  }
151  }
152  }
153  if (ll > 0) {
154  raw_ll = bytes_utf8len(str, ll);
155  rz_xwrite(fd, str, raw_ll);
156  linelen += ll;
157  }
158  esc = 0;
159  str = ptr + 1;
160  if (vmode) {
161  int wlen = cols - linelen;
162  char white[1024];
163  if (wlen > 0 && wlen < sizeof(white)) {
164  memset(white, ' ', sizeof(white));
165  rz_xwrite(fd, white, wlen - 1);
166  }
167  }
168  rz_xwrite(fd, "\n\r", 2);
169  // reset colors for next line
170  SetConsoleTextAttribute(hConsole, 1 | 2 | 4 | 8);
171  linelen = 0;
172  continue;
173  }
174  if (ptr[0] == 0x1b) {
175  raw_ll = (size_t)(ptr - str);
176  ll = utf8len_fixed(str, raw_ll);
177  if (str[0] == '\n') {
178  str++;
179  ll--;
180  if (vmode) {
181  int wlen = cols - linelen - 1;
182  char white[1024];
183  // wlen = 5;
184  if (wlen > 0) {
185  memset(white, ' ', sizeof(white));
186  rz_xwrite(fd, white, wlen);
187  }
188  }
189  rz_xwrite(fd, "\n\r", 2);
190  // write (fd, "\r\n", 2);
191  // lines--;
192  linelen = 0;
193  }
194  if (vmode) {
195  if (linelen + ll >= cols) {
196  // chop line if too long
197  ll = (cols - linelen) - 1;
198  if (ll > 0) {
199  // fix utf8 len here
200  ll = wrapline((const char *)str, cols - linelen - 1);
201  }
202  }
203  }
204  if (ll > 0) {
205  raw_ll = bytes_utf8len(str, ll);
206  rz_xwrite(fd, str, raw_ll);
207  linelen += ll;
208  }
209  esc = 1;
210  str = ptr + 1;
211  continue;
212  }
213  if (esc == 1) {
214  // \x1b[2J
215  if (ptr[0] != '[') {
216  eprintf("Oops invalid escape char\n");
217  esc = 0;
218  str = ptr + 1;
219  continue;
220  }
221  esc = 2;
222  continue;
223  } else if (esc == 2) {
224  const char *ptr2 = NULL;
225  int x, y, i, state = 0;
226  for (i = 0; ptr[i] && state >= 0; i++) {
227  switch (state) {
228  case 0:
229  if (ptr[i] == ';') {
230  y = atoi((const char *)ptr);
231  state = 1;
232  ptr2 = (const char *)ptr + i + 1;
233  } else if (ptr[i] >= '0' && ptr[i] <= '9') {
234  // ok
235  } else {
236  state = -1; // END FAIL
237  }
238  break;
239  case 1:
240  if (ptr[i] == 'H') {
241  x = atoi(ptr2);
242  state = -2; // END OK
243  } else if (ptr[i] >= '0' && ptr[i] <= '9') {
244  // ok
245  } else {
246  state = -1; // END FAIL
247  }
248  break;
249  }
250  }
251  if (state == -2) {
252  rz_cons_w32_gotoxy(fd, x, y);
253  ptr += i;
254  str = ptr; // + i-2;
255  continue;
256  }
257  bool bright = false;
258  if (ptr[0] == '0' && ptr[1] == ';' && ptr[2] == '0') {
259  // \x1b[0;0H
261  if (vmode) {
262  // fill row here
263  __fill_tail(cols, lines);
264  }
265  rz_cons_w32_gotoxy(fd, 0, 0);
266  lines = 0;
267  esc = 0;
268  ptr += 3;
269  str = ptr + 1;
270  continue;
271  } else if (ptr[0] == '2' && ptr[1] == 'J') {
272  rz_cons_w32_clear();
273  esc = 0;
274  ptr = ptr + 1;
275  str = ptr + 1;
276  continue;
277  } else if (ptr[0] == '0' && (ptr[1] == 'm' || ptr[1] == 'K')) {
278  SetConsoleTextAttribute(hConsole, 1 | 2 | 4 | 8);
279  fg = 1 | 2 | 4 | 8;
280  bg = 0;
281  inv = 0;
282  esc = 0;
283  ptr++;
284  str = ptr + 1;
285  continue;
286  // reset color
287  } else if (ptr[0] == '2' && ptr[1] == '7' && ptr[2] == 'm') {
288  SetConsoleTextAttribute(hConsole, bg | fg);
289  inv = 0;
290  esc = 0;
291  ptr = ptr + 2;
292  str = ptr + 1;
293  continue;
294  // invert off
295  } else if (ptr[0] == '7' && ptr[1] == 'm') {
296  SetConsoleTextAttribute(hConsole, bg | fg | COMMON_LVB_REVERSE_VIDEO);
298  esc = 0;
299  ptr = ptr + 1;
300  str = ptr + 1;
301  continue;
302  // invert
303  } else if ((ptr[0] == '3' || (bright = ptr[0] == '9')) && (ptr[2] == 'm' || ptr[2] == ';')) {
304  switch (ptr[1]) {
305  case '0': // BLACK
306  fg = 0;
307  break;
308  case '1': // RED
309  fg = 4;
310  break;
311  case '2': // GREEN
312  fg = 2;
313  break;
314  case '3': // YELLOW
315  fg = 2 | 4;
316  break;
317  case '4': // BLUE
318  fg = 1;
319  break;
320  case '5': // MAGENTA
321  fg = 1 | 4;
322  break;
323  case '6': // CYAN
324  fg = 1 | 2;
325  break;
326  case '7': // WHITE
327  fg = 1 | 2 | 4;
328  break;
329  case '8': // ???
330  case '9':
331  break;
332  }
333  if (bright) {
334  fg |= 8;
335  }
336  SetConsoleTextAttribute(hConsole, bg | fg | inv);
337  esc = 0;
338  ptr = ptr + 2;
339  str = ptr + 1;
340  continue;
341  } else if ((ptr[0] == '4' && ptr[2] == 'm') || (bright = ptr[0] == '1' && ptr[1] == '0' && ptr[3] == 'm')) {
342  /* background color */
343  ut8 col = bright ? ptr[2] : ptr[1];
344  switch (col) {
345  case '0': // BLACK
346  bg = 0x0;
347  break;
348  case '1': // RED
349  bg = 0x40;
350  break;
351  case '2': // GREEN
352  bg = 0x20;
353  break;
354  case '3': // YELLOW
355  bg = 0x20 | 0x40;
356  break;
357  case '4': // BLUE
358  bg = 0x10;
359  break;
360  case '5': // MAGENTA
361  bg = 0x10 | 0x40;
362  break;
363  case '6': // CYAN
364  bg = 0x10 | 0x20;
365  break;
366  case '7': // WHITE
367  bg = 0x10 | 0x20 | 0x40;
368  break;
369  case '8': // ???
370  case '9':
371  break;
372  }
373  if (bright) {
374  bg |= 0x80;
375  }
376  SetConsoleTextAttribute(hConsole, bg | fg | inv);
377  esc = 0;
378  ptr = ptr + (bright ? 3 : 2);
379  str = ptr + 1;
380  continue;
381  }
382  }
383  ret++;
384  }
385  if (vmode) {
386  /* fill partial line */
387  int wlen = cols - linelen - 1;
388  if (wlen > 0) {
389  char white[1024];
390  memset(white, ' ', sizeof(white));
391  rz_xwrite(fd, white, wlen);
392  }
393  /* fill tail */
394  __fill_tail(cols, lines);
395  } else {
396  int ll = (size_t)(ptr - str);
397  if (ll > 0) {
398  rz_xwrite(fd, str, ll);
399  linelen += ll;
400  }
401  }
402  return ret;
403 }
404 
405 RZ_API int rz_cons_w32_print(const char *ptr, int len, bool vmode) {
406  return rz_cons_w32_hprint(STD_OUTPUT_HANDLE, ptr, len, vmode);
407 }
408 
409 RZ_API int rz_cons_win_vhprintf(DWORD hdl, bool vmode, const char *fmt, va_list ap) {
410  va_list ap2;
411  int ret = -1;
412  FILE *con = hdl == STD_OUTPUT_HANDLE ? stdout : stderr;
413  if (!strchr(fmt, '%')) {
414  size_t len = strlen(fmt);
415  if (I->vtmode != RZ_VIRT_TERM_MODE_DISABLE) {
416  return fwrite(fmt, 1, len, con);
417  }
418  return rz_cons_w32_hprint(hdl, fmt, len, vmode);
419  }
420  va_copy(ap2, ap);
421  int num_chars = vsnprintf(NULL, 0, fmt, ap2);
422  num_chars++;
423  char *buf = calloc(1, num_chars);
424  if (buf) {
425  (void)vsnprintf(buf, num_chars, fmt, ap);
426  if (I->vtmode != RZ_VIRT_TERM_MODE_DISABLE) {
427  ret = fwrite(buf, 1, num_chars - 1, con);
428  } else {
429  ret = rz_cons_w32_hprint(hdl, buf, num_chars - 1, vmode);
430  }
431  free(buf);
432  }
433  va_end(ap2);
434  return ret;
435 }
436 
437 RZ_API int rz_cons_win_printf(bool vmode, const char *fmt, ...) {
438  va_list ap;
439  int ret;
440  rz_return_val_if_fail(fmt, -1);
441 
442  va_start(ap, fmt);
443  ret = rz_cons_win_vhprintf(STD_OUTPUT_HANDLE, vmode, fmt, ap);
444  va_end(ap);
445  return ret;
446 }
447 
448 RZ_API int rz_cons_win_eprintf(bool vmode, const char *fmt, ...) {
449  va_list ap;
450  int ret;
451  rz_return_val_if_fail(fmt, -1);
452 
453  va_start(ap, fmt);
454  ret = rz_cons_win_vhprintf(STD_ERROR_HANDLE, vmode, fmt, ap);
455  va_end(ap);
456  return ret;
457 }
458 #endif
size_t len
Definition: 6502dis.c:15
lzma_index ** i
Definition: index.h:629
RzBinInfo * info(RzBinFile *bf)
Definition: bin_ne.c:86
static RzBinSourceLineInfo * lines(RzBinFile *bf)
Definition: bin_symbols.c:427
RZ_API int rz_cons_get_size(int *rows)
Definition: cons.c:1446
RZ_API void rz_cons_strcat(const char *str)
Definition: cons.c:1263
RZ_API int rz_cons_printf(const char *format,...)
Definition: cons.c:1202
#define RZ_API
#define NULL
Definition: cris-opc.c:27
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void * buf
Definition: ioapi.h:138
vsnprintf
Definition: kernel.h:366
uint8_t ut8
Definition: lh5801.h:11
return memset(p, 0, total)
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
int x
Definition: mipsasm.c:20
int n
Definition: mipsasm.c:19
string FILE
Definition: benchmark.py:21
#define I
Definition: output.c:6
#define eprintf(x, y...)
Definition: rlcc.c:7
static RzSocket * s
Definition: rtr.c:28
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
@ RZ_VIRT_TERM_MODE_DISABLE
Windows only: Use console c api for everything (Windows <= 8)
Definition: rz_cons.h:449
#define RZ_CONS_CLEAR_SCREEN
Definition: rz_cons.h:594
#define Color_RESET
Definition: rz_cons.h:617
RZ_API bool rz_file_is_directory(const char *str)
Definition: file.c:167
RZ_API bool rz_str_char_fullwidth(const char *s, size_t left)
Definition: str.c:2277
RZ_API size_t rz_str_len_utf8char(const char *s, int left)
Definition: str.c:2697
RZ_API size_t rz_str_utf8_charsize(const char *str)
Definition: str.c:2298
#define rz_xwrite(fd, buf, count)
Definition: rz_types.h:642
#define RZ_MIN(x, y)
int size_t
Definition: sftypes.h:40
Definition: dis.h:43
#define COMMON_LVB_REVERSE_VIDEO
Definition: tty.c:34
DWORD * HANDLE
DWORD
static const z80_opcode fd[]
Definition: z80_tab.h:997