mxml-private.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /*
  2. * Private functions for Mini-XML, a small XML file parsing library.
  3. *
  4. * https://www.msweet.org/mxml
  5. *
  6. * Copyright © 2003-2022 by Michael R Sweet.
  7. *
  8. * Licensed under Apache License v2.0. See the file "LICENSE" for more
  9. * information.
  10. */
  11. /*
  12. * Include necessary headers...
  13. */
  14. #include "mxml-private.h"
  15. /*
  16. * Some crazy people think that unloading a shared object is a good or safe
  17. * thing to do. Unfortunately, most objects are simply *not* safe to unload
  18. * and bad things *will* happen.
  19. *
  20. * The following mess of conditional code allows us to provide a destructor
  21. * function in Mini-XML for our thread-global storage so that it can possibly
  22. * be unloaded safely, although since there is no standard way to do so I
  23. * can't even provide any guarantees that you can do it safely on all platforms.
  24. *
  25. * This code currently supports AIX, HP-UX, Linux, macOS, Solaris, and
  26. * Windows. It might work on the BSDs and IRIX, but I haven't tested that.
  27. */
  28. #if defined(__sun) || defined(_AIX)
  29. # pragma fini(_mxml_fini)
  30. # define _MXML_FINI _mxml_fini
  31. #elif defined(__hpux)
  32. # pragma FINI _mxml_fini
  33. # define _MXML_FINI _mxml_fini
  34. #elif defined(__GNUC__) /* Linux and macOS */
  35. # define _MXML_FINI __attribute((destructor)) _mxml_fini
  36. #else
  37. # define _MXML_FINI _fini
  38. #endif /* __sun */
  39. /*
  40. * 'mxml_error()' - Display an error message.
  41. */
  42. void
  43. mxml_error(const char *format, /* I - Printf-style format string */
  44. ...) /* I - Additional arguments as needed */
  45. {
  46. va_list ap; /* Pointer to arguments */
  47. char s[1024]; /* Message string */
  48. _mxml_global_t *global = _mxml_global();
  49. /* Global data */
  50. /*
  51. * Range check input...
  52. */
  53. if (!format)
  54. return;
  55. /*
  56. * Format the error message string...
  57. */
  58. va_start(ap, format);
  59. vsnprintf(s, sizeof(s), format, ap);
  60. va_end(ap);
  61. /*
  62. * And then display the error message...
  63. */
  64. if (global->error_cb)
  65. (*global->error_cb)(s);
  66. else
  67. fprintf(stderr, "mxml: %s\n", s);
  68. }
  69. /*
  70. * 'mxml_ignore_cb()' - Default callback for ignored values.
  71. */
  72. mxml_type_t /* O - Node type */
  73. mxml_ignore_cb(mxml_node_t *node) /* I - Current node */
  74. {
  75. (void)node;
  76. return (MXML_IGNORE);
  77. }
  78. /*
  79. * 'mxml_integer_cb()' - Default callback for integer values.
  80. */
  81. mxml_type_t /* O - Node type */
  82. mxml_integer_cb(mxml_node_t *node) /* I - Current node */
  83. {
  84. (void)node;
  85. return (MXML_INTEGER);
  86. }
  87. /*
  88. * 'mxml_opaque_cb()' - Default callback for opaque values.
  89. */
  90. mxml_type_t /* O - Node type */
  91. mxml_opaque_cb(mxml_node_t *node) /* I - Current node */
  92. {
  93. (void)node;
  94. return (MXML_OPAQUE);
  95. }
  96. /*
  97. * 'mxml_real_cb()' - Default callback for real number values.
  98. */
  99. mxml_type_t /* O - Node type */
  100. mxml_real_cb(mxml_node_t *node) /* I - Current node */
  101. {
  102. (void)node;
  103. return (MXML_REAL);
  104. }
  105. #ifdef HAVE_PTHREAD_H /**** POSIX threading ****/
  106. # include <pthread.h>
  107. static int _mxml_initialized = 0;
  108. /* Have we been initialized? */
  109. static pthread_key_t _mxml_key; /* Thread local storage key */
  110. static pthread_once_t _mxml_key_once = PTHREAD_ONCE_INIT;
  111. /* One-time initialization object */
  112. static void _mxml_init(void);
  113. static void _mxml_destructor(void *g);
  114. /*
  115. * '_mxml_destructor()' - Free memory used for globals...
  116. */
  117. static void
  118. _mxml_destructor(void *g) /* I - Global data */
  119. {
  120. free(g);
  121. }
  122. /*
  123. * '_mxml_fini()' - Clean up when unloaded.
  124. */
  125. static void
  126. _MXML_FINI(void)
  127. {
  128. if (_mxml_initialized)
  129. pthread_key_delete(_mxml_key);
  130. }
  131. /*
  132. * '_mxml_global()' - Get global data.
  133. */
  134. _mxml_global_t * /* O - Global data */
  135. _mxml_global(void)
  136. {
  137. _mxml_global_t *global; /* Global data */
  138. pthread_once(&_mxml_key_once, _mxml_init);
  139. if ((global = (_mxml_global_t *)pthread_getspecific(_mxml_key)) == NULL)
  140. {
  141. global = (_mxml_global_t *)calloc(1, sizeof(_mxml_global_t));
  142. pthread_setspecific(_mxml_key, global);
  143. global->num_entity_cbs = 1;
  144. global->entity_cbs[0] = _mxml_entity_cb;
  145. global->wrap = 72;
  146. }
  147. return (global);
  148. }
  149. /*
  150. * '_mxml_init()' - Initialize global data...
  151. */
  152. static void
  153. _mxml_init(void)
  154. {
  155. _mxml_initialized = 1;
  156. pthread_key_create(&_mxml_key, _mxml_destructor);
  157. }
  158. #elif defined(_WIN32) && defined(MXML1_EXPORTS) /**** WIN32 threading ****/
  159. # include <windows.h>
  160. static DWORD _mxml_tls_index; /* Index for global storage */
  161. /*
  162. * 'DllMain()' - Main entry for library.
  163. */
  164. BOOL WINAPI /* O - Success/failure */
  165. DllMain(HINSTANCE hinst, /* I - DLL module handle */
  166. DWORD reason, /* I - Reason */
  167. LPVOID reserved) /* I - Unused */
  168. {
  169. _mxml_global_t *global; /* Global data */
  170. (void)hinst;
  171. (void)reserved;
  172. switch (reason)
  173. {
  174. case DLL_PROCESS_ATTACH : /* Called on library initialization */
  175. if ((_mxml_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES)
  176. return (FALSE);
  177. break;
  178. case DLL_THREAD_DETACH : /* Called when a thread terminates */
  179. if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL)
  180. free(global);
  181. break;
  182. case DLL_PROCESS_DETACH : /* Called when library is unloaded */
  183. if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL)
  184. free(global);
  185. TlsFree(_mxml_tls_index);
  186. break;
  187. default:
  188. break;
  189. }
  190. return (TRUE);
  191. }
  192. /*
  193. * '_mxml_global()' - Get global data.
  194. */
  195. _mxml_global_t * /* O - Global data */
  196. _mxml_global(void)
  197. {
  198. _mxml_global_t *global; /* Global data */
  199. if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) == NULL)
  200. {
  201. global = (_mxml_global_t *)calloc(1, sizeof(_mxml_global_t));
  202. global->num_entity_cbs = 1;
  203. global->entity_cbs[0] = _mxml_entity_cb;
  204. global->wrap = 72;
  205. TlsSetValue(_mxml_tls_index, (LPVOID)global);
  206. }
  207. return (global);
  208. }
  209. #else /**** No threading ****/
  210. /*
  211. * '_mxml_global()' - Get global data.
  212. */
  213. _mxml_global_t * /* O - Global data */
  214. _mxml_global(void)
  215. {
  216. static _mxml_global_t global = /* Global data */
  217. {
  218. NULL, /* error_cb */
  219. 1, /* num_entity_cbs */
  220. { _mxml_entity_cb }, /* entity_cbs */
  221. 72, /* wrap */
  222. NULL, /* custom_load_cb */
  223. NULL /* custom_save_cb */
  224. };
  225. return (&global);
  226. }
  227. #endif /* HAVE_PTHREAD_H */