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