1
2use std::fs;
3use std::io;
4use std::io::prelude::*;
5
6use nom::{IResult};
7
8#[derive(Debug)]
10pub enum Error {
11 Io(io::Error),
12 Lex(String, usize, String),
14}
15
16impl From<io::Error> for Error {
17 fn from(e: io::Error) -> Error {
18 Error::Io(e)
19 }
20}
21
22#[derive(Debug)]
23pub enum Token {
24 Header(String),
26 Pair(String, String),
28 Single(String),
30}
31
32named!(parse_header<&str, &str>, do_parse!(
34 tag!("[") >>
35 inner: take_until!("]") >>
36 tag!("]") >>
37 (inner.trim())
38));
39
40named!(parse_key<&str, &str>, do_parse!(
42 key: take_until!("=") >>
43 tag!("=") >>
44 (key.trim())
45));
46
47pub fn lex_ini(filename: &str) -> Result<Vec<Token>, Error> {
53
54 let mut tok_list = Vec::new();
55
56 let config_file = fs::File::open(filename)?;
57 let config_reader = io::BufReader::new(config_file);
58
59
60 for line in config_reader.lines() {
61 let line = line?;
62 let line = line.trim();
63
64 if line.is_empty() || line.starts_with("#") {
65 } else if let IResult::Done(_, name) = parse_header(&line) {
67 tok_list.push(Token::Header(name.into()))
68 } else if let IResult::Done(value, key) = parse_key(&line) {
69 let value = value.trim();
70 if key == "Include" {
71 tok_list.append(&mut lex_ini(value)?);
73 } else {
74 tok_list.push(Token::Pair(key.into(), value.into()));
75 }
76 } else {
77 tok_list.push(Token::Single(line.into()));
78 }
79
80 }
81
82 Ok(tok_list)
83}
84
85#[cfg(test)]
86mod tests {
87 #[test]
88 fn it_works() {
89 }
90}