1 /* radare2 - LGPL - Copyright 2008-2019 - pancake */
2
3 #include <r_cons.h>
4 #include <r_regex.h>
5 #include <r_util.h>
6 #include "pager_private.h"
7
r_cons_more_str(const char * str,const char * exitkeys)8 R_API int r_cons_more_str(const char *str, const char *exitkeys) {
9 static bool inHelp = false;
10 static const char *r_cons_more_help = \
11 " space - page up\n"
12 " j - line down\n"
13 " / - search in buffer\n"
14 " _ - enter the hud mode\n"
15 " n - next search result\n"
16 " q - quit\n"
17 " ? - show this help\n"
18 "\n";
19 int lines_count = 0;
20 RRegex *rx = NULL;
21 int w, h, ch, to, ui = 1, from = 0, i;
22 const char *sreg;
23 RList **mla;
24
25 if (!str || !*str) {
26 return 0;
27 }
28 // rcons kills str after flushing the buffer, so we must keep a copy
29 char *ostr = strdup (str);
30 if (!ostr) {
31 return 0;
32 }
33 char *p = strdup (str);
34 if (!p) {
35 free (ostr);
36 return 0;
37 }
38 int *lines = pager_splitlines (p, &lines_count);
39 if (lines_count < 1) {
40 mla = NULL;
41 } else {
42 mla = calloc (lines_count, sizeof (RList *));
43 if (!mla) {
44 free (p);
45 free (ostr);
46 free (lines);
47 return 0;
48 }
49 }
50 for (i = 0; i < lines_count; i++) {
51 mla[i] = r_list_new ();
52 }
53 r_cons_set_raw (true);
54 r_cons_show_cursor (false);
55 r_cons_reset ();
56 h = 0;
57 while (ui) {
58 w = r_cons_get_size (&h);
59 to = R_MIN (lines_count, from + h);
60 if (from + 3 > lines_count) {
61 from = lines_count - 3;
62 }
63 if (from < 0) {
64 from = 0;
65 }
66 pager_printpage (p, lines, mla, from, to, w);
67 ch = r_cons_readchar ();
68 if (exitkeys && strchr (exitkeys, ch)) {
69 for (i = 0; i < lines_count; i++) {
70 r_list_free (mla[i]);
71 }
72 free (p);
73 free (mla);
74 free (ostr);
75 free (lines);
76 return ch;
77 }
78 ch = r_cons_arrow_to_hjkl (ch);
79 switch (ch) {
80 case '_':
81 r_cons_hud_string (ostr);
82 break;
83 case '?':
84 if (!inHelp) {
85 inHelp = true;
86 r_cons_more_str (r_cons_more_help, NULL);
87 inHelp = false;
88 }
89 break;
90 case ' ': from += h; break;
91 case -1: // EOF
92 case '\x03': // ^C
93 case 'q': ui = 0; break;
94 case '\r':
95 case '\n':
96 case 'j': from++; break;
97 case 'J': from+=h; break;
98 case '/': /* search */
99 r_cons_reset_colors ();
100 r_line_set_prompt ("/");
101 sreg = r_line_readline ();
102 from = R_MIN (lines_count - 1, from);
103 /* repeat last search if empty string is provided */
104 if (sreg[0]) { /* prepare for a new search */
105 if (rx) {
106 r_regex_free (rx);
107 }
108 rx = r_regex_new (sreg, "");
109 } else { /* we got an empty string */
110 from = pager_next_match (from, mla, lines_count);
111 break;
112 }
113 if (!rx) {
114 break;
115 }
116 /* find all occurrences */
117 if (pager_all_matches (p, rx, mla, lines, lines_count)) {
118 from = pager_next_match (from, mla, lines_count);
119 }
120 break;
121 case 'n': /* next match */
122 /* search already performed */
123 if (rx) {
124 from = pager_next_match (from, mla, lines_count);
125 }
126 break;
127 }
128 }
129 for (i = 0; i < lines_count; i++) {
130 r_list_free (mla[i]);
131 }
132 free (mla);
133 r_regex_free (rx);
134 free (lines);
135 free (p);
136 r_cons_reset_colors ();
137 r_cons_set_raw (false);
138 r_cons_show_cursor (true);
139 free (ostr);
140 return 0;
141 }
142
r_cons_more(void)143 R_API void r_cons_more(void) {
144 (void)r_cons_more_str (r_cons_singleton ()->context->buffer, NULL);
145 }
146