Subversion Repositories tpanel

Rev

Blame | Last modification | View Log | RSS feed

/*
 * Private functions for Mini-XML, a small XML file parsing library.
 *
 * https://www.msweet.org/mxml
 *
 * Copyright © 2003-2019 by Michael R Sweet.
 *
 * Licensed under Apache License v2.0.  See the file "LICENSE" for more
 * information.
 */

/*
 * Include necessary headers...
 */

#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, Mac OS X, 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 Mac OS X */
#  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, "mxml: %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_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_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_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_REAL);
}


#ifdef HAVE_PTHREAD_H                   /**** POSIX threading ****/
#  include <pthread.h>

static pthread_key_t    _mxml_key = -1; /* 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)
{
  _mxml_global_t        *global;        /* Global data */


  if (_mxml_key != (pthread_key_t)-1)
  {
    if ((global = (_mxml_global_t *)pthread_getspecific(_mxml_key)) != NULL)
      _mxml_destructor(global);

    pthread_key_delete(_mxml_key);
    _mxml_key = -1;
  }
}


/*
 * '_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)
{
  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 */