radare2/libr/cons/grep.c
David Martínez Moreno cedef51ce4 Fix a round of typos and incorrect man macros.
The macro Em. was present in all the manpages and it's incorrect, plus
 there's some typos here and there, some of them spotted by lintian.
2013-12-31 23:52:46 -08:00

351 lines
8.1 KiB
C

/* radare - LGPL - Copyright 2009-2013 - pancake, nibble */
#include <r_cons.h>
#include <r_util.h>
R_API void r_cons_grep_help() {
eprintf (
"Usage: [command]~[modifier][word,word][[column][:line]\n"
" modifiers\n"
" & all words must match to grep the line\n"
" ^ words must be placed at the beginning of line\n"
" ! negate grep\n"
" ? count number of matching lines\n"
" examples:\n"
" i~:0 # show fist line o 'i' output\n"
" pd~mov # disasm and grep for mov\n"
" pi~[0] # show only opcode\n"
);
}
R_API void r_cons_grep(const char *str) {
int wlen, len;
RCons *cons;
char buf[4096];
char *ptr, *optr, *ptr2, *ptr3;
if (!str || !*str)
return;
cons = r_cons_singleton ();
cons->grep.str = NULL;
cons->grep.neg = 0;
cons->grep.amp = 0;
cons->grep.end = 0;
cons->grep.begin = 0;
cons->grep.nstrings = 0;
cons->grep.tokenfrom = 0;
cons->grep.tokento = ST32_MAX;
cons->grep.line = -1;
cons->grep.counter = cons->grep.neg = 0;
while (*str) {
switch (*str) {
case '&': str++; cons->grep.amp = 1; break;
case '^': str++; cons->grep.begin = 1; break;
case '!': str++; cons->grep.neg = 1; break;
case '?': str++; cons->grep.counter = 1;
if (*str=='?') {
r_cons_grep_help ();
return;
}
break;
default: goto while_end;
}
} while_end:
len = strlen (str)-1;
if (len>0 && str[len] == '?') {
cons->grep.counter = 1;
strncpy (buf, str, R_MIN (len, sizeof (buf)-1));
buf[len]=0;
len--;
} else strncpy (buf, str, sizeof (buf)-1);
if (len>1 && buf[len]=='$' && buf[len-1]!='\\') {
cons->grep.end = 1;
buf[len] = 0;
}
ptr = buf;
ptr3 = strchr (ptr, '['); // column number
if (ptr3) {
ptr3[0] = '\0';
cons->grep.tokenfrom = r_num_get (cons->num, ptr3+1);
ptr3 = strchr (ptr3+1, '-');
if (ptr3) {
cons->grep.tokento = r_num_get (cons->num, ptr3+1);
if (cons->grep.tokento == 0)
cons->grep.tokento = ST32_MAX;
} else cons->grep.tokento = cons->grep.tokenfrom;
if (cons->grep.tokenfrom<0)
cons->grep.tokenfrom = 0;
if (cons->grep.tokento<0)
cons->grep.tokento = ST32_MAX;
}
ptr2 = strchr (ptr, ':'); // line number
if (ptr2) {
*ptr2 = '\0';
cons->grep.line = r_num_get (cons->num, ptr2+1);
if (cons->grep.line<0)
cons->grep.line = -1;
}
free (cons->grep.str);
if (*ptr) {
cons->grep.str = (char *)strdup (ptr);
do {
optr = ptr;
ptr = strchr (ptr, ','); // grep keywords
if (ptr) *ptr++ = '\0';
wlen = strlen (optr);
if (wlen==0) continue;
if (wlen>=R_CONS_GREP_WORD_SIZE-1) {
eprintf ("grep string too long\n");
continue;
}
strncpy (cons->grep.strings[cons->grep.nstrings],
optr, R_CONS_GREP_WORD_SIZE-1);
cons->grep.nstrings++;
if (cons->grep.nstrings>R_CONS_GREP_WORDS-1) {
eprintf ("too many grep strings\n");
break;
}
} while (ptr);
} else {
cons->grep.str = strdup (ptr);
cons->grep.nstrings++;
cons->grep.strings[0][0] = 0;
}
}
R_API int r_cons_grepbuf(char *buf, int len) {
RCons *cons = r_cons_singleton ();
char *tline, *tbuf, *p, *out, *in = buf;
int ret, buffer_len = 0, l = 0, tl = 0;
if (!cons->buffer) {
cons->buffer_len = len+20;
cons->buffer = malloc (cons->buffer_len);
cons->buffer[0] = 0;
}
out = tbuf = calloc (1, len);
tline = malloc (len);
cons->lines = 0;
while (in-buf<len) {
p = strchr (in, '\n');
if (!p) {
free (tbuf);
free (tline);
return 0;
}
l = p-in;
if (l > 0) {
memcpy (tline, in, l);
tl = r_str_ansi_filter (tline, l);
if (tl < 0)
ret = -1;
else ret = r_cons_grep_line (tline, tl);
if (ret > 0) {
if (cons->grep.line == -1 ||
(cons->grep.line != -1 && cons->grep.line == cons->lines)) {
memcpy (out, tline, ret);
memcpy (out+ret, "\n", 1);
out += ret+1;
buffer_len += ret+1;
}
cons->lines++;
} else if (ret < 0) {
free (tbuf);
free (tline);
return 0;
}
in += l+1;
} else in++;
}
memcpy (buf, tbuf, len);
cons->buffer_len = buffer_len;
free (tbuf);
free (tline);
if (cons->grep.counter) {
if (cons->buffer_len<10) cons->buffer_len = 10; // HACK
snprintf (cons->buffer, cons->buffer_len, "%d\n", cons->lines);
cons->buffer_len = strlen (cons->buffer);
}
return cons->lines;
}
R_API int r_cons_grep_line(char *buf, int len) {
RCons *cons = r_cons_singleton ();
const char delims[4][2] = { "|", ",", ";", "\t" };
char *in, *out, *tok = NULL;
int hit = cons->grep.neg;
int i, j, outlen = 0;
in = calloc (1, len+1);
out = calloc (1, len+2);
memcpy (in, buf, len);
if (cons->grep.nstrings>0) {
int ampfail = cons->grep.amp;
for (i=0; i<cons->grep.nstrings; i++) {
char *p = strstr (in, cons->grep.strings[i]);
if (!p) {
ampfail = 0;
continue;
}
if (cons->grep.begin)
hit = (p == in)? 1: 0;
else hit = !cons->grep.neg;
if (cons->grep.end){
for (j=0; cons->grep.strings[i][j] && p[j]; j++);
if (!(cons->grep.strings[i][j] || p[j]))
hit = 0;
}
if (!cons->grep.amp)
break;
}
if (cons->grep.amp)
hit = ampfail;
} else hit = 1;
if (hit) {
if ((cons->grep.tokenfrom != 0 || cons->grep.tokento != ST32_MAX) &&
(cons->grep.line == -1 || cons->grep.line == cons->lines)) {
const int delims_count = sizeof (delims) / 2;
for (i=0; i<len; i++) for (j=0; j<delims_count; j++)
if (in[i] == delims[j][0])
in[i] = ' ';
for (i=0; i <= cons->grep.tokento; i++) {
tok = (char *) strtok (i?NULL:in, " ");
if (tok) {
if (i >= cons->grep.tokenfrom) {
int toklen = strlen (tok);
memcpy (out+outlen, tok, toklen);
memcpy (out+outlen+toklen, " ", 2);
outlen += toklen+1;
}
} else {
if (!(*out)) {
free (in);
free (out);
return -1;
} else break;
}
}
outlen = outlen>0? outlen - 1: 0;
if (outlen>len) { // should never happen
eprintf ("r_cons_grep_line: wtf, how you reach this?\n");
free (in);
free (out);
return -1;
}
memcpy (buf, out, len);
len = outlen;
}
} else len = 0;
free (in);
free (out);
return len;
}
static const char *gethtmlcolor(const char ptrch, const char *def) {
switch (ptrch) {
case '0': return "#000"; // BLACK
case '1': return "#f00"; // RED
case '2': return "#0f0"; // GREEN
case '3': return "#ff0"; // YELLOW
case '4': return "#00f"; // BLUE
case '5': return "#f0f"; // MAGENTA
case '6': return "#aaf"; // TURQOISE
case '7': return "#fff"; // WHITE
case '8': return "#777"; // GREY
case '9': break; // ???
}
return def;
}
// XXX: rename char *r_cons_filter_html(const char *ptr)
R_API int r_cons_html_print(const char *ptr) {
const char *str = ptr;
int esc = 0;
int len = 0;
int inv = 0;
int tmp;
if (!ptr)
return 0;
for (;ptr[0]; ptr = ptr + 1) {
if (0 && ptr[0] == '\n') {
printf ("<br />");
fflush (stdout);
}
if (ptr[0] == 0x1b) {
esc = 1;
tmp = (int) (size_t) (ptr-str);
if (write (1, str, tmp) != tmp)
eprintf ("r_cons_html_print: write: error\n");
str = ptr + 1;
continue;
}
if (esc == 1) {
// \x1b[2J
if (ptr[0] != '[') {
eprintf ("Oops invalid escape char\n");
esc = 0;
str = ptr + 1;
continue;
}
esc = 2;
continue;
} else
if (esc == 2) {
// TODO: use dword comparison here
if (ptr[0]=='2' && ptr[1]=='J') {
printf ("<hr />\n"); fflush(stdout);
ptr++;
esc = 0;
str = ptr;
continue;
} else
if (ptr[0]=='0' && ptr[1]==';' && ptr[2]=='0') {
r_cons_gotoxy (0, 0);
ptr += 4;
esc = 0;
str = ptr;
continue;
} else
if (ptr[0]=='0' && ptr[1]=='m') {
str = (++ptr) + 1;
esc = inv = 0;
continue;
// reset color
} else
if (ptr[0]=='7' && ptr[1]=='m') {
str = (++ptr) +1;
inv = 128;
esc = 0;
continue;
// reset color
} else
if (ptr[0]=='3' && ptr[2]=='m') {
// TODO: honor inv here
printf ("<font color='%s'>", gethtmlcolor (ptr[1], "#000"));
fflush(stdout);
ptr = ptr + 1;
str = ptr + 2;
esc = 0;
continue;
} else
if (ptr[0]=='4' && ptr[2]=='m') {
// TODO: USE INV HERE
printf ("<font style='background-color:%s'>", gethtmlcolor (ptr[1], "#fff"));
fflush(stdout);
}
}
len++;
}
write (1, str, ptr-str);
return len;
}