diff options
author | Yorhel <git@yorhel.nl> | 2016-09-02 19:10:46 +0200 |
---|---|---|
committer | Yorhel <git@yorhel.nl> | 2016-09-02 19:10:46 +0200 |
commit | 39eb2ac55f5b8f4192064f1c05e6c77b8ca11eaa (patch) | |
tree | 04798e75286d6c6167f34f23f73728910d2ccd9b |
Initial commit. Mostly learning Rust
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Cargo.lock | 129 | ||||
-rw-r--r-- | Cargo.toml | 10 | ||||
-rw-r--r-- | src/config.rs | 131 | ||||
-rw-r--r-- | src/main.rs | 68 |
5 files changed, 340 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c6262ea --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +target +*.swp diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..728b178 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,129 @@ +[root] +name = "webs" +version = "0.1.0" +dependencies = [ + "env_logger 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "nom 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "aho-corasick" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "env_logger" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "getopts" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "log" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memchr" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "nom" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "regex" +version = "0.1.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "thread-id" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "utf8-ranges" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b3fb52b09c1710b961acb35390d514be82e4ac96a9969a8e38565a29b878dc9" +"checksum env_logger 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "82dcb9ceed3868a03b335657b85a159736c961900f7e7747d3b0b97b9ccb5ccb" +"checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "23e3757828fa702a20072c37ff47938e9dd331b92fac6e223d26d4b7a55f7ee2" +"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054" +"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" +"checksum nom 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce" +"checksum regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)" = "56b7ee9f764ecf412c6e2fff779bca4b22980517ae335a21aeaf4e32625a5df2" +"checksum regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "31040aad7470ad9d8c46302dcffba337bb4289ca5da2e3cd6e37b64109a85199" +"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" +"checksum thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "55dd963dbaeadc08aa7266bf7f91c3154a7805e32bb94b820b769d2ef3b4744d" +"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" +"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..9a6c76d --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "webs" +version = "0.1.0" +authors = ["Yorhel <git@yorhel.nl>"] + +[dependencies] +log = "0.*" +env_logger = "0.*" +getopts = "0.2" +nom = "1.2" diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..7d01c77 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,131 @@ +use std; +use nom; +use std::str; +use std::net::SocketAddr; +use nom::{IResult,Input,Consumer,ConsumerState,Move,Producer,HexDisplay}; +use nom::{alphanumeric,space,multispace,line_ending,not_line_ending}; + +#[derive(Debug,Clone)] +pub struct Interface { + addr: Vec<SocketAddr> +} + +#[derive(Debug,Clone)] +pub struct Config { + itf: Vec<Interface> +} + + +#[derive(Debug)] +pub enum Err { + Io(std::io::Error), + Parse(()) // TODO: error info +} + + +#[derive(Debug,PartialEq,Eq)] +enum Expr<'a> { + Keyval(&'a str,&'a str), + Interface(&'a str), + Close, + Comment +} + +enum ParseState { + Root, + Interface +} + +named!(one_multispace, value!(b" ", one_of!(" \t\r\n"))); + +named!(keyval<&[u8],Expr>, chain!( + key: map_res!(alphanumeric, std::str::from_utf8) ~ + space ~ + val: map_res!(not_line_ending, std::str::from_utf8) ~ + line_ending, + ||{ Expr::Keyval(key, val.trim()) } +)); + +named!(expr<&[u8],Expr>, + // The switch!() macro doesn't support wildcard, so put keyval in an alt!() + alt!( + switch!(peek!(alt!(tag!("#") | tag!("}") | one_multispace)), + b" " => value!(Expr::Comment, multispace) | + b"#" => value!(Expr::Comment, delimited!(tag!("#"), not_line_ending, line_ending)) | + b"}" => value!(Expr::Close, take!(1)) + ) | keyval + ) +); + + +struct ConfigConsumer { + c_state: ConsumerState<(), (), nom::Move>, + state: ParseState, + cfg: Config +} + + +impl<'a> Consumer<&'a[u8], (), (), nom::Move> for ConfigConsumer { + fn handle(&mut self, input: Input<&[u8]>) -> &ConsumerState<(), (), nom::Move> { + match input { + Input::Eof(None) => { self.c_state = ConsumerState::Done(Move::Consume(0), ()); }, + Input::Empty => { self.c_state = ConsumerState::Continue(Move::Consume(0)); }, + Input::Element(x) | Input::Eof(Some(x)) => { + match expr(x) { + IResult::Done(i, e) => { + println!("{:?}", e); + // TODO: Pass to state handler (if not comment) + self.c_state = ConsumerState::Continue(Move::Consume(x.offset(i))); + }, + IResult::Error(_) => { self.c_state = ConsumerState::Error(()); }, + IResult::Incomplete(i) => { self.c_state = ConsumerState::Continue(Move::Await(i)); } + } + } + } + &self.c_state + } + + fn state(&self) -> &ConsumerState<(), (), nom::Move> { + &self.c_state + } +} + + +impl Config { + fn new() -> Config { + Config { + itf: Vec::new() + } + } + + pub fn parse(file: &str) -> Result<Config, Err> { + let mut p = try!(nom::FileProducer::new(file, 4096).map_err(Err::Io)); + let mut c = ConfigConsumer{ + state: ParseState::Root, + c_state: ConsumerState::Continue(Move::Consume(0)), + cfg: Config::new() + }; + loop { + match *p.apply(&mut c) { + ConsumerState::Done(_, x) => { return Ok(c.cfg) } + ConsumerState::Error(e) => { return Result::Err(Err::Parse(e)) } + ConsumerState::Continue(_) => {} + } + } + } +} + + +#[test] +fn parse_expr() { + let x = |e| { IResult::Done(&b"x"[..], e) }; + assert_eq!(expr(b" \r\n\tx"), x(Expr::Comment)); + assert_eq!(expr(b"\nx"), x(Expr::Comment)); + assert_eq!(expr(b"#\nx"), x(Expr::Comment)); + assert_eq!(expr(b"##/!@$% \nx"), x(Expr::Comment)); + assert_eq!(expr(b"}x"), x(Expr::Close)); + assert_eq!(expr(b"key val\nx"), x(Expr::Keyval("key", "val"))); + assert_eq!(expr(b"ke\t v a \nx"), x(Expr::Keyval("ke", "v a"))); + assert_eq!(expr(b""), IResult::Incomplete(nom::Needed::Size(1))); + assert_eq!(expr(b"something"), IResult::Error(nom::Err::Position(nom::ErrorKind::Alt, &b"something"[..]))); +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..215670d --- /dev/null +++ b/src/main.rs @@ -0,0 +1,68 @@ +// I'm playing around. Let me. +#![allow(dead_code)] +#![allow(unused_variables)] +#![allow(unused_mut)] +#![allow(unused_imports)] + +#[macro_use] extern crate nom; +#[macro_use] extern crate log; +extern crate env_logger; +extern crate getopts; + + +use std::process::exit; +use std::io::prelude::*; + +mod config; + + +struct CliOpts { + config: String, +} + +impl CliOpts { + fn new() -> CliOpts { + CliOpts { + config: "/etc/webs.conf".to_string() + } + } + + fn parse(mut self) -> CliOpts { + let mut args = std::env::args(); + let prog = args.next().unwrap(); + + let mut opts = getopts::Options::new(); + opts.optflag("h", "help", "print this help menu"); + opts.optflag("V", "version", "show program version"); + opts.optopt("c", "config", "config file", "FILE"); + + let m = match opts.parse(args) { + Ok(m) => { m } + Err(e) => { + let _ = writeln!(std::io::stderr(), "{}", e); + exit(1); + } + }; + if m.opt_present("h") { + let _ = println!("{}", opts.usage(&prog)); + exit(0); + } + if m.opt_present("V") { + let _ = println!("{} {}", prog, option_env!("CARGO_PKG_VERSION").unwrap_or("")); + exit(0); + } + if let Some(f) = m.opt_str("c") { + self.config = f; + } + + self + } +} + + +fn main() { + let opts = CliOpts::new().parse(); + let conf = config::Config::parse(&opts.config); + println!("{:?}", conf); + env_logger::init().unwrap(); +} |