mxml/mxml-private.c
2024-02-27 15:04:27 -05:00

293 lines
5.9 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// 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.
//
#include "mxml-private.h"
//
// 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.
//
#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
#elif defined(__GNUC__) // Linux and macOS
# define _MXML_FINI __attribute((destructor)) _mxml_fini
#else
# define _MXML_FINI _fini
#endif // __sun
//
// 'mxml_error()' - Display an error message.
//
void
mxml_error(const char *format, // I - Printf-style format string
...) // I - Additional arguments as needed
{
va_list ap; // Pointer to arguments
char s[1024]; // Message string
_mxml_global_t *global = _mxml_global();
// Global data
// Range check input...
if (!format)
return;
// Format the error message string...
va_start(ap, format);
vsnprintf(s, sizeof(s), format, ap);
va_end(ap);
// And then display the error message...
if (global->error_cb)
(*global->error_cb)(s);
else
fprintf(stderr, "%s\n", s);
}
//
// 'mxml_ignore_cb()' - Default callback for ignored values.
//
mxml_type_t // O - Node type
mxml_ignore_cb(mxml_node_t *node) // I - Current node
{
(void)node;
return (MXML_TYPE_IGNORE);
}
//
// 'mxml_integer_cb()' - Default callback for integer values.
//
mxml_type_t // O - Node type
mxml_integer_cb(mxml_node_t *node) // I - Current node
{
(void)node;
return (MXML_TYPE_INTEGER);
}
//
// 'mxml_opaque_cb()' - Default callback for opaque values.
//
mxml_type_t // O - Node type
mxml_opaque_cb(mxml_node_t *node) // I - Current node
{
(void)node;
return (MXML_TYPE_OPAQUE);
}
//
// 'mxml_real_cb()' - Default callback for real number values.
//
mxml_type_t // O - Node type
mxml_real_cb(mxml_node_t *node) // I - Current node
{
(void)node;
return (MXML_TYPE_REAL);
}
#ifdef HAVE_PTHREAD_H // POSIX threading
# include <pthread.h>
static int _mxml_initialized = 0;
// Have we been initialized?
static pthread_key_t _mxml_key; // Thread local storage key
static pthread_once_t _mxml_key_once = PTHREAD_ONCE_INIT;
// One-time initialization object
static void _mxml_init(void);
static void _mxml_destructor(void *g);
//
// '_mxml_destructor()' - Free memory used for globals...
//
static void
_mxml_destructor(void *g) // I - Global data
{
free(g);
}
//
// '_mxml_fini()' - Clean up when unloaded.
//
static void
_MXML_FINI(void)
{
if (_mxml_initialized)
pthread_key_delete(_mxml_key);
}
//
// '_mxml_global()' - Get global data.
//
_mxml_global_t * // O - Global data
_mxml_global(void)
{
_mxml_global_t *global; // Global data
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);
}
//
// '_mxml_init()' - Initialize global data...
//
static void
_mxml_init(void)
{
_mxml_initialized = 1;
pthread_key_create(&_mxml_key, _mxml_destructor);
}
#elif defined(_WIN32) && defined(MXML1_EXPORTS) // WIN32 threading
# include <windows.h>
static DWORD _mxml_tls_index; // Index for global storage
//
// 'DllMain()' - Main entry for library.
//
BOOL WINAPI // O - Success/failure
DllMain(HINSTANCE hinst, // I - DLL module handle
DWORD reason, // I - Reason
LPVOID reserved) // I - Unused
{
_mxml_global_t *global; // Global data
(void)hinst;
(void)reserved;
switch (reason)
{
case DLL_PROCESS_ATTACH : // Called on library initialization
if ((_mxml_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES)
return (FALSE);
break;
case DLL_THREAD_DETACH : // Called when a thread terminates
if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL)
free(global);
break;
case DLL_PROCESS_DETACH : // Called when library is unloaded
if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL)
free(global);
TlsFree(_mxml_tls_index);
break;
default:
break;
}
return (TRUE);
}
//
// '_mxml_global()' - Get global data.
//
_mxml_global_t * // O - Global data
_mxml_global(void)
{
_mxml_global_t *global; // Global data
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;
TlsSetValue(_mxml_tls_index, (LPVOID)global);
}
return (global);
}
#else // No threading
//
// '_mxml_global()' - Get global data.
//
_mxml_global_t * // O - Global data
_mxml_global(void)
{
static _mxml_global_t global = // Global data
{
NULL, // error_cb
1, // num_entity_cbs
{ _mxml_entity_cb }, // entity_cbs
72, // wrap
NULL, // custom_load_cb
NULL // custom_save_cb
};
return (&global);
}
#endif // HAVE_PTHREAD_H