sysutils: basic grep-like utility
This commit is contained in:
parent
4a7aa8d831
commit
770021df6a
@ -24,6 +24,8 @@ serde_json.workspace = true
|
|||||||
sha2.workspace = true
|
sha2.workspace = true
|
||||||
chrono.workspace = true
|
chrono.workspace = true
|
||||||
|
|
||||||
|
# Own regex implementation?
|
||||||
|
regex = "1.11.1"
|
||||||
pci-ids = { version = "0.2.5" }
|
pci-ids = { version = "0.2.5" }
|
||||||
|
|
||||||
init = { path = "../init" }
|
init = { path = "../init" }
|
||||||
@ -97,6 +99,10 @@ path = "src/dd.rs"
|
|||||||
name = "view"
|
name = "view"
|
||||||
path = "src/view.rs"
|
path = "src/view.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "grep"
|
||||||
|
path = "src/grep.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "chmod"
|
name = "chmod"
|
||||||
path = "src/chmod.rs"
|
path = "src/chmod.rs"
|
||||||
|
102
userspace/sysutils/src/grep.rs
Normal file
102
userspace/sysutils/src/grep.rs
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
#![feature(seek_stream_len, slice_split_once, slice_internals)]
|
||||||
|
#![allow(internal_features)]
|
||||||
|
use std::{
|
||||||
|
fs::File,
|
||||||
|
io::{self, stdout, Seek, Write},
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
process::ExitCode,
|
||||||
|
};
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
|
use cross::mem::FileMapping;
|
||||||
|
use regex::bytes::Regex;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
enum Error {
|
||||||
|
#[error("{0}")]
|
||||||
|
Io(#[from] io::Error),
|
||||||
|
#[error("Invalid expression: {0}")]
|
||||||
|
Regex(#[from] regex::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Input {
|
||||||
|
fn next_line(&mut self) -> io::Result<Option<&[u8]>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FileInput {
|
||||||
|
mmap: FileMapping,
|
||||||
|
position: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileInput {
|
||||||
|
pub fn open<P: AsRef<Path>>(path: P) -> io::Result<Self> {
|
||||||
|
let mut file = File::open(path)?;
|
||||||
|
let size = file.stream_len()?.try_into().unwrap();
|
||||||
|
// TODO handle non-mmap()able files
|
||||||
|
let mmap = FileMapping::map(file, size)?;
|
||||||
|
Ok(Self { mmap, position: 0 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Input for FileInput {
|
||||||
|
fn next_line(&mut self) -> io::Result<Option<&[u8]>> {
|
||||||
|
if self.position >= self.mmap.len() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(nl) = core::slice::memchr::memchr(b'\n', &self.mmap[self.position..]) {
|
||||||
|
let line = &self.mmap[self.position..self.position + nl];
|
||||||
|
self.position += line.len() + 1;
|
||||||
|
Ok(Some(line))
|
||||||
|
} else {
|
||||||
|
let slice = &self.mmap[self.position..];
|
||||||
|
self.position = self.mmap.len();
|
||||||
|
Ok(Some(slice))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_on<I: Input>(input: &mut I, regex: &Regex) -> io::Result<bool> {
|
||||||
|
let mut any = false;
|
||||||
|
loop {
|
||||||
|
let Some(line) = input.next_line()? else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
if regex.is_match(line) {
|
||||||
|
any = true;
|
||||||
|
stdout().write_all(line).ok();
|
||||||
|
stdout().write_all(b"\n").ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(any)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Parser)]
|
||||||
|
struct Args {
|
||||||
|
expression: String,
|
||||||
|
filename: 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, ®ex)?;
|
||||||
|
Ok(any)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> ExitCode {
|
||||||
|
let args = Args::parse();
|
||||||
|
match run(&args) {
|
||||||
|
Ok(true) => {
|
||||||
|
ExitCode::SUCCESS
|
||||||
|
}
|
||||||
|
Ok(false) => {
|
||||||
|
ExitCode::FAILURE
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
eprintln!("{error}");
|
||||||
|
ExitCode::FAILURE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1 +1,5 @@
|
|||||||
fn main() {}
|
fn main() {
|
||||||
|
for i in 0..8 {
|
||||||
|
println!("\x1B[3{i}mHello\x1B[1molleH\x1B[0m");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -40,6 +40,7 @@ const PROGRAMS: &[(&str, &str)] = &[
|
|||||||
("dd", "bin/dd"),
|
("dd", "bin/dd"),
|
||||||
("random", "bin/random"),
|
("random", "bin/random"),
|
||||||
("view", "bin/view"),
|
("view", "bin/view"),
|
||||||
|
("grep", "bin/grep"),
|
||||||
("chmod", "bin/chmod"),
|
("chmod", "bin/chmod"),
|
||||||
("sha256sum", "bin/sha256sum"),
|
("sha256sum", "bin/sha256sum"),
|
||||||
("sysmon", "bin/sysmon"),
|
("sysmon", "bin/sysmon"),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user