#![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>) -> i32 {
return match result {
Ok(answer) => answer as i32,
Err(e) => {
change_error_string_value(errors_to_string(&e));
-1
},
};
}
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{ 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 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]
#[allow(unused_variables)]
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 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 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) ),
}
}
#[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) ),
}
}
pub extern "C" fn GetNavigationMathMLIdOffset() -> i32 {
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() -> i32 {
return match get_navigation_mathml() {
Err(e) => set_int_error(Err(e)),
Ok((_, nav_offset)) => set_int_error( Ok(nav_offset) ),
}
}