Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow uci get() on a list type to return all the values seperated by … #3

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 57 additions & 14 deletions rust-uci/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,15 @@ pub mod error;
use core::ptr;
use std::{
ffi::{CStr, CString},
fmt::Display,
ops::{Deref, DerefMut},
};

use libuci_sys::{
uci_alloc_context, uci_commit, uci_context, uci_delete, uci_free_context, uci_get_errorstr,
uci_lookup_ptr, uci_option_type_UCI_TYPE_STRING, uci_ptr, uci_ptr_UCI_LOOKUP_COMPLETE,
uci_revert, uci_save, uci_set, uci_set_confdir, uci_set_savedir, uci_type_UCI_TYPE_OPTION,
uci_type_UCI_TYPE_SECTION, uci_unload,
uci_alloc_context, uci_commit, uci_context, uci_delete, uci_element, uci_free_context,
uci_get_errorstr, uci_list, uci_lookup_ptr, uci_option_type_UCI_TYPE_STRING, uci_ptr,
uci_ptr_UCI_LOOKUP_COMPLETE, uci_revert, uci_save, uci_set, uci_set_confdir, uci_set_savedir,
uci_type_UCI_TYPE_OPTION, uci_type_UCI_TYPE_SECTION, uci_unload,
};
use log::debug;

Expand All @@ -71,6 +72,25 @@ const UCI_OK: i32 = libuci_sys::UCI_OK as i32;
/// Contains the native `uci_context`
pub struct Uci(*mut uci_context);

/// A `UciValue` obtained from the get method can be either
/// a simple string value or a list which is implemented as a vector of string values
#[derive(Debug, Clone)]
pub enum UciValue {
String(String),
List(Vec<String>),
}

impl Display for UciValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
UciValue::String(value) => Display::fmt(value, f),
UciValue::List(list) => {
write!(f, "{}", list.join(" "))
}
}
}
}

impl Drop for Uci {
fn drop(&mut self) {
unsafe { uci_free_context(self.0) }
Expand Down Expand Up @@ -298,7 +318,7 @@ impl Uci {
/// Allowed keys are like `network.wan.proto`, `network.@interface[-1].iface`, `network.lan` and `network.@interface[-1]`
///
/// if the entry does not exist an `Err` is returned.
pub fn get(&mut self, key: &str) -> Result<String> {
pub fn get(&mut self, key: &str) -> Result<UciValue> {
let ptr = self.get_ptr(key)?;
if ptr.flags & uci_ptr_UCI_LOOKUP_COMPLETE == 0 {
return Err(Error::Message(format!("Lookup failed: {}", key)));
Expand All @@ -308,12 +328,6 @@ impl Uci {
match last.type_ {
uci_type_UCI_TYPE_OPTION => {
let opt = unsafe { *ptr.o };
if opt.type_ != uci_option_type_UCI_TYPE_STRING {
return Err(Error::Message(format!(
"Cannot get string value of non-string: {} {}",
key, opt.type_
)));
}
if opt.section.is_null() {
return Err(Error::Message(format!("uci section was null: {}", key)));
}
Expand All @@ -322,7 +336,36 @@ impl Uci {
return Err(Error::Message(format!("uci package was null: {}", key)));
}
let pack = unsafe { *sect.package };
let value = unsafe { CStr::from_ptr(opt.v.string).to_str()? };

let mut list_str = String::new();
let value = match opt.type_ {
uci_option_type_UCI_TYPE_STRING => {
let value = unsafe { String::from(CStr::from_ptr(opt.v.string).to_str()?) };
UciValue::String(value)
}
uci_option_type_UCI_TYPE_LIST => {
let mut list = vec![];
let mut elem_ptr = unsafe { opt.v.list.next as *const uci_element };
let list_ptr = unsafe { &(*elem_ptr).list as *const uci_list };
loop {
let list_ptr_next = unsafe { (*elem_ptr).list.next as *const uci_list };
if list_ptr_next == list_ptr {
break;
}
let list_value =
unsafe { String::from(CStr::from_ptr((*elem_ptr).name).to_str()?) };
list.push(list_value);
elem_ptr = unsafe { (*elem_ptr).list.next as *const uci_element };
}
UciValue::List(list)
}
_ => {
return Err(Error::Message(format!(
"Cannot get values of a non-string or a non-list: {} {}",
key, opt.type_
)));
}
};

debug!(
"{}.{}.{}={}",
Expand All @@ -331,7 +374,7 @@ impl Uci {
unsafe { CStr::from_ptr(opt.e.name) }.to_str()?,
value
);
Ok(String::from(value))
Ok(value)
}
uci_type_UCI_TYPE_SECTION => {
let sect = unsafe { *ptr.s };
Expand All @@ -347,7 +390,7 @@ impl Uci {
unsafe { CStr::from_ptr(sect.e.name) }.to_str()?,
typ
);
Ok(String::from(typ))
Ok(UciValue::String(String::from(typ)))
}
_ => return Err(Error::Message(format!("unsupported type: {}", last.type_))),
}
Expand Down