libalpm_utils/
ini.rs

1
2use std::fs;
3use std::io;
4use std::io::prelude::*;
5
6use nom::{IResult};
7
8/// Library error type
9#[derive(Debug)]
10pub enum Error {
11    Io(io::Error),
12    /// Filename, line number, text
13    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    /// Start of a new section
25    Header(String),
26    /// A key/value pair
27    Pair(String, String),
28    /// A single value without key
29    Single(String),
30}
31
32/// Matches a header line
33named!(parse_header<&str, &str>, do_parse!(
34    tag!("[") >>
35    inner: take_until!("]") >>
36    tag!("]") >>
37    (inner.trim())
38));
39
40/// Matches a key and the '='
41named!(parse_key<&str, &str>, do_parse!(
42    key: take_until!("=") >>
43    tag!("=") >>
44    (key.trim())
45));
46
47///
48/// Lexes a pacman-style INI config file.
49///
50/// Returns a list of tokens. `Include` directives are expanded.
51///
52pub 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            // skip comments
66        } 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                // Then we include the tokens from the filename in value into the token list
72                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}