commit 385d191f276c525758a3c3b01ca93b43f9e2a777 Author: Avril Date: Sun May 31 21:01:08 2020 +0100 arg parse ok diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e2a3069 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +*~ diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..d2df98f --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "leaky-pipe" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..4fe486d --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "leaky-pipe" +version = "0.1.0" +authors = ["Avril "] +edition = "2018" +description = "Pipe a process to muliple output processies" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[features] +default = ["broken-pipe"] + +broken-pipe = [] + +[dependencies] diff --git a/src/arg/mod.rs b/src/arg/mod.rs new file mode 100644 index 0000000..3b2fd94 --- /dev/null +++ b/src/arg/mod.rs @@ -0,0 +1,123 @@ +use std::{ + error, + fmt, +}; + +#[cfg(feature = "broken-pipe")] +pub const BROKEN_PIPE: char = '¦'; + +#[cfg(not(feature = "broken-pipe"))] +pub const BROKEN_PIPE: char = '|'; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ProcessArgs +{ + pub name: String, + pub args: Vec, +} + +mod proc_args; +pub use proc_args::*; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Operation +{ + input: ProcessArgs, + outputs: Vec, + output_to_tty: bool, +} + +#[derive(Clone, Debug)] +pub struct Error(String, String); +impl error::Error for Error{} +impl fmt::Display for Error +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + write!(f, "<{}>: {}", self.1, self.0) + } +} +impl Error +{ + pub fn new(message: T) -> Self + where T: AsRef + { + Self(message.as_ref().to_owned(), program()) + } +} +impl From for Error +where T: AsRef +{ + fn from(input: T) -> Self + { + Self::new(input) + } +} + +impl Operation +{ + pub fn new(input: ProcessArgs) -> Self + { + Self { + input, + outputs: Vec::new(), + output_to_tty: false, + } + } + + pub fn parent(&self) -> &ProcessArgs + { + &self.input + } + pub fn children(&self) -> &Vec + { + &self.outputs + } + + pub fn validate(&self) -> Result<(), String> + { + if !self.output_to_tty && self.outputs.len()<1 { + return Err("Need at least one output.".to_owned()); + } + + self.input.verify().or_else(|err| Err(format!("bad input <{}>: {}", &self.input, err)))?; + + for x in self.outputs.iter() + { + x.verify().or_else(|err| Err(format!("bad output <{}>: {}", &x, err)))?; + } + + Ok(()) + } +} + +pub fn program() -> String +{ + std::env::args().next().unwrap() +} + +pub fn parse() -> Result +{ + let mut iter = std::env::args(); + + let this = iter.next().unwrap(); + let mut not_last = false; + let input = ProcessArgs::parse(&mut iter, &mut not_last).or(Err("Expected at least one input"))?; + + if !not_last { + return Err(Error::new("Need at least one output.")); + } + + let mut output = Operation::new(input); + while let Ok(op) = ProcessArgs::parse(&mut iter, &mut not_last) { + output.outputs.push(op); + } + + if not_last { + output.output_to_tty = true; + } + + output.validate()?; + + Ok(output) +} diff --git a/src/arg/proc_args.rs b/src/arg/proc_args.rs new file mode 100644 index 0000000..3621079 --- /dev/null +++ b/src/arg/proc_args.rs @@ -0,0 +1,36 @@ +use super::*; + +impl ProcessArgs +{ + pub fn parse(string: &mut T, not_last: &mut bool) -> Result + where T: Iterator, + U: AsRef + { + let name = string.next().ok_or("No process name")?.as_ref().to_owned(); + let mut args = Vec::new(); + *not_last = false; + while let Some(arg) = string.next() { + let arg = arg.as_ref(); + let mut chars = arg.chars(); + if let Some(BROKEN_PIPE) = chars.next() { + *not_last = true; + break; + } else { + args.push(arg.to_owned()); + } + } + + Ok(Self{ + name, + args, + }) + } + + pub fn verify(&self) -> Result<(), &'static str> + { + //TODO: Check file path of executable + Ok(()) + } +} + +//TODO: impl fmt::Display for ProcessArgs diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..fb90c0b --- /dev/null +++ b/src/main.rs @@ -0,0 +1,16 @@ +#![allow(unused_variables)] +#![allow(dead_code)] + +use std::{ + error::Error, +}; + +mod arg; + +fn main() -> Result<(), Box> { + let op = arg::parse()?; + + //println!("{:?}", op); yay! + + Ok(()) +}