libxml_rs/abi/data_globals.rs
1//! Exported C data globals — the classic libxml2/libxslt public variables
2//! (11.1-G data-ABI closure, residual R-000135).
3//!
4//! Downstream C code reads and writes these symbols directly
5//! (e.g. `xmlDoValidityCheckingDefaultValue = 1;`), so they must exist with
6//! upstream names, types and defaults. The parser-default accessors in
7//! `src/xml/globals/mod.rs` read and write the SAME statics (single source
8//! of truth): a C write is immediately observable by the candidate parser.
9//!
10//! Defaults match upstream `globals.c` (libxml2 2.15.3) and `xslt.c`
11//! (libxslt 1.1.45).
12//!
13//! # SAFETY
14//!
15//! `static mut` globals are unsafe to touch from Rust; every access goes
16//! through the accessor functions in `crate::xml::globals` (or directly
17//! here with an explicit safety note). C accesses are inherently racy in
18//! upstream too — upstream documents these globals as deprecated and
19//! not thread-safe.
20
21use core::ffi::c_void;
22use std::os::raw::{c_char, c_int, c_uint};
23
24use crate::abi::callbacks::{xmlGenericErrorFunc, xmlStructuredErrorFunc};
25use crate::abi::types::xmlChar;
26
27/// Serializes writes to the exported `xmlLastError` mirror.
28///
29/// Upstream's `xmlLastError` is a bare racy global (deprecated, documented
30/// not thread-safe), and the candidate preserves the C-visible semantics:
31/// downstream C consumers read the symbol directly without a lock. The
32/// candidate's internal deep-copy/free writers are serialized here so that
33/// concurrent error raises on different threads can never free the same
34/// mirror string twice or write while another thread is freeing — observed
35/// as heap corruption (`double free or corruption (!prev)`) in the parallel
36/// lib test suite (xml::errors tests racing with any other raising thread).
37static LAST_ERROR_MIRROR_LOCK: parking_lot::Mutex<()> = parking_lot::Mutex::new(());
38
39// ═══════════════════════════════════════════════════════════════════════════════
40// Parser defaults (upstream globals.c)
41// ═══════════════════════════════════════════════════════════════════════════════
42
43/// `int xmlDoValidityCheckingDefaultValue` (default 0)
44#[no_mangle]
45pub static mut xmlDoValidityCheckingDefaultValue: c_int = 0;
46
47/// `int xmlGetWarningsDefaultValue` (default 1)
48#[no_mangle]
49pub static mut xmlGetWarningsDefaultValue: c_int = 1;
50
51/// `int xmlLoadExtDtdDefaultValue` (default 0)
52#[no_mangle]
53pub static mut xmlLoadExtDtdDefaultValue: c_int = 0;
54
55/// `int xmlPedanticParserDefaultValue` (default 0)
56#[no_mangle]
57pub static mut xmlPedanticParserDefaultValue: c_int = 0;
58
59/// `int xmlLineNumbersDefaultValue` (default 1 — upstream globals.c
60/// `xmlLineNumbersDefaultValueThrDef = 1`)
61#[no_mangle]
62pub static mut xmlLineNumbersDefaultValue: c_int = 1;
63
64/// `int xmlKeepBlanksDefaultValue` (default 1)
65#[no_mangle]
66pub static mut xmlKeepBlanksDefaultValue: c_int = 1;
67
68/// `int xmlSubstituteEntitiesDefaultValue` (default 0)
69#[no_mangle]
70pub static mut xmlSubstituteEntitiesDefaultValue: c_int = 0;
71
72/// `int xmlParserDebugEntities` (default 0)
73#[no_mangle]
74pub static mut xmlParserDebugEntities: c_int = 0;
75
76/// `int xmlIndentTreeOutput` (default 1 — upstream globals.c
77/// `xmlIndentTreeOutputThrDef = 1`)
78#[no_mangle]
79pub static mut xmlIndentTreeOutput: c_int = 1;
80
81/// `const xmlChar *xmlTreeIndentString` (default " " — upstream globals.c
82/// `xmlTreeIndentStringThrDef = " "`)
83#[no_mangle]
84pub static mut xmlTreeIndentString: *const xmlChar = {
85 static S: [u8; 3] = *b" \0";
86 S.as_ptr()
87};
88
89/// `int xmlSaveNoEmptyTags` (default 0)
90#[no_mangle]
91pub static mut xmlSaveNoEmptyTags: c_int = 0;
92
93/// Upstream `xmlRegisterNodeFunc xmlRegisterNodeDefaultValue` (default NULL)
94#[no_mangle]
95pub static mut xmlRegisterNodeDefaultValue: Option<
96 unsafe extern "C" fn(*mut crate::abi::structs::_xmlNode),
97> = None;
98
99/// Upstream static `xmlRegisterCallbacks` (tree.c): the gate that arms the
100/// node register/deregister hooks once a callback has been registered.
101pub static XML_REGISTER_CALLBACKS: core::sync::atomic::AtomicBool =
102 core::sync::atomic::AtomicBool::new(false);
103
104/// Upstream `xmlRegisterNodeCallback(node)` — invoke the registered node
105/// hook, gated by `xmlRegisterCallbacks` (tree.c).
106///
107/// # SAFETY
108///
109/// - `node` must be a valid, fully-initialised node or NULL.
110pub fn register_node_hook(node: *mut crate::abi::structs::_xmlNode) {
111 if !XML_REGISTER_CALLBACKS.load(core::sync::atomic::Ordering::Relaxed) {
112 return;
113 }
114 let hook = unsafe { xmlRegisterNodeDefaultValue };
115 if let Some(h) = hook {
116 if !node.is_null() {
117 // SAFETY: the hook is a valid C callback registered by the user.
118 unsafe { h(node) };
119 }
120 }
121}
122
123/// Upstream `xmlDeregisterNodeCallback(node)` — invoke the registered node
124/// deregister hook, gated by `xmlRegisterCallbacks` (tree.c).
125///
126/// # SAFETY
127///
128/// - `node` must be a valid node about to be freed, or NULL.
129pub fn deregister_node_hook(node: *mut crate::abi::structs::_xmlNode) {
130 if !XML_REGISTER_CALLBACKS.load(core::sync::atomic::Ordering::Relaxed) {
131 return;
132 }
133 let hook = unsafe { xmlDeregisterNodeDefaultValue };
134 if let Some(h) = hook {
135 if !node.is_null() {
136 // SAFETY: the hook is a valid C callback registered by the user.
137 unsafe { h(node) };
138 }
139 }
140}
141
142/// `xmlDeregisterNodeFunc xmlDeregisterNodeDefaultValue` (default NULL)
143#[no_mangle]
144pub static mut xmlDeregisterNodeDefaultValue: Option<
145 unsafe extern "C" fn(*mut crate::abi::structs::_xmlNode),
146> = None;
147
148/// `const char *xmlParserVersion` — matched to the system oracle build
149/// (libxml2 2.15.3 GIT build: LIBXML_VERSION_STRING "21503" plus the
150/// upstream version extra "-GITv2.15.3").
151///
152/// SAFETY: the pointed-to string is a static, immutable, null-terminated
153/// literal; `static mut` is used because C raw pointers are not `Sync`.
154/// Reads/writes of the pointer itself are racy only if C code mutates it
155/// (upstream treats it as a constant).
156#[no_mangle]
157pub static mut xmlParserVersion: *const c_char = {
158 static V: [u8; 17] = *b"21503-GITv2.15.3\0";
159 V.as_ptr() as *const c_char
160};
161
162/// `int xmlParserMaxDepth` (default 256)
163#[no_mangle]
164pub static mut xmlParserMaxDepth: c_int = 256;
165
166// ═══════════════════════════════════════════════════════════════════════════════
167// Buffer globals (upstream tree.h / xmlIO.c)
168// ═══════════════════════════════════════════════════════════════════════════════
169
170/// `int xmlDefaultBufferSize` (default 4096)
171#[no_mangle]
172pub static mut xmlDefaultBufferSize: c_int = 4096;
173
174/// `xmlBufferAllocationScheme xmlBufferAllocScheme` (default XML_BUFFER_ALLOC_EXACT = 1;
175/// upstream globals.c `xmlBufferAllocSchemeThrDef = XML_BUFFER_ALLOC_EXACT`)
176#[no_mangle]
177pub static mut xmlBufferAllocScheme: c_int = 1;
178
179// ═══════════════════════════════════════════════════════════════════════════════
180// Error callback globals (upstream xmlerror.h)
181// ═══════════════════════════════════════════════════════════════════════════════
182
183/// `xmlGenericErrorFunc xmlGenericError` — the generic error callback.
184///
185/// Upstream defaults to `xmlGenericErrorDefaultFunc` (a variadic stderr
186/// printer, error.c); the candidate's shim below reproduces it, so a
187/// freshly-initialized library routes errors to stderr exactly like upstream.
188#[cfg(target_arch = "x86_64")]
189#[no_mangle]
190pub static mut xmlGenericError: Option<xmlGenericErrorFunc> = Some(XML_GENERIC_ERROR_DEFAULT);
191
192#[cfg(not(target_arch = "x86_64"))]
193#[no_mangle]
194pub static mut xmlGenericError: Option<xmlGenericErrorFunc> = None;
195
196/// `void *xmlGenericErrorContext` — context for the generic error callback.
197#[no_mangle]
198pub static mut xmlGenericErrorContext: *mut c_void = core::ptr::null_mut();
199
200/// `xmlStructuredErrorFunc xmlStructuredError` — the structured error callback.
201#[no_mangle]
202pub static mut xmlStructuredError: Option<xmlStructuredErrorFunc> = None;
203
204/// `void *xmlStructuredErrorContext` — context for the structured callback.
205#[no_mangle]
206pub static mut xmlStructuredErrorContext: *mut c_void = core::ptr::null_mut();
207
208// ═══════════════════════════════════════════════════════════════════════════════
209// Variadic default error handlers (upstream error.c / xsltutils.c)
210// ═══════════════════════════════════════════════════════════════════════════════
211//
212// Upstream `xmlGenericErrorDefaultFunc(void *ctx, const char *msg, ...)`
213// prints the formatted message to `xmlGenericErrorContext` (stderr when
214// NULL). Stable Rust cannot define a variadic extern fn body, so the ABI
215// entry is an x86_64 SysV inline-asm shim that materialises the caller's
216// register/stack arguments into a `va_list` and forwards to a non-variadic
217// receiver — the same pattern as `xsltTransformError`
218// (exports_xslt_util.rs) and the writer's `vfmt_shim!`. Neither default
219// function is a dynamic export upstream (both are internal); the exported
220// data globals merely point at them.
221
222/// System V AMD64 `__va_list_tag` (24 bytes) — same layout as the writer's
223/// shims and `exports_xslt_util.rs`.
224#[cfg(target_arch = "x86_64")]
225#[repr(C)]
226#[derive(Clone, Copy, Debug)]
227pub struct VaListTag {
228 gp_offset: c_uint,
229 fp_offset: c_uint,
230 overflow_arg_area: *mut c_void,
231 reg_save_area: *mut c_void,
232}
233
234#[cfg(target_arch = "x86_64")]
235unsafe extern "C" {
236 fn vfprintf(stream: *mut c_void, format: *const c_char, ap: *mut VaListTag) -> c_int;
237}
238
239/// The `stderr` FILE* — glibc exports the `stderr` data object, an
240/// 8-byte pointer variable whose value is `&_IO_2_1_stderr_`. Upstream
241/// `xmlGenericErrorDefaultFunc` defaults the error context to `stderr`;
242/// using the real stdio object (unbuffered, fd-2 relative) keeps writes
243/// byte-exact and honors fd-2 redirection, unlike a private `fdopen(2)`
244/// FILE* which is fully buffered and lands at exit on whatever fd 2 then
245/// points to.
246#[cfg(target_arch = "x86_64")]
247unsafe fn stderr_file() -> *mut c_void {
248 extern "C" {
249 static stderr: *mut c_void;
250 }
251 unsafe { stderr }
252}
253
254/// Variadic receiver for the `xmlGenericErrorDefaultFunc` shim (upstream
255/// error.c semantics: default the context to stderr, then `vfprintf`).
256///
257/// # SAFETY
258///
259/// - `_ctx`, `ap` must be valid pointers (or NULL
260/// where the upstream C contract allows), obtained from the
261/// matching constructor/owner and not yet freed; the callee may
262/// take or keep ownership exactly as the C API specifies.
263///
264/// - `msg` must point to valid NUL-terminated
265/// strings (or NULL where the C contract allows) for the lifetime
266/// of the call.
267///
268/// The caller must not race this call with concurrent mutation of the
269/// same objects from other threads (per-object state is not internally
270/// synchronized). Violating any of the above is undefined behavior.
271///
272/// Exercised by the C-API differential courts
273/// (courts/suites/data-abi/*-family-probe.c) and the CLI differential
274/// courts; those pass byte-for-byte against the upstream oracle.
275#[cfg(target_arch = "x86_64")]
276#[no_mangle]
277pub unsafe extern "C" fn xmlGenericErrorDefaultFuncV(
278 _ctx: *mut c_void,
279 msg: *const c_char,
280 ap: *mut VaListTag,
281) -> c_int {
282 unsafe {
283 if crate::abi::data_globals::xmlGenericErrorContext.is_null() {
284 crate::abi::data_globals::xmlGenericErrorContext = stderr_file();
285 }
286 let stream = crate::abi::data_globals::xmlGenericErrorContext;
287 if msg.is_null() || stream.is_null() {
288 return 0;
289 }
290 vfprintf(stream, msg, ap)
291 }
292}
293
294/// `xmlGenericErrorDefaultFunc(void *ctx, const char *msg, ...)` — the
295/// upstream default generic error handler. Not exported dynamically (matches
296/// upstream, where the symbol is internal).
297///
298/// 2 fixed args (ctx=rdi, msg=rsi) → `gp_offset` 16; the va_list pointer is
299/// passed as the 3rd arg (rdx) of the receiver.
300///
301/// # SAFETY
302///
303/// The function touches crate-global state only; it is safe
304/// as long as the caller respects the library's global
305/// initialization/cleanup ordering (xmlInitParser before use,
306/// xmlCleanupParser only after all users are done).
307///
308/// Violating the global lifecycle ordering, or calling this after
309/// teardown or from a signal handler, is undefined behavior.
310#[cfg(target_arch = "x86_64")]
311pub unsafe extern "C" fn xmlGenericErrorDefaultFunc() -> c_int {
312 unsafe {
313 core::arch::asm!(
314 "sub rsp, 240",
315 "mov [rsp+0], rdi",
316 "mov [rsp+8], rsi",
317 "mov [rsp+16], rdx",
318 "mov [rsp+24], rcx",
319 "mov [rsp+32], r8",
320 "mov [rsp+40], r9",
321 "movaps [rsp+48], xmm0",
322 "movaps [rsp+64], xmm1",
323 "movaps [rsp+80], xmm2",
324 "movaps [rsp+96], xmm3",
325 "movaps [rsp+112], xmm4",
326 "movaps [rsp+128], xmm5",
327 "movaps [rsp+144], xmm6",
328 "movaps [rsp+160], xmm7",
329 "mov dword ptr [rsp+176], 16",
330 "mov dword ptr [rsp+180], 48",
331 "lea rax, [rsp+256]",
332 "mov [rsp+184], rax",
333 "lea rax, [rsp]",
334 "mov [rsp+192], rax",
335 "lea rdx, [rsp+176]",
336 "call xmlGenericErrorDefaultFuncV",
337 "add rsp, 240",
338 "add rsp, 8",
339 "ret",
340 options(noreturn),
341 );
342 }
343}
344
345/// Default value of the exported `xmlGenericError` data global.
346#[cfg(target_arch = "x86_64")]
347const XML_GENERIC_ERROR_DEFAULT: xmlGenericErrorFunc = unsafe {
348 // SAFETY: the shim and the function-pointer type have identical ABI
349 // (a code pointer); the declared arity is a Rust-side fiction required
350 // to store a variadic entry in the non-variadic pointer type.
351 core::mem::transmute::<
352 unsafe extern "C" fn() -> c_int,
353 unsafe extern "C" fn(*mut c_void, *const c_char),
354 >(xmlGenericErrorDefaultFunc)
355};
356
357/// Variadic receiver for the `xsltGenericErrorDefaultFunc` shim (upstream
358/// xsltutils.c semantics: default the context to stderr, then `vfprintf`).
359///
360/// # SAFETY
361///
362/// - `_ctx`, `ap` must be valid pointers (or NULL
363/// where the upstream C contract allows), obtained from the
364/// matching constructor/owner and not yet freed; the callee may
365/// take or keep ownership exactly as the C API specifies.
366///
367/// - `msg` must point to valid NUL-terminated
368/// strings (or NULL where the C contract allows) for the lifetime
369/// of the call.
370///
371/// The caller must not race this call with concurrent mutation of the
372/// same objects from other threads (per-object state is not internally
373/// synchronized). Violating any of the above is undefined behavior.
374///
375/// Exercised by the C-API differential courts
376/// (courts/suites/data-abi/*-family-probe.c) and the CLI differential
377/// courts; those pass byte-for-byte against the upstream oracle.
378#[cfg(target_arch = "x86_64")]
379#[no_mangle]
380pub unsafe extern "C" fn xsltGenericErrorDefaultFuncV(
381 _ctx: *mut c_void,
382 msg: *const c_char,
383 ap: *mut VaListTag,
384) -> c_int {
385 unsafe {
386 if crate::abi::data_globals::xsltGenericErrorContext.is_null() {
387 crate::abi::data_globals::xsltGenericErrorContext = stderr_file();
388 }
389 let stream = crate::abi::data_globals::xsltGenericErrorContext;
390 if msg.is_null() || stream.is_null() {
391 return 0;
392 }
393 vfprintf(stream, msg, ap)
394 }
395}
396
397/// `xsltGenericErrorDefaultFunc(void *ctx, const char *msg, ...)` — the
398/// upstream default XSLT error handler (xsltutils.c).
399///
400/// # SAFETY
401///
402/// The function touches crate-global state only; it is safe
403/// as long as the caller respects the library's global
404/// initialization/cleanup ordering (xmlInitParser before use,
405/// xmlCleanupParser only after all users are done).
406///
407/// Violating the global lifecycle ordering, or calling this after
408/// teardown or from a signal handler, is undefined behavior.
409#[cfg(target_arch = "x86_64")]
410pub unsafe extern "C" fn xsltGenericErrorDefaultFunc() -> c_int {
411 unsafe {
412 core::arch::asm!(
413 "sub rsp, 240",
414 "mov [rsp+0], rdi",
415 "mov [rsp+8], rsi",
416 "mov [rsp+16], rdx",
417 "mov [rsp+24], rcx",
418 "mov [rsp+32], r8",
419 "mov [rsp+40], r9",
420 "movaps [rsp+48], xmm0",
421 "movaps [rsp+64], xmm1",
422 "movaps [rsp+80], xmm2",
423 "movaps [rsp+96], xmm3",
424 "movaps [rsp+112], xmm4",
425 "movaps [rsp+128], xmm5",
426 "movaps [rsp+144], xmm6",
427 "movaps [rsp+160], xmm7",
428 "mov dword ptr [rsp+176], 16",
429 "mov dword ptr [rsp+180], 48",
430 "lea rax, [rsp+256]",
431 "mov [rsp+184], rax",
432 "lea rax, [rsp]",
433 "mov [rsp+192], rax",
434 "lea rdx, [rsp+176]",
435 "call xsltGenericErrorDefaultFuncV",
436 "add rsp, 240",
437 "add rsp, 8",
438 "ret",
439 options(noreturn),
440 );
441 }
442}
443
444/// Default value of the exported `xsltGenericError` data global.
445#[cfg(target_arch = "x86_64")]
446const XSLT_GENERIC_ERROR_DEFAULT: xmlGenericErrorFunc = unsafe {
447 // SAFETY: as above — ABI-identical code pointer.
448 core::mem::transmute::<
449 unsafe extern "C" fn() -> c_int,
450 unsafe extern "C" fn(*mut c_void, *const c_char),
451 >(xsltGenericErrorDefaultFunc)
452};
453
454/// The built-in default generic error handler (upstream
455/// `xmlGenericErrorDefaultFunc`), for use when a caller resets the handler
456/// with NULL. Only available on x86_64 (the variadic shim is SysV-specific);
457/// on other targets there is no default (resets leave the handler unset).
458pub fn default_generic_error_func() -> Option<xmlGenericErrorFunc> {
459 #[cfg(target_arch = "x86_64")]
460 {
461 Some(XML_GENERIC_ERROR_DEFAULT)
462 }
463 #[cfg(not(target_arch = "x86_64"))]
464 {
465 None
466 }
467}
468
469// ═══════════════════════════════════════════════════════════════════════════════
470// Static strings (upstream xmlstring.h / tree.c)
471// ═══════════════════════════════════════════════════════════════════════════════
472
473/// `const xmlChar xmlStringText[]` — "text"
474#[no_mangle]
475pub static xmlStringText: [xmlChar; 5] = [b't', b'e', b'x', b't', 0];
476
477/// `const xmlChar xmlStringTextNoenc[]` — "textnoenc"
478#[no_mangle]
479pub static xmlStringTextNoenc: [xmlChar; 9] = *b"textnoenc";
480
481/// `const xmlChar xmlStringComment[]` — "comment"
482#[no_mangle]
483pub static xmlStringComment: [xmlChar; 8] = [b'c', b'o', b'm', b'm', b'e', b'n', b't', 0];
484
485// ═══════════════════════════════════════════════════════════════════════════════
486// XPath numeric constants (upstream xpath.c)
487// ═══════════════════════════════════════════════════════════════════════════════
488
489/// `double xmlXPathNAN` — NaN
490#[no_mangle]
491pub static xmlXPathNAN: f64 = f64::NAN;
492
493/// `double xmlXPathPINF` — +infinity
494#[no_mangle]
495pub static xmlXPathPINF: f64 = f64::INFINITY;
496
497/// `double xmlXPathNINF` — -infinity
498#[no_mangle]
499pub static xmlXPathNINF: f64 = f64::NEG_INFINITY;
500
501// ═══════════════════════════════════════════════════════════════════════════════
502// libxslt globals (upstream xslt.c / xsltutils.c / documents.c / xslt.h)
503// ═══════════════════════════════════════════════════════════════════════════════
504// xsltMaxDepth / xsltMaxVars are exported from src/xslt/transform/mod.rs
505// (they are read by the transform engine).
506
507/// `const int xsltLibxmlVersion` = 21501 — the libxml2 version the system
508/// libxslt 1.1.45 was compiled against (upstream xslt.c `LIBXML_VERSION`;
509/// the system libxslt was built against libxml2 2.15.1). Byte-parity with
510/// the oracle DSO, read directly by `xsltproc -V`.
511#[no_mangle]
512pub static xsltLibxmlVersion: c_int = 21501;
513
514/// `const int xsltLibxsltVersion` = 10145 — the libxslt version
515/// (upstream xslt.c `XSLTPUBVAR const int xsltLibxsltVersion = LIBXSLT_VERSION`;
516/// oracle DSO symbol type R). Was previously exported as a function (T)
517/// — R-000167.
518#[no_mangle]
519pub static xsltLibxsltVersion: c_int = 10145;
520
521/// `const char *xsltEngineVersion` = "10145-GITv1.1.45" — the libxslt engine
522/// version string (upstream xslt.c `XSLTPUBVAR const char *xsltEngineVersion`;
523/// oracle DSO symbol type D). Was previously exported as a function (T)
524/// — R-000167. `static mut` follows the xmlParserVersion pattern (raw
525/// pointers are not Sync).
526#[no_mangle]
527pub static mut xsltEngineVersion: *const c_char = {
528 static S: [u8; 17] = *b"10145-GITv1.1.45\0";
529 S.as_ptr() as *const c_char
530};
531
532/// `const char *exsltLibraryVersion` = "825-GITv1.1.45" — the libexslt
533/// library version string (upstream exslt.c `EXSLTPUBVAR const char *`;
534/// oracle DSO symbol type D). Read by `xsltproc -V`.
535#[no_mangle]
536pub static mut exsltLibraryVersion: *const c_char = {
537 static S: [u8; 15] = *b"825-GITv1.1.45\0";
538 S.as_ptr() as *const c_char
539};
540
541/// `const int exsltLibexsltVersion` = 825 — the libexslt version
542/// (upstream exslt.h `EXSLTPUBVAR const int`; oracle DSO symbol type R).
543#[no_mangle]
544pub static exsltLibexsltVersion: c_int = 825;
545
546/// `const int exsltLibxmlVersion` = 21501 — the libxml2 version the system
547/// libexslt 0.8.25 was compiled against (oracle DSO symbol type R).
548#[no_mangle]
549pub static exsltLibxmlVersion: c_int = 21501;
550
551/// `const int exsltLibxsltVersion` = 10145 — the libxslt version the system
552/// libexslt 0.8.25 was compiled against (oracle DSO symbol type R).
553#[no_mangle]
554pub static exsltLibxsltVersion: c_int = 10145;
555
556/// `int xslDebugStatus` — the libxslt debugger status (upstream xsltutils.c
557/// `XSLTPUBVAR int xslDebugStatus;`, default XSLT_DEBUG_NONE = 0; oracle DSO
558/// symbol type B). Written by `xsltSetDebuggerStatus`; read by the transform
559/// engine's profiling gates (R-000165 DATA_MISSING closure).
560#[no_mangle]
561pub static mut xslDebugStatus: c_int = 0;
562
563/// `xmlGenericErrorFunc xsltGenericError` — the libxslt error callback.
564/// Upstream defaults to `xsltGenericErrorDefaultFunc` (xsltutils.c, a variadic
565/// stderr printer); the candidate's shim below reproduces it (R-000135
566/// divergence now closed).
567#[cfg(target_arch = "x86_64")]
568#[no_mangle]
569pub static mut xsltGenericError: Option<xmlGenericErrorFunc> = Some(XSLT_GENERIC_ERROR_DEFAULT);
570
571#[cfg(not(target_arch = "x86_64"))]
572#[no_mangle]
573pub static mut xsltGenericError: Option<xmlGenericErrorFunc> = None;
574
575/// `void *xsltGenericErrorContext` (default NULL)
576#[no_mangle]
577pub static mut xsltGenericErrorContext: *mut c_void = core::ptr::null_mut();
578
579/// `void *xsltGenericDebugContext` (default NULL)
580#[no_mangle]
581pub static mut xsltGenericDebugContext: *mut c_void = core::ptr::null_mut();
582
583/// `const xmlChar xsltExtMarker[]` — empty string used to mark extension
584/// nodes (upstream transform.c).
585#[no_mangle]
586pub static xsltExtMarker: [xmlChar; 1] = [0];
587
588/// `xsltDocLoaderFunc xsltDocDefaultLoader` — the document loader callback.
589/// Upstream defaults to `xsltDocDefaultLoaderFunc`; the candidate defaults
590/// to NULL and its internal loader path is used — documented safe
591/// divergence (residual R-000135).
592#[no_mangle]
593pub static mut xsltDocDefaultLoader: Option<
594 unsafe extern "C" fn(
595 *const xmlChar,
596 *mut c_void,
597 c_int,
598 *mut crate::abi::structs::_xsltStylesheet,
599 *mut crate::abi::structs::_xsltTransformContext,
600 ) -> *mut crate::abi::structs::_xmlDoc,
601> = None;
602
603// ═══════════════════════════════════════════════════════════════════════════════
604// I/O filename callback globals (upstream xmlIO.h)
605// ═══════════════════════════════════════════════════════════════════════════════
606
607/// `xmlParserInputBufferCreateFilenameFunc xmlParserInputBufferCreateFilenameValue`
608#[no_mangle]
609pub static mut xmlParserInputBufferCreateFilenameValue: Option<
610 unsafe extern "C" fn(*const c_char, c_int) -> *mut crate::abi::structs::_xmlParserInputBuffer,
611> = None;
612
613/// `xmlOutputBufferCreateFilenameFunc xmlOutputBufferCreateFilenameValue`
614#[no_mangle]
615pub static mut xmlOutputBufferCreateFilenameValue: Option<
616 unsafe extern "C" fn(
617 *const c_char,
618 crate::abi::structs::xmlCharEncodingHandlerPtr,
619 c_int,
620 ) -> *mut crate::abi::structs::_xmlOutputBuffer,
621> = None;
622
623// ═══════════════════════════════════════════════════════════════════════════════
624// Default SAX v1 handler structs + locator (upstream globals.c 2.15.3)
625// ═══════════════════════════════════════════════════════════════════════════════
626//
627// `const xmlSAXHandlerV1 xmlDefaultSAXHandler` and `htmlDefaultSAXHandler`
628// (parser.h / HTMLparser.h), plus `const xmlSAXLocator xmlDefaultSAXLocator`.
629// The handler instances reproduce the upstream initializer lists exactly
630// (globals.c); every referenced xmlSAX2* entry point is a real candidate
631// export.
632
633/// `const xmlSAXHandlerV1 xmlDefaultSAXHandler` (globals.c 2.15.3).
634#[no_mangle]
635pub static xmlDefaultSAXHandler: crate::abi::structs::_xmlSAXHandlerV1 =
636 crate::abi::structs::_xmlSAXHandlerV1 {
637 internalSubset: Some(crate::abi::exports_xml2::xmlSAX2InternalSubset),
638 isStandalone: Some(crate::abi::exports_xml2::xmlSAX2IsStandalone),
639 hasInternalSubset: Some(crate::abi::exports_xml2::xmlSAX2HasInternalSubset),
640 hasExternalSubset: Some(crate::abi::exports_xml2::xmlSAX2HasExternalSubset),
641 resolveEntity: Some(crate::abi::exports_xml2::xmlSAX2ResolveEntity),
642 getEntity: Some(crate::abi::exports_xml2::xmlSAX2GetEntity),
643 entityDecl: Some(crate::abi::exports_xml2::xmlSAX2EntityDecl),
644 notationDecl: Some(crate::abi::exports_xml2::xmlSAX2NotationDecl),
645 attributeDecl: Some(crate::abi::exports_xml2::xmlSAX2AttributeDecl),
646 elementDecl: Some(crate::abi::exports_xml2::xmlSAX2ElementDecl),
647 unparsedEntityDecl: Some(crate::abi::exports_xml2::xmlSAX2UnparsedEntityDecl),
648 setDocumentLocator: Some(crate::abi::exports_xml2::xmlSAX2SetDocumentLocator),
649 startDocument: Some(crate::abi::exports_xml2::xmlSAX2StartDocument),
650 endDocument: Some(crate::abi::exports_xml2::xmlSAX2EndDocument),
651 startElement: Some(crate::abi::exports_xml2::xmlSAX2StartElement),
652 endElement: Some(crate::abi::exports_xml2::xmlSAX2EndElement),
653 reference: Some(crate::abi::exports_xml2::xmlSAX2Reference),
654 characters: Some(crate::abi::exports_xml2::xmlSAX2Characters),
655 ignorableWhitespace: Some(crate::abi::exports_xml2::xmlSAX2IgnorableWhitespace),
656 processingInstruction: Some(crate::abi::exports_xml2::xmlSAX2ProcessingInstruction),
657 comment: Some(crate::abi::exports_xml2::xmlSAX2Comment),
658 warning: Some(crate::xml::errors::xmlParserWarning),
659 error: Some(crate::xml::errors::xmlParserError),
660 fatalError: Some(crate::xml::errors::xmlParserError),
661 getParameterEntity: Some(crate::abi::exports_xml2::xmlSAX2GetParameterEntity),
662 cdataBlock: Some(crate::abi::exports_xml2::xmlSAX2CDataBlock),
663 externalSubset: Some(crate::abi::exports_xml2::xmlSAX2ExternalSubset),
664 initialized: 1,
665 };
666
667/// `const xmlSAXHandlerV1 htmlDefaultSAXHandler` (globals.c 2.15.3).
668#[no_mangle]
669pub static htmlDefaultSAXHandler: crate::abi::structs::_xmlSAXHandlerV1 =
670 crate::abi::structs::_xmlSAXHandlerV1 {
671 internalSubset: Some(crate::abi::exports_xml2::xmlSAX2InternalSubset),
672 isStandalone: None,
673 hasInternalSubset: None,
674 hasExternalSubset: None,
675 resolveEntity: None,
676 getEntity: Some(crate::abi::exports_xml2::xmlSAX2GetEntity),
677 entityDecl: None,
678 notationDecl: None,
679 attributeDecl: None,
680 elementDecl: None,
681 unparsedEntityDecl: None,
682 setDocumentLocator: Some(crate::abi::exports_xml2::xmlSAX2SetDocumentLocator),
683 startDocument: Some(crate::abi::exports_xml2::xmlSAX2StartDocument),
684 endDocument: Some(crate::abi::exports_xml2::xmlSAX2EndDocument),
685 startElement: Some(crate::abi::exports_xml2::xmlSAX2StartElement),
686 endElement: Some(crate::abi::exports_xml2::xmlSAX2EndElement),
687 reference: None,
688 characters: Some(crate::abi::exports_xml2::xmlSAX2Characters),
689 ignorableWhitespace: Some(crate::abi::exports_xml2::xmlSAX2IgnorableWhitespace),
690 processingInstruction: Some(crate::abi::exports_xml2::xmlSAX2ProcessingInstruction),
691 comment: Some(crate::abi::exports_xml2::xmlSAX2Comment),
692 warning: Some(crate::xml::errors::xmlParserWarning),
693 error: Some(crate::xml::errors::xmlParserError),
694 fatalError: Some(crate::xml::errors::xmlParserError),
695 getParameterEntity: None,
696 cdataBlock: Some(crate::abi::exports_xml2::xmlSAX2CDataBlock),
697 externalSubset: None,
698 initialized: 1,
699 };
700
701/// `const xmlSAXLocator xmlDefaultSAXLocator` (globals.c 2.15.3).
702#[no_mangle]
703pub static xmlDefaultSAXLocator: crate::abi::callbacks::_xmlSAXLocator =
704 crate::abi::callbacks::_xmlSAXLocator {
705 getPublicId: Some(crate::abi::exports_xml2::xmlSAX2GetPublicId),
706 getSystemId: Some(crate::abi::exports_xml2::xmlSAX2GetSystemId),
707 getLineNumber: Some(crate::abi::exports_xml2::xmlSAX2GetLineNumber),
708 getColumnNumber: Some(crate::abi::exports_xml2::xmlSAX2GetColumnNumber),
709 };
710
711// ═══════════════════════════════════════════════════════════════════════════════
712// xmlLastError — the exported C global mirror of the thread-local error state
713// ═══════════════════════════════════════════════════════════════════════════════
714//
715// Upstream `XMLPUBVAR xmlError xmlLastError` (xmlerror.h). The candidate's
716// internal error state is thread-local (safe divergence, more correct than
717// upstream's racy global); this mirror is deep-copied on every error raise
718// and freed on reset, so C consumers observe upstream-equivalent lifetime
719// semantics. Residual R-000135.
720
721/// `xmlError xmlLastError` — most recent error (mirror).
722#[no_mangle]
723pub static mut xmlLastError: crate::abi::structs::_xmlError = crate::abi::structs::_xmlError {
724 domain: 0,
725 code: 0,
726 message: core::ptr::null_mut(),
727 level: 0,
728 file: core::ptr::null_mut(),
729 line: 0,
730 str1: core::ptr::null_mut(),
731 str2: core::ptr::null_mut(),
732 str3: core::ptr::null_mut(),
733 int1: 0,
734 int2: 0,
735 ctxt: core::ptr::null_mut(),
736 node: core::ptr::null_mut(),
737};
738
739/// Deep-copy `err` into the exported `xmlLastError` global.
740///
741/// The string fields are copied with `libc::malloc`/`memcpy` so the mirror
742/// owns them (previous mirror strings are freed first — upstream
743/// xmlResetError semantics).
744///
745/// # SAFETY
746///
747/// - `err` must point to a valid `_xmlError` whose string fields are
748/// NUL-terminated or NULL.
749pub unsafe fn sync_xml_last_error(err: *const crate::abi::structs::_xmlError) {
750 if err.is_null() {
751 return;
752 }
753 let _guard = LAST_ERROR_MIRROR_LOCK.lock();
754 unsafe { sync_xml_last_error_locked(err) };
755}
756
757/// Mirror write helper; caller must hold `LAST_ERROR_MIRROR_LOCK`.
758unsafe fn sync_xml_last_error_locked(err: *const crate::abi::structs::_xmlError) {
759 unsafe {
760 reset_xml_last_error_locked();
761 let src = &*err;
762 let dst = core::ptr::addr_of_mut!(xmlLastError);
763 (*dst).domain = src.domain;
764 (*dst).code = src.code;
765 (*dst).level = src.level;
766 (*dst).line = src.line;
767 (*dst).int1 = src.int1;
768 (*dst).int2 = src.int2;
769 (*dst).ctxt = src.ctxt;
770 (*dst).node = src.node;
771 (*dst).message = dup_cstr(src.message as *const u8);
772 (*dst).file = dup_cstr(src.file as *const u8);
773 (*dst).str1 = dup_cstr(src.str1 as *const u8);
774 (*dst).str2 = dup_cstr(src.str2 as *const u8);
775 (*dst).str3 = dup_cstr(src.str3 as *const u8);
776 }
777}
778
779/// Reset the exported `xmlLastError` global, freeing owned strings
780/// (upstream xmlResetError).
781///
782/// # SAFETY
783///
784/// Only call while no other thread is reading the global (upstream has the
785/// same race; documented).
786pub unsafe fn reset_xml_last_error() {
787 let _guard = LAST_ERROR_MIRROR_LOCK.lock();
788 unsafe { reset_xml_last_error_locked() };
789}
790
791/// Mirror reset helper; caller must hold `LAST_ERROR_MIRROR_LOCK`.
792unsafe fn reset_xml_last_error_locked() {
793 unsafe {
794 let dst = core::ptr::addr_of_mut!(xmlLastError);
795 if !(*dst).message.is_null() {
796 libc::free((*dst).message as *mut libc::c_void);
797 }
798 if !(*dst).file.is_null() {
799 libc::free((*dst).file as *mut libc::c_void);
800 }
801 if !(*dst).str1.is_null() {
802 libc::free((*dst).str1 as *mut libc::c_void);
803 }
804 if !(*dst).str2.is_null() {
805 libc::free((*dst).str2 as *mut libc::c_void);
806 }
807 if !(*dst).str3.is_null() {
808 libc::free((*dst).str3 as *mut libc::c_void);
809 }
810 *dst = crate::abi::structs::_xmlError {
811 domain: 0,
812 code: 0,
813 message: core::ptr::null_mut(),
814 level: 0,
815 file: core::ptr::null_mut(),
816 line: 0,
817 str1: core::ptr::null_mut(),
818 str2: core::ptr::null_mut(),
819 str3: core::ptr::null_mut(),
820 int1: 0,
821 int2: 0,
822 ctxt: core::ptr::null_mut(),
823 node: core::ptr::null_mut(),
824 };
825 }
826}
827
828/// Heap-copy a NUL-terminated string (NULL-safe).
829unsafe fn dup_cstr(s: *const u8) -> *mut c_char {
830 if s.is_null() {
831 return core::ptr::null_mut();
832 }
833 unsafe {
834 let len = libc::strlen(s as *const libc::c_char) as usize;
835 let p = libc::malloc(len + 1) as *mut u8;
836 if p.is_null() {
837 return core::ptr::null_mut();
838 }
839 libc::memcpy(p as *mut libc::c_void, s as *const libc::c_void, len + 1);
840 p as *mut c_char
841 }
842}
843
844// ═══════════════════════════════════════════════════════════════════════════════
845// Default accessor functions (upstream parser.h / tree.h / xmlsave.h)
846// ═══════════════════════════════════════════════════════════════════════════════
847//
848// The deprecated `xmlXxxDefault(v)` accessors set the corresponding global
849// when `v != 0` and return the (new) value — upstream semantics (they
850// predate the plain globals; the modern behavior is conditional-set-and-
851// return, see upstream globals.c / parser.c).
852
853/// Upstream `xmlKeepBlanksDefault(int v)`.
854///
855/// # SAFETY
856///
857/// The function touches crate-global state only; it is safe
858/// as long as the caller respects the library's global
859/// initialization/cleanup ordering (xmlInitParser before use,
860/// xmlCleanupParser only after all users are done).
861///
862/// Violating the global lifecycle ordering, or calling this after
863/// teardown or from a signal handler, is undefined behavior.
864#[no_mangle]
865pub unsafe extern "C" fn xmlKeepBlanksDefault(v: c_int) -> c_int {
866 unsafe {
867 if v != 0 {
868 xmlKeepBlanksDefaultValue = v;
869 }
870 xmlKeepBlanksDefaultValue
871 }
872}
873
874/// Upstream `xmlLineNumbersDefault(int v)`.
875///
876/// # SAFETY
877///
878/// The function touches crate-global state only; it is safe
879/// as long as the caller respects the library's global
880/// initialization/cleanup ordering (xmlInitParser before use,
881/// xmlCleanupParser only after all users are done).
882///
883/// Violating the global lifecycle ordering, or calling this after
884/// teardown or from a signal handler, is undefined behavior.
885#[no_mangle]
886pub unsafe extern "C" fn xmlLineNumbersDefault(v: c_int) -> c_int {
887 unsafe {
888 if v != 0 {
889 xmlLineNumbersDefaultValue = v;
890 }
891 xmlLineNumbersDefaultValue
892 }
893}
894
895/// Upstream `xmlSubstituteEntitiesDefault(int v)`.
896///
897/// # SAFETY
898///
899/// The function touches crate-global state only; it is safe
900/// as long as the caller respects the library's global
901/// initialization/cleanup ordering (xmlInitParser before use,
902/// xmlCleanupParser only after all users are done).
903///
904/// Violating the global lifecycle ordering, or calling this after
905/// teardown or from a signal handler, is undefined behavior.
906#[no_mangle]
907pub unsafe extern "C" fn xmlSubstituteEntitiesDefault(v: c_int) -> c_int {
908 unsafe {
909 if v != 0 {
910 xmlSubstituteEntitiesDefaultValue = v;
911 }
912 xmlSubstituteEntitiesDefaultValue
913 }
914}
915
916/// Upstream `xmlPedanticParserDefault(int v)`.
917///
918/// # SAFETY
919///
920/// The function touches crate-global state only; it is safe
921/// as long as the caller respects the library's global
922/// initialization/cleanup ordering (xmlInitParser before use,
923/// xmlCleanupParser only after all users are done).
924///
925/// Violating the global lifecycle ordering, or calling this after
926/// teardown or from a signal handler, is undefined behavior.
927#[no_mangle]
928pub unsafe extern "C" fn xmlPedanticParserDefault(v: c_int) -> c_int {
929 unsafe {
930 if v != 0 {
931 xmlPedanticParserDefaultValue = v;
932 }
933 xmlPedanticParserDefaultValue
934 }
935}
936
937/// Upstream `xmlDoValidityCheckingDefaultValue` accessor is the global
938/// itself; `xmlGetWarningsDefaultValue` likewise (no accessor functions
939/// exist for those in upstream 2.15).
940/// Upstream `xmlRegisterNodeDefault(xmlRegisterNodeFunc func)`.
941///
942/// # SAFETY
943///
944///
945/// - `func` must be a valid callback (or None);
946/// the callback is invoked with the documented context pointer and
947/// must itself uphold the same pointer invariants.
948///
949/// The caller must not race this call with concurrent mutation of the
950/// same objects from other threads (per-object state is not internally
951/// synchronized). Violating any of the above is undefined behavior.
952///
953/// Exercised by the C-API differential courts
954/// (courts/suites/data-abi/*-family-probe.c) and the CLI differential
955/// courts; those pass byte-for-byte against the upstream oracle.
956#[no_mangle]
957pub unsafe extern "C" fn xmlRegisterNodeDefault(
958 func: Option<unsafe extern "C" fn(*mut crate::abi::structs::_xmlNode)>,
959) -> Option<unsafe extern "C" fn(*mut crate::abi::structs::_xmlNode)> {
960 unsafe {
961 // UPSTREAM-PARITY (tree.c): registering any callback arms the
962 // xmlRegisterCallbacks gate.
963 XML_REGISTER_CALLBACKS.store(true, core::sync::atomic::Ordering::Relaxed);
964 if func.is_some() {
965 xmlRegisterNodeDefaultValue = func;
966 }
967 xmlRegisterNodeDefaultValue
968 }
969}
970
971/// Upstream `xmlDeregisterNodeDefault(xmlDeregisterNodeFunc func)`.
972///
973/// # SAFETY
974///
975///
976/// - `func` must be a valid callback (or None);
977/// the callback is invoked with the documented context pointer and
978/// must itself uphold the same pointer invariants.
979///
980/// The caller must not race this call with concurrent mutation of the
981/// same objects from other threads (per-object state is not internally
982/// synchronized). Violating any of the above is undefined behavior.
983///
984/// Exercised by the C-API differential courts
985/// (courts/suites/data-abi/*-family-probe.c) and the CLI differential
986/// courts; those pass byte-for-byte against the upstream oracle.
987#[no_mangle]
988pub unsafe extern "C" fn xmlDeregisterNodeDefault(
989 func: Option<unsafe extern "C" fn(*mut crate::abi::structs::_xmlNode)>,
990) -> Option<unsafe extern "C" fn(*mut crate::abi::structs::_xmlNode)> {
991 unsafe {
992 // UPSTREAM-PARITY (tree.c): registering any callback arms the
993 // xmlRegisterCallbacks gate.
994 XML_REGISTER_CALLBACKS.store(true, core::sync::atomic::Ordering::Relaxed);
995 if func.is_some() {
996 xmlDeregisterNodeDefaultValue = func;
997 }
998 xmlDeregisterNodeDefaultValue
999 }
1000}
1001
1002/// Upstream `__xmlIndentTreeOutput(void)` (parser.h) — returns a pointer to
1003/// the `xmlIndentTreeOutput` global.
1004///
1005/// # SAFETY
1006///
1007/// The function touches crate-global state only; it is safe
1008/// as long as the caller respects the library's global
1009/// initialization/cleanup ordering (xmlInitParser before use,
1010/// xmlCleanupParser only after all users are done).
1011///
1012/// Violating the global lifecycle ordering, or calling this after
1013/// teardown or from a signal handler, is undefined behavior.
1014#[no_mangle]
1015pub unsafe extern "C" fn __xmlIndentTreeOutput() -> *mut c_int {
1016 core::ptr::addr_of_mut!(xmlIndentTreeOutput)
1017}
1018
1019/// Upstream `__xmlSaveNoEmptyTags(void)` (parser.h) — returns a pointer to
1020/// the `xmlSaveNoEmptyTags` global.
1021///
1022/// # SAFETY
1023///
1024/// The function touches crate-global state only; it is safe
1025/// as long as the caller respects the library's global
1026/// initialization/cleanup ordering (xmlInitParser before use,
1027/// xmlCleanupParser only after all users are done).
1028///
1029/// Violating the global lifecycle ordering, or calling this after
1030/// teardown or from a signal handler, is undefined behavior.
1031#[no_mangle]
1032pub unsafe extern "C" fn __xmlSaveNoEmptyTags() -> *mut c_int {
1033 core::ptr::addr_of_mut!(xmlSaveNoEmptyTags)
1034}
1035
1036/// Upstream `__xmlTreeIndentString(void)` (parser.h) — returns a pointer to
1037/// the `xmlTreeIndentString` global.
1038///
1039/// # SAFETY
1040///
1041/// The function touches crate-global state only; it is safe
1042/// as long as the caller respects the library's global
1043/// initialization/cleanup ordering (xmlInitParser before use,
1044/// xmlCleanupParser only after all users are done).
1045///
1046/// Violating the global lifecycle ordering, or calling this after
1047/// teardown or from a signal handler, is undefined behavior.
1048#[no_mangle]
1049pub unsafe extern "C" fn __xmlTreeIndentString() -> *mut *const xmlChar {
1050 core::ptr::addr_of_mut!(xmlTreeIndentString)
1051}
1052
1053// ═══════════════════════════════════════════════════════════════════════════════
1054// xmlThrDef* accessors (upstream threads.c / globals.c)
1055// ═══════════════════════════════════════════════════════════════════════════════
1056//
1057// The deprecated `xmlThrDef*` family reads/writes the public globals with
1058// the upstream semantics: when `v != 0` the global is set, and the (new)
1059// value is returned. In upstream these were thread-local definitions before
1060// the globals became plain variables; the modern behavior is exactly this
1061// conditional-set-and-return on the global (see upstream globals.c).
1062
1063/// Upstream `xmlThrDefDoValidityCheckingDefaultValue(int v)`.
1064///
1065/// # SAFETY
1066///
1067/// The function touches crate-global state only; it is safe
1068/// as long as the caller respects the library's global
1069/// initialization/cleanup ordering (xmlInitParser before use,
1070/// xmlCleanupParser only after all users are done).
1071///
1072/// Violating the global lifecycle ordering, or calling this after
1073/// teardown or from a signal handler, is undefined behavior.
1074#[no_mangle]
1075pub unsafe extern "C" fn xmlThrDefDoValidityCheckingDefaultValue(v: c_int) -> c_int {
1076 unsafe {
1077 if v != 0 {
1078 xmlDoValidityCheckingDefaultValue = v;
1079 }
1080 xmlDoValidityCheckingDefaultValue
1081 }
1082}
1083
1084/// Upstream `xmlThrDefGetWarningsDefaultValue(int v)`.
1085///
1086/// # SAFETY
1087///
1088/// The function touches crate-global state only; it is safe
1089/// as long as the caller respects the library's global
1090/// initialization/cleanup ordering (xmlInitParser before use,
1091/// xmlCleanupParser only after all users are done).
1092///
1093/// Violating the global lifecycle ordering, or calling this after
1094/// teardown or from a signal handler, is undefined behavior.
1095#[no_mangle]
1096pub unsafe extern "C" fn xmlThrDefGetWarningsDefaultValue(v: c_int) -> c_int {
1097 unsafe {
1098 if v != 0 {
1099 xmlGetWarningsDefaultValue = v;
1100 }
1101 xmlGetWarningsDefaultValue
1102 }
1103}
1104
1105/// Upstream `xmlThrDefLoadExtDtdDefaultValue(int v)`.
1106///
1107/// # SAFETY
1108///
1109/// The function touches crate-global state only; it is safe
1110/// as long as the caller respects the library's global
1111/// initialization/cleanup ordering (xmlInitParser before use,
1112/// xmlCleanupParser only after all users are done).
1113///
1114/// Violating the global lifecycle ordering, or calling this after
1115/// teardown or from a signal handler, is undefined behavior.
1116#[no_mangle]
1117pub unsafe extern "C" fn xmlThrDefLoadExtDtdDefaultValue(v: c_int) -> c_int {
1118 unsafe {
1119 if v != 0 {
1120 xmlLoadExtDtdDefaultValue = v;
1121 }
1122 xmlLoadExtDtdDefaultValue
1123 }
1124}
1125
1126/// Upstream `xmlThrDefPedanticParserDefaultValue(int v)`.
1127///
1128/// # SAFETY
1129///
1130/// The function touches crate-global state only; it is safe
1131/// as long as the caller respects the library's global
1132/// initialization/cleanup ordering (xmlInitParser before use,
1133/// xmlCleanupParser only after all users are done).
1134///
1135/// Violating the global lifecycle ordering, or calling this after
1136/// teardown or from a signal handler, is undefined behavior.
1137#[no_mangle]
1138pub unsafe extern "C" fn xmlThrDefPedanticParserDefaultValue(v: c_int) -> c_int {
1139 unsafe {
1140 if v != 0 {
1141 xmlPedanticParserDefaultValue = v;
1142 }
1143 xmlPedanticParserDefaultValue
1144 }
1145}
1146
1147/// Upstream `xmlThrDefLineNumbersDefaultValue(int v)`.
1148///
1149/// # SAFETY
1150///
1151/// The function touches crate-global state only; it is safe
1152/// as long as the caller respects the library's global
1153/// initialization/cleanup ordering (xmlInitParser before use,
1154/// xmlCleanupParser only after all users are done).
1155///
1156/// Violating the global lifecycle ordering, or calling this after
1157/// teardown or from a signal handler, is undefined behavior.
1158#[no_mangle]
1159pub unsafe extern "C" fn xmlThrDefLineNumbersDefaultValue(v: c_int) -> c_int {
1160 unsafe {
1161 if v != 0 {
1162 xmlLineNumbersDefaultValue = v;
1163 }
1164 xmlLineNumbersDefaultValue
1165 }
1166}
1167
1168/// Upstream `xmlThrDefKeepBlanksDefaultValue(int v)`.
1169///
1170/// # SAFETY
1171///
1172/// The function touches crate-global state only; it is safe
1173/// as long as the caller respects the library's global
1174/// initialization/cleanup ordering (xmlInitParser before use,
1175/// xmlCleanupParser only after all users are done).
1176///
1177/// Violating the global lifecycle ordering, or calling this after
1178/// teardown or from a signal handler, is undefined behavior.
1179#[no_mangle]
1180pub unsafe extern "C" fn xmlThrDefKeepBlanksDefaultValue(v: c_int) -> c_int {
1181 unsafe {
1182 if v != 0 {
1183 xmlKeepBlanksDefaultValue = v;
1184 }
1185 xmlKeepBlanksDefaultValue
1186 }
1187}
1188
1189/// Upstream `xmlThrDefSubstituteEntitiesDefaultValue(int v)`.
1190///
1191/// # SAFETY
1192///
1193/// The function touches crate-global state only; it is safe
1194/// as long as the caller respects the library's global
1195/// initialization/cleanup ordering (xmlInitParser before use,
1196/// xmlCleanupParser only after all users are done).
1197///
1198/// Violating the global lifecycle ordering, or calling this after
1199/// teardown or from a signal handler, is undefined behavior.
1200#[no_mangle]
1201pub unsafe extern "C" fn xmlThrDefSubstituteEntitiesDefaultValue(v: c_int) -> c_int {
1202 unsafe {
1203 if v != 0 {
1204 xmlSubstituteEntitiesDefaultValue = v;
1205 }
1206 xmlSubstituteEntitiesDefaultValue
1207 }
1208}
1209
1210/// Upstream `xmlThrDefParserDebugEntities(int v)`.
1211///
1212/// # SAFETY
1213///
1214/// The function touches crate-global state only; it is safe
1215/// as long as the caller respects the library's global
1216/// initialization/cleanup ordering (xmlInitParser before use,
1217/// xmlCleanupParser only after all users are done).
1218///
1219/// Violating the global lifecycle ordering, or calling this after
1220/// teardown or from a signal handler, is undefined behavior.
1221#[no_mangle]
1222pub unsafe extern "C" fn xmlThrDefParserDebugEntities(v: c_int) -> c_int {
1223 unsafe {
1224 if v != 0 {
1225 xmlParserDebugEntities = v;
1226 }
1227 xmlParserDebugEntities
1228 }
1229}
1230
1231/// Upstream `xmlThrDefIndentTreeOutput(int v)`.
1232///
1233/// # SAFETY
1234///
1235/// The function touches crate-global state only; it is safe
1236/// as long as the caller respects the library's global
1237/// initialization/cleanup ordering (xmlInitParser before use,
1238/// xmlCleanupParser only after all users are done).
1239///
1240/// Violating the global lifecycle ordering, or calling this after
1241/// teardown or from a signal handler, is undefined behavior.
1242#[no_mangle]
1243pub unsafe extern "C" fn xmlThrDefIndentTreeOutput(v: c_int) -> c_int {
1244 unsafe {
1245 if v != 0 {
1246 xmlIndentTreeOutput = v;
1247 }
1248 xmlIndentTreeOutput
1249 }
1250}
1251
1252/// Upstream `xmlThrDefTreeIndentString(const char *v)` — sets the indent
1253/// string when non-NULL and returns the current pointer.
1254///
1255/// # SAFETY
1256///
1257///
1258/// - `v` must point to valid NUL-terminated
1259/// strings (or NULL where the C contract allows) for the lifetime
1260/// of the call.
1261///
1262/// The caller must not race this call with concurrent mutation of the
1263/// same objects from other threads (per-object state is not internally
1264/// synchronized). Violating any of the above is undefined behavior.
1265///
1266/// Exercised by the C-API differential courts
1267/// (courts/suites/data-abi/*-family-probe.c) and the CLI differential
1268/// courts; those pass byte-for-byte against the upstream oracle.
1269#[no_mangle]
1270pub unsafe extern "C" fn xmlThrDefTreeIndentString(v: *const c_char) -> *const c_char {
1271 unsafe {
1272 if !v.is_null() {
1273 xmlTreeIndentString = v as *const xmlChar;
1274 }
1275 xmlTreeIndentString as *const c_char
1276 }
1277}
1278
1279/// Upstream `xmlThrDefSaveNoEmptyTags(int v)`.
1280///
1281/// # SAFETY
1282///
1283/// The function touches crate-global state only; it is safe
1284/// as long as the caller respects the library's global
1285/// initialization/cleanup ordering (xmlInitParser before use,
1286/// xmlCleanupParser only after all users are done).
1287///
1288/// Violating the global lifecycle ordering, or calling this after
1289/// teardown or from a signal handler, is undefined behavior.
1290#[no_mangle]
1291pub unsafe extern "C" fn xmlThrDefSaveNoEmptyTags(v: c_int) -> c_int {
1292 unsafe {
1293 if v != 0 {
1294 xmlSaveNoEmptyTags = v;
1295 }
1296 xmlSaveNoEmptyTags
1297 }
1298}
1299
1300/// Upstream `xmlThrDefRegisterNodeDefault(xmlRegisterNodeFunc func)`.
1301///
1302/// # SAFETY
1303///
1304///
1305/// - `func` must be a valid callback (or None);
1306/// the callback is invoked with the documented context pointer and
1307/// must itself uphold the same pointer invariants.
1308///
1309/// The caller must not race this call with concurrent mutation of the
1310/// same objects from other threads (per-object state is not internally
1311/// synchronized). Violating any of the above is undefined behavior.
1312///
1313/// Exercised by the C-API differential courts
1314/// (courts/suites/data-abi/*-family-probe.c) and the CLI differential
1315/// courts; those pass byte-for-byte against the upstream oracle.
1316#[no_mangle]
1317pub unsafe extern "C" fn xmlThrDefRegisterNodeDefault(
1318 func: Option<unsafe extern "C" fn(*mut crate::abi::structs::_xmlNode)>,
1319) -> Option<unsafe extern "C" fn(*mut crate::abi::structs::_xmlNode)> {
1320 unsafe {
1321 if func.is_some() {
1322 xmlRegisterNodeDefaultValue = func;
1323 }
1324 xmlRegisterNodeDefaultValue
1325 }
1326}
1327
1328/// Upstream `xmlThrDefDeregisterNodeDefault(xmlDeregisterNodeFunc func)`.
1329///
1330/// # SAFETY
1331///
1332///
1333/// - `func` must be a valid callback (or None);
1334/// the callback is invoked with the documented context pointer and
1335/// must itself uphold the same pointer invariants.
1336///
1337/// The caller must not race this call with concurrent mutation of the
1338/// same objects from other threads (per-object state is not internally
1339/// synchronized). Violating any of the above is undefined behavior.
1340///
1341/// Exercised by the C-API differential courts
1342/// (courts/suites/data-abi/*-family-probe.c) and the CLI differential
1343/// courts; those pass byte-for-byte against the upstream oracle.
1344#[no_mangle]
1345pub unsafe extern "C" fn xmlThrDefDeregisterNodeDefault(
1346 func: Option<unsafe extern "C" fn(*mut crate::abi::structs::_xmlNode)>,
1347) -> Option<unsafe extern "C" fn(*mut crate::abi::structs::_xmlNode)> {
1348 unsafe {
1349 if func.is_some() {
1350 xmlDeregisterNodeDefaultValue = func;
1351 }
1352 xmlDeregisterNodeDefaultValue
1353 }
1354}
1355
1356/// Upstream `xmlThrDefSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc func)`.
1357///
1358/// # SAFETY
1359///
1360/// - `ctx` must be valid pointers (or NULL
1361/// where the upstream C contract allows), obtained from the
1362/// matching constructor/owner and not yet freed; the callee may
1363/// take or keep ownership exactly as the C API specifies.
1364///
1365/// - `func` must be a valid callback (or None);
1366/// the callback is invoked with the documented context pointer and
1367/// must itself uphold the same pointer invariants.
1368///
1369/// The caller must not race this call with concurrent mutation of the
1370/// same objects from other threads (per-object state is not internally
1371/// synchronized). Violating any of the above is undefined behavior.
1372///
1373/// Exercised by the C-API differential courts
1374/// (courts/suites/data-abi/*-family-probe.c) and the CLI differential
1375/// courts; those pass byte-for-byte against the upstream oracle.
1376#[no_mangle]
1377pub unsafe extern "C" fn xmlThrDefSetGenericErrorFunc(
1378 ctx: *mut c_void,
1379 func: Option<xmlGenericErrorFunc>,
1380) {
1381 unsafe {
1382 xmlGenericErrorContext = ctx;
1383 xmlGenericError = func;
1384 }
1385}
1386
1387/// Upstream `xmlThrDefSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc func)`.
1388///
1389/// # SAFETY
1390///
1391/// - `ctx` must be valid pointers (or NULL
1392/// where the upstream C contract allows), obtained from the
1393/// matching constructor/owner and not yet freed; the callee may
1394/// take or keep ownership exactly as the C API specifies.
1395///
1396/// - `func` must be a valid callback (or None);
1397/// the callback is invoked with the documented context pointer and
1398/// must itself uphold the same pointer invariants.
1399///
1400/// The caller must not race this call with concurrent mutation of the
1401/// same objects from other threads (per-object state is not internally
1402/// synchronized). Violating any of the above is undefined behavior.
1403///
1404/// Exercised by the C-API differential courts
1405/// (courts/suites/data-abi/*-family-probe.c) and the CLI differential
1406/// courts; those pass byte-for-byte against the upstream oracle.
1407#[no_mangle]
1408pub unsafe extern "C" fn xmlThrDefSetStructuredErrorFunc(
1409 ctx: *mut c_void,
1410 func: Option<xmlStructuredErrorFunc>,
1411) {
1412 unsafe {
1413 xmlStructuredErrorContext = ctx;
1414 xmlStructuredError = func;
1415 }
1416}
1417
1418/// Upstream `xmlThrDefDefaultBufferSize(int v)`.
1419///
1420/// # SAFETY
1421///
1422/// The function touches crate-global state only; it is safe
1423/// as long as the caller respects the library's global
1424/// initialization/cleanup ordering (xmlInitParser before use,
1425/// xmlCleanupParser only after all users are done).
1426///
1427/// Violating the global lifecycle ordering, or calling this after
1428/// teardown or from a signal handler, is undefined behavior.
1429#[no_mangle]
1430pub unsafe extern "C" fn xmlThrDefDefaultBufferSize(v: c_int) -> c_int {
1431 unsafe {
1432 if v != 0 {
1433 xmlDefaultBufferSize = v;
1434 }
1435 xmlDefaultBufferSize
1436 }
1437}
1438
1439/// Upstream `xmlThrDefBufferAllocScheme(xmlBufferAllocationScheme v)`.
1440///
1441/// # SAFETY
1442///
1443/// The function touches crate-global state only; it is safe
1444/// as long as the caller respects the library's global
1445/// initialization/cleanup ordering (xmlInitParser before use,
1446/// xmlCleanupParser only after all users are done).
1447///
1448/// Violating the global lifecycle ordering, or calling this after
1449/// teardown or from a signal handler, is undefined behavior.
1450#[no_mangle]
1451pub unsafe extern "C" fn xmlThrDefBufferAllocScheme(v: c_int) -> c_int {
1452 unsafe {
1453 if v != 0 {
1454 xmlBufferAllocScheme = v;
1455 }
1456 xmlBufferAllocScheme
1457 }
1458}
1459
1460/// Upstream `xmlThrDefParserInputBufferCreateFilenameDefault(...)`.
1461///
1462/// # SAFETY
1463///
1464///
1465/// - `func` must be a valid callback (or None);
1466/// the callback is invoked with the documented context pointer and
1467/// must itself uphold the same pointer invariants.
1468///
1469/// The caller must not race this call with concurrent mutation of the
1470/// same objects from other threads (per-object state is not internally
1471/// synchronized). Violating any of the above is undefined behavior.
1472///
1473/// Exercised by the C-API differential courts
1474/// (courts/suites/data-abi/*-family-probe.c) and the CLI differential
1475/// courts; those pass byte-for-byte against the upstream oracle.
1476#[no_mangle]
1477pub unsafe extern "C" fn xmlThrDefParserInputBufferCreateFilenameDefault(
1478 func: Option<
1479 unsafe extern "C" fn(
1480 *const c_char,
1481 c_int,
1482 ) -> *mut crate::abi::structs::_xmlParserInputBuffer,
1483 >,
1484) -> Option<
1485 unsafe extern "C" fn(*const c_char, c_int) -> *mut crate::abi::structs::_xmlParserInputBuffer,
1486> {
1487 unsafe {
1488 if func.is_some() {
1489 xmlParserInputBufferCreateFilenameValue = func;
1490 }
1491 xmlParserInputBufferCreateFilenameValue
1492 }
1493}
1494
1495/// Upstream `xmlThrDefOutputBufferCreateFilenameDefault(...)`.
1496///
1497/// # SAFETY
1498///
1499///
1500/// - `func` must be a valid callback (or None);
1501/// the callback is invoked with the documented context pointer and
1502/// must itself uphold the same pointer invariants.
1503///
1504/// The caller must not race this call with concurrent mutation of the
1505/// same objects from other threads (per-object state is not internally
1506/// synchronized). Violating any of the above is undefined behavior.
1507///
1508/// Exercised by the C-API differential courts
1509/// (courts/suites/data-abi/*-family-probe.c) and the CLI differential
1510/// courts; those pass byte-for-byte against the upstream oracle.
1511#[no_mangle]
1512pub unsafe extern "C" fn xmlThrDefOutputBufferCreateFilenameDefault(
1513 func: Option<
1514 unsafe extern "C" fn(
1515 *const c_char,
1516 crate::abi::structs::xmlCharEncodingHandlerPtr,
1517 c_int,
1518 ) -> *mut crate::abi::structs::_xmlOutputBuffer,
1519 >,
1520) -> Option<
1521 unsafe extern "C" fn(
1522 *const c_char,
1523 crate::abi::structs::xmlCharEncodingHandlerPtr,
1524 c_int,
1525 ) -> *mut crate::abi::structs::_xmlOutputBuffer,
1526> {
1527 unsafe {
1528 if func.is_some() {
1529 xmlOutputBufferCreateFilenameValue = func;
1530 }
1531 xmlOutputBufferCreateFilenameValue
1532 }
1533}
1534
1535// ═══════════════════════════════════════════════════════════════════════════════
1536// __xmlXxx() pointer accessors (upstream threads.c / globals.c)
1537// ═══════════════════════════════════════════════════════════════════════════════
1538// The deprecated thread-local API exports one `__xmlXxx(void)` accessor per
1539// global; each returns a pointer to the global so callers can read/write it.
1540
1541/// Upstream `__xmlBufferAllocScheme(void)` — returns a pointer to `xmlBufferAllocScheme`.
1542///
1543/// # SAFETY
1544///
1545/// The function touches crate-global state only; it is safe
1546/// as long as the caller respects the library's global
1547/// initialization/cleanup ordering (xmlInitParser before use,
1548/// xmlCleanupParser only after all users are done).
1549///
1550/// Violating the global lifecycle ordering, or calling this after
1551/// teardown or from a signal handler, is undefined behavior.
1552#[no_mangle]
1553pub unsafe extern "C" fn __xmlBufferAllocScheme() -> *mut c_int {
1554 // SAFETY: returning a pointer to an exported static; the caller may
1555 // read/write it exactly as with upstream's deprecated accessor.
1556 core::ptr::addr_of_mut!(xmlBufferAllocScheme)
1557}
1558
1559/// Upstream `__xmlDefaultBufferSize(void)` — returns a pointer to `xmlDefaultBufferSize`.
1560///
1561/// # SAFETY
1562///
1563/// The function touches crate-global state only; it is safe
1564/// as long as the caller respects the library's global
1565/// initialization/cleanup ordering (xmlInitParser before use,
1566/// xmlCleanupParser only after all users are done).
1567///
1568/// Violating the global lifecycle ordering, or calling this after
1569/// teardown or from a signal handler, is undefined behavior.
1570#[no_mangle]
1571pub unsafe extern "C" fn __xmlDefaultBufferSize() -> *mut c_int {
1572 // SAFETY: returning a pointer to an exported static; the caller may
1573 // read/write it exactly as with upstream's deprecated accessor.
1574 core::ptr::addr_of_mut!(xmlDefaultBufferSize)
1575}
1576
1577/// Upstream `__xmlDeregisterNodeDefaultValue(void)` — returns a pointer to `xmlDeregisterNodeDefaultValue`.
1578///
1579/// # SAFETY
1580///
1581/// The function touches crate-global state only; it is safe
1582/// as long as the caller respects the library's global
1583/// initialization/cleanup ordering (xmlInitParser before use,
1584/// xmlCleanupParser only after all users are done).
1585///
1586/// Violating the global lifecycle ordering, or calling this after
1587/// teardown or from a signal handler, is undefined behavior.
1588#[no_mangle]
1589pub unsafe extern "C" fn __xmlDeregisterNodeDefaultValue(
1590) -> *mut Option<unsafe extern "C" fn(*mut crate::abi::structs::_xmlNode)> {
1591 // SAFETY: returning a pointer to an exported static; the caller may
1592 // read/write it exactly as with upstream's deprecated accessor.
1593 core::ptr::addr_of_mut!(xmlDeregisterNodeDefaultValue)
1594}
1595
1596/// Upstream `__xmlDoValidityCheckingDefaultValue(void)` — returns a pointer to `xmlDoValidityCheckingDefaultValue`.
1597///
1598/// # SAFETY
1599///
1600/// The function touches crate-global state only; it is safe
1601/// as long as the caller respects the library's global
1602/// initialization/cleanup ordering (xmlInitParser before use,
1603/// xmlCleanupParser only after all users are done).
1604///
1605/// Violating the global lifecycle ordering, or calling this after
1606/// teardown or from a signal handler, is undefined behavior.
1607#[no_mangle]
1608pub unsafe extern "C" fn __xmlDoValidityCheckingDefaultValue() -> *mut c_int {
1609 // SAFETY: returning a pointer to an exported static; the caller may
1610 // read/write it exactly as with upstream's deprecated accessor.
1611 core::ptr::addr_of_mut!(xmlDoValidityCheckingDefaultValue)
1612}
1613
1614/// Upstream `__xmlGenericError(void)` — returns a pointer to `xmlGenericError`.
1615///
1616/// # SAFETY
1617///
1618/// The function touches crate-global state only; it is safe
1619/// as long as the caller respects the library's global
1620/// initialization/cleanup ordering (xmlInitParser before use,
1621/// xmlCleanupParser only after all users are done).
1622///
1623/// Violating the global lifecycle ordering, or calling this after
1624/// teardown or from a signal handler, is undefined behavior.
1625#[no_mangle]
1626pub unsafe extern "C" fn __xmlGenericError() -> *mut Option<xmlGenericErrorFunc> {
1627 // SAFETY: returning a pointer to an exported static; the caller may
1628 // read/write it exactly as with upstream's deprecated accessor.
1629 core::ptr::addr_of_mut!(xmlGenericError)
1630}
1631
1632/// Upstream `__xmlGenericErrorContext(void)` — returns a pointer to `xmlGenericErrorContext`.
1633///
1634/// # SAFETY
1635///
1636/// The function touches crate-global state only; it is safe
1637/// as long as the caller respects the library's global
1638/// initialization/cleanup ordering (xmlInitParser before use,
1639/// xmlCleanupParser only after all users are done).
1640///
1641/// Violating the global lifecycle ordering, or calling this after
1642/// teardown or from a signal handler, is undefined behavior.
1643#[no_mangle]
1644pub unsafe extern "C" fn __xmlGenericErrorContext() -> *mut *mut c_void {
1645 // SAFETY: returning a pointer to an exported static; the caller may
1646 // read/write it exactly as with upstream's deprecated accessor.
1647 core::ptr::addr_of_mut!(xmlGenericErrorContext)
1648}
1649
1650/// Upstream `__xmlGetWarningsDefaultValue(void)` — returns a pointer to `xmlGetWarningsDefaultValue`.
1651///
1652/// # SAFETY
1653///
1654/// The function touches crate-global state only; it is safe
1655/// as long as the caller respects the library's global
1656/// initialization/cleanup ordering (xmlInitParser before use,
1657/// xmlCleanupParser only after all users are done).
1658///
1659/// Violating the global lifecycle ordering, or calling this after
1660/// teardown or from a signal handler, is undefined behavior.
1661#[no_mangle]
1662pub unsafe extern "C" fn __xmlGetWarningsDefaultValue() -> *mut c_int {
1663 // SAFETY: returning a pointer to an exported static; the caller may
1664 // read/write it exactly as with upstream's deprecated accessor.
1665 core::ptr::addr_of_mut!(xmlGetWarningsDefaultValue)
1666}
1667
1668/// Upstream `__xmlKeepBlanksDefaultValue(void)` — returns a pointer to `xmlKeepBlanksDefaultValue`.
1669///
1670/// # SAFETY
1671///
1672/// The function touches crate-global state only; it is safe
1673/// as long as the caller respects the library's global
1674/// initialization/cleanup ordering (xmlInitParser before use,
1675/// xmlCleanupParser only after all users are done).
1676///
1677/// Violating the global lifecycle ordering, or calling this after
1678/// teardown or from a signal handler, is undefined behavior.
1679#[no_mangle]
1680pub unsafe extern "C" fn __xmlKeepBlanksDefaultValue() -> *mut c_int {
1681 // SAFETY: returning a pointer to an exported static; the caller may
1682 // read/write it exactly as with upstream's deprecated accessor.
1683 core::ptr::addr_of_mut!(xmlKeepBlanksDefaultValue)
1684}
1685
1686/// Upstream `__xmlLineNumbersDefaultValue(void)` — returns a pointer to `xmlLineNumbersDefaultValue`.
1687///
1688/// # SAFETY
1689///
1690/// The function touches crate-global state only; it is safe
1691/// as long as the caller respects the library's global
1692/// initialization/cleanup ordering (xmlInitParser before use,
1693/// xmlCleanupParser only after all users are done).
1694///
1695/// Violating the global lifecycle ordering, or calling this after
1696/// teardown or from a signal handler, is undefined behavior.
1697#[no_mangle]
1698pub unsafe extern "C" fn __xmlLineNumbersDefaultValue() -> *mut c_int {
1699 // SAFETY: returning a pointer to an exported static; the caller may
1700 // read/write it exactly as with upstream's deprecated accessor.
1701 core::ptr::addr_of_mut!(xmlLineNumbersDefaultValue)
1702}
1703
1704/// Upstream `__xmlLoadExtDtdDefaultValue(void)` — returns a pointer to `xmlLoadExtDtdDefaultValue`.
1705///
1706/// # SAFETY
1707///
1708/// The function touches crate-global state only; it is safe
1709/// as long as the caller respects the library's global
1710/// initialization/cleanup ordering (xmlInitParser before use,
1711/// xmlCleanupParser only after all users are done).
1712///
1713/// Violating the global lifecycle ordering, or calling this after
1714/// teardown or from a signal handler, is undefined behavior.
1715#[no_mangle]
1716pub unsafe extern "C" fn __xmlLoadExtDtdDefaultValue() -> *mut c_int {
1717 // SAFETY: returning a pointer to an exported static; the caller may
1718 // read/write it exactly as with upstream's deprecated accessor.
1719 core::ptr::addr_of_mut!(xmlLoadExtDtdDefaultValue)
1720}
1721
1722/// Upstream `__xmlOutputBufferCreateFilenameValue(void)` — returns a pointer to `xmlOutputBufferCreateFilenameValue`.
1723///
1724/// # SAFETY
1725///
1726/// The function touches crate-global state only; it is safe
1727/// as long as the caller respects the library's global
1728/// initialization/cleanup ordering (xmlInitParser before use,
1729/// xmlCleanupParser only after all users are done).
1730///
1731/// Violating the global lifecycle ordering, or calling this after
1732/// teardown or from a signal handler, is undefined behavior.
1733#[no_mangle]
1734pub unsafe extern "C" fn __xmlOutputBufferCreateFilenameValue() -> *mut Option<
1735 unsafe extern "C" fn(
1736 *const c_char,
1737 crate::abi::structs::xmlCharEncodingHandlerPtr,
1738 c_int,
1739 ) -> *mut crate::abi::structs::_xmlOutputBuffer,
1740> {
1741 // SAFETY: returning a pointer to an exported static; the caller may
1742 // read/write it exactly as with upstream's deprecated accessor.
1743 core::ptr::addr_of_mut!(xmlOutputBufferCreateFilenameValue)
1744}
1745
1746/// Upstream `__xmlParserDebugEntities(void)` — returns a pointer to `xmlParserDebugEntities`.
1747///
1748/// # SAFETY
1749///
1750/// The function touches crate-global state only; it is safe
1751/// as long as the caller respects the library's global
1752/// initialization/cleanup ordering (xmlInitParser before use,
1753/// xmlCleanupParser only after all users are done).
1754///
1755/// Violating the global lifecycle ordering, or calling this after
1756/// teardown or from a signal handler, is undefined behavior.
1757#[no_mangle]
1758pub unsafe extern "C" fn __xmlParserDebugEntities() -> *mut c_int {
1759 // SAFETY: returning a pointer to an exported static; the caller may
1760 // read/write it exactly as with upstream's deprecated accessor.
1761 core::ptr::addr_of_mut!(xmlParserDebugEntities)
1762}
1763
1764/// Upstream `__xmlParserInputBufferCreateFilenameValue(void)` — returns a pointer to `xmlParserInputBufferCreateFilenameValue`.
1765///
1766/// # SAFETY
1767///
1768/// The function touches crate-global state only; it is safe
1769/// as long as the caller respects the library's global
1770/// initialization/cleanup ordering (xmlInitParser before use,
1771/// xmlCleanupParser only after all users are done).
1772///
1773/// Violating the global lifecycle ordering, or calling this after
1774/// teardown or from a signal handler, is undefined behavior.
1775#[no_mangle]
1776pub unsafe extern "C" fn __xmlParserInputBufferCreateFilenameValue() -> *mut Option<
1777 unsafe extern "C" fn(*const c_char, c_int) -> *mut crate::abi::structs::_xmlParserInputBuffer,
1778> {
1779 // SAFETY: returning a pointer to an exported static; the caller may
1780 // read/write it exactly as with upstream's deprecated accessor.
1781 core::ptr::addr_of_mut!(xmlParserInputBufferCreateFilenameValue)
1782}
1783
1784/// Upstream `__xmlParserVersion(void)` — returns a pointer to `xmlParserVersion`.
1785///
1786/// # SAFETY
1787///
1788/// The function touches crate-global state only; it is safe
1789/// as long as the caller respects the library's global
1790/// initialization/cleanup ordering (xmlInitParser before use,
1791/// xmlCleanupParser only after all users are done).
1792///
1793/// Violating the global lifecycle ordering, or calling this after
1794/// teardown or from a signal handler, is undefined behavior.
1795#[no_mangle]
1796pub unsafe extern "C" fn __xmlParserVersion() -> *mut *const c_char {
1797 // SAFETY: returning a pointer to an exported static; the caller may
1798 // read/write it exactly as with upstream's deprecated accessor.
1799 core::ptr::addr_of_mut!(xmlParserVersion)
1800}
1801
1802/// Upstream `__xmlPedanticParserDefaultValue(void)` — returns a pointer to `xmlPedanticParserDefaultValue`.
1803///
1804/// # SAFETY
1805///
1806/// The function touches crate-global state only; it is safe
1807/// as long as the caller respects the library's global
1808/// initialization/cleanup ordering (xmlInitParser before use,
1809/// xmlCleanupParser only after all users are done).
1810///
1811/// Violating the global lifecycle ordering, or calling this after
1812/// teardown or from a signal handler, is undefined behavior.
1813#[no_mangle]
1814pub unsafe extern "C" fn __xmlPedanticParserDefaultValue() -> *mut c_int {
1815 // SAFETY: returning a pointer to an exported static; the caller may
1816 // read/write it exactly as with upstream's deprecated accessor.
1817 core::ptr::addr_of_mut!(xmlPedanticParserDefaultValue)
1818}
1819
1820/// Upstream `__xmlRegisterNodeDefaultValue(void)` — returns a pointer to `xmlRegisterNodeDefaultValue`.
1821///
1822/// # SAFETY
1823///
1824/// The function touches crate-global state only; it is safe
1825/// as long as the caller respects the library's global
1826/// initialization/cleanup ordering (xmlInitParser before use,
1827/// xmlCleanupParser only after all users are done).
1828///
1829/// Violating the global lifecycle ordering, or calling this after
1830/// teardown or from a signal handler, is undefined behavior.
1831#[no_mangle]
1832pub unsafe extern "C" fn __xmlRegisterNodeDefaultValue(
1833) -> *mut Option<unsafe extern "C" fn(*mut crate::abi::structs::_xmlNode)> {
1834 // SAFETY: returning a pointer to an exported static; the caller may
1835 // read/write it exactly as with upstream's deprecated accessor.
1836 core::ptr::addr_of_mut!(xmlRegisterNodeDefaultValue)
1837}
1838
1839/// Upstream `__xmlStructuredError(void)` — returns a pointer to `xmlStructuredError`.
1840///
1841/// # SAFETY
1842///
1843/// The function touches crate-global state only; it is safe
1844/// as long as the caller respects the library's global
1845/// initialization/cleanup ordering (xmlInitParser before use,
1846/// xmlCleanupParser only after all users are done).
1847///
1848/// Violating the global lifecycle ordering, or calling this after
1849/// teardown or from a signal handler, is undefined behavior.
1850#[no_mangle]
1851pub unsafe extern "C" fn __xmlStructuredError() -> *mut Option<xmlStructuredErrorFunc> {
1852 // SAFETY: returning a pointer to an exported static; the caller may
1853 // read/write it exactly as with upstream's deprecated accessor.
1854 core::ptr::addr_of_mut!(xmlStructuredError)
1855}
1856
1857/// Upstream `__xmlStructuredErrorContext(void)` — returns a pointer to `xmlStructuredErrorContext`.
1858///
1859/// # SAFETY
1860///
1861/// The function touches crate-global state only; it is safe
1862/// as long as the caller respects the library's global
1863/// initialization/cleanup ordering (xmlInitParser before use,
1864/// xmlCleanupParser only after all users are done).
1865///
1866/// Violating the global lifecycle ordering, or calling this after
1867/// teardown or from a signal handler, is undefined behavior.
1868#[no_mangle]
1869pub unsafe extern "C" fn __xmlStructuredErrorContext() -> *mut *mut c_void {
1870 // SAFETY: returning a pointer to an exported static; the caller may
1871 // read/write it exactly as with upstream's deprecated accessor.
1872 core::ptr::addr_of_mut!(xmlStructuredErrorContext)
1873}
1874
1875/// Upstream `__xmlSubstituteEntitiesDefaultValue(void)` — returns a pointer to `xmlSubstituteEntitiesDefaultValue`.
1876///
1877/// # SAFETY
1878///
1879/// The function touches crate-global state only; it is safe
1880/// as long as the caller respects the library's global
1881/// initialization/cleanup ordering (xmlInitParser before use,
1882/// xmlCleanupParser only after all users are done).
1883///
1884/// Violating the global lifecycle ordering, or calling this after
1885/// teardown or from a signal handler, is undefined behavior.
1886#[no_mangle]
1887pub unsafe extern "C" fn __xmlSubstituteEntitiesDefaultValue() -> *mut c_int {
1888 // SAFETY: returning a pointer to an exported static; the caller may
1889 // read/write it exactly as with upstream's deprecated accessor.
1890 core::ptr::addr_of_mut!(xmlSubstituteEntitiesDefaultValue)
1891}
1892
1893// ═══════════════════════════════════════════════════════════════════════════════
1894// Regression court — xmlLastError mirror concurrency (11.1-X)
1895// ═══════════════════════════════════════════════════════════════════════════════
1896//
1897// R-000135 discovery during 11.1-X: the exported `xmlLastError` mirror was
1898// deep-copied and freed without synchronization, so concurrent error raises
1899// on different threads double-freed the mirror strings. The parallel lib
1900// test suite observed this as `double free or corruption (!prev)` aborts
1901// (xml::errors tests racing with any other raising thread). The writers are
1902// serialized via LAST_ERROR_MIRROR_LOCK; these courts hammer the exact
1903// interleavings and must complete without crashing.
1904
1905#[cfg(test)]
1906mod tests {
1907 use super::*;
1908 use crate::abi::allocator::xmlMallocImpl;
1909 use crate::abi::structs::_xmlError;
1910 use crate::xml::globals;
1911 use core::ptr;
1912
1913 /// Allocate a NUL-terminated C string owned by xmlMallocImpl (the same
1914 /// allocator the thread-local error slot uses).
1915 unsafe fn alloc_cstr(s: &str) -> *mut c_char {
1916 let bytes = s.as_bytes();
1917 let p = unsafe { xmlMallocImpl(bytes.len() + 1) as *mut c_char };
1918 assert!(!p.is_null(), "alloc_cstr: xmlMallocImpl failed");
1919 unsafe {
1920 ptr::copy_nonoverlapping(bytes.as_ptr(), p as *mut u8, bytes.len());
1921 *((p as *mut u8).add(bytes.len())) = 0;
1922 }
1923 p
1924 }
1925
1926 /// Build an owned `_xmlError` with distinct string fields.
1927 unsafe fn build_error(tag: &str) -> _xmlError {
1928 _xmlError {
1929 domain: 1,
1930 code: 2,
1931 message: unsafe { alloc_cstr(&format!("msg {tag}")) },
1932 level: 3,
1933 file: unsafe { alloc_cstr(&format!("file {tag}")) },
1934 line: 4,
1935 str1: unsafe { alloc_cstr(&format!("str1 {tag}")) },
1936 str2: ptr::null_mut(),
1937 str3: ptr::null_mut(),
1938 int1: 0,
1939 int2: 0,
1940 ctxt: ptr::null_mut(),
1941 node: ptr::null_mut(),
1942 }
1943 }
1944
1945 /// Concurrent sync/reset hammer: one thread raises errors while another
1946 /// resets. Before the mirror lock this double-freed the shared strings;
1947 /// the test crashes (SIGABRT) under the old code and passes now.
1948 #[test]
1949 fn test_last_error_mirror_concurrent_sync_reset() {
1950 let sync = std::thread::spawn(|| {
1951 for i in 0..400 {
1952 unsafe { globals::set_last_error(build_error(&format!("sync {i}"))) };
1953 }
1954 });
1955 let reset = std::thread::spawn(|| {
1956 for _ in 0..400 {
1957 globals::reset_last_error();
1958 }
1959 });
1960 sync.join().unwrap();
1961 reset.join().unwrap();
1962 // Leave the mirror in a clean state for later tests. (No thread-local
1963 // assertion: the harness reuses OS threads across tests, so a prior
1964 // test's error may legitimately live in this thread's slot.)
1965 globals::reset_last_error();
1966 }
1967
1968 /// Many threads raising concurrently (the full parallel-suite shape that
1969 /// originally aborted in `test_encode_entities_reentrant_*` victims).
1970 #[test]
1971 fn test_last_error_mirror_many_threads() {
1972 let mut handles = Vec::new();
1973 for t in 0..8 {
1974 handles.push(std::thread::spawn(move || {
1975 for i in 0..150 {
1976 unsafe { globals::set_last_error(build_error(&format!("t{t} i{i}"))) };
1977 if i % 7 == 0 {
1978 globals::reset_last_error();
1979 }
1980 }
1981 }));
1982 }
1983 for h in handles {
1984 h.join().unwrap();
1985 }
1986 globals::reset_last_error();
1987 }
1988}