radare2/libr/cons/less.c

218 lines
5.2 KiB
C
Raw Normal View History

2015-04-13 09:52:29 +00:00
/* radare2 - LGPL - Copyright 2014-2015 - pancake, Judge_Dredd */
#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>
static void color_line(const char *line, RStrpool *p, RList *ml){
int m_len, offset = 0;
2015-06-01 20:54:40 +00:00
char *m_addr;
RListIter *it;
RRegexMatch *m;
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])};
r_strpool_empty(p);
r_list_foreach (ml, it, m) {
/* highlight a match */
r_strpool_memcat (p, line + offset,
m->rm_so - offset);
r_strpool_memcat (p, inv[0], linv[0]);
m_len = m->rm_eo - m->rm_so;
if (m_len<0) m_len = 0;
m_addr = r_str_ndup (line + m->rm_so, m_len);
if (m_addr) {
/* in case there's a CSI in the middle of this match*/
m_len = r_str_ansi_filter(m_addr,
NULL, NULL, m_len);
2015-06-03 10:34:15 +00:00
if (m_len<0) m_len = 0;
r_strpool_memcat (p, m_addr, m_len);
r_strpool_memcat (p, inv[1], linv[1]);
offset = m->rm_eo;
free(m_addr);
}
}
/* append final part of string w/o matches */
r_strpool_append(p, line + offset);
}
static void printpage (const char *line, int *index, RList **mla,
int from, int to, int w) {
int i;
RStrpool *p;
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);
for (i=from; i<to; i++) {
color_line(line + index[i], p, mla[i]);
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);
}
2015-04-12 12:59:13 +00:00
r_strpool_free(p);
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;
}
static int next_match(int from, RList **mla, int lcount){
int l;
if(from > lcount - 2) return from;
for(l = from + 1; l < lcount; l++){
/* if there's at least one match on the line */
if(r_list_first(mla[l])) return l;
}
return from;
}
static int prev_match(int from, RList **mla){
int l;
if(from < 1) return from;
for(l = from - 1; l > 0; l--){
if(r_list_first(mla[l])) return l;
}
return from;
}
static int all_matches(const char *s, RRegex *rx, RList **mla,
int *lines, int lcount){
int l, f = R_FALSE;
RRegexMatch m;
int slen;
for(l = 0; l < lcount; l++){
m.rm_so = 0;
const char *loff = s + lines[l]; /* current line offset */
2015-06-01 15:41:07 +00:00
char *clean = strdup(loff);
int *cpos;
r_str_ansi_filter(clean, NULL, &cpos, 0);
m.rm_eo = slen = strlen(clean);
r_list_purge(mla[l]);
while(!r_regex_exec(rx, clean, 1, &m, R_REGEX_STARTEND)){
RRegexMatch *ms = malloc(sizeof(RRegexMatch));
ms->rm_so = cpos[m.rm_so];
ms->rm_eo = cpos[m.rm_eo];
r_list_append(mla[l], ms);
m.rm_so = m.rm_eo;
m.rm_eo = slen;
f = R_TRUE;
}
2015-06-01 15:41:07 +00:00
free(cpos);
free(clean);
}
return f;
}
R_API void r_cons_less_str(const char *str) {
int lines_count;
2015-02-08 17:42:02 +00:00
RRegex *rx = NULL;
int w, h, ch, to, ui = 1, from = 0, i;
2015-02-09 23:05:18 +00:00
const char *sreg;
2015-05-03 17:14:56 +00:00
if(str == NULL || str[0] == '\0') return;
2015-02-09 23:05:18 +00:00
char *p = strdup (str);
int *lines = splitlines (p, &lines_count);
RList **mla = malloc(lines_count * sizeof(RList *));
for(i = 0; i < lines_count; i++)
mla[i] = r_list_new();
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;
while (ui) {
2015-04-12 12:59:13 +00:00
w = r_cons_get_size (&h);
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;
printpage (p, lines, mla, from, to, w);
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
case 'q': ui = 0; break;
case '\r':
case '\n':
case 'j': from++; break;
case 'J': from+=h; break;
case 'k': if (from>0) from--; break;
2014-03-09 23:53:25 +00:00
case 'K': from = (from>=h)? from-h: 0;
break;
2015-02-08 17:42:02 +00:00
case '/': /* search */
r_cons_reset_colors();
2015-02-08 17:42:02 +00:00
r_line_set_prompt("/");
sreg = r_line_readline();
from = R_MIN(lines_count - 1, from);
/* repeat last search if empty string is provided */
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, "");
} else { /* we got an empty string */
from = next_match(from, mla, lines_count);
break;
2015-02-08 17:42:02 +00:00
}
if(!rx) break;
/* find all occurences */
if(all_matches(p, rx, mla, lines, lines_count))
from = next_match(from, mla, lines_count);
break;
case 'n': /* next match */
/* search already performed */
if(rx) from = next_match(from, mla, lines_count);
break;
case 'p': /* previous match */
if(rx) from = prev_match(from, mla);
break;
}
}
for(i = 0; i < lines_count; i++) r_list_free(mla[i]);
free(mla);
2015-02-08 17:42:02 +00:00
if(rx) r_regex_free(rx);
free (lines);
2014-04-29 22:55:07 +00:00
free (p);
r_cons_reset_colors();
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