1use crate::Result;
2use log::{debug, error, warn};
3use std::{io::{self, BufRead, Read, Write}, process::Stdio};
4
5pub fn read_to_chunks<R: Read>(reader: R, delim: char) -> std::io::Split<std::io::BufReader<R>> {
6 io::BufReader::new(reader).split(delim as u8)
7}
8
9pub fn map_chunks<const INVALID_FAIL: bool>(iter: impl Iterator<Item = std::io::Result<Vec<u8>>>, mut f: impl FnMut(String) -> Result<()>)
12{
13 for (i, chunk_result) in iter.enumerate() {
14 if i == u32::MAX as usize {
15 warn!("Reached maximum segment limit, stopping input read");
16 break;
17 }
18
19 let chunk = match chunk_result {
20 Ok(bytes) => bytes,
21 Err(e) => {
22 error!("Error reading from stdin: {e}");
23 break;
24 }
25 };
26
27 match String::from_utf8(chunk) {
28 Ok(s) => {
29 debug!("Read: {s}");
30 if f(s).is_err() {
31 break;
32 }
33 }
34 Err(e) => {
35 error!("Invalid UTF-8 in stdin at byte {}: {}", e.utf8_error().valid_up_to(), e);
36 if INVALID_FAIL {
38 break
39 } else {
40 continue
41 }
42 }
43 }
44 }
45}
46
47pub fn map_reader_lines<const INVALID_FAIL: bool>(reader: impl Read, mut f: impl FnMut(String) -> Result<()>) {
48 let buf_reader = io::BufReader::new(reader);
49
50 for (i, line) in buf_reader.lines().enumerate() {
51 if i == u32::MAX as usize {
52 eprintln!("Reached maximum line limit, stopping input read");
53 break;
54 }
55 match line {
56 Ok(l) => {
57 if f(l).is_err() {
58 break;
59 }
60 }
61 Err(e) => {
62 eprintln!("Error reading line: {}", e);
63 if INVALID_FAIL {
64 break
65 } else {
66 continue
67 }
68 }
69 }
70 }
71}
72
73pub fn tty_or_null() -> Stdio {
74 if let Ok(mut tty) = std::fs::File::open("/dev/tty") {
75 let _ = tty.flush(); Stdio::from(tty)
77 } else {
78 error!("Failed to open /dev/tty");
79 Stdio::inherit()
80 }
81}