Skip to content

Instantly share code, notes, and snippets.

@Profpatsch
Last active May 15, 2020 22:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Profpatsch/fe6616f64c8ceda879d1846c65648613 to your computer and use it in GitHub Desktop.
Save Profpatsch/fe6616f64c8ceda879d1846c65648613 to your computer and use it in GitHub Desktop.
el_subsitute wrapper
extern crate errno;
extern crate libc;
extern crate ascii;
use std::ffi::{CStr, CString};
use ascii::AsciiStr;
#[repr(C)]
pub struct Stralloc_C {
s: *mut libc::c_char,
len: libc::size_t,
a: libc::size_t
}
fn stralloc_zero() -> Stralloc_C {
Stralloc_C {
s: std::ptr::null_mut(),
len: 0,
a: 0
}
}
#[link(name = "skarnet")]
extern "C" {
fn stralloc_free(sa: *mut Stralloc_C);
fn stralloc_ready_tuned(
sa: *mut Stralloc_C,
n: libc::size_t,
base: libc::size_t,
a: libc::size_t,
b: libc::size_t,
) -> libc::c_int;
fn stralloc_catb(
sa: *mut Stralloc_C,
s: *const libc::c_char,
len: libc::size_t
) -> libc::c_int;
fn stralloc_copyb(
sa: *mut Stralloc_C,
s: *const libc::c_char,
len: libc::size_t
) -> libc::c_int;
}
fn stralloc_ready(sa: *mut Stralloc_C, n: libc::size_t) {
unsafe {
if (stralloc_ready_tuned(sa, n, 8, 1, 8) == 0) {
panic!("{}", errno::errno());
}
}
}
struct Stralloc(Stralloc_C);
impl Stralloc {
fn new() -> Self {
let mut sa = stralloc_zero();
unsafe {
stralloc_ready(&mut sa, 0);
}
Stralloc(sa)
}
}
impl AsMut<Stralloc_C> for Stralloc {
fn as_mut(&mut self) -> &mut Stralloc_C {
match self {
Stralloc(s) => s
}
}
}
impl AsRef<Stralloc_C> for Stralloc {
fn as_ref(&self) -> &Stralloc_C {
match self {
Stralloc(s) => s
}
}
}
impl<'a> From<&mut [u8]> for Stralloc {
fn from(s: &mut [u8]) -> Self {
let mut sa = stralloc_zero();
let ptr = s.as_mut_ptr() as *mut libc::c_char;
unsafe {
if stralloc_copyb(&mut sa, ptr, s.len()) == 0 {
panic!("{}", errno::errno());
}
}
Stralloc(sa)
}
}
// TODO not sure if stralloc will always be a contiguous block?
// that’s the precondition for from_raw_parts
impl AsRef<[u8]> for Stralloc_C {
fn as_ref(&self) -> &[u8] {
let ptr = self.s as *const u8;
unsafe {
std::slice::from_raw_parts(ptr, self.len)
}
}
}
impl Drop for Stralloc {
fn drop(&mut self) {
match self {
Stralloc(inner) => {
unsafe {
stralloc_free(inner);
}
}
}
}
}
#[repr(C)]
#[derive(Debug)]
pub struct Elsubst_C
{
var: libc::size_t,
value: libc::size_t,
// values are \0-separated strings,
// and n is the amount of elements in one such string
n: libc::c_uint
}
#[link(name = "execline")]
extern "C" {
fn el_substitute(
dst: *mut Stralloc_C,
src: *const libc::c_char,
len: libc::size_t,
// length is given by nsubst
vars: *const libc::c_char,
// length is given by nsubst
values: *const libc::c_char,
substs: *const Elsubst_C,
nsubst: libc::size_t
) -> libc::c_int;
}
struct Subst<'a> {
var: &'a CStr,
value: &'a CStr,
}
fn simple_substitute<'a, 'b>(subst: &[Subst<'a>], src: &CStr) -> CString {
let len = src.to_bytes_with_nul().len() as libc::size_t;
let src = src.as_ptr() as *const libc::c_char;
let mut vars : Vec<u8> = Vec::new();
let mut values : Vec<u8> = Vec::new();
let mut substs : Vec<Elsubst_C> = Vec::new();
let mut var_i = 0;
let mut value_i = 0;
for s in subst {
let var = s.var.to_bytes_with_nul();
let value = s.value.to_bytes_with_nul();
vars.extend_from_slice(var);
values.extend_from_slice(value);
substs.push(Elsubst_C {
// these index into the vars/values arrays given to el_substitute
var: var_i,
value: value_i,
// we don’t deal with split values here
n: 1
});
var_i += var.len();
value_i = value.len();
}
let nsubst = subst.len();
let mut dst = stralloc_zero();
unsafe {
if el_substitute(
&mut dst,
src,
len,
vars.as_ptr() as *const libc::c_char,
values.as_ptr() as *const libc::c_char,
substs.as_ptr() as *const Elsubst_C,
nsubst
) == -1 {
panic!("{}", errno::errno());
}
// el_substitute returns a \0-delim C string
CStr::from_bytes_with_nul_unchecked(dst.as_ref()).to_owned()
}
}
fn main() -> std::io::Result<()> {
let a = simple_substitute(&vec![
Subst{
var: CStr::from_bytes_with_nul(b"hi\0").unwrap(),
value: CStr::from_bytes_with_nul(b"aaaa\0").unwrap()
},
Subst{
var: CStr::from_bytes_with_nul(b"foo\0").unwrap(),
value: CStr::from_bytes_with_nul(b"bbbb\0").unwrap(),
}
], CStr::from_bytes_with_nul(b"${foo}\0").unwrap());
assert_eq!(
AsciiStr::from_ascii(&a.into_bytes()),
AsciiStr::from_ascii(b"foo_aaaa_bar")
);
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment