2015-04-13 09:52:29 +00:00
|
|
|
/* radare2 - LGPL - Copyright 2014-2015 - pancake, Judge_Dredd */
|
2014-02-11 01:32:37 +00:00
|
|
|
|
|
|
|
#include <r_cons.h>
|
2015-02-08 17:42:02 +00:00
|
|
|
#include <r_regex.h> /* less / regex search */
|
2015-04-12 12:59:13 +00:00
|
|
|
#include <r_util.h>
|
2014-02-11 01:32:37 +00:00
|
|
|
|
2015-04-12 12:59:13 +00:00
|
|
|
static void printpage (const char *line, int *index, RRegexMatch *ms,
|
|
|
|
int from, int to, int w) {
|
2014-02-11 01:32:37 +00:00
|
|
|
int i;
|
2015-02-11 14:22:39 +00:00
|
|
|
const char *laddr;
|
2015-04-13 09:52:29 +00:00
|
|
|
RStrpool *p;
|
2015-04-12 12:59:13 +00:00
|
|
|
char *inv[2] = {R_CONS_INVERT(R_TRUE, R_TRUE),
|
|
|
|
R_CONS_INVERT(R_FALSE, R_TRUE)};
|
|
|
|
int linv[2] = {strlen(inv[0]), strlen(inv[1])};
|
2014-02-11 01:32:37 +00:00
|
|
|
r_cons_clear00 ();
|
2015-04-13 04:43:42 +00:00
|
|
|
if (from <0 || to <0) {
|
2015-04-07 11:21:52 +00:00
|
|
|
return;
|
2015-04-13 04:43:42 +00:00
|
|
|
}
|
2015-04-13 09:52:29 +00:00
|
|
|
p = r_strpool_new(0);
|
2014-02-11 01:32:37 +00:00
|
|
|
for (i=from; i<to; i++) {
|
2015-04-12 12:59:13 +00:00
|
|
|
r_strpool_empty(p);
|
2015-02-11 14:22:39 +00:00
|
|
|
laddr = line + index[i];
|
2015-04-07 11:21:52 +00:00
|
|
|
if (ms[i].rm_eo) {/* highlight a match */
|
2015-04-12 12:59:13 +00:00
|
|
|
r_strpool_memcat(p, laddr, ms[i].rm_so);
|
|
|
|
r_strpool_memcat(p, inv[0], linv[0]);
|
|
|
|
r_strpool_memcat(p, laddr + ms[i].rm_so,
|
|
|
|
ms[i].rm_eo - ms[i].rm_so);
|
|
|
|
r_strpool_memcat(p, inv[1], linv[1]);
|
|
|
|
r_strpool_append(p, laddr + ms[i].rm_eo);
|
2015-04-07 11:21:52 +00:00
|
|
|
} else {
|
2015-04-12 12:59:13 +00:00
|
|
|
r_strpool_append(p, laddr);
|
2015-02-11 14:22:39 +00:00
|
|
|
}
|
2015-04-12 12:59:13 +00:00
|
|
|
r_strpool_ansi_chop(p, w);
|
|
|
|
r_cons_reset_colors();
|
|
|
|
r_cons_printf ("%s\n", p->str);
|
2014-02-11 01:32:37 +00:00
|
|
|
}
|
2015-04-12 12:59:13 +00:00
|
|
|
r_strpool_free(p);
|
2014-02-11 01:32:37 +00:00
|
|
|
r_cons_flush ();
|
|
|
|
}
|
|
|
|
|
|
|
|
static int *splitlines (char *s, int *lines_count) {
|
|
|
|
int lines_size = 128;
|
|
|
|
int *lines = malloc (lines_size*sizeof(int));
|
|
|
|
int i, row = 0;
|
|
|
|
int sidx = 0;
|
|
|
|
lines[row++] = 0;
|
|
|
|
for (i=0; s[i]; i++) {
|
|
|
|
if (row>=lines_size) {
|
|
|
|
lines_size += 128;
|
|
|
|
lines = realloc (lines, lines_size*sizeof(int));
|
|
|
|
}
|
|
|
|
if (s[i]=='\n') {
|
|
|
|
s[i] = 0;
|
|
|
|
lines[row++] = i+1;
|
|
|
|
}
|
|
|
|
sidx++;
|
|
|
|
}
|
|
|
|
*lines_count = row;
|
|
|
|
return lines;
|
|
|
|
}
|
|
|
|
|
2015-02-11 14:22:39 +00:00
|
|
|
static int next_match(int from, RRegexMatch *ms, int lcount){
|
|
|
|
int l;
|
|
|
|
if(from > lcount - 2) return from;
|
|
|
|
for(l = from + 1; l < lcount; l++){
|
|
|
|
if(ms[l].rm_eo) return l;
|
|
|
|
}
|
|
|
|
return from;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int prev_match(int from, RRegexMatch *ms){
|
|
|
|
int l;
|
|
|
|
if(from < 1) return from;
|
|
|
|
for(l = from - 1; l > 0; l--){
|
|
|
|
if(ms[l].rm_eo) return l;
|
|
|
|
}
|
|
|
|
return from;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find all matches, ms[i] will contain match offsets relative to start
|
|
|
|
* of string number i! */
|
|
|
|
static int all_matches(const char *s, RRegex *rx, RRegexMatch *ms,
|
|
|
|
int *lines, int lcount){
|
|
|
|
int l, fnd, f = R_FALSE;
|
|
|
|
RRegexMatch m;
|
|
|
|
for(l = 0; l < lcount; l++){
|
|
|
|
fnd = r_regex_exec(rx, s + lines[l], 1, &m, 0);
|
|
|
|
if(!fnd){
|
|
|
|
ms[l] = m;
|
|
|
|
f = R_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
2014-02-11 01:32:37 +00:00
|
|
|
R_API void r_cons_less_str(const char *str) {
|
|
|
|
int lines_count;
|
2015-02-08 17:42:02 +00:00
|
|
|
RRegex *rx = NULL;
|
2015-04-12 12:59:13 +00:00
|
|
|
int w, h, ch, to, ui = 1, from = 0;
|
2015-02-09 23:05:18 +00:00
|
|
|
const char *sreg;
|
|
|
|
char *p = strdup (str);
|
2014-02-11 01:32:37 +00:00
|
|
|
int *lines = splitlines (p, &lines_count);
|
2015-02-11 14:22:39 +00:00
|
|
|
RRegexMatch *ms = calloc(lines_count, sizeof(RRegexMatch));
|
2014-02-11 01:32:37 +00:00
|
|
|
r_cons_set_raw (R_TRUE);
|
|
|
|
r_cons_show_cursor (R_FALSE);
|
|
|
|
r_cons_reset ();
|
2015-04-12 12:59:13 +00:00
|
|
|
w = h = 0;
|
2014-02-11 01:32:37 +00:00
|
|
|
while (ui) {
|
2015-04-12 12:59:13 +00:00
|
|
|
w = r_cons_get_size (&h);
|
2014-02-11 01:32:37 +00:00
|
|
|
to = R_MIN (lines_count, from+h);
|
|
|
|
if (from+3>lines_count)
|
|
|
|
from = lines_count-3;
|
2015-04-07 11:21:52 +00:00
|
|
|
if (from<0) from = 0;
|
2015-04-12 12:59:13 +00:00
|
|
|
printpage (p, lines, ms, from, to, w);
|
2014-02-11 01:32:37 +00:00
|
|
|
ch = r_cons_readchar ();
|
|
|
|
ch = r_cons_arrow_to_hjkl (ch);
|
|
|
|
switch (ch) {
|
|
|
|
case ' ': from += h; break;
|
|
|
|
case 'g': from = 0; break;
|
|
|
|
case 'G': from = lines_count-1-h; break;
|
2015-03-23 15:18:35 +00:00
|
|
|
case -1: // EOF
|
2014-02-11 01:32:37 +00:00
|
|
|
case 'q': ui = 0; break;
|
2014-03-09 20:38:37 +00:00
|
|
|
case '\r':
|
|
|
|
case '\n':
|
2014-02-11 01:32:37 +00:00
|
|
|
case 'j': from++; break;
|
|
|
|
case 'J': from+=h; break;
|
2014-03-09 20:38:37 +00:00
|
|
|
case 'k': if (from>0) from--; break;
|
2014-03-09 23:53:25 +00:00
|
|
|
case 'K': from = (from>=h)? from-h: 0;
|
2014-02-11 01:32:37 +00:00
|
|
|
break;
|
2015-02-08 17:42:02 +00:00
|
|
|
case '/': /* search */
|
|
|
|
r_line_set_prompt("/");
|
|
|
|
sreg = r_line_readline();
|
|
|
|
from = R_MIN(lines_count - 1, from);
|
|
|
|
/* repeat last search if empty string is provided */
|
2015-02-11 14:22:39 +00:00
|
|
|
if(sreg[0]){ /* prepare for a new search */
|
2015-02-08 17:42:02 +00:00
|
|
|
if(rx) r_regex_free(rx);
|
|
|
|
rx = r_regex_new(sreg, "");
|
2015-02-11 14:22:39 +00:00
|
|
|
memset (ms, 0, lines_count*sizeof(RRegexMatch));
|
|
|
|
} else { /* we got an empty string */
|
|
|
|
from = next_match(from, ms, lines_count);
|
|
|
|
break;
|
2015-02-08 17:42:02 +00:00
|
|
|
}
|
|
|
|
if(!rx) break;
|
2015-02-11 14:22:39 +00:00
|
|
|
/* find all occurences */
|
|
|
|
if(all_matches(p, rx, ms, lines, lines_count))
|
|
|
|
from = next_match(from, ms, lines_count);
|
|
|
|
break;
|
|
|
|
case 'n': /* next match */
|
|
|
|
/* search already performed */
|
|
|
|
if(rx) from = next_match(from, ms, lines_count);
|
|
|
|
break;
|
|
|
|
case 'p': /* previous match */
|
|
|
|
if(rx) from = prev_match(from, ms);
|
|
|
|
break;
|
2014-02-11 01:32:37 +00:00
|
|
|
}
|
|
|
|
}
|
2015-02-08 17:42:02 +00:00
|
|
|
if(rx) r_regex_free(rx);
|
2014-02-11 01:32:37 +00:00
|
|
|
free (lines);
|
2014-04-29 22:55:07 +00:00
|
|
|
free (p);
|
2015-02-16 23:34:51 +00:00
|
|
|
free (ms);
|
2014-02-11 01:32:37 +00:00
|
|
|
r_cons_set_raw (R_FALSE);
|
|
|
|
r_cons_show_cursor (R_TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API void r_cons_less() {
|
|
|
|
r_cons_less_str (r_cons_singleton ()->buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
main (int argc, char **argv) {
|
|
|
|
char *s = r_file_slurp (argv[1], NULL);
|
|
|
|
r_cons_new ();
|
|
|
|
r_cons_less (s);
|
|
|
|
}
|
|
|
|
#endif
|