2016-10-25 12:03:55 +02:00
|
|
|
/* radare - LGPL - Copyright 2009-2016 - pancake, nibble */
|
2009-02-05 22:08:46 +01:00
|
|
|
|
|
|
|
#include <r_cons.h>
|
2010-08-13 01:18:06 +02:00
|
|
|
#include <r_util.h>
|
2014-11-22 02:26:30 +01:00
|
|
|
#define sdb_json_indent r_cons_json_indent
|
2014-11-23 11:03:24 +01:00
|
|
|
#define sdb_json_unindent r_cons_json_unindent
|
2014-11-22 01:51:51 +01:00
|
|
|
#include "../../shlr/sdb/src/json/indent.c"
|
|
|
|
|
2016-10-25 12:39:36 +02:00
|
|
|
/* TODO: remove globals */
|
2016-10-25 12:03:55 +02:00
|
|
|
static RList *sorted_lines = NULL;
|
2016-10-25 14:37:25 +02:00
|
|
|
static RList *unsorted_lines = NULL;
|
2016-10-25 12:03:55 +02:00
|
|
|
static int sorted_column = -1;
|
|
|
|
|
2012-08-09 18:19:00 +02:00
|
|
|
R_API void r_cons_grep_help() {
|
|
|
|
eprintf (
|
2015-09-23 23:00:14 +02:00
|
|
|
"|Usage: [command]~[modifier][word,word][endmodifier][[column]][:line]\n"
|
|
|
|
"| modifiers:\n"
|
|
|
|
"| & all words must match to grep the line\n"
|
2016-10-25 12:03:55 +02:00
|
|
|
"| $[n] sort numerically / alphabetically the Nth column\n"
|
2015-09-23 23:00:14 +02:00
|
|
|
"| ^ words must be placed at the beginning of line\n"
|
|
|
|
"| ! negate grep\n"
|
|
|
|
"| ? count number of matching lines\n"
|
|
|
|
"| .. internal 'less'\n"
|
|
|
|
"| {} json indentation\n"
|
|
|
|
"| {}.. less json indentation\n"
|
|
|
|
"| endmodifiers:\n"
|
|
|
|
"| $ words must be placed at the end of line\n"
|
|
|
|
"| column:\n"
|
|
|
|
"| [n] show only column n\n"
|
|
|
|
"| [n-m] show column n to m\n"
|
|
|
|
"| [n-] show all columns starting from column n\n"
|
2014-11-22 02:26:30 +01:00
|
|
|
"| examples:\n"
|
2015-09-23 23:00:14 +02:00
|
|
|
"| i~:0 show fist line of 'i' output\n"
|
|
|
|
"| pd~mov disasm and grep for mov\n"
|
|
|
|
"| pi~[0] show only opcode\n"
|
|
|
|
"| i~0x400$ show lines ending with 0x400\n"
|
2012-08-09 18:19:00 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2014-04-23 01:57:14 +04:00
|
|
|
#define R_CONS_GREP_BUFSIZE 4096
|
|
|
|
|
2010-02-21 20:21:36 +01:00
|
|
|
R_API void r_cons_grep(const char *str) {
|
2015-09-23 23:00:14 +02:00
|
|
|
int wlen, len, is_range, num_is_parsed, fail = 0;
|
|
|
|
ut64 range_begin, range_end;
|
2010-02-21 20:21:36 +01:00
|
|
|
RCons *cons;
|
2014-04-23 01:57:14 +04:00
|
|
|
char buf[R_CONS_GREP_BUFSIZE];
|
2010-07-16 14:53:06 +02:00
|
|
|
char *ptr, *optr, *ptr2, *ptr3;
|
2012-08-04 00:46:00 +02:00
|
|
|
|
2016-08-28 17:35:28 +02:00
|
|
|
if (!str || !*str) {
|
2012-08-08 10:56:25 +02:00
|
|
|
return;
|
2016-08-28 17:35:28 +02:00
|
|
|
}
|
2010-02-21 20:21:36 +01:00
|
|
|
cons = r_cons_singleton ();
|
2015-09-23 23:00:14 +02:00
|
|
|
memset (&(cons->grep), 0, sizeof (cons->grep));
|
2016-10-25 12:39:36 +02:00
|
|
|
sorted_column = 0;
|
|
|
|
cons->grep.sort = -1;
|
2014-02-11 02:32:37 +01:00
|
|
|
cons->grep.line = -1;
|
2012-08-09 18:19:00 +02:00
|
|
|
while (*str) {
|
|
|
|
switch (*str) {
|
2014-02-11 02:32:37 +01:00
|
|
|
case '.':
|
2015-09-23 23:00:14 +02:00
|
|
|
if (str[1] == '.') {
|
2014-02-11 02:32:37 +01:00
|
|
|
cons->grep.less = 1;
|
|
|
|
return;
|
|
|
|
}
|
2014-03-10 14:19:29 +01:00
|
|
|
str++;
|
2014-02-11 02:32:37 +01:00
|
|
|
break;
|
2014-11-22 01:51:51 +01:00
|
|
|
case '{':
|
2015-09-23 23:00:14 +02:00
|
|
|
if (str[1] == '}') {
|
2014-11-22 01:51:51 +01:00
|
|
|
cons->grep.json = 1;
|
2016-10-19 13:10:10 +02:00
|
|
|
if (!strncmp (str, "{}..", 4)) {
|
2014-11-22 01:51:51 +01:00
|
|
|
cons->grep.less = 1;
|
2016-10-19 13:10:10 +02:00
|
|
|
}
|
2014-11-22 01:51:51 +01:00
|
|
|
str++;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
str++;
|
|
|
|
break;
|
2016-10-25 12:03:55 +02:00
|
|
|
case '$':
|
|
|
|
str++;
|
2016-10-25 12:39:36 +02:00
|
|
|
if (*str == '!') {
|
|
|
|
cons->grep.sort_invert = true;
|
|
|
|
str++;
|
|
|
|
} else {
|
|
|
|
cons->grep.sort_invert = false;
|
|
|
|
}
|
2016-10-25 12:03:55 +02:00
|
|
|
cons->grep.sort = atoi (str);
|
|
|
|
while (IS_NUMBER (*str)) {
|
|
|
|
str++;
|
|
|
|
}
|
2016-10-25 14:37:25 +02:00
|
|
|
if (*str == ':') {
|
|
|
|
cons->grep.sort_row = atoi (++str);
|
|
|
|
str++;
|
|
|
|
}
|
2016-10-19 13:10:10 +02:00
|
|
|
break;
|
2016-10-25 12:03:55 +02:00
|
|
|
case '&':
|
|
|
|
str++;
|
|
|
|
cons->grep.amp = 1;
|
2016-10-19 13:10:10 +02:00
|
|
|
break;
|
2016-10-25 12:03:55 +02:00
|
|
|
case '^':
|
|
|
|
str++;
|
|
|
|
cons->grep.begin = 1;
|
|
|
|
break;
|
|
|
|
case '!':
|
|
|
|
str++;
|
|
|
|
cons->grep.neg = 1;
|
2016-10-19 13:10:10 +02:00
|
|
|
break;
|
2012-08-09 18:19:00 +02:00
|
|
|
case '?': str++; cons->grep.counter = 1;
|
2016-10-25 12:03:55 +02:00
|
|
|
if (*str == '?') {
|
2012-08-09 18:19:00 +02:00
|
|
|
r_cons_grep_help ();
|
2014-01-12 01:34:11 +01:00
|
|
|
return;
|
2012-08-09 18:19:00 +02:00
|
|
|
}
|
|
|
|
break;
|
2016-10-25 12:03:55 +02:00
|
|
|
default:
|
2016-10-19 13:10:10 +02:00
|
|
|
goto while_end;
|
2012-08-09 18:19:00 +02:00
|
|
|
}
|
2016-10-25 12:03:55 +02:00
|
|
|
}
|
2016-10-19 13:10:10 +02:00
|
|
|
while_end:
|
2012-08-09 18:19:00 +02:00
|
|
|
|
2015-09-23 23:00:14 +02:00
|
|
|
len = strlen (str) - 1;
|
2014-04-23 01:57:14 +04:00
|
|
|
if (len > R_CONS_GREP_BUFSIZE - 1) {
|
|
|
|
eprintf("r_cons_grep: too long!\n");
|
|
|
|
return;
|
|
|
|
}
|
2015-09-23 23:00:14 +02:00
|
|
|
if (len > 0 && str[len] == '?') {
|
2012-08-04 00:46:00 +02:00
|
|
|
cons->grep.counter = 1;
|
2015-09-23 23:00:14 +02:00
|
|
|
strncpy (buf, str, R_MIN (len, sizeof (buf) - 1));
|
2012-08-08 10:56:25 +02:00
|
|
|
buf[len]=0;
|
2012-08-04 00:46:00 +02:00
|
|
|
len--;
|
2016-10-19 13:10:10 +02:00
|
|
|
} else {
|
|
|
|
strncpy (buf, str, sizeof (buf) - 1);
|
|
|
|
}
|
2010-07-16 14:53:06 +02:00
|
|
|
|
2015-09-23 23:00:14 +02:00
|
|
|
if (len > 1 && buf[len] == '$' && buf[len - 1] != '\\') {
|
2012-08-04 00:46:00 +02:00
|
|
|
cons->grep.end = 1;
|
|
|
|
buf[len] = 0;
|
2012-06-21 10:12:02 +02:00
|
|
|
}
|
2015-09-23 23:00:14 +02:00
|
|
|
|
2010-07-16 14:53:06 +02:00
|
|
|
ptr = buf;
|
2015-09-23 23:00:14 +02:00
|
|
|
ptr2 = strchr (ptr, '[');
|
|
|
|
ptr3 = strchr (ptr, ']');
|
|
|
|
is_range = 0;
|
|
|
|
num_is_parsed = 0;
|
|
|
|
fail = 0;
|
|
|
|
range_begin = range_end = -1;
|
|
|
|
|
2015-10-03 13:54:46 +02:00
|
|
|
if (ptr2 && ptr3) {
|
2015-09-23 23:00:14 +02:00
|
|
|
ptr2[0] = '\0';
|
|
|
|
ptr2++;
|
|
|
|
for (; ptr2 <= ptr3; ++ptr2) {
|
|
|
|
if (fail) {
|
|
|
|
memset (cons->grep.tokens, 0, R_CONS_GREP_TOKENS);
|
|
|
|
cons->grep.tokens_used = 0;
|
|
|
|
fail = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch (*ptr2) {
|
|
|
|
case '-':
|
|
|
|
is_range = 1;
|
|
|
|
num_is_parsed = 0;
|
|
|
|
break;
|
|
|
|
case ']': // fallthrough to handle ']' like ','
|
|
|
|
case ',':
|
|
|
|
for (; range_begin <= range_end; range_begin++) {
|
|
|
|
if (range_begin >= R_CONS_GREP_TOKENS) {
|
|
|
|
fail = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
cons->grep.tokens[range_begin] = 1;
|
|
|
|
cons->grep.tokens_used = 1;
|
|
|
|
}
|
|
|
|
is_range = 0;
|
|
|
|
num_is_parsed = 0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (!num_is_parsed) {
|
|
|
|
if (is_range) {
|
|
|
|
range_end = r_num_get (cons->num, ptr2);
|
|
|
|
} else {
|
|
|
|
range_begin = range_end = r_num_get (cons->num, ptr2);
|
|
|
|
}
|
|
|
|
num_is_parsed = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-07-16 14:53:06 +02:00
|
|
|
}
|
2015-09-23 23:00:14 +02:00
|
|
|
|
2010-07-16 14:53:06 +02:00
|
|
|
ptr2 = strchr (ptr, ':'); // line number
|
2016-10-19 16:18:04 +02:00
|
|
|
cons->grep.range_line = 2; //there is not :
|
2015-10-19 12:53:14 +02:00
|
|
|
if (ptr2 && ptr2[1] != ':') {
|
2011-06-26 23:49:11 +02:00
|
|
|
*ptr2 = '\0';
|
2016-10-19 16:18:04 +02:00
|
|
|
char *p, *token = ptr + 1;
|
|
|
|
p = strstr (token, "..");
|
|
|
|
if (!p) {
|
|
|
|
cons->grep.line = r_num_get (cons->num, ptr2 + 1);
|
|
|
|
cons->grep.range_line = 0;
|
|
|
|
} else {
|
|
|
|
*p = '\0';
|
2016-10-25 12:03:55 +02:00
|
|
|
cons->grep.range_line = 1;
|
2016-10-19 16:18:04 +02:00
|
|
|
if (!*token) {
|
|
|
|
cons->grep.f_line = 0;
|
|
|
|
} else {
|
|
|
|
cons->grep.f_line = r_num_get (cons->num, token);
|
|
|
|
}
|
|
|
|
if (!p[2]) {
|
|
|
|
cons->grep.l_line = -1;
|
|
|
|
} else {
|
|
|
|
cons->grep.l_line = r_num_get (cons->num, p + 2);
|
|
|
|
}
|
2015-10-22 04:48:56 +02:00
|
|
|
}
|
2010-07-16 14:53:06 +02:00
|
|
|
}
|
2011-02-05 02:55:50 +01:00
|
|
|
free (cons->grep.str);
|
2010-07-16 14:53:06 +02:00
|
|
|
if (*ptr) {
|
|
|
|
cons->grep.str = (char *)strdup (ptr);
|
|
|
|
do {
|
|
|
|
optr = ptr;
|
|
|
|
ptr = strchr (ptr, ','); // grep keywords
|
2016-10-19 13:10:10 +02:00
|
|
|
if (ptr) {
|
|
|
|
*ptr++ = '\0';
|
|
|
|
}
|
2015-09-23 23:00:14 +02:00
|
|
|
wlen = strlen (optr);
|
2016-10-19 13:10:10 +02:00
|
|
|
if (!wlen) {
|
|
|
|
continue;
|
|
|
|
}
|
2015-09-23 23:00:14 +02:00
|
|
|
if (wlen >= R_CONS_GREP_WORD_SIZE - 1) {
|
2012-08-09 18:19:00 +02:00
|
|
|
eprintf ("grep string too long\n");
|
|
|
|
continue;
|
|
|
|
}
|
2012-09-18 03:39:32 +02:00
|
|
|
strncpy (cons->grep.strings[cons->grep.nstrings],
|
2015-09-23 23:00:14 +02:00
|
|
|
optr, R_CONS_GREP_WORD_SIZE - 1);
|
2010-02-21 20:21:36 +01:00
|
|
|
cons->grep.nstrings++;
|
2015-09-23 23:00:14 +02:00
|
|
|
if (cons->grep.nstrings > R_CONS_GREP_WORDS - 1) {
|
2012-08-09 18:19:00 +02:00
|
|
|
eprintf ("too many grep strings\n");
|
|
|
|
break;
|
|
|
|
}
|
2010-07-16 14:53:06 +02:00
|
|
|
} while (ptr);
|
2011-02-05 02:55:50 +01:00
|
|
|
} else {
|
|
|
|
cons->grep.str = strdup (ptr);
|
|
|
|
cons->grep.nstrings++;
|
|
|
|
cons->grep.strings[0][0] = 0;
|
2010-01-30 14:02:53 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-25 12:03:55 +02:00
|
|
|
static int cmp (const void *a, const void *b) {
|
|
|
|
char *da = NULL;
|
|
|
|
char *db = NULL;
|
|
|
|
const char *ca = r_str_chop_ro (a);
|
|
|
|
const char *cb = r_str_chop_ro (b);
|
|
|
|
if (!a || !b) {
|
|
|
|
return (int)(size_t)(a - b);
|
|
|
|
}
|
|
|
|
if (sorted_column > 0) {
|
|
|
|
da = strdup (ca);
|
|
|
|
db = strdup (cb);
|
|
|
|
int colsa = r_str_word_set0 (da);
|
|
|
|
int colsb = r_str_word_set0 (db);
|
|
|
|
ca = (colsa > sorted_column) ? r_str_word_get0 (da, sorted_column): "";
|
|
|
|
cb = (colsb > sorted_column) ? r_str_word_get0 (db, sorted_column): "";
|
|
|
|
}
|
|
|
|
if (IS_NUMBER (*ca) && IS_NUMBER (*cb)) {
|
|
|
|
ut64 na = r_num_get (NULL, ca);
|
|
|
|
ut64 nb = r_num_get (NULL, cb);
|
|
|
|
int ret = na > nb;
|
|
|
|
free (da);
|
|
|
|
free (db);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
if (da && db) {
|
|
|
|
int ret = strcmp (ca, cb);
|
|
|
|
free (da);
|
|
|
|
free (db);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
return strcmp (a, b);
|
|
|
|
}
|
|
|
|
|
2010-06-25 01:44:15 +02:00
|
|
|
R_API int r_cons_grepbuf(char *buf, int len) {
|
2010-07-16 14:53:06 +02:00
|
|
|
RCons *cons = r_cons_singleton ();
|
2010-08-03 13:30:58 +02:00
|
|
|
char *tline, *tbuf, *p, *out, *in = buf;
|
2016-10-19 16:18:04 +02:00
|
|
|
int ret, total_lines = 0, buffer_len = 0, l = 0, tl = 0;
|
|
|
|
bool show = false;
|
2010-07-16 14:53:06 +02:00
|
|
|
|
2016-10-19 13:10:10 +02:00
|
|
|
if ((!len || !buf || buf[0] == '\0') &&
|
2015-09-23 23:00:14 +02:00
|
|
|
(cons->grep.json || cons->grep.less)) {
|
2015-06-09 13:18:56 +03:00
|
|
|
cons->grep.json = 0;
|
|
|
|
cons->grep.less = 0;
|
2015-05-03 20:14:56 +03:00
|
|
|
return 0;
|
2015-06-09 13:18:56 +03:00
|
|
|
}
|
2014-11-22 01:51:51 +01:00
|
|
|
if (cons->grep.json) {
|
|
|
|
char *out = sdb_json_indent (buf);
|
|
|
|
free (cons->buffer);
|
|
|
|
cons->buffer = out;
|
|
|
|
cons->buffer_len = strlen (out);
|
2015-09-23 23:00:14 +02:00
|
|
|
cons->buffer_sz = cons->buffer_len + 1;
|
2014-11-22 01:51:51 +01:00
|
|
|
cons->grep.json = 0;
|
|
|
|
if (cons->grep.less) {
|
|
|
|
cons->grep.less = 0;
|
2015-10-29 12:54:19 +01:00
|
|
|
r_cons_less_str (cons->buffer, NULL);
|
2014-11-22 01:51:51 +01:00
|
|
|
}
|
|
|
|
return 3;
|
|
|
|
}
|
2014-02-11 02:32:37 +01:00
|
|
|
if (cons->grep.less) {
|
|
|
|
cons->grep.less = 0;
|
2015-10-29 12:54:19 +01:00
|
|
|
r_cons_less_str (buf, NULL);
|
2014-02-11 02:32:37 +01:00
|
|
|
buf[0] = 0;
|
|
|
|
cons->buffer_len = 0;
|
2016-10-19 13:10:10 +02:00
|
|
|
if (cons->buffer) {
|
2014-02-11 02:32:37 +01:00
|
|
|
cons->buffer[0] = 0;
|
2016-10-19 13:10:10 +02:00
|
|
|
}
|
2014-02-11 02:32:37 +01:00
|
|
|
free (cons->buffer);
|
|
|
|
cons->buffer = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
2012-08-28 17:50:49 +02:00
|
|
|
if (!cons->buffer) {
|
2015-09-23 23:00:14 +02:00
|
|
|
cons->buffer_len = len + 20;
|
2012-08-28 17:50:49 +02:00
|
|
|
cons->buffer = malloc (cons->buffer_len);
|
|
|
|
cons->buffer[0] = 0;
|
|
|
|
}
|
2010-07-16 18:44:39 +02:00
|
|
|
out = tbuf = calloc (1, len);
|
2010-08-03 13:30:58 +02:00
|
|
|
tline = malloc (len);
|
2010-07-16 14:53:06 +02:00
|
|
|
cons->lines = 0;
|
2016-10-19 16:18:04 +02:00
|
|
|
//used to count lines and change negative grep.line values
|
|
|
|
while ((int)(size_t)(in-buf) < len) {
|
|
|
|
p = strchr (in, '\n');
|
|
|
|
if (!p) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
l = p - in;
|
|
|
|
if (l > 0) {
|
|
|
|
in += l + 1;
|
|
|
|
} else {
|
|
|
|
in++;
|
|
|
|
}
|
|
|
|
total_lines++;
|
|
|
|
}
|
|
|
|
if (!cons->grep.range_line && cons->grep.line < 0) {
|
|
|
|
cons->grep.line = total_lines + cons->grep.line;
|
2016-10-25 12:03:55 +02:00
|
|
|
}
|
2016-10-19 16:18:04 +02:00
|
|
|
if (cons->grep.range_line == 1) {
|
|
|
|
if (cons->grep.f_line < 0) {
|
|
|
|
cons->grep.f_line = total_lines + cons->grep.f_line;
|
|
|
|
}
|
|
|
|
if (cons->grep.l_line < 0) {
|
|
|
|
cons->grep.l_line = total_lines + cons->grep.l_line;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
in = buf;
|
2015-09-23 23:00:14 +02:00
|
|
|
while ((int)(size_t)(in-buf) < len) {
|
2010-07-16 14:53:06 +02:00
|
|
|
p = strchr (in, '\n');
|
2010-07-16 18:44:39 +02:00
|
|
|
if (!p) {
|
|
|
|
free (tbuf);
|
2010-08-03 13:30:58 +02:00
|
|
|
free (tline);
|
2010-07-16 18:44:39 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2015-09-23 23:00:14 +02:00
|
|
|
l = p - in;
|
2010-08-03 13:30:58 +02:00
|
|
|
if (l > 0) {
|
2010-07-16 14:53:06 +02:00
|
|
|
memcpy (tline, in, l);
|
2015-05-27 18:24:35 +03:00
|
|
|
tl = r_str_ansi_filter (tline, NULL, NULL, l);
|
2016-10-19 13:10:10 +02:00
|
|
|
if (tl < 0) {
|
2010-08-13 01:18:06 +02:00
|
|
|
ret = -1;
|
2016-10-19 13:10:10 +02:00
|
|
|
} else {
|
|
|
|
ret = r_cons_grep_line (tline, tl);
|
2016-10-19 16:18:04 +02:00
|
|
|
if (!cons->grep.range_line) {
|
|
|
|
if (cons->grep.line == cons->lines) {
|
|
|
|
show = true;
|
|
|
|
}
|
|
|
|
} else if (cons->grep.range_line == 1) {
|
|
|
|
if (cons->grep.f_line == cons->lines) {
|
|
|
|
show = true;
|
|
|
|
}
|
|
|
|
if (cons->grep.l_line == cons->lines) {
|
|
|
|
show = false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
show = true;
|
|
|
|
}
|
2016-10-19 13:10:10 +02:00
|
|
|
}
|
2010-07-16 14:53:06 +02:00
|
|
|
if (ret > 0) {
|
2016-10-19 16:18:04 +02:00
|
|
|
if (show) {
|
2010-07-16 14:53:06 +02:00
|
|
|
memcpy (out, tline, ret);
|
2015-09-23 23:00:14 +02:00
|
|
|
memcpy (out + ret, "\n", 1);
|
|
|
|
out += ret + 1;
|
|
|
|
buffer_len += ret + 1;
|
2010-07-16 14:53:06 +02:00
|
|
|
}
|
2016-10-19 16:18:04 +02:00
|
|
|
if (!cons->grep.range_line) {
|
|
|
|
show = false;
|
|
|
|
}
|
2010-07-16 14:53:06 +02:00
|
|
|
cons->lines++;
|
2010-07-16 18:44:39 +02:00
|
|
|
} else if (ret < 0) {
|
2010-07-16 14:53:06 +02:00
|
|
|
free (tbuf);
|
2010-08-03 13:30:58 +02:00
|
|
|
free (tline);
|
2010-07-16 14:53:06 +02:00
|
|
|
return 0;
|
2015-09-23 23:00:14 +02:00
|
|
|
}
|
|
|
|
in += l + 1;
|
2016-10-19 13:10:10 +02:00
|
|
|
} else {
|
|
|
|
in++;
|
|
|
|
}
|
2010-06-25 01:44:15 +02:00
|
|
|
}
|
2010-07-16 14:53:06 +02:00
|
|
|
memcpy (buf, tbuf, len);
|
|
|
|
cons->buffer_len = buffer_len;
|
|
|
|
free (tbuf);
|
2010-08-03 13:30:58 +02:00
|
|
|
free (tline);
|
2011-02-05 02:55:50 +01:00
|
|
|
if (cons->grep.counter) {
|
2016-10-19 13:10:10 +02:00
|
|
|
if (cons->buffer_len < 10) {
|
|
|
|
cons->buffer_len = 10; // HACK
|
|
|
|
}
|
2011-04-04 18:33:27 +02:00
|
|
|
snprintf (cons->buffer, cons->buffer_len, "%d\n", cons->lines);
|
2012-08-28 17:50:49 +02:00
|
|
|
cons->buffer_len = strlen (cons->buffer);
|
2011-02-05 02:55:50 +01:00
|
|
|
}
|
2016-10-25 12:03:55 +02:00
|
|
|
if (cons->grep.sort != -1) {
|
2016-10-25 14:37:25 +02:00
|
|
|
#define INSERT_LINES(list) \
|
|
|
|
do {\
|
|
|
|
r_list_foreach (list, iter, str) { \
|
|
|
|
int len = strlen (str);\
|
|
|
|
memcpy (ptr, str, len);\
|
|
|
|
memcpy (ptr + len, "\n", 2); \
|
|
|
|
ptr += len + 1; \
|
|
|
|
nl++; \
|
|
|
|
} \
|
|
|
|
} while (false)
|
|
|
|
|
2016-10-25 12:03:55 +02:00
|
|
|
RListIter *iter;
|
|
|
|
int nl = 0;
|
|
|
|
char *ptr = cons->buffer;
|
|
|
|
char *str;
|
|
|
|
sorted_column = cons->grep.sort;
|
|
|
|
r_list_sort (sorted_lines, cmp);
|
2016-10-25 12:39:36 +02:00
|
|
|
if (cons->grep.sort_invert) {
|
|
|
|
r_list_reverse (sorted_lines);
|
|
|
|
}
|
2016-10-25 14:37:25 +02:00
|
|
|
INSERT_LINES (unsorted_lines);
|
|
|
|
INSERT_LINES (sorted_lines);
|
2016-10-25 12:03:55 +02:00
|
|
|
cons->lines = nl;
|
|
|
|
r_list_free (sorted_lines);
|
|
|
|
sorted_lines = NULL;
|
2016-10-25 14:37:25 +02:00
|
|
|
r_list_free (unsorted_lines);
|
|
|
|
unsorted_lines = NULL;
|
2016-10-25 12:03:55 +02:00
|
|
|
}
|
2010-07-16 14:53:06 +02:00
|
|
|
return cons->lines;
|
2010-06-25 01:44:15 +02:00
|
|
|
}
|
2010-07-16 14:53:06 +02:00
|
|
|
|
2010-06-25 01:44:15 +02:00
|
|
|
R_API int r_cons_grep_line(char *buf, int len) {
|
2010-02-21 20:21:36 +01:00
|
|
|
RCons *cons = r_cons_singleton ();
|
2015-09-23 23:00:14 +02:00
|
|
|
const char *delims = " |,;=\t";
|
2010-08-03 13:30:58 +02:00
|
|
|
char *in, *out, *tok = NULL;
|
2010-07-16 14:53:06 +02:00
|
|
|
int hit = cons->grep.neg;
|
2015-09-23 23:00:14 +02:00
|
|
|
int outlen = 0;
|
2016-10-19 16:18:04 +02:00
|
|
|
bool use_tok = false;
|
2015-09-23 23:00:14 +02:00
|
|
|
size_t i;
|
2010-01-30 14:02:53 +01:00
|
|
|
|
2015-09-23 23:00:14 +02:00
|
|
|
in = calloc (1, len + 1);
|
2016-10-19 13:10:10 +02:00
|
|
|
if (!in) {
|
|
|
|
return 0;
|
|
|
|
}
|
2015-09-23 23:00:14 +02:00
|
|
|
out = calloc (1, len + 2);
|
2016-05-19 16:20:35 +01:00
|
|
|
if (!out) {
|
|
|
|
free (in);
|
|
|
|
return 0;
|
|
|
|
}
|
2010-08-03 13:30:58 +02:00
|
|
|
memcpy (in, buf, len);
|
|
|
|
|
2015-09-23 23:00:14 +02:00
|
|
|
if (cons->grep.nstrings > 0) {
|
2012-08-09 18:19:00 +02:00
|
|
|
int ampfail = cons->grep.amp;
|
2015-09-23 23:00:14 +02:00
|
|
|
for (i = 0; i < cons->grep.nstrings; i++) {
|
2012-06-21 10:12:02 +02:00
|
|
|
char *p = strstr (in, cons->grep.strings[i]);
|
2012-08-09 18:19:00 +02:00
|
|
|
if (!p) {
|
|
|
|
ampfail = 0;
|
|
|
|
continue;
|
|
|
|
}
|
2016-10-19 13:10:10 +02:00
|
|
|
if (cons->grep.begin) {
|
2015-09-23 23:00:14 +02:00
|
|
|
hit = (p == in) ? 1 : 0;
|
2016-10-19 13:10:10 +02:00
|
|
|
} else {
|
|
|
|
hit = !cons->grep.neg;
|
|
|
|
}
|
2014-07-17 04:45:32 +02:00
|
|
|
// TODO: optimize without strlen without breaking t/feat_grep (grep end)
|
2016-10-19 13:10:10 +02:00
|
|
|
if (cons->grep.end && (strlen (cons->grep.strings[i]) != strlen (p))) {
|
2014-07-17 04:45:32 +02:00
|
|
|
hit = 0 ;
|
2016-10-19 13:10:10 +02:00
|
|
|
}
|
|
|
|
if (!cons->grep.amp) {
|
2012-08-09 18:19:00 +02:00
|
|
|
break;
|
2016-10-19 13:10:10 +02:00
|
|
|
}
|
2012-06-21 10:12:02 +02:00
|
|
|
}
|
2016-10-19 13:10:10 +02:00
|
|
|
if (cons->grep.amp) {
|
2012-08-09 18:19:00 +02:00
|
|
|
hit = ampfail;
|
2016-10-19 13:10:10 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
hit = 1;
|
|
|
|
}
|
2010-01-30 14:02:53 +01:00
|
|
|
|
2010-07-16 14:53:06 +02:00
|
|
|
if (hit) {
|
2016-10-19 16:18:04 +02:00
|
|
|
if (!cons->grep.range_line) {
|
|
|
|
if (cons->grep.line == cons->lines) {
|
|
|
|
use_tok = true;
|
|
|
|
}
|
|
|
|
} else if (cons->grep.range_line == 1) {
|
|
|
|
if (cons->grep.f_line == cons->lines) {
|
|
|
|
use_tok = true;
|
|
|
|
}
|
|
|
|
if (cons->grep.l_line == cons->lines) {
|
|
|
|
use_tok = false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
use_tok = true;
|
|
|
|
}
|
|
|
|
if (use_tok && cons->grep.tokens_used) {
|
2015-09-23 23:00:14 +02:00
|
|
|
for (i = 0; i < R_CONS_GREP_TOKENS; i++) {
|
|
|
|
tok = strtok (i ? NULL : in, delims);
|
|
|
|
|
2011-04-04 18:33:27 +02:00
|
|
|
if (tok) {
|
2015-09-23 23:00:14 +02:00
|
|
|
if (cons->grep.tokens[i]) {
|
2011-04-04 18:33:27 +02:00
|
|
|
int toklen = strlen (tok);
|
2015-09-23 23:00:14 +02:00
|
|
|
memcpy (out + outlen, tok, toklen);
|
|
|
|
memcpy (out + outlen + toklen, " ", 2);
|
|
|
|
outlen += toklen + 1;
|
|
|
|
if (!(*out)) {
|
|
|
|
free (in);
|
|
|
|
free (out);
|
|
|
|
return -1;
|
|
|
|
}
|
2011-04-04 18:33:27 +02:00
|
|
|
}
|
|
|
|
} else {
|
2013-10-22 14:59:32 +01:00
|
|
|
if (!(*out)) {
|
2010-08-03 13:30:58 +02:00
|
|
|
free (in);
|
|
|
|
free (out);
|
|
|
|
return -1;
|
2016-10-19 13:10:10 +02:00
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
2010-08-03 11:36:41 +02:00
|
|
|
}
|
2010-01-30 14:02:53 +01:00
|
|
|
}
|
2015-09-23 23:00:14 +02:00
|
|
|
|
|
|
|
outlen = outlen > 0 ? outlen - 1 : 0;
|
|
|
|
if (outlen > len) { // should never happen
|
2011-04-04 18:33:27 +02:00
|
|
|
eprintf ("r_cons_grep_line: wtf, how you reach this?\n");
|
2012-08-08 17:19:48 +02:00
|
|
|
free (in);
|
|
|
|
free (out);
|
2011-04-04 18:33:27 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2015-09-23 23:00:14 +02:00
|
|
|
|
2010-08-03 11:36:41 +02:00
|
|
|
memcpy (buf, out, len);
|
2011-04-04 18:33:27 +02:00
|
|
|
len = outlen;
|
2010-06-25 11:22:14 +02:00
|
|
|
}
|
2016-10-19 13:10:10 +02:00
|
|
|
} else {
|
|
|
|
len = 0;
|
|
|
|
}
|
2010-08-03 13:30:58 +02:00
|
|
|
free (in);
|
|
|
|
free (out);
|
2016-10-25 12:03:55 +02:00
|
|
|
if (cons->grep.sort != -1) {
|
|
|
|
char ch = buf[len];
|
|
|
|
buf[len] = 0;
|
|
|
|
if (!sorted_lines) {
|
|
|
|
sorted_lines = r_list_newf (free);
|
|
|
|
}
|
2016-10-25 14:37:25 +02:00
|
|
|
if (!unsorted_lines) {
|
|
|
|
unsorted_lines = r_list_newf (free);
|
|
|
|
}
|
|
|
|
if (cons->lines > cons->grep.sort_row) {
|
|
|
|
r_list_append (sorted_lines, strdup (buf));
|
|
|
|
} else {
|
|
|
|
r_list_append (unsorted_lines, strdup (buf));
|
|
|
|
}
|
2016-10-25 12:03:55 +02:00
|
|
|
buf[len] = ch;
|
|
|
|
}
|
2010-08-03 13:30:58 +02:00
|
|
|
|
2010-07-16 14:53:06 +02:00
|
|
|
return len;
|
2010-01-30 14:02:53 +01:00
|
|
|
}
|
|
|
|
|
2015-01-13 01:22:33 +01:00
|
|
|
static const char *gethtmlrgb(const char *str) {
|
|
|
|
static char buf[32];
|
|
|
|
ut8 r, g, b;
|
|
|
|
r = g = b = 0;
|
|
|
|
r_cons_rgb_parse (str, &r, &g, &b, 0);
|
|
|
|
sprintf (buf, "#%02x%02x%02x", r, g, b);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2011-04-29 10:38:01 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-01-26 01:28:33 +01:00
|
|
|
// XXX: rename char *r_cons_filter_html(const char *ptr)
|
2010-03-08 00:18:58 +01:00
|
|
|
R_API int r_cons_html_print(const char *ptr) {
|
2010-01-26 01:28:33 +01:00
|
|
|
const char *str = ptr;
|
2009-02-05 22:08:46 +01:00
|
|
|
int esc = 0;
|
|
|
|
int len = 0;
|
|
|
|
int inv = 0;
|
2010-10-27 16:31:51 +02:00
|
|
|
int tmp;
|
2016-09-03 18:38:12 +02:00
|
|
|
bool tag_font = false;
|
2009-02-05 22:08:46 +01:00
|
|
|
|
2016-10-19 13:10:10 +02:00
|
|
|
if (!ptr) {
|
2011-09-02 02:03:38 +02:00
|
|
|
return 0;
|
2016-10-19 13:10:10 +02:00
|
|
|
}
|
2009-02-05 22:08:46 +01:00
|
|
|
for (;ptr[0]; ptr = ptr + 1) {
|
2012-09-05 03:25:03 +02:00
|
|
|
if (0 && ptr[0] == '\n') {
|
2010-06-25 01:44:15 +02:00
|
|
|
printf ("<br />");
|
|
|
|
fflush (stdout);
|
2009-02-05 22:08:46 +01:00
|
|
|
}
|
2016-03-27 05:49:30 +02:00
|
|
|
if (ptr[0] == '<') {
|
|
|
|
tmp = (int) (size_t) (ptr-str);
|
2016-10-19 13:10:10 +02:00
|
|
|
if (write (1, str, tmp) != tmp) {
|
2016-03-27 05:49:30 +02:00
|
|
|
eprintf ("r_cons_html_print: write: error\n");
|
2016-10-19 13:10:10 +02:00
|
|
|
}
|
2016-03-27 05:49:30 +02:00
|
|
|
printf ("<");
|
|
|
|
fflush (stdout);
|
|
|
|
str = ptr + 1;
|
|
|
|
continue;
|
|
|
|
} else if (ptr[0] == '>') {
|
|
|
|
tmp = (int) (size_t) (ptr-str);
|
2016-10-19 13:10:10 +02:00
|
|
|
if (write (1, str, tmp) != tmp) {
|
2016-03-27 05:49:30 +02:00
|
|
|
eprintf ("r_cons_html_print: write: error\n");
|
2016-10-19 13:10:10 +02:00
|
|
|
}
|
2016-03-27 05:49:30 +02:00
|
|
|
printf (">");
|
|
|
|
fflush (stdout);
|
|
|
|
str = ptr + 1;
|
|
|
|
continue;
|
|
|
|
}
|
2009-02-05 22:08:46 +01:00
|
|
|
if (ptr[0] == 0x1b) {
|
|
|
|
esc = 1;
|
2010-10-27 16:31:51 +02:00
|
|
|
tmp = (int) (size_t) (ptr-str);
|
2016-09-03 18:38:12 +02:00
|
|
|
if (write (1, str, tmp) != tmp) {
|
2010-10-27 16:31:51 +02:00
|
|
|
eprintf ("r_cons_html_print: write: error\n");
|
2016-09-03 18:38:12 +02:00
|
|
|
}
|
2015-02-01 02:28:17 +01:00
|
|
|
if (tag_font) {
|
|
|
|
printf ("</font>");
|
2016-09-03 18:38:12 +02:00
|
|
|
fflush (stdout);
|
|
|
|
tag_font = false;
|
2015-02-01 02:28:17 +01:00
|
|
|
}
|
2009-02-05 22:08:46 +01:00
|
|
|
str = ptr + 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (esc == 1) {
|
|
|
|
// \x1b[2J
|
|
|
|
if (ptr[0] != '[') {
|
2010-06-25 01:44:15 +02:00
|
|
|
eprintf ("Oops invalid escape char\n");
|
2009-02-05 22:08:46 +01:00
|
|
|
esc = 0;
|
|
|
|
str = ptr + 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
esc = 2;
|
|
|
|
continue;
|
2016-10-19 13:10:10 +02:00
|
|
|
} else if (esc == 2) {
|
2012-08-04 00:46:00 +02:00
|
|
|
// TODO: use dword comparison here
|
2015-09-23 23:00:14 +02:00
|
|
|
if (ptr[0] == '2' && ptr[1] == 'J') {
|
2015-02-01 02:28:17 +01:00
|
|
|
printf ("<hr />\n");
|
2016-09-03 18:38:12 +02:00
|
|
|
fflush (stdout);
|
2011-04-29 10:38:01 +02:00
|
|
|
ptr++;
|
2009-02-05 22:08:46 +01:00
|
|
|
esc = 0;
|
|
|
|
str = ptr;
|
|
|
|
continue;
|
2016-10-19 13:10:10 +02:00
|
|
|
} else if (!strncmp (ptr, "38;5;", 5)) {
|
2015-01-13 01:22:33 +01:00
|
|
|
char *end = strchr (ptr, 'm');
|
|
|
|
printf ("<font color='%s'>", gethtmlrgb (ptr));
|
|
|
|
fflush (stdout);
|
2016-09-03 18:38:12 +02:00
|
|
|
tag_font = true;
|
2015-01-13 01:22:33 +01:00
|
|
|
ptr = end;
|
|
|
|
str = ptr + 1;
|
|
|
|
esc = 0;
|
2016-10-19 13:10:10 +02:00
|
|
|
} else if (ptr[0] == '0' && ptr[1] == ';' && ptr[2] == '0') {
|
2012-08-04 00:46:00 +02:00
|
|
|
r_cons_gotoxy (0, 0);
|
2011-04-29 10:38:01 +02:00
|
|
|
ptr += 4;
|
2009-02-05 22:08:46 +01:00
|
|
|
esc = 0;
|
|
|
|
str = ptr;
|
|
|
|
continue;
|
2016-10-19 13:10:10 +02:00
|
|
|
} else if (ptr[0] == '0' && ptr[1] == 'm') {
|
2012-08-04 00:46:00 +02:00
|
|
|
str = (++ptr) + 1;
|
2011-04-29 10:38:01 +02:00
|
|
|
esc = inv = 0;
|
2009-02-05 22:08:46 +01:00
|
|
|
continue;
|
|
|
|
// reset color
|
2016-10-19 13:10:10 +02:00
|
|
|
} else if (ptr[0] == '7' && ptr[1] == 'm') {
|
2015-09-23 23:00:14 +02:00
|
|
|
str = (++ptr) + 1;
|
2009-02-05 22:08:46 +01:00
|
|
|
inv = 128;
|
|
|
|
esc = 0;
|
|
|
|
continue;
|
|
|
|
// reset color
|
2016-10-19 13:10:10 +02:00
|
|
|
} else if (ptr[0] == '3' && ptr[2] == 'm') {
|
2015-09-23 23:00:14 +02:00
|
|
|
printf ("<font color='%s'>", gethtmlcolor (ptr[1], inv ? "#fff" : "#000"));
|
2016-04-07 14:22:57 +02:00
|
|
|
fflush (stdout);
|
2016-09-03 18:38:12 +02:00
|
|
|
tag_font = true;
|
2009-02-05 22:08:46 +01:00
|
|
|
ptr = ptr + 1;
|
|
|
|
str = ptr + 2;
|
|
|
|
esc = 0;
|
|
|
|
continue;
|
2016-10-19 13:10:10 +02:00
|
|
|
} else if (ptr[0] == '4' && ptr[2] == 'm') {
|
2014-08-04 19:25:23 +02:00
|
|
|
printf ("<font style='background-color:%s'>",
|
2015-09-23 23:00:14 +02:00
|
|
|
gethtmlcolor (ptr[1], inv ? "#000" : "#fff"));
|
2016-04-07 14:22:57 +02:00
|
|
|
fflush (stdout);
|
2016-09-03 18:38:12 +02:00
|
|
|
tag_font = true;
|
2016-04-07 14:22:57 +02:00
|
|
|
ptr = ptr + 1;
|
|
|
|
str = ptr + 2;
|
|
|
|
esc = 0;
|
|
|
|
continue;
|
2009-02-05 22:08:46 +01:00
|
|
|
}
|
2015-09-23 23:00:14 +02:00
|
|
|
}
|
2009-02-05 22:08:46 +01:00
|
|
|
len++;
|
|
|
|
}
|
2016-09-03 18:38:12 +02:00
|
|
|
if (tag_font) {
|
|
|
|
printf ("</font>");
|
|
|
|
fflush (stdout);
|
|
|
|
tag_font = false;
|
|
|
|
}
|
2015-09-23 23:00:14 +02:00
|
|
|
write (1, str, ptr - str);
|
2009-02-05 22:08:46 +01:00
|
|
|
return len;
|
|
|
|
}
|