bash_builtins/variables/
arrays.rs1use std::convert::TryFrom;
4use std::ffi::{c_int, c_void, CStr, CString};
5
6use super::VariableError;
7use crate::ffi::variables as ffi;
8
9pub fn array_set<T>(name: &str, index: usize, value: T) -> Result<(), VariableError>
15where
16 T: AsRef<[u8]>,
17{
18 let name = CString::new(name).map_err(|_| VariableError::InvalidName)?;
19 let value = CString::new(value.as_ref()).map_err(|_| VariableError::InvalidValue)?;
20
21 let res = unsafe {
22 if ffi::legal_identifier(name.as_ptr()) == 0 {
23 return Err(VariableError::InvalidName);
24 }
25
26 ffi::bind_array_variable(name.as_ptr(), index as _, value.as_ptr(), 0)
27 };
28
29 if res.is_null() {
30 Err(VariableError::InvalidValue)
31 } else {
32 Ok(())
33 }
34}
35
36pub fn array_get(name: &str, index: usize) -> Option<CString> {
38 let var = super::find_raw(name)?;
39
40 let mut result = None;
41
42 unsafe {
43 if !var.is_array() {
44 return None;
45 }
46
47 #[repr(C)]
48 struct Data {
49 result: *mut Option<CString>,
50 index: usize,
51 }
52
53 unsafe extern "C" fn collect(elem: *mut ffi::ArrayElement, data: *mut c_void) -> c_int {
54 let data = &mut *data.cast::<Data>();
55
56 if usize::try_from((*elem).ind) == Ok(data.index) {
57 data.result
58 .write(Some(CStr::from_ptr((*elem).value).to_owned()));
59 -1
60 } else {
61 1
62 }
63 }
64
65 let data = Data {
66 result: &mut result,
67 index,
68 };
69
70 ffi::array_walk(
71 (*var.0.as_ptr()).value,
72 collect,
73 &data as *const Data as *const c_void,
74 );
75 }
76
77 result
78}
79
80pub(crate) unsafe fn array_items(shell_var: *const ffi::ShellVar) -> Vec<(i64, CString)> {
81 let array: ffi::ArrayPtr = unsafe { (*shell_var).value.cast() };
82 let mut vec = Vec::new();
83
84 #[repr(C)]
85 struct Data(*mut Vec<(i64, CString)>);
86
87 unsafe extern "C" fn collect(elem: *mut ffi::ArrayElement, data: *mut c_void) -> c_int {
88 let vec = &mut *(*data.cast::<Data>()).0;
89
90 let index = (*elem).ind;
91 let value = CStr::from_ptr((*elem).value).to_owned();
92
93 vec.push((index, value));
94
95 1
96 }
97
98 ffi::array_walk(
99 array,
100 collect,
101 &Data(&mut vec) as *const Data as *const c_void,
102 );
103
104 vec
105}