#![allow(non_snake_case)]
#![allow(clippy::needless_return)]
use libmathcat::*;
use std::cell::RefCell;
use std::ffi::{CString, CStr};
use std::os::raw::c_char;
const ILLEGAL_STRING: &str = "Internal MathCAT error -- internal null";
thread_local!{
pub static ERROR_STRING: RefCell<String> = RefCell::new(String::default());
}
fn change_error_string_value(new_string: String) {
ERROR_STRING.with(|string: &RefCell<String>| {
let mut string = string.borrow_mut();
string.clear();
string.push_str(&new_string);
})
}
#[no_mangle]
pub extern "C" fn GetError() -> *const c_char {
ERROR_STRING.with(|string: &RefCell<String>| {
let mut string = string.borrow_mut();
let result = CString::new(string.as_bytes()).expect(ILLEGAL_STRING);
string.clear();
return result.into_raw();
})
}
fn safe_string(cstr: *const c_char) -> String {
return unsafe {
CStr::from_ptr(cstr).to_string_lossy().into_owned()
}
}
fn set_string_error(result: Result<String, libmathcat::errors::Error>) -> *const c_char {
let result = match result {
Ok(answer) => CString::new(answer).expect(ILLEGAL_STRING),
Err(e) => {
change_error_string_value(errors_to_string(&e));
CString::new("").unwrap()
},
};
return result.into_raw();
}
fn set_int_error(result: Result<usize, libmathcat::errors::Error>) -> u32 {
return match result {
Ok(answer) => answer as u32,
Err(e) => {
change_error_string_value(errors_to_string(&e));
0
},
};
}
fn set_empty_error(result: Result<(), libmathcat::errors::Error>) -> *const c_char {
let result = match result {
Ok(_) => CString::new("Ok").expect(ILLEGAL_STRING),
Err(e) => {
change_error_string_value(errors_to_string(&e));
CString::new("").unwrap()
},
};
return result.into_raw();
}
#[no_mangle]
pub extern "C" fn FreeMathCATString(str: *mut c_char) {
unsafe{
if !str.is_null() {
drop(CString::from_raw(str));
};
}
}
#[no_mangle]
pub extern "C" fn SetRulesDir(rules_dir_location: *const c_char) -> *const c_char {
return set_empty_error(
set_rules_dir(safe_string(rules_dir_location))
);
}
#[no_mangle]
pub extern "C" fn SetMathML(mathml_str: *const c_char) -> *const c_char {
return set_string_error(
set_mathml(safe_string(mathml_str))
);
}
#[no_mangle]
pub extern "C" fn GetMathCATVersion() -> *const c_char {
return set_string_error( Ok(get_version()) );
}
#[no_mangle]
pub extern "C" fn GetSpokenText() -> *const c_char {
return set_string_error( get_spoken_text() );
}
#[no_mangle]
pub extern "C" fn SetPreference(name: *const c_char, value: *const c_char) -> *const c_char {
let name = safe_string(name);
let value = safe_string(value);
return set_empty_error( set_preference(name, value) );
}
#[no_mangle]
pub extern "C" fn GetPreference(name: *const c_char) -> *const c_char {
return match get_preference( safe_string(name) ) {
Ok(value) => {
set_string_error( Ok(value))
},
Err(_) => {
change_error_string_value( format!("Unknown preference name {}", safe_string(name)) );
set_string_error( Ok( String::default() ) )
},
};
}
#[no_mangle]
pub extern "C" fn GetBraille(nav_node_id: *const c_char) -> *const c_char {
return set_string_error( get_braille(safe_string(nav_node_id)) );
}
#[no_mangle]
pub extern "C" fn GetNavigationBraille() -> *const c_char {
return set_string_error( get_navigation_braille() );
}
#[no_mangle]
pub extern "C" fn DoNavigateKeyPress(key: usize, shift_key: bool, control_key: bool, alt_key: bool, meta_key: bool) -> *const c_char {
return set_string_error( do_navigate_keypress(key, shift_key, control_key, alt_key, meta_key) );
}
#[no_mangle]
pub extern "C" fn DoNavigateCommand(command: *const c_char) -> *const c_char {
return set_string_error( do_navigate_command(safe_string(command)) );
}
#[no_mangle]
pub extern "C" fn GetNavigationMathML() -> *const c_char {
return match get_navigation_mathml() {
Err(e) => set_string_error(Err(e)),
Ok((nav_mathml, _)) => set_string_error( Ok(nav_mathml) ),
}
}
#[no_mangle]
pub extern "C" fn GetNavigationMathMLId() -> *const c_char {
return match get_navigation_mathml_id() {
Err(e) => set_string_error(Err(e)),
Ok((nav_id, _)) => set_string_error( Ok(nav_id) ),
}
}
pub extern "C" fn GetNavigationMathMLIdOffset() -> u32 {
return match get_navigation_mathml_id() {
Err(e) => set_int_error(Err(e)),
Ok((_, nav_offset)) => set_int_error( Ok(nav_offset) ),
}
}
#[no_mangle]
pub extern "C" fn GetNavigationMathMLOffset() -> u32 {
return match get_navigation_mathml() {
Err(e) => set_int_error(Err(e)),
Ok((_, nav_offset)) => set_int_error( Ok(nav_offset) ),
}
}
#[repr(C)]
pub struct NavigationLocation {
id: *const c_char,
offset: u32,
}
#[no_mangle]
pub extern "C" fn SetNavigationLocation(location: NavigationLocation) -> *const c_char {
return set_empty_error(
set_navigation_node(safe_string(location.id), location.offset as usize)
)
}
#[no_mangle]
pub extern "C" fn GetNavigationLocation() -> NavigationLocation {
return match get_navigation_mathml_id() {
Err(e) => {
change_error_string_value(errors_to_string(&e));
NavigationLocation {
id: CString::new("").unwrap().into_raw(),
offset: 0_u32,
}
},
Ok((nav_id, nav_offset)) => {
NavigationLocation {
id: CString::new(nav_id).expect(ILLEGAL_STRING).into_raw(),
offset: nav_offset as u32,
}
},
}
}
#[no_mangle]
pub extern "C" fn GetNavigationLocationFromBraillePosition(position: u32) -> NavigationLocation {
return match get_navigation_node_from_braille_position(position as usize) {
Err(e) => {
change_error_string_value(errors_to_string(&e));
NavigationLocation {
id: CString::new("").unwrap().into_raw(),
offset: 0_u32,
}
},
Ok((nav_id, nav_offset)) => {
NavigationLocation {
id: CString::new(nav_id).expect(ILLEGAL_STRING).into_raw(),
offset: nav_offset as u32,
}
},
}
}
#[repr(C)]
pub struct CStringArray {
pub data: *mut *mut c_char,
pub len: usize,
}
#[no_mangle]
pub extern "C" fn FreeMathCATStringArray(array: CStringArray) {
unsafe {
let mut vec = Vec::from_raw_parts(array.data, array.len, array.len); for ptr in vec.drain(..) {
let _ = CString::from_raw(ptr); }
}
}
#[no_mangle]
pub extern "C" fn GetSupportedBrailleCodes() -> CStringArray {
match libmathcat::get_supported_braille_codes() {
Ok(codes) => vec_to_cstring_array(codes),
Err(e) => {
change_error_string_value(errors_to_string(&e));
CStringArray { data: std::ptr::null_mut(), len: 0 }
}
}
}
#[no_mangle]
pub extern "C" fn GetSupportedLanguages() -> CStringArray {
match libmathcat::get_supported_languages() {
Ok(languages) => vec_to_cstring_array(languages),
Err(e) => {
change_error_string_value(errors_to_string(&e));
CStringArray { data: std::ptr::null_mut(), len: 0 }
}
}
}
#[no_mangle]
pub extern "C" fn GetSupportedSpeechStyles(language: *const c_char) -> CStringArray {
match libmathcat::get_supported_speech_styles(safe_string(language)) {
Ok(styles) => vec_to_cstring_array(styles),
Err(e) => {
change_error_string_value(errors_to_string(&e));
CStringArray { data: std::ptr::null_mut(), len: 0 }
}
}
}
fn vec_to_cstring_array(vec: Vec<String>) -> CStringArray {
let mut c_strings: Vec<*mut c_char> = vec.iter()
.map(|s| CString::new(s.as_bytes()).expect(ILLEGAL_STRING).into_raw())
.collect();
let len = c_strings.len();
let data = c_strings.as_mut_ptr();
std::mem::forget(c_strings); return CStringArray { data, len };
}