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