1use std::fs::{File};
29use std::io::{Read, Seek, SeekFrom};
30use std::io::{BufRead, BufReader};
31
32pub const BLOCK_SIZE: u64 = 1 << 16;
33pub struct ReverseChunks<'a> {
34 file: &'a File,
35 size: u64,
36 max_blocks_to_read: usize,
37 block_idx: usize,
38}
39
40impl<'a> ReverseChunks<'a> {
41 pub fn new(file: &'a mut File) -> ReverseChunks<'a> {
42 let size = file.seek(SeekFrom::End(0)).unwrap();
43 let max_blocks_to_read = (size as f64 / BLOCK_SIZE as f64).ceil() as usize;
44 let block_idx = 0;
45 ReverseChunks {
46 file,
47 size,
48 max_blocks_to_read,
49 block_idx,
50 }
51 }
52}
53
54impl<'a> Iterator for ReverseChunks<'a> {
55 type Item = Vec<u8>;
56
57 fn next(&mut self) -> Option<Self::Item> {
58 if self.block_idx >= self.max_blocks_to_read {
59 return None;
60 }
61 let block_size = if self.block_idx == self.max_blocks_to_read - 1 {
62 self.size % BLOCK_SIZE
63 } else {
64 BLOCK_SIZE
65 };
66 let mut buf = vec![0; BLOCK_SIZE as usize];
67 let pos = self
68 .file
69 .seek(SeekFrom::Current(-(block_size as i64)))
70 .unwrap();
71 self.file
72 .read_exact(&mut buf[0..(block_size as usize)])
73 .unwrap();
74 let pos2 = self
75 .file
76 .seek(SeekFrom::Current(-(block_size as i64)))
77 .unwrap();
78 assert_eq!(pos, pos2);
79
80 self.block_idx += 1;
81
82 Some(buf[0..(block_size as usize)].to_vec())
83 }
84}
85
86pub fn backward(file: &mut File, num_delimiters: u64, delimiter: u8) {
87 let mut counter = 0;
88 for (block_idx, slice) in ReverseChunks::new(file).enumerate() {
89 let mut iter = slice.iter().enumerate().rev();
90 if block_idx == 0 {
91 if let Some(c) = slice.last() {
92 if *c == delimiter {
93 iter.next();
94 }
95 }
96 }
97 for (i, ch) in iter {
98 if *ch == delimiter {
99 counter += 1;
100 if counter >= num_delimiters {
101 file.seek(SeekFrom::Current((i + 1) as i64)).unwrap();
102 return;
103 }
104 }
105 }
106 }
107}
108
109pub fn extract_from_line(line: &str, begin_delimiter: &str, end_delimiter: &str) -> String {
111 let mut value = line;
112 if begin_delimiter.is_empty() == true && end_delimiter.is_empty() == true {
113 value = line;
114 }
115 if begin_delimiter.is_empty() == false && end_delimiter.is_empty() == false {
116 value = line
117 .split(begin_delimiter)
118 .nth(1)
119 .unwrap()
120 .split(end_delimiter)
121 .next()
122 .unwrap();
123 }
124 return value.to_string();
125}
126
127
128pub fn parse_line(line: &str, begin_delimiter: &str, end_delimiter: &str)-> String {
130 let r = extract_from_line(line, begin_delimiter, end_delimiter);
131 return r;
132}
133
134pub fn count_lines(path: &str) -> u64 {
136 let file = BufReader::new(File::open(path).expect("Unable to open file"));
137 let mut cnt = 0;
138
139 for _ in file.lines() {
140 cnt = cnt + 1;
141 }
142
143 return cnt;
144}
145
146pub fn match_lines(matchers: &[&str], line: &str) -> bool {
148 for m in matchers {
149 if line.contains(m){
150 return true;
151 }
152 }
153 return false;
154}
155
156pub fn extract_lines(lines: String, begin_delimiter: &str, end_delimiter: &str, search: &str, ignore: &str) -> Vec<String> {
158 let mut parsed_lines = Vec::new();
159 let search_lines: Vec<&str> = search
161 .split(",")
162 .map(|s| s.trim())
163 .filter(|s| !s.is_empty())
164 .collect::<Vec<_>>();
165 let ignore_lines: Vec<&str> = ignore
166 .split(",")
167 .map(|s| s.trim())
168 .filter(|s| !s.is_empty())
169 .collect::<Vec<_>>();
170 for line in lines.split("\n") {
172 if ignore != "" {
173 if match_lines(&ignore_lines, line) {
174 continue;
175 }
176 }
177 if match_lines(&search_lines, line) {
179 let parsed_line = extract_from_line(line, begin_delimiter, end_delimiter);
180 if !parsed_line.is_empty() {
182 let result_line;
183 let trim_line = parsed_line.trim();
184 if trim_line.len() < parsed_line.len() {
185 result_line = trim_line.to_string();
186 }
187 else{
188 result_line = parsed_line;
189 }
190 parsed_lines.push(result_line);
191 }
192 }
193 }
194 return parsed_lines;
195}
196
197
198pub fn fsearch(filename: &str, search: &str, ignore: &str, ignore_mode: bool, number_of_lines: u64) -> Vec<String> {
199 let mut n = number_of_lines;
200 if n == 0 {
202 n = count_lines(filename);
203 }
204 let r;
205 let mut contents = File::open(&filename)
206 .expect("Something went wrong reading the file");
207 if ignore_mode {
208 r = tail_parse(&mut contents, n, "", "", search, ignore);
209 }
210 else{
211 r = tail_parse(&mut contents, n, "", "", search, "");
212 }
213 return r;
214}
215
216pub fn fsearch_last_line(filename: &str, search: &str, ignore: &str, ignore_mode: bool) -> Vec<String> {
217 let mut counter = 0u64;
218 let mut search_found;
219 loop {
220 counter += 1;
221 if ignore_mode {
222 search_found = fsearch(filename, search, ignore, true, counter);
223 }
224 else{
225 search_found = fsearch(filename, search, "", false, counter);
226 }
227 if !search_found.is_empty() {
228 break;
229 }
230 }
231 return search_found;
232}
233
234
235pub fn search_last_line(filename: &str, search: &str) -> Vec<String> {
236 let r = fsearch_last_line(filename, search, "", false);
237 return r;
238}
239
240
241pub fn isearch_last_line(filename: &str, search: &str, ignore: &str) -> Vec<String> {
242 let r = fsearch_last_line(filename, search, ignore, true);
243 return r;
244}
245
246
247pub fn search_lines(filename: &str, search: &str, number_of_lines: u64) -> Vec<String> {
248 let r = fsearch(filename, search, "", false, number_of_lines);
249 return r;
250}
251
252
253pub fn search_all(filename: &str, search: &str) -> Vec<String> {
254 let r = fsearch(filename, search, "", false, 0);
255 return r;
256}
257
258
259pub fn isearch_all(filename: &str, search: &str, ignore: &str) -> Vec<String> {
260 let ignore_mode = true;
261 let r = fsearch(filename, search, ignore, ignore_mode, 0);
262 return r;
263}
264
265
266pub fn isearch_lines(filename: &str, search: &str, ignore: &str, number_of_lines: u64) -> Vec<String> {
267 let ignore_mode = true;
268 let r = fsearch(filename, search, ignore, ignore_mode, number_of_lines);
269 return r;
270}
271
272pub fn tail_parse(file: &mut File, lines_number: u64, begin_delimiter: &str, end_delimiter: &str, search: &str, ignore: &str) -> Vec<String> {
273 let delimiter = b'\n';
275 backward(file, lines_number, delimiter);
276 let mut lines = String::new();
277 file.read_to_string(&mut lines).expect("The string cannot be read");
278 let vec = extract_lines(lines, begin_delimiter, end_delimiter, search, ignore);
279 return vec;
280}
281
282
283 pub fn lines(filename: &str, number_of_lines: u64) -> Vec<String> {
284 let mut n = number_of_lines;
285 if n == 0 {
287 n = count_lines(filename);
288 }
289 let mut contents = File::open(&filename)
290 .expect("Something went wrong reading the file");
291 let r = tail_parse(&mut contents, n, "", "", "", "");
292 return r;
293}
294