Skip to main content

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}