radare2/libr/cons/cons.c
pancake 0f2503f781 * Sync local random changes with public repo
* Forwport of the 'Y' yesno issue of r1
* R_APIize r_util a bit more
* Added r_str_ansi_* helper functions
2009-05-20 12:41:04 +00:00

514 lines
10 KiB
C

/* radare - LGPL - Copyright 2008-2009 pancake<nopcode.org> */
#include <r_cons.h>
#include "r_types.h"
#include "r_util.h"
#if HAVE_DIETLINE
#include "r_line.h"
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#if __UNIX__
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/socket.h>
#endif
#if __WINDOWS__
#include <windows.h>
#endif
#define MOAR_VALUE 4096*4
// WTF //
char *strsub (char *string, char *pat, char *rep, int global);
int r_cons_stdout_fd = 1;
FILE *r_cons_stdin_fd = NULL; // TODO use int fd here too!
static int r_cons_buffer_sz = 0;
static int r_cons_buffer_len = 0;
static char *r_cons_buffer = NULL;
static char *r_cons_lastline = NULL;
char *r_cons_filterline = NULL;
char *r_cons_teefile = NULL;
int r_cons_is_html = 0;
int r_cons_interactive = 1;
int r_cons_lines = 0;
int r_cons_noflush = 0;
static int grepline = -1, greptoken = -1, grepcounter = 0, grepneg = 0;
static char *grepstr = NULL;
static char grepstrings[10][64] = { "", };
static int grepstrings_n = 0;
int r_cons_breaked = 0;
static void (*r_cons_break_cb)(void *user);
static void *r_cons_break_user;
static void break_signal(int sig)
{
r_cons_breaked = 1;
if (r_cons_break_cb)
r_cons_break_cb(r_cons_break_user);
}
R_API void r_cons_break(void (*cb)(void *u), void *user)
{
r_cons_breaked = 0;
r_cons_break_user = user;
r_cons_break_cb = cb;
#if __UNIX__
signal(SIGINT, break_signal);
#endif
}
R_API void r_cons_break_end()
{
r_cons_breaked = 0;
#if __UNIX__
signal(SIGINT, SIG_IGN);
#endif
}
R_API int r_cons_init()
{
r_cons_stdin_fd = stdin;
#if HAVE_DIETLINE
r_line_init();
#endif
//r_cons_palette_init(NULL);
return 0;
}
static void palloc(int moar)
{
if (r_cons_buffer == NULL) {
r_cons_buffer_sz = moar+MOAR_VALUE;
r_cons_buffer = (char *)malloc(r_cons_buffer_sz);
r_cons_buffer[0]='\0';
} else
if (moar + r_cons_buffer_len > r_cons_buffer_sz) {
r_cons_buffer_sz += moar+MOAR_VALUE;
r_cons_buffer = (char *)realloc(r_cons_buffer, r_cons_buffer_sz);
}
}
R_API int r_cons_eof()
{
return feof(r_cons_stdin_fd);
}
/* XXX unused ? */
#if 0
static void r_cons_print_real(const char *buf)
{
#if __WINDOWS__
if (r_cons_stdout_fd == 1)
r_cons_w32_print(buf);
else
#endif
if (r_cons_is_html)
r_cons_html_print(buf);
else write(r_cons_stdout_fd, buf, r_cons_buffer_len);
}
#endif
R_API void r_cons_gotoxy(int x, int y)
{
#if __WINDOWS__
static HANDLE hStdout = NULL;
COORD coord;
coord.X = x;
coord.Y = y;
if(!hStdout)
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hStdout,coord);
#else
r_cons_strcat("\x1b[0;0H");
#endif
}
R_API void r_cons_clear00()
{
r_cons_clear();
r_cons_gotoxy(0, 0);
}
R_API void r_cons_clear()
{
#if __WINDOWS__
static HANDLE hStdout = NULL;
static CONSOLE_SCREEN_BUFFER_INFO csbi;
const COORD startCoords = {0,0};
DWORD dummy;
if(!hStdout) {
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(hStdout,&csbi);
}
FillConsoleOutputCharacter(hStdout, ' ', csbi.dwSize.X * csbi.dwSize.Y, startCoords, &dummy);
r_cons_gotoxy(0,0);
#else
r_cons_strcat("\x1b[2J");
#endif
r_cons_flush();
r_cons_lines = 0;
}
R_API void r_cons_reset()
{
if (r_cons_buffer)
r_cons_buffer[0] = '\0';
r_cons_buffer_len = 0;
r_cons_lines = 0;
r_cons_lastline = r_cons_buffer;
grepstrings_n = 0; // XXX
grepline = -1;
grepstr = NULL;
greptoken = -1;
}
R_API const char *r_cons_get_buffer()
{
return r_cons_buffer;
}
R_API void r_cons_grep(const char *str)
{
char *optr, *tptr;
char *ptr, *ptr2, *ptr3;
grepcounter=0;
/* set grep string */
if (str != NULL && *str) {
if (*str == '!') {
grepneg = 1;
str = str + 1;
} else grepneg = 0;
if (*str == '?') {
grepcounter = 1;
str = str + 1;
}
ptr = alloca(strlen(str)+2);
strcpy(ptr, str);
ptr3 = strchr(ptr, '[');
ptr2 = strchr(ptr, '#');
if (ptr3) {
ptr3[0]='\0';
greptoken = atoi(ptr3+1);
if (greptoken<0)
greptoken--;
}
if (ptr2) {
ptr2[0]='\0';
grepline = atoi(ptr2+1);
}
grepstrings_n = 0;
if (*ptr) {
free(grepstr);
grepstr = (char *)strdup(ptr);
/* set the rest of words to grep */
grepstrings_n = 0;
// TODO: refactor this ugly loop
optr = grepstr;
tptr = strchr(optr, '!');
while(tptr) {
tptr[0] = '\0';
// TODO: check if keyword > 64
strncpy(grepstrings[grepstrings_n], optr, 63);
grepstrings_n++;
optr = tptr+1;
tptr = strchr(optr, '!');
}
strncpy(grepstrings[grepstrings_n], optr, 63);
grepstrings_n++;
ptr = optr;
}
} else {
greptoken = -1;
grepline = -1;
grepstr = NULL;
grepstrings_n = 0;
}
}
R_API void r_cons_flush()
{
char *tee = r_cons_teefile;
if (r_cons_noflush)
return;
if (r_cons_interactive) {
if (r_cons_buffer_len > CONS_MAX_USER) {
if (r_cons_yesno('n', "Do you want to print %d bytes? (y/N)", r_cons_buffer_len)== 0) {
r_cons_reset();
return;
}
}
}
if (tee&&tee[0]) {
FILE *d = fopen(tee, "a+");
if (d != NULL) {
fwrite(r_cons_buffer, strlen(r_cons_buffer), 1, d);
fclose(d);
}
// TODO: make this 'write' portable
} else write(1, r_cons_buffer, r_cons_buffer_len);
r_cons_reset();
}
R_API void r_cons_printf(const char *format, ...)
{
int len;
char buf[CONS_BUFSZ];
va_list ap;
if (strchr(format,'%')==NULL) {
r_cons_strcat(format);
return;
}
va_start(ap, format);
len = vsnprintf(buf, CONS_BUFSZ-1, format, ap);
if (len>0)
r_cons_memcat(buf, len);
va_end(ap);
}
/* TODO: use const char * instead ..strdup at the beggining? */
R_API int r_cons_grepbuf(char *buf, int len)
{
int donotline = 0;
int i, j, hit = 0;
char delims[6][2] = {"|", "/", "\\", ",", ";", "\t"};
char *n = memchr(buf, '\n', len);
if (grepstrings_n==0) {
if (n) r_cons_lines++;
return len;
}
if (r_cons_lastline==NULL)
r_cons_lastline = r_cons_buffer;
if (!n) return len;
for(i=0;i<grepstrings_n;i++) {
grepstr = grepstrings[i];
if ( (!grepneg && strstr(buf, grepstr))
|| (grepneg && !strstr(buf, grepstr))) {
hit = 1;
break;
}
}
if (hit) {
if (grepline != -1) {
if (grepline==r_cons_lines) {
r_cons_lastline = buf+len;
//r_cons_lines++;
} else {
donotline = 1;
r_cons_lines++;
}
}
} else donotline = 1;
if (donotline) {
r_cons_buffer_len -= strlen(r_cons_lastline)-len;
r_cons_lastline[0]='\0';
len = 0;
} else {
if (greptoken != -1) {
//ptr = alloca(strlen(r_cons_lastline));
char *tok = NULL;
char *ptr = alloca(1024); // XXX
strcpy(ptr, r_cons_lastline);
for (i=0; i<len; i++) for (j=0;j<6;j++)
if (ptr[i] == delims[j][0])
ptr[i] = ' ';
tok = ptr;
for (i=0;tok != NULL && i<=greptoken;i++) {
if (i==0) tok = (char *)strtok(ptr, " ");
else tok = (char *)strtok(NULL, " ");
}
if (tok) {
// XXX remove strlen here!
r_cons_buffer_len -= strlen(r_cons_lastline)-len;
len = strlen(tok);
memcpy(r_cons_lastline, tok, len);
if (r_cons_lastline[len-1]!='\n')
memcpy(r_cons_lastline+len, "\n", 2);
len++;
r_cons_lastline +=len;
}
} else r_cons_lastline = buf+len;
r_cons_lines++;
}
return len;
}
/* final entrypoint for adding stuff in the buffer screen */
R_API void r_cons_memcat(const char *str, int len)
{
palloc(len);
memcpy(r_cons_buffer+r_cons_buffer_len, str, len+1); // XXX +1??
r_cons_buffer_len += r_cons_grepbuf(r_cons_buffer+r_cons_buffer_len, len);
}
R_API void r_cons_strcat(const char *str)
{
int len = strlen(str);
if (len>0)
r_cons_memcat(str, len);
}
R_API void r_cons_newline()
{
if (r_cons_is_html)
r_cons_strcat("<br />\n");
else r_cons_strcat("\n");
}
R_API int r_cons_get_columns()
{
int columns_i = r_cons_get_real_columns();
char buf[64];
if (columns_i<2)
columns_i = 78;
sprintf(buf, "%d", columns_i);
r_sys_setenv("COLUMNS", buf, 0);
return columns_i;
}
R_API int r_cons_get_real_columns()
{
#if __UNIX__
struct winsize win;
if (ioctl(1, TIOCGWINSZ, &win)) {
/* default values */
win.ws_col = 80;
win.ws_row = 23;
}
#ifdef RADARE_CORE
config.width = win.ws_col;
config.height = win.ws_row;
#endif
return win.ws_col;
#else
return 80;
#endif
}
R_API int r_cons_yesno(int def, const char *fmt, ...)
{
va_list ap;
int key = def;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fflush(stderr);
r_cons_set_raw(1);
read(0, &key, 1); write(2, "\n", 1);
if (key == 'Y') key = 'y';
r_cons_set_raw(0);
if (key=='\n'||key=='\r')
key = def;
else key = 'y';
return key=='y';
}
/**
*
* void r_cons_set_raw( [0,1] )
*
* Change canonicality of the terminal
*
* For optimization reasons, there's no initialization flag, so you need to
* ensure that the make the first call to r_cons_set_raw() with '1' and
* the next calls ^=1, so: 1, 0, 1, 0, 1, ...
*
* If you doesn't use this order you'll probably loss your terminal properties.
*
*/
#if __UNIX__
static struct termios tio_old, tio_new;
#endif
static int termios_init = 0;
R_API void r_cons_set_raw(int b)
{
#if __UNIX__
if (b) {
if (termios_init == 0) {
tcgetattr(0, &tio_old);
memcpy (&tio_new,&tio_old,sizeof(struct termios));
tio_new.c_iflag &= ~(BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
tio_new.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
tio_new.c_cflag &= ~(CSIZE|PARENB);
tio_new.c_cflag |= CS8;
tio_new.c_cc[VMIN]=1; // Solaris stuff hehe
termios_init = 1;
}
tcsetattr(0, TCSANOW, &tio_new);
} else
tcsetattr(0, TCSANOW, &tio_old);
#else
/* TODO : W32 */
#endif
fflush(stdout);
}
#if 1
// XXX: major refactorize : get_arrow
//int r_cons_0x1b_to_hjkl(int ch)
R_API int r_cons_get_arrow(int ch)
{
#if 0
printf("ARROW(0x%x)\n", ch);
fflush(stdout);
r_sys_sleep(3);
#endif
if (ch==0x1b) {
ch = r_cons_readchar();
if (ch==0x5b) {
// TODO: must also work in interactive visual write ascii mode
ch = r_cons_readchar();
switch(ch) {
case 0x35: ch='K'; break; // re.pag
case 0x36: ch='J'; break; // av.pag
case 0x41: ch='k'; break; // up
case 0x42: ch='j'; break; // down
case 0x43: ch='l'; break; // right
case 0x44: ch='h'; break; // left
case 0x3b:
break;
default:
ch = 0;
}
}
}
return ch;
}
#endif