libconfig: implemented config write

Config write and config remove are now implemented.
Config keys are now treated case insensitively, which is consistence to
the filesystem behavior.
BOOT.BIN can be replaced by setting the config key "boot".
pull/71/head
pca006132 2020-10-30 16:11:18 +08:00
parent 22833ef0c6
commit 0efc7a616f
1 changed files with 61 additions and 3 deletions

View File

@ -3,7 +3,7 @@ extern crate alloc;
use core::fmt; use core::fmt;
use alloc::{string::FromUtf8Error, string::String, vec::Vec, rc::Rc}; use alloc::{string::FromUtf8Error, string::String, vec::Vec, rc::Rc};
use core_io::{self as io, BufRead, BufReader, Read}; use core_io::{self as io, BufRead, BufReader, Read, Write, Seek, SeekFrom};
use libboard_zynq::sdio; use libboard_zynq::sdio;
pub mod sd_reader; pub mod sd_reader;
@ -56,9 +56,9 @@ fn parse_config<'a>(
buffer: &mut Vec<u8>, buffer: &mut Vec<u8>,
file: fatfs::File<sd_reader::SdReader>, file: fatfs::File<sd_reader::SdReader>,
) -> Result<'a, ()> { ) -> Result<'a, ()> {
let prefix = [key, "="].concat(); let prefix = [key, "="].concat().to_lowercase();
for line in BufReader::new(file).lines() { for line in BufReader::new(file).lines() {
let line = line?; let line = line?.to_lowercase();
if line.starts_with(&prefix) { if line.starts_with(&prefix) {
buffer.extend(line[prefix.len()..].as_bytes()); buffer.extend(line[prefix.len()..].as_bytes());
return Ok(()); return Ok(());
@ -71,6 +71,8 @@ pub struct Config {
fs: Option<Rc<fatfs::FileSystem<sd_reader::SdReader>>>, fs: Option<Rc<fatfs::FileSystem<sd_reader::SdReader>>>,
} }
const NEWLINE: &[u8] = b"\n";
impl Config { impl Config {
pub fn new() -> Result<'static, Self> { pub fn new() -> Result<'static, Self> {
let sdio = sdio::Sdio::sdio0(true); let sdio = sdio::Sdio::sdio0(true);
@ -112,4 +114,60 @@ impl Config {
pub fn read_str<'b>(&self, key: &'b str) -> Result<'b, String> { pub fn read_str<'b>(&self, key: &'b str) -> Result<'b, String> {
Ok(String::from_utf8(self.read(key)?)?) Ok(String::from_utf8(self.read(key)?)?)
} }
pub fn remove<'b>(&self, key: &'b str) -> Result<'b, ()> {
if let Some(fs) = &self.fs {
let root_dir = fs.root_dir();
match root_dir.remove(&["/CONFIG/", key, ".BIN"].concat()) {
Ok(()) => Ok(()),
Err(_) => {
let prefix = [key, "="].concat().to_lowercase();
match root_dir.create_file("/CONFIG.TXT") {
Ok(mut f) => {
let mut buffer = String::new();
f.read_to_string(&mut buffer)?;
f.seek(SeekFrom::Start(0))?;
f.truncate()?;
for line in buffer.lines() {
if line.len() > 0 && !line.to_lowercase().starts_with(&prefix) {
f.write(line.as_bytes())?;
f.write(NEWLINE)?;
}
}
Ok(())
},
Err(_) => Err(Error::KeyNotFoundError(key))
}
}
}
} else {
Err(Error::NoConfig)
}
}
pub fn write<'b>(&self, key: &'b str, value: Vec<u8>) -> Result<'b, ()> {
if self.fs.is_none() {
return Err(Error::NoConfig);
}
let fs = self.fs.as_ref().unwrap();
let root_dir = fs.root_dir();
let is_str = value.len() <= 100 && value.is_ascii() && !value.contains(&b'\n');
if key == "boot" {
let mut f = root_dir.create_file("/BOOT.BIN")?;
f.truncate()?;
f.write_all(&value)?;
drop(f);
} else {
let _ = self.remove(key);
if is_str {
let mut f = root_dir.create_file("/CONFIG.TXT")?;
f.seek(SeekFrom::End(0))?;
write!(f, "{}={}\n", key, String::from_utf8(value).unwrap())?;
} else {
let mut f = root_dir.create_file(&["/CONFIG/", key, ".BIN"].concat())?;
f.write_all(&value)?;
}
}
Ok(())
}
} }