libxml_rs/xslt/errors/
mod.rs1use crate::abi::structs::*;
12use std::os::raw::c_int;
13use std::ptr;
14
15pub const XSLT_ERR_NONE: c_int = 0;
22
23pub const XSLT_ERR_UNKNOWN: c_int = 1;
25
26pub const XSLT_ERR_MISSING_NAMESPACE: c_int = 2;
28
29pub const XSLT_ERR_INVALID_NAMESPACE: c_int = 3;
31
32pub const XSLT_ERR_MISSING_ATTRIBUTE: c_int = 4;
34
35pub const XSLT_ERR_INVALID_ATTRIBUTE: c_int = 5;
37
38pub const XSLT_ERR_MISSING_ELEMENT: c_int = 6;
40
41pub const XSLT_ERR_INVALID_ELEMENT: c_int = 7;
43
44pub const XSLT_ERR_MISSING_MATCH: c_int = 8;
46
47pub const XSLT_ERR_MISSING_NAME: c_int = 9;
49
50pub const XSLT_ERR_MISSING_SELECT: c_int = 10;
52
53pub const XSLT_ERR_MISSING_TEST: c_int = 11;
55
56pub const XSLT_ERR_MISSING_USE: c_int = 12;
58
59pub const XSLT_ERR_INVALID_MATCH: c_int = 13;
61
62pub const XSLT_ERR_INVALID_SELECT: c_int = 14;
64
65pub const XSLT_ERR_INVALID_TEST: c_int = 15;
67
68pub const XSLT_ERR_INVALID_USE: c_int = 16;
70
71pub const XSLT_ERR_MISSING_NS: c_int = 17;
73
74pub const XSLT_ERR_CYCLIC_REFERENCE: c_int = 18;
76
77pub const XSLT_ERR_RECURSION: c_int = 19;
79
80pub const XSLT_ERR_INTERNAL: c_int = 20;
82
83pub const XSLT_ERR_LEVEL_NONE: c_int = 0;
90
91pub const XSLT_ERR_LEVEL_WARNING: c_int = 1;
93
94pub const XSLT_ERR_LEVEL_ERROR: c_int = 2;
96
97pub const XSLT_ERR_LEVEL_FATAL: c_int = 3;
99
100pub type xsltTransformErrorFunc = Option<
111 unsafe extern "C" fn(
112 *mut std::ffi::c_void,
113 *mut std::ffi::c_void,
114 *mut _xsltStylesheet,
115 *const crate::abi::types::xmlChar,
116 ...
117 ),
118>;
119
120use std::sync::Mutex;
124
125static LAST_XSLT_ERROR: Mutex<Option<Vec<u8>>> = Mutex::new(None);
126
127static mut XSLT_GENERIC_DEBUG: Option<
129 unsafe extern "C" fn(*mut std::ffi::c_void, *const std::os::raw::c_char),
130> = None;
131
132#[no_mangle]
143pub unsafe extern "C" fn xsltSetGenericDebugFunc(
144 ctx: *mut std::ffi::c_void,
145 handler: Option<unsafe extern "C" fn(*mut std::ffi::c_void, *const std::os::raw::c_char)>,
146) {
147 unsafe {
148 XSLT_GENERIC_DEBUG_CONTEXT = ctx;
149 if handler.is_some() {
150 XSLT_GENERIC_DEBUG = handler;
151 }
152 }
153}
154
155static mut XSLT_GENERIC_DEBUG_CONTEXT: *mut std::ffi::c_void = std::ptr::null_mut();
156
157#[no_mangle]
159pub unsafe extern "C" fn xsltGenericDebug(
160 ctx: *mut std::ffi::c_void,
161 msg: *const std::os::raw::c_char,
162) {
163 if ctx.is_null() || msg.is_null() {
164 return;
165 }
166 let len = libc::strlen(msg);
167 libc::write(2, msg as *const libc::c_void, len);
168}
169
170pub fn xsltSetTransformErrorFunc(
183 ctxt: *mut _xsltTransformContext,
184 ctx: *mut std::ffi::c_void,
185 handler: Option<unsafe extern "C" fn(*mut std::ffi::c_void, *const std::os::raw::c_char)>,
186) {
187 if ctxt.is_null() {
188 return;
189 }
190 unsafe {
192 (*ctxt).error = handler;
193 (*ctxt).errctx = ctx;
194 }
195}
196
197pub fn xsltTransformError(
217 ctxt: *mut _xsltTransformContext,
218 style: *mut _xsltStylesheet,
219 inst: *mut _xmlNode,
220 msg: *const std::os::raw::c_char,
221) {
222 if msg.is_null() {
223 return;
224 }
225 let bytes =
227 unsafe { core::slice::from_raw_parts(msg as *const u8, libc::strlen(msg) as usize) };
228 let text = String::from_utf8_lossy(bytes).into_owned();
229
230 if let Ok(mut last) = LAST_XSLT_ERROR.lock() {
233 *last = Some(text.clone().into_bytes());
234 }
235
236 if !ctxt.is_null() {
239 let ctx = unsafe { &mut *ctxt };
241 if ctx.state == crate::xslt::transform::XSLT_STATE_OK {
242 ctx.state = crate::xslt::transform::XSLT_STATE_ERROR;
243 }
244 let mut node = inst;
245 if node.is_null() {
246 node = ctx.inst;
247 }
248 let context_line = print_error_context(ctxt, style, node);
251 let full = format!("{}{}", context_line, text);
252 let mut cmsg = full.into_bytes();
253 let msg_len = cmsg.len();
254 cmsg.push(0);
255 let ctx = unsafe { &*ctxt };
256 if let Some(handler) = ctx.error {
257 unsafe { handler(ctx.errctx, cmsg.as_ptr() as *const std::os::raw::c_char) };
258 return;
259 }
260 let _ = unsafe { libc::write(2, cmsg.as_ptr() as *const libc::c_void, msg_len) };
261 return;
262 }
263
264 let context_line = print_error_context(ptr::null_mut(), style, inst);
268 let full = format!("{}{}", context_line, text);
269 let mut cmsg = full.into_bytes();
270 let msg_len = cmsg.len();
271 cmsg.push(0);
272 let _ = unsafe { libc::write(2, cmsg.as_ptr() as *const libc::c_void, msg_len) };
273 let _ = style;
274}
275
276fn print_error_context(
289 ctxt: *mut _xsltTransformContext,
290 style: *mut _xsltStylesheet,
291 node: *mut _xmlNode,
292) -> String {
293 let mut line = 0i64;
294 let mut file: *const std::os::raw::c_char = ptr::null();
295 let mut name: *const std::os::raw::c_char = ptr::null();
296
297 if !node.is_null() {
298 let node_ref = unsafe { &*node };
300 if node_ref.type_ == crate::abi::types::xmlElementType::XML_DOCUMENT_NODE as c_int
301 || node_ref.type_ == crate::abi::types::xmlElementType::XML_HTML_DOCUMENT_NODE as c_int
302 {
303 let doc = node as *mut crate::abi::structs::_xmlDoc;
304 file = unsafe { (*doc).URL } as *const std::os::raw::c_char;
306 } else {
307 line = unsafe { crate::abi::exports_xml2::xmlGetLineNo(node) as i64 };
308 let doc = unsafe { (*node_ref).doc };
310 if !doc.is_null() {
311 file = unsafe { (*doc).URL } as *const std::os::raw::c_char;
312 }
313 name = node_ref.name as *const std::os::raw::c_char;
314 }
315 }
316
317 let errtype = if !ctxt.is_null() {
318 "runtime error"
319 } else if !style.is_null() {
320 "compilation error"
321 } else {
322 "error"
323 };
324
325 let s = |p: *const std::os::raw::c_char| -> String {
326 if p.is_null() {
327 String::new()
328 } else {
329 unsafe { std::ffi::CStr::from_ptr(p).to_string_lossy().into_owned() }
330 }
331 };
332 let file_s = s(file);
333 let name_s = s(name);
334 let has_file = !file.is_null();
335 let has_name = !name.is_null();
336
337 if has_file && line != 0 && has_name {
338 format!(
339 "{}: file {} line {} element {}\n",
340 errtype, file_s, line, name_s
341 )
342 } else if has_file && has_name {
343 format!("{}: file {} element {}\n", errtype, file_s, name_s)
344 } else if has_file && line != 0 {
345 format!("{}: file {} line {}\n", errtype, file_s, line)
346 } else if has_file {
347 format!("{}: file {}\n", errtype, file_s)
348 } else if has_name {
349 format!("{}: element {}\n", errtype, name_s)
350 } else {
351 format!("{}\n", errtype)
352 }
353}
354
355pub fn xsltGetLastError() -> *mut std::ffi::c_void {
360 let guard = match LAST_XSLT_ERROR.lock() {
361 Ok(g) => g,
362 Err(_) => return std::ptr::null_mut(),
363 };
364 match guard.as_ref() {
365 Some(bytes) => {
366 let len = bytes.len();
367 let p = unsafe { libc::malloc(len + 1) } as *mut u8;
369 if p.is_null() {
370 return std::ptr::null_mut();
371 }
372 unsafe {
373 core::ptr::copy_nonoverlapping(bytes.as_ptr(), p, len);
374 *p.add(len) = 0;
375 }
376 p as *mut std::ffi::c_void
377 }
378 None => std::ptr::null_mut(),
379 }
380}