1use std::io::Read;
2
3pub fn read(mut reader: impl Read) -> (String, bool) {
4 let mut buffer = [0; 1]; let mut change = false;
7 let mut li = Vec::new();
8 let mut line = Vec::new();
9
10 while let Ok(bytes_read) = xerr::ok!(reader.read(&mut buffer)) {
11 if bytes_read == 0 {
12 break;
13 }
14
15 let c = buffer[0];
16 match c {
17 b'\n' => {
18 let t = String::from_utf8_lossy(&line);
19 let trimmed_line = t.trim_end();
20 if trimmed_line.len() != t.len() {
21 change = true;
22 }
23 li.push(trimmed_line.to_owned());
24 line.clear();
25 }
26 b'\r' => {
27 change = true;
28 let t = String::from_utf8_lossy(&line);
29 let trimmed_line = t.trim_end();
30 li.push(trimmed_line.to_owned());
31 line.clear();
32 if let Ok(bytes_read) = xerr::ok!(reader.read(&mut buffer)) {
33 if bytes_read > 0 {
34 let c = buffer[0];
35 if c != b'\n' {
36 if c == b'\r' {
38 li.push("".into());
39 } else {
40 line.push(c);
41 }
42 }
43 }
44 }
45 }
46 b'\0' => {
47 change = true;
49 }
50 _ => {
51 line.push(c);
52 }
53 }
54 }
55
56 if !line.is_empty() {
57 let t = String::from_utf8_lossy(&line);
58 let trimmed_line = t.trim_end();
59 if trimmed_line.len() != t.len() {
60 change = true;
61 }
62 li.push(trimmed_line.to_owned());
63 }
64
65 while let Some(i) = li.last() {
66 if i.is_empty() {
67 change = true;
68 li.pop();
69 } else {
70 break;
71 }
72 }
73
74 let txt = li.join("\n");
75 (txt, change)
76}
77
78#[cfg(feature = "fs")]
79pub fn fp(fp: impl AsRef<std::path::Path>) -> std::io::Result<String> {
80 use std::{
81 fs::File,
82 io::{BufReader, Write},
83 };
84 let file = File::open(&fp)?;
85 let mut reader = BufReader::new(file);
86 let (txt, change) = read(&mut reader);
87 if change {
88 let mut file = File::create(fp)?;
89 file.write_all(txt.as_bytes())?;
90 }
91
92 Ok(txt)
93}
94
95#[cfg(feature = "str")]
96pub fn str(txt: impl AsRef<str>) -> (String, bool) {
97 use std::io::Cursor;
98 let txt = txt.as_ref();
99 read(Cursor::new(txt))
100}