sysutils: grep for stdin

This commit is contained in:
Mark Poliakov 2025-03-01 23:52:38 +02:00
parent aefa7a93fa
commit de98ae1082

View File

@ -3,7 +3,7 @@
use std::{
fs::File,
io::{self, stdout, Seek, Write},
io::{self, stdout, Seek, Stdin, Write},
path::{Path, PathBuf},
process::ExitCode,
};
@ -29,6 +29,22 @@ struct FileInput {
position: usize,
}
struct StdinInput {
stdin: Stdin,
buffer: String,
eof: bool,
}
impl StdinInput {
pub fn new() -> Self {
Self {
stdin: io::stdin(),
buffer: String::new(),
eof: false,
}
}
}
impl FileInput {
pub fn open<P: AsRef<Path>>(path: P) -> io::Result<Self> {
let mut file = File::open(path)?;
@ -39,6 +55,22 @@ impl FileInput {
}
}
impl Input for StdinInput {
fn next_line(&mut self) -> io::Result<Option<&[u8]>> {
if self.eof {
return Ok(None);
}
self.buffer.clear();
if self.stdin.read_line(&mut self.buffer)? == 0 {
self.eof = true;
return Ok(None);
}
Ok(Some(self.buffer.trim_end_matches('\n').as_bytes()))
}
}
impl Input for FileInput {
fn next_line(&mut self) -> io::Result<Option<&[u8]>> {
if self.position >= self.mmap.len() {
@ -57,7 +89,7 @@ impl Input for FileInput {
}
}
fn run_on<I: Input>(input: &mut I, regex: &Regex) -> io::Result<bool> {
fn run_on<I: Input>(input: &mut I, regex: &Regex) -> Result<bool, Error> {
let mut any = false;
loop {
let Some(line) = input.next_line()? else {
@ -76,14 +108,18 @@ fn run_on<I: Input>(input: &mut I, regex: &Regex) -> io::Result<bool> {
#[derive(Debug, Parser)]
struct Args {
expression: String,
filename: PathBuf,
filename: Option<PathBuf>,
}
fn run(args: &Args) -> Result<bool, Error> {
let regex = Regex::new(&args.expression)?;
let mut input = FileInput::open(&args.filename)?;
let any = run_on(&mut input, &regex)?;
Ok(any)
if let Some(filename) = args.filename.as_deref() {
let mut input = FileInput::open(filename)?;
run_on(&mut input, &regex)
} else {
let mut input = StdinInput::new();
run_on(&mut input, &regex)
}
}
fn main() -> ExitCode {