2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
|
|
|
|
// Private functions for Mini-XML, a small XML file parsing library.
|
|
|
|
|
//
|
|
|
|
|
// https://www.msweet.org/mxml
|
|
|
|
|
//
|
|
|
|
|
// Copyright © 2003-2024 by Michael R Sweet.
|
|
|
|
|
//
|
|
|
|
|
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
|
|
|
|
// information.
|
|
|
|
|
//
|
2003-09-28 21:09:04 +00:00
|
|
|
|
|
2007-09-21 04:46:02 +00:00
|
|
|
|
#include "mxml-private.h"
|
2003-12-03 03:59:04 +00:00
|
|
|
|
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
|
|
|
|
// Some crazy people think that unloading a shared object is a good or safe
|
|
|
|
|
// thing to do. Unfortunately, most objects are simply *not* safe to unload
|
|
|
|
|
// and bad things *will* happen.
|
|
|
|
|
//
|
|
|
|
|
// The following mess of conditional code allows us to provide a destructor
|
|
|
|
|
// function in Mini-XML for our thread-global storage so that it can possibly
|
|
|
|
|
// be unloaded safely, although since there is no standard way to do so I
|
|
|
|
|
// can't even provide any guarantees that you can do it safely on all platforms.
|
|
|
|
|
//
|
|
|
|
|
// This code currently supports AIX, HP-UX, Linux, macOS, Solaris, and
|
|
|
|
|
// Windows. It might work on the BSDs and IRIX, but I haven't tested that.
|
|
|
|
|
//
|
2010-09-19 04:56:51 +00:00
|
|
|
|
|
|
|
|
|
#if defined(__sun) || defined(_AIX)
|
|
|
|
|
# pragma fini(_mxml_fini)
|
|
|
|
|
# define _MXML_FINI _mxml_fini
|
|
|
|
|
#elif defined(__hpux)
|
|
|
|
|
# pragma FINI _mxml_fini
|
|
|
|
|
# define _MXML_FINI _mxml_fini
|
2024-02-27 20:04:27 +00:00
|
|
|
|
#elif defined(__GNUC__) // Linux and macOS
|
2010-09-19 04:56:51 +00:00
|
|
|
|
# define _MXML_FINI __attribute((destructor)) _mxml_fini
|
|
|
|
|
#else
|
|
|
|
|
# define _MXML_FINI _fini
|
2024-02-27 20:04:27 +00:00
|
|
|
|
#endif // __sun
|
2010-09-19 04:56:51 +00:00
|
|
|
|
|
|
|
|
|
|
2024-03-07 19:06:50 +00:00
|
|
|
|
//
|
|
|
|
|
// 'mxmlSetCustomHandlers()' - Set the custom data callbacks.
|
|
|
|
|
//
|
|
|
|
|
// This function sets the callbacks that are used for loading and saving custom
|
|
|
|
|
// data types. The load callback `load_cb` accepts the callback data pointer
|
|
|
|
|
// `cbdata`, a node pointer, and a data string and returns `true` on success and
|
|
|
|
|
// `false` on error, for example:
|
|
|
|
|
//
|
|
|
|
|
// ```c
|
|
|
|
|
// typedef struct
|
|
|
|
|
// {
|
|
|
|
|
// unsigned year, /* Year */
|
|
|
|
|
// month, /* Month */
|
|
|
|
|
// day, /* Day */
|
|
|
|
|
// hour, /* Hour */
|
|
|
|
|
// minute, /* Minute */
|
|
|
|
|
// second; /* Second */
|
|
|
|
|
// time_t unix; /* UNIX time */
|
|
|
|
|
// } iso_date_time_t;
|
|
|
|
|
//
|
|
|
|
|
// bool
|
|
|
|
|
// my_custom_load_cb(void *cbdata, mxml_node_t *node, const char *data)
|
|
|
|
|
// {
|
|
|
|
|
// iso_date_time_t *dt;
|
|
|
|
|
// struct tm tmdata;
|
|
|
|
|
//
|
|
|
|
|
// /* Allocate custom data structure ... */
|
|
|
|
|
// dt = calloc(1, sizeof(iso_date_time_t));
|
|
|
|
|
//
|
|
|
|
|
// /* Parse the data string... */
|
|
|
|
|
// if (sscanf(data, "%u-%u-%uT%u:%u:%uZ", &(dt->year), &(dt->month),
|
|
|
|
|
// &(dt->day), &(dt->hour), &(dt->minute), &(dt->second)) != 6)
|
|
|
|
|
// {
|
|
|
|
|
// /* Unable to parse date and time numbers... */
|
|
|
|
|
// free(dt);
|
|
|
|
|
// return (false);
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// /* Range check values... */
|
|
|
|
|
// if (dt->month < 1 || dt->month > 12 || dt->day < 1 || dt->day > 31 ||
|
|
|
|
|
// dt->hour < 0 || dt->hour > 23 || dt->minute < 0 || dt->minute > 59 ||
|
|
|
|
|
// dt->second < 0 || dt->second > 60)
|
|
|
|
|
// {
|
|
|
|
|
// /* Date information is out of range... */
|
|
|
|
|
// free(dt);
|
|
|
|
|
// return (false);
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// /* Convert ISO time to UNIX time in seconds... */
|
|
|
|
|
// tmdata.tm_year = dt->year - 1900;
|
|
|
|
|
// tmdata.tm_mon = dt->month - 1;
|
|
|
|
|
// tmdata.tm_day = dt->day;
|
|
|
|
|
// tmdata.tm_hour = dt->hour;
|
|
|
|
|
// tmdata.tm_min = dt->minute;
|
|
|
|
|
// tmdata.tm_sec = dt->second;
|
|
|
|
|
//
|
|
|
|
|
// dt->unix = gmtime(&tmdata);
|
|
|
|
|
//
|
|
|
|
|
// /* Set custom data and free function... */
|
|
|
|
|
// mxmlSetCustom(node, data, free);
|
|
|
|
|
//
|
|
|
|
|
// /* Return with no errors... */
|
|
|
|
|
// return (true);
|
|
|
|
|
// }
|
|
|
|
|
// ```
|
|
|
|
|
//
|
|
|
|
|
// The save callback `save_cb` accepts the callback data pointer `cbdata` and a
|
|
|
|
|
// node pointer and returns a malloc'd string on success and `NULL` on error,
|
|
|
|
|
// for example:
|
|
|
|
|
//
|
|
|
|
|
// ```c
|
|
|
|
|
// char *
|
|
|
|
|
// my_custom_save_cb(void *cbdata, mxml_node_t *node)
|
|
|
|
|
// {
|
|
|
|
|
// char data[255];
|
|
|
|
|
// iso_date_time_t *dt;
|
|
|
|
|
//
|
|
|
|
|
// /* Get the custom data structure */
|
|
|
|
|
// dt = (iso_date_time_t *)mxmlGetCustom(node);
|
|
|
|
|
//
|
|
|
|
|
// /* Generate string version of the date/time... */
|
|
|
|
|
// snprintf(data, sizeof(data), "%04u-%02u-%02uT%02u:%02u:%02uZ",
|
|
|
|
|
// dt->year, dt->month, dt->day, dt->hour, dt->minute, dt->second);
|
|
|
|
|
//
|
|
|
|
|
// /* Duplicate the string and return... */
|
|
|
|
|
// return (strdup(data));
|
|
|
|
|
// }
|
|
|
|
|
// ```
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
mxmlSetCustomCallbacks(
|
|
|
|
|
mxml_custom_load_cb_t load_cb, // I - Load callback function
|
|
|
|
|
mxml_custom_save_cb_t save_cb, // I - Save callback function
|
|
|
|
|
void *cbdata) // I - Callback data
|
|
|
|
|
{
|
|
|
|
|
_mxml_global_t *global = _mxml_global();
|
|
|
|
|
// Global data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
global->custom_load_cb = load_cb;
|
|
|
|
|
global->custom_save_cb = save_cb;
|
|
|
|
|
global->custom_cbdata = cbdata;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// 'mxmlSetErrorCallback()' - Set the error message callback.
|
|
|
|
|
//
|
|
|
|
|
// This function sets a function to use when reporting errors. The callback
|
|
|
|
|
// `cb` accepts the data pointer `cbdata` and a string pointer containing the
|
|
|
|
|
// error message:
|
|
|
|
|
//
|
|
|
|
|
// ```c
|
|
|
|
|
// void my_error_cb(void *cbdata, const char *message)
|
|
|
|
|
// {
|
|
|
|
|
// fprintf(stderr, "myprogram: %s\n", message);
|
|
|
|
|
// }
|
|
|
|
|
// ```
|
|
|
|
|
//
|
|
|
|
|
// The default error callback writes the error message to the `stderr` file.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
mxmlSetErrorCallback(
|
|
|
|
|
mxml_error_cb_t cb, // I - Error callback function
|
|
|
|
|
void *cbdata) // I - Error callback data
|
|
|
|
|
{
|
|
|
|
|
_mxml_global_t *global = _mxml_global();
|
|
|
|
|
// Global data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
global->error_cb = cb;
|
|
|
|
|
global->error_cbdata = cbdata;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// 'mxmlSetStringCallbacks()' - Set the string copy/free callback functions.
|
|
|
|
|
//
|
|
|
|
|
// This function sets the string copy/free callback functions for the current
|
|
|
|
|
// thread. The `strcopy_cb` function makes a copy of the provided string while
|
|
|
|
|
// the `strfree_cb` function frees the copy. Each callback accepts the
|
|
|
|
|
// `str_cbdata` pointer along with the pointer to the string:
|
|
|
|
|
//
|
|
|
|
|
// ```c
|
|
|
|
|
// char *my_strcopy_cb(void *cbdata, const char *s)
|
|
|
|
|
// {
|
|
|
|
|
// ... make a copy of "s" ...
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// void my_strfree_cb(void *cbdata, char *s)
|
|
|
|
|
// {
|
|
|
|
|
// ... release the memory used by "s" ...
|
|
|
|
|
// }
|
|
|
|
|
// ```
|
|
|
|
|
//
|
|
|
|
|
// The default `strcopy_cb` function calls `strdup` while the default
|
|
|
|
|
// `strfree_cb` function calls `free`.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
mxmlSetStringCallbacks(
|
|
|
|
|
mxml_strcopy_cb_t strcopy_cb, // I - String copy callback function
|
|
|
|
|
mxml_strfree_cb_t strfree_cb, // I - String free callback function
|
|
|
|
|
void *str_cbdata) // I - String callback data
|
|
|
|
|
{
|
|
|
|
|
_mxml_global_t *global = _mxml_global();
|
|
|
|
|
// Global data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
global->strcopy_cb = strcopy_cb;
|
|
|
|
|
global->strfree_cb = strfree_cb;
|
|
|
|
|
global->str_cbdata = str_cbdata;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
2024-03-06 19:45:10 +00:00
|
|
|
|
// '_mxml_error()' - Display an error message.
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
2003-12-03 03:59:04 +00:00
|
|
|
|
|
|
|
|
|
void
|
2024-03-06 19:45:10 +00:00
|
|
|
|
_mxml_error(const char *format, // I - Printf-style format string
|
2024-03-06 23:18:29 +00:00
|
|
|
|
...) // I - Additional arguments as needed
|
2003-12-03 03:59:04 +00:00
|
|
|
|
{
|
2024-02-27 20:04:27 +00:00
|
|
|
|
va_list ap; // Pointer to arguments
|
|
|
|
|
char s[1024]; // Message string
|
2007-09-21 04:46:02 +00:00
|
|
|
|
_mxml_global_t *global = _mxml_global();
|
2024-02-27 20:04:27 +00:00
|
|
|
|
// Global data
|
2003-12-03 03:59:04 +00:00
|
|
|
|
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
// Range check input...
|
2003-12-03 03:59:04 +00:00
|
|
|
|
if (!format)
|
|
|
|
|
return;
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
// Format the error message string...
|
2003-12-03 03:59:04 +00:00
|
|
|
|
va_start(ap, format);
|
2005-08-16 14:46:18 +00:00
|
|
|
|
vsnprintf(s, sizeof(s), format, ap);
|
2003-12-03 03:59:04 +00:00
|
|
|
|
va_end(ap);
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
// And then display the error message...
|
2007-09-21 04:46:02 +00:00
|
|
|
|
if (global->error_cb)
|
2024-03-06 23:18:29 +00:00
|
|
|
|
(*global->error_cb)(global->error_cbdata, s);
|
2003-12-03 03:59:04 +00:00
|
|
|
|
else
|
2024-02-27 20:04:27 +00:00
|
|
|
|
fprintf(stderr, "%s\n", s);
|
2003-12-03 03:59:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-03-07 19:06:50 +00:00
|
|
|
|
//
|
|
|
|
|
// '_mxml_strcopy()' - Copy a string.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
char * // O - Copy of string
|
|
|
|
|
_mxml_strcopy(const char *s) // I - String
|
|
|
|
|
{
|
|
|
|
|
_mxml_global_t *global = _mxml_global();
|
|
|
|
|
// Global data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!s)
|
|
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
|
|
if (global->strcopy_cb)
|
|
|
|
|
return ((global->strcopy_cb)(global->str_cbdata, s));
|
|
|
|
|
else
|
|
|
|
|
return (strdup(s));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// '_mxml_strfree()' - Free a string.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
_mxml_strfree(char *s) // I - String
|
|
|
|
|
{
|
|
|
|
|
_mxml_global_t *global = _mxml_global();
|
|
|
|
|
// Global data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!s)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (global->strfree_cb)
|
|
|
|
|
(global->strfree_cb)(global->str_cbdata, s);
|
|
|
|
|
else
|
|
|
|
|
free((void *)s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
#ifdef HAVE_PTHREAD_H // POSIX threading
|
2007-09-22 21:00:56 +00:00
|
|
|
|
# include <pthread.h>
|
|
|
|
|
|
2022-07-14 13:52:34 +00:00
|
|
|
|
static int _mxml_initialized = 0;
|
2024-02-27 20:04:27 +00:00
|
|
|
|
// Have we been initialized?
|
|
|
|
|
static pthread_key_t _mxml_key; // Thread local storage key
|
2007-09-22 21:00:56 +00:00
|
|
|
|
static pthread_once_t _mxml_key_once = PTHREAD_ONCE_INIT;
|
2024-02-27 20:04:27 +00:00
|
|
|
|
// One-time initialization object
|
2007-09-22 21:00:56 +00:00
|
|
|
|
static void _mxml_init(void);
|
|
|
|
|
static void _mxml_destructor(void *g);
|
|
|
|
|
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
|
|
|
|
// '_mxml_destructor()' - Free memory used for globals...
|
|
|
|
|
//
|
2010-09-19 04:56:51 +00:00
|
|
|
|
|
|
|
|
|
static void
|
2024-02-27 20:04:27 +00:00
|
|
|
|
_mxml_destructor(void *g) // I - Global data
|
2010-09-19 04:56:51 +00:00
|
|
|
|
{
|
|
|
|
|
free(g);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
|
|
|
|
// '_mxml_fini()' - Clean up when unloaded.
|
|
|
|
|
//
|
2010-09-19 04:56:51 +00:00
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_MXML_FINI(void)
|
|
|
|
|
{
|
2022-07-14 13:52:34 +00:00
|
|
|
|
if (_mxml_initialized)
|
|
|
|
|
pthread_key_delete(_mxml_key);
|
2010-09-19 04:56:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
|
|
|
|
// '_mxml_global()' - Get global data.
|
|
|
|
|
//
|
2007-09-22 21:00:56 +00:00
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
_mxml_global_t * // O - Global data
|
2007-09-22 21:00:56 +00:00
|
|
|
|
_mxml_global(void)
|
|
|
|
|
{
|
2024-02-27 20:04:27 +00:00
|
|
|
|
_mxml_global_t *global; // Global data
|
2007-09-22 21:00:56 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pthread_once(&_mxml_key_once, _mxml_init);
|
|
|
|
|
|
|
|
|
|
if ((global = (_mxml_global_t *)pthread_getspecific(_mxml_key)) == NULL)
|
|
|
|
|
{
|
|
|
|
|
global = (_mxml_global_t *)calloc(1, sizeof(_mxml_global_t));
|
|
|
|
|
pthread_setspecific(_mxml_key, global);
|
|
|
|
|
|
|
|
|
|
global->num_entity_cbs = 1;
|
|
|
|
|
global->entity_cbs[0] = _mxml_entity_cb;
|
|
|
|
|
global->wrap = 72;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (global);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
|
|
|
|
// '_mxml_init()' - Initialize global data...
|
|
|
|
|
//
|
2007-09-22 21:00:56 +00:00
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_mxml_init(void)
|
|
|
|
|
{
|
2022-07-14 13:52:34 +00:00
|
|
|
|
_mxml_initialized = 1;
|
2007-09-22 21:00:56 +00:00
|
|
|
|
pthread_key_create(&_mxml_key, _mxml_destructor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
#elif defined(_WIN32) && defined(MXML1_EXPORTS) // WIN32 threading
|
2007-11-22 18:01:52 +00:00
|
|
|
|
# include <windows.h>
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
static DWORD _mxml_tls_index; // Index for global storage
|
2007-11-22 18:01:52 +00:00
|
|
|
|
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
|
|
|
|
// 'DllMain()' - Main entry for library.
|
|
|
|
|
//
|
2014-01-04 21:50:06 +00:00
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
BOOL WINAPI // O - Success/failure
|
|
|
|
|
DllMain(HINSTANCE hinst, // I - DLL module handle
|
|
|
|
|
DWORD reason, // I - Reason
|
|
|
|
|
LPVOID reserved) // I - Unused
|
2007-11-22 18:01:52 +00:00
|
|
|
|
{
|
2024-02-27 20:04:27 +00:00
|
|
|
|
_mxml_global_t *global; // Global data
|
2007-11-22 18:01:52 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(void)hinst;
|
|
|
|
|
(void)reserved;
|
|
|
|
|
|
2014-01-04 21:50:06 +00:00
|
|
|
|
switch (reason)
|
|
|
|
|
{
|
2024-02-27 20:04:27 +00:00
|
|
|
|
case DLL_PROCESS_ATTACH : // Called on library initialization
|
2014-01-04 21:50:06 +00:00
|
|
|
|
if ((_mxml_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES)
|
|
|
|
|
return (FALSE);
|
|
|
|
|
break;
|
2007-11-22 18:01:52 +00:00
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
case DLL_THREAD_DETACH : // Called when a thread terminates
|
2007-11-22 18:01:52 +00:00
|
|
|
|
if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL)
|
|
|
|
|
free(global);
|
2014-01-04 21:50:06 +00:00
|
|
|
|
break;
|
2007-11-22 18:01:52 +00:00
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
case DLL_PROCESS_DETACH : // Called when library is unloaded
|
2007-11-22 18:01:52 +00:00
|
|
|
|
if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL)
|
|
|
|
|
free(global);
|
|
|
|
|
|
2014-01-04 21:50:06 +00:00
|
|
|
|
TlsFree(_mxml_tls_index);
|
|
|
|
|
break;
|
2007-11-22 18:01:52 +00:00
|
|
|
|
|
2014-01-04 21:50:06 +00:00
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2007-11-22 18:01:52 +00:00
|
|
|
|
|
|
|
|
|
return (TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
|
|
|
|
// '_mxml_global()' - Get global data.
|
|
|
|
|
//
|
2007-11-22 18:01:52 +00:00
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
_mxml_global_t * // O - Global data
|
2007-11-22 18:01:52 +00:00
|
|
|
|
_mxml_global(void)
|
|
|
|
|
{
|
2024-02-27 20:04:27 +00:00
|
|
|
|
_mxml_global_t *global; // Global data
|
2007-11-22 18:01:52 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) == NULL)
|
|
|
|
|
{
|
|
|
|
|
global = (_mxml_global_t *)calloc(1, sizeof(_mxml_global_t));
|
|
|
|
|
|
|
|
|
|
global->num_entity_cbs = 1;
|
|
|
|
|
global->entity_cbs[0] = _mxml_entity_cb;
|
|
|
|
|
global->wrap = 72;
|
|
|
|
|
|
2014-01-04 21:50:06 +00:00
|
|
|
|
TlsSetValue(_mxml_tls_index, (LPVOID)global);
|
2007-11-22 18:01:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (global);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
#else // No threading
|
|
|
|
|
//
|
|
|
|
|
// '_mxml_global()' - Get global data.
|
|
|
|
|
//
|
2007-09-22 21:00:56 +00:00
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
_mxml_global_t * // O - Global data
|
2007-09-22 21:00:56 +00:00
|
|
|
|
_mxml_global(void)
|
|
|
|
|
{
|
2024-02-27 20:04:27 +00:00
|
|
|
|
static _mxml_global_t global = // Global data
|
2007-09-22 21:00:56 +00:00
|
|
|
|
{
|
2024-02-27 20:04:27 +00:00
|
|
|
|
NULL, // error_cb
|
|
|
|
|
1, // num_entity_cbs
|
|
|
|
|
{ _mxml_entity_cb }, // entity_cbs
|
|
|
|
|
72, // wrap
|
|
|
|
|
NULL, // custom_load_cb
|
|
|
|
|
NULL // custom_save_cb
|
2007-09-22 21:00:56 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return (&global);
|
|
|
|
|
}
|
2024-02-27 20:04:27 +00:00
|
|
|
|
#endif // HAVE_PTHREAD_H
|