radare2/libr/cons/less.c

181 lines
3.8 KiB
C
Raw Normal View History

/* radare2 - LGPL - Copyright 2014-2023 - pancake, Judge_Dredd */
#include <r_cons.h>
2016-06-29 10:33:31 +00:00
#include <r_regex.h>
2015-04-12 12:59:13 +00:00
#include <r_util.h>
#include "pager_private.h"
static const char *r_cons_less_help = \
" u/space - page up/down\n"
" jk - line down/up\n"
" gG - begin/end buffer\n"
" / - search in buffer\n"
" _ - enter the hud mode\n"
" n/p - next/prev search result\n"
" q - quit\n"
" ? - show this help\n"
"\n";
R_API int r_cons_less_str(const char *str, const char *exitkeys) {
2019-06-09 16:50:36 +00:00
r_return_val_if_fail (str && *str, 0);
if (!r_cons_is_interactive ()) {
R_LOG_ERROR ("Internal less requires scr.interactive=true");
return 0;
}
2019-06-09 16:50:36 +00:00
int in_help = false;
2016-01-27 02:14:19 +00:00
int lines_count = 0;
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;
2016-01-27 02:14:19 +00:00
RList **mla;
// rcons kills str after flushing the buffer, so we must keep a copy
char *ostr = strdup (str);
if (!ostr) {
return 0;
}
2015-02-09 23:05:18 +00:00
char *p = strdup (str);
2016-11-02 21:59:32 +00:00
if (!p) {
free (ostr);
2016-11-02 21:59:32 +00:00
return 0;
}
int *lines = pager_splitlines (p, &lines_count);
2016-11-02 21:59:32 +00:00
if (lines_count < 1) {
2016-01-27 02:14:19 +00:00
mla = NULL;
} else {
mla = calloc (lines_count, sizeof (RList *));
2016-05-24 06:03:15 +00:00
if (!mla) {
free (p);
free (ostr);
2016-05-24 06:04:34 +00:00
free (lines);
2016-05-24 06:03:15 +00:00
return 0;
}
2016-01-27 02:14:19 +00:00
}
2016-06-29 10:33:31 +00:00
for (i = 0; i < lines_count; i++) {
2016-01-27 02:14:19 +00:00
mla[i] = r_list_new ();
2016-06-29 10:33:31 +00:00
}
2015-09-14 00:08:31 +00:00
r_cons_set_raw (true);
r_cons_show_cursor (false);
r_cons_reset ();
2018-12-11 09:28:01 +00:00
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);
2016-11-02 21:59:32 +00:00
if (from + 3 > lines_count) {
2016-05-16 00:59:42 +00:00
from = lines_count - 3;
2016-11-02 21:59:32 +00:00
}
if (from < 0) {
from = 0;
}
pager_printpage (p, lines, mla, from, to, w);
ch = r_cons_readchar ();
if (exitkeys && strchr (exitkeys, ch)) {
2015-11-01 04:47:16 +00:00
for (i = 0; i < lines_count; i++) {
2016-01-27 02:14:19 +00:00
r_list_free (mla[i]);
2015-11-01 04:47:16 +00:00
}
free (p);
free (mla);
free (ostr);
free (lines);
return ch;
}
ch = r_cons_arrow_to_hjkl (ch);
switch (ch) {
case '_':
r_cons_hud_string (ostr);
break;
2016-01-14 22:27:09 +00:00
case '?':
if (!in_help) {
in_help = true;
2019-06-09 16:50:36 +00:00
(void)r_cons_less_str (r_cons_less_help, NULL);
2016-01-14 22:27:09 +00:00
in_help = false;
}
break;
case 'u':
from -= h;
2016-11-02 21:59:32 +00:00
if (from < 0) {
from = 0;
}
2016-01-14 22:27:09 +00:00
break;
case ' ': from += h; break;
case 'g': from = 0; break;
case 'G': from = lines_count - h; break;
2015-03-23 15:18:35 +00:00
case -1: // EOF
2018-10-23 09:55:09 +00:00
case '\x03': // ^C
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;
case 'K': from = (from>=h)? from - h: 0;
break;
2015-02-08 17:42:02 +00:00
case '/': /* search */
2016-01-14 22:27:09 +00:00
r_cons_reset_colors ();
r_line_set_prompt ("/");
sreg = r_line_readline ();
from = R_MIN (lines_count - 1, from);
2015-02-08 17:42:02 +00:00
/* repeat last search if empty string is provided */
2016-01-14 22:27:09 +00:00
if (sreg[0]) { /* prepare for a new search */
if (rx) {
r_regex_free (rx);
}
rx = r_regex_new (sreg, "");
} else { /* we got an empty string */
from = pager_next_match (from, mla, lines_count);
break;
2015-02-08 17:42:02 +00:00
}
if (!rx) {
break;
}
2019-06-20 04:45:00 +00:00
/* find all occurrences */
if (pager_all_matches (p, rx, mla, lines, lines_count)) {
from = pager_next_match (from, mla, lines_count);
}
r_cons_set_raw (true);
break;
case 'n': /* next match */
/* search already performed */
2016-06-29 10:33:31 +00:00
if (rx) {
from = pager_next_match (from, mla, lines_count);
2016-06-29 10:33:31 +00:00
}
break;
case 'N':
case 'p': /* previous match */
2016-06-29 10:33:31 +00:00
if (rx) {
from = pager_prev_match (from, mla);
2016-06-29 10:33:31 +00:00
}
break;
}
}
for (i = 0; i < lines_count; i++) {
2016-01-14 22:27:09 +00:00
r_list_free (mla[i]);
}
free (mla);
r_regex_free (rx);
free (lines);
2014-04-29 22:55:07 +00:00
free (p);
r_cons_reset_colors ();
2015-09-14 00:08:31 +00:00
r_cons_set_raw (false);
r_cons_show_cursor (true);
free (ostr);
return 0;
}
2019-06-09 16:50:36 +00:00
R_API void r_cons_less(void) {
(void)r_cons_less_str (r_cons_context ()->buffer, NULL);
}
#if 0
main (int argc, char **argv) {
char *s = r_file_slurp (argv[1], NULL);
r_cons_new ();
r_cons_less (s);
}
#endif