1 /* radare2 - LGPL - Copyright 2019 - pancake */
2 
3 #include <r_regex.h>
4 #include <r_util.h>
5 #include <r_cons.h>
6 #include "pager_private.h"
7 
pager_color_line(const char * line,RStrpool * p,RList * ml)8 R_IPI void pager_color_line(const char *line, RStrpool *p, RList *ml) {
9 	int m_len, offset = 0;
10 	char *m_addr;
11 	RListIter *it;
12 	RRegexMatch *m;
13 	char *inv[2] = {
14 		R_CONS_INVERT (true, true),
15 		R_CONS_INVERT (false, true)
16 	};
17 	int linv[2] = {
18 		strlen (inv[0]),
19 		strlen (inv[1])
20 	};
21 	r_strpool_empty (p);
22 	r_list_foreach (ml, it, m) {
23 		/* highlight a match */
24 		r_strpool_memcat (p, line + offset, m->rm_so - offset);
25 		r_strpool_memcat (p, inv[0], linv[0]);
26 		m_len = m->rm_eo - m->rm_so;
27 		if (m_len < 0) {
28 			m_len = 0;
29 		}
30 		m_addr = r_str_ndup (line + m->rm_so, m_len);
31 		if (m_addr) {
32 			/* in case there's a CSI in the middle of this match*/
33 			m_len = r_str_ansi_filter (m_addr, NULL, NULL, m_len);
34 			if (m_len < 0) {
35 				m_len = 0;
36 			}
37 			r_strpool_memcat (p, m_addr, m_len);
38 			r_strpool_memcat (p, inv[1], linv[1]);
39 			offset = m->rm_eo;
40 			free (m_addr);
41 		}
42 
43 	}
44 	/* append final part of string w/o matches */
45 	r_strpool_append (p, line + offset);
46 }
47 
pager_printpage(const char * line,int * index,RList ** mla,int from,int to,int w)48 R_IPI void pager_printpage(const char *line, int *index, RList **mla, int from, int to, int w) {
49 	int i;
50 
51 	r_cons_clear00 ();
52 	if (from < 0 || to < 0) {
53 		return;
54 	}
55 
56 	RStrpool *p = r_strpool_new (0);
57 	if (!p) {
58 		return;
59 	}
60 	for (i = from; i < to; i++) {
61 		pager_color_line (line + index[i], p, mla[i]);
62 		r_strpool_ansi_chop (p, w);
63 		r_cons_reset_colors ();
64 		if (i + 1 == to) {
65 			r_cons_print (p->str);
66 		} else {
67 			r_cons_println (p->str);
68 		}
69 	}
70 	r_strpool_free (p);
71 	r_cons_flush ();
72 }
73 
pager_next_match(int from,RList ** mla,int lcount)74 R_IPI int pager_next_match(int from, RList **mla, int lcount) {
75 	int l;
76 	if (from > lcount - 2) {
77 		return from;
78 	}
79 	for (l = from + 1; l < lcount; l++){
80 		/* if there's at least one match on the line */
81 		if (r_list_first (mla[l])) {
82 			return l;
83 		}
84 	}
85 	return from;
86 }
87 
pager_prev_match(int from,RList ** mla)88 R_IPI int pager_prev_match(int from, RList **mla) {
89 	int l;
90 	if (from < 1) {
91 		return from;
92 	}
93 	for (l = from - 1; l > 0; l--) {
94 		if (r_list_first (mla[l])) {
95 			return l;
96 		}
97 	}
98 	return from;
99 }
100 
pager_all_matches(const char * s,RRegex * rx,RList ** mla,int * lines,int lcount)101 R_IPI bool pager_all_matches(const char *s, RRegex *rx, RList **mla, int *lines, int lcount) {
102 	bool res = false;
103 	RRegexMatch m = {0};
104 	int l, slen;
105 	for (l = 0; l < lcount; l++) {
106 		m.rm_so = 0;
107 		const char *loff = s + lines[l]; /* current line offset */
108 		char *clean = strdup (loff);
109 		if (!clean) {
110 			return false;
111 		}
112 		int *cpos = NULL;
113 		int ncpos = r_str_ansi_filter (clean, NULL, &cpos, -1);
114 		m.rm_eo = slen = strlen (clean);
115 		r_list_purge (mla[l]);
116 		while (!r_regex_exec (rx, clean, 1, &m, R_REGEX_STARTEND)) {
117 			if (!cpos || m.rm_so >= ncpos) {
118 				break;
119 			}
120 			RRegexMatch *ms = R_NEW0 (RRegexMatch);
121 			if (ms && cpos) {
122 				ms->rm_so = cpos[m.rm_so];
123 				ms->rm_eo = cpos[m.rm_eo];
124 				r_list_append (mla[l], ms);
125 			}
126 			m.rm_so = m.rm_eo;
127 			m.rm_eo = slen;
128 			res = true;
129 		}
130 		free (cpos);
131 		free (clean);
132 	}
133 	return res;
134 }
135 
pager_splitlines(char * s,int * lines_count)136 R_IPI int *pager_splitlines(char *s, int *lines_count) {
137 	int lines_size = 128;
138 	int *lines = NULL;
139 	int i, row = 0;
140 	int sidx = 0;
141 
142 	if (lines_size * sizeof (int) < lines_size) {
143 		return NULL;
144 	}
145 	lines = malloc (lines_size * sizeof (int));
146 	if (lines) {
147 		lines[row++] = 0;
148 		for (i = 0; s[i]; i++) {
149 			if (row >= lines_size) {
150 				int *tmp;
151 				lines_size += 128;
152 				if (lines_size * sizeof (int) < lines_size) {
153 					free (lines);
154 					return NULL;
155 				}
156 				tmp = realloc (lines, lines_size * sizeof (int));
157 				if (!tmp) {
158 					free (lines);
159 					return NULL;
160 				}
161 				lines = tmp;
162 			}
163 			if (s[i] == '\n') {
164 				s[i] = 0;
165 				lines[row++] = i + 1;
166 			}
167 			sidx++;
168 		}
169 		*lines_count = row;
170 	}
171 	return lines;
172 }
173