use crate::abi::structs::*;
use std::os::raw::c_int;
use std::ptr;
pub const XSLT_ERR_NONE: c_int = 0;
pub const XSLT_ERR_UNKNOWN: c_int = 1;
pub const XSLT_ERR_MISSING_NAMESPACE: c_int = 2;
pub const XSLT_ERR_INVALID_NAMESPACE: c_int = 3;
pub const XSLT_ERR_MISSING_ATTRIBUTE: c_int = 4;
pub const XSLT_ERR_INVALID_ATTRIBUTE: c_int = 5;
pub const XSLT_ERR_MISSING_ELEMENT: c_int = 6;
pub const XSLT_ERR_INVALID_ELEMENT: c_int = 7;
pub const XSLT_ERR_MISSING_MATCH: c_int = 8;
pub const XSLT_ERR_MISSING_NAME: c_int = 9;
pub const XSLT_ERR_MISSING_SELECT: c_int = 10;
pub const XSLT_ERR_MISSING_TEST: c_int = 11;
pub const XSLT_ERR_MISSING_USE: c_int = 12;
pub const XSLT_ERR_INVALID_MATCH: c_int = 13;
pub const XSLT_ERR_INVALID_SELECT: c_int = 14;
pub const XSLT_ERR_INVALID_TEST: c_int = 15;
pub const XSLT_ERR_INVALID_USE: c_int = 16;
pub const XSLT_ERR_MISSING_NS: c_int = 17;
pub const XSLT_ERR_CYCLIC_REFERENCE: c_int = 18;
pub const XSLT_ERR_RECURSION: c_int = 19;
pub const XSLT_ERR_INTERNAL: c_int = 20;
pub const XSLT_ERR_LEVEL_NONE: c_int = 0;
pub const XSLT_ERR_LEVEL_WARNING: c_int = 1;
pub const XSLT_ERR_LEVEL_ERROR: c_int = 2;
pub const XSLT_ERR_LEVEL_FATAL: c_int = 3;
pub type xsltTransformErrorFunc = Option<
unsafe extern "C" fn(
*mut std::ffi::c_void,
*mut std::ffi::c_void,
*mut _xsltStylesheet,
*const crate::abi::types::xmlChar,
...
),
>;
use std::sync::Mutex;
static LAST_XSLT_ERROR: Mutex<Option<Vec<u8>>> = Mutex::new(None);
static mut XSLT_GENERIC_DEBUG: Option<
unsafe extern "C" fn(*mut std::ffi::c_void, *const std::os::raw::c_char),
> = None;
#[no_mangle]
pub unsafe extern "C" fn xsltSetGenericDebugFunc(
ctx: *mut std::ffi::c_void,
handler: Option<unsafe extern "C" fn(*mut std::ffi::c_void, *const std::os::raw::c_char)>,
) {
unsafe {
XSLT_GENERIC_DEBUG_CONTEXT = ctx;
if handler.is_some() {
XSLT_GENERIC_DEBUG = handler;
}
}
}
static mut XSLT_GENERIC_DEBUG_CONTEXT: *mut std::ffi::c_void = std::ptr::null_mut();
#[no_mangle]
pub unsafe extern "C" fn xsltGenericDebug(
ctx: *mut std::ffi::c_void,
msg: *const std::os::raw::c_char,
) {
if ctx.is_null() || msg.is_null() {
return;
}
let len = libc::strlen(msg);
libc::write(2, msg as *const libc::c_void, len);
}
pub fn xsltSetTransformErrorFunc(
ctxt: *mut _xsltTransformContext,
ctx: *mut std::ffi::c_void,
handler: Option<unsafe extern "C" fn(*mut std::ffi::c_void, *const std::os::raw::c_char)>,
) {
if ctxt.is_null() {
return;
}
unsafe {
(*ctxt).error = handler;
(*ctxt).errctx = ctx;
}
}
pub fn xsltTransformError(
ctxt: *mut _xsltTransformContext,
style: *mut _xsltStylesheet,
inst: *mut _xmlNode,
msg: *const std::os::raw::c_char,
) {
if msg.is_null() {
return;
}
let bytes =
unsafe { core::slice::from_raw_parts(msg as *const u8, libc::strlen(msg) as usize) };
let text = String::from_utf8_lossy(bytes).into_owned();
if let Ok(mut last) = LAST_XSLT_ERROR.lock() {
*last = Some(text.clone().into_bytes());
}
if !ctxt.is_null() {
let ctx = unsafe { &mut *ctxt };
if ctx.state == crate::xslt::transform::XSLT_STATE_OK {
ctx.state = crate::xslt::transform::XSLT_STATE_ERROR;
}
let mut node = inst;
if node.is_null() {
node = ctx.inst;
}
let context_line = print_error_context(ctxt, style, node);
let full = format!("{}{}", context_line, text);
let mut cmsg = full.into_bytes();
let msg_len = cmsg.len();
cmsg.push(0);
let ctx = unsafe { &*ctxt };
if let Some(handler) = ctx.error {
unsafe { handler(ctx.errctx, cmsg.as_ptr() as *const std::os::raw::c_char) };
return;
}
let _ = unsafe { libc::write(2, cmsg.as_ptr() as *const libc::c_void, msg_len) };
return;
}
let context_line = print_error_context(ptr::null_mut(), style, inst);
let full = format!("{}{}", context_line, text);
let mut cmsg = full.into_bytes();
let msg_len = cmsg.len();
cmsg.push(0);
let _ = unsafe { libc::write(2, cmsg.as_ptr() as *const libc::c_void, msg_len) };
let _ = style;
}
fn print_error_context(
ctxt: *mut _xsltTransformContext,
style: *mut _xsltStylesheet,
node: *mut _xmlNode,
) -> String {
let mut line = 0i64;
let mut file: *const std::os::raw::c_char = ptr::null();
let mut name: *const std::os::raw::c_char = ptr::null();
if !node.is_null() {
let node_ref = unsafe { &*node };
if node_ref.type_ == crate::abi::types::xmlElementType::XML_DOCUMENT_NODE as c_int
|| node_ref.type_ == crate::abi::types::xmlElementType::XML_HTML_DOCUMENT_NODE as c_int
{
let doc = node as *mut crate::abi::structs::_xmlDoc;
file = unsafe { (*doc).URL } as *const std::os::raw::c_char;
} else {
line = unsafe { crate::abi::exports_xml2::xmlGetLineNo(node) as i64 };
let doc = unsafe { (*node_ref).doc };
if !doc.is_null() {
file = unsafe { (*doc).URL } as *const std::os::raw::c_char;
}
name = node_ref.name as *const std::os::raw::c_char;
}
}
let errtype = if !ctxt.is_null() {
"runtime error"
} else if !style.is_null() {
"compilation error"
} else {
"error"
};
let s = |p: *const std::os::raw::c_char| -> String {
if p.is_null() {
String::new()
} else {
unsafe { std::ffi::CStr::from_ptr(p).to_string_lossy().into_owned() }
}
};
let file_s = s(file);
let name_s = s(name);
let has_file = !file.is_null();
let has_name = !name.is_null();
if has_file && line != 0 && has_name {
format!(
"{}: file {} line {} element {}\n",
errtype, file_s, line, name_s
)
} else if has_file && has_name {
format!("{}: file {} element {}\n", errtype, file_s, name_s)
} else if has_file && line != 0 {
format!("{}: file {} line {}\n", errtype, file_s, line)
} else if has_file {
format!("{}: file {}\n", errtype, file_s)
} else if has_name {
format!("{}: element {}\n", errtype, name_s)
} else {
format!("{}\n", errtype)
}
}
pub fn xsltGetLastError() -> *mut std::ffi::c_void {
let guard = match LAST_XSLT_ERROR.lock() {
Ok(g) => g,
Err(_) => return std::ptr::null_mut(),
};
match guard.as_ref() {
Some(bytes) => {
let len = bytes.len();
let p = unsafe { libc::malloc(len + 1) } as *mut u8;
if p.is_null() {
return std::ptr::null_mut();
}
unsafe {
core::ptr::copy_nonoverlapping(bytes.as_ptr(), p, len);
*p.add(len) = 0;
}
p as *mut std::ffi::c_void
}
None => std::ptr::null_mut(),
}
}