Skip to content

Commit

Permalink
implement ini parser
Browse files Browse the repository at this point in the history
  • Loading branch information
derdilla committed Jun 30, 2024
1 parent b60e8aa commit 21129c4
Show file tree
Hide file tree
Showing 5 changed files with 551 additions and 2 deletions.
248 changes: 248 additions & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
resolver = "2"

members = [
"dir_size",
]
"dir_size", "ini-conf", "vcs",
]
7 changes: 7 additions & 0 deletions rust/ini-conf/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "ini-conf"
version = "0.1.0"
edition = "2021"

[dependencies]
log = "0.4.22"
110 changes: 110 additions & 0 deletions rust/ini-conf/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
use std::fs;
use std::path::PathBuf;
use log::warn;

pub struct IniFile {
path: PathBuf,
sections: Vec<Section>,
}
impl IniFile {
/// Open an existing file
pub fn open(path: PathBuf) -> Result<Self, IniFileOpenError> {
if path.is_file() {
if let Ok(data) = fs::read_to_string(&path) {
if let Some(sections) = Self::parse(data) {
Ok(IniFile{
path,
sections,
})
} else {
Err(IniFileOpenError::FormatError)
}
} else {
Err(IniFileOpenError::IOError)
}
} else {
Err(IniFileOpenError::IOError)
}
}

fn parse(data: String) -> Option<Vec<Section>> {
let mut sections = Vec::new();
let mut curr_sect: Option<Section> = None;
for token in tokenize(&data) {
match token {
IniToken::Empty => {}
IniToken::Comment(_) => {}
IniToken::SectionHeader(name) => {
if let Some(curr_sect) = curr_sect {
sections.push(curr_sect);
}
curr_sect = Some(Section::new(name));
}
IniToken::KeyValuePair(key, value) => {
if let Some(ref mut curr_sect) = curr_sect {
curr_sect.kv_pairs.push((key, value));
} else {
return None;
}
}
IniToken::Unknown(line) => {
warn!("Unrecognized token: {line}");
}
}
}
Some(sections)
}
}

pub struct Section {
name: String,
pub(crate) kv_pairs: Vec<(String, String)>,
}

impl Section {
pub(crate) fn new(name: String) -> Self {
Section {
name,
kv_pairs: Vec::new(),
}
}
}

pub enum IniFileOpenError {
/// File is doesn't exist, is read protected, ect...
IOError,
/// File is in invalid format.
FormatError,
}


fn tokenize(data: &String) -> Vec<IniToken> {
let mut tokens = Vec::new();
for line in data.lines() {
let line = line.trim();
let t = if line.starts_with(";") || line.starts_with("#") {
IniToken::Comment(line.to_string())
} else if line.starts_with("[") && line.ends_with("]") {
let header = &line[1..(line.len()-1)];
IniToken::SectionHeader(header.to_string())
} else if line.is_empty() {
IniToken::Empty
} else if let Some(kv) = line.split_once("="){
let key= kv.0.trim().to_string();
let value= kv.1.trim().to_string();
IniToken::KeyValuePair(key, value)
} else {
IniToken::Unknown(line.to_string())
};
tokens.push(t);
}
tokens
}

enum IniToken {
Empty,
Comment(String),
SectionHeader(String),
KeyValuePair(String, String),
Unknown(String),
}
Loading

0 comments on commit 21129c4

Please sign in to comment.