mxml-private.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /*
  2. * Private functions for Mini-XML, a small XML file parsing library.
  3. *
  4. * https://www.msweet.org/mxml
  5. *
  6. * Copyright © 2003-2019 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, Mac OS X, 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 Mac OS X */
  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 pthread_key_t _mxml_key = -1; /* Thread local storage key */
  108. static pthread_once_t _mxml_key_once = PTHREAD_ONCE_INIT;
  109. /* One-time initialization object */
  110. static void _mxml_init(void);
  111. static void _mxml_destructor(void *g);
  112. /*
  113. * '_mxml_destructor()' - Free memory used for globals...
  114. */
  115. static void
  116. _mxml_destructor(void *g) /* I - Global data */
  117. {
  118. free(g);
  119. }
  120. /*
  121. * '_mxml_fini()' - Clean up when unloaded.
  122. */
  123. static void
  124. _MXML_FINI(void)
  125. {
  126. _mxml_global_t *global; /* Global data */
  127. if (_mxml_key != -1)
  128. {
  129. if ((global = (_mxml_global_t *)pthread_getspecific(_mxml_key)) != NULL)
  130. _mxml_destructor(global);
  131. pthread_key_delete(_mxml_key);
  132. _mxml_key = -1;
  133. }
  134. }
  135. /*
  136. * '_mxml_global()' - Get global data.
  137. */
  138. _mxml_global_t * /* O - Global data */
  139. _mxml_global(void)
  140. {
  141. _mxml_global_t *global; /* Global data */
  142. pthread_once(&_mxml_key_once, _mxml_init);
  143. if ((global = (_mxml_global_t *)pthread_getspecific(_mxml_key)) == NULL)
  144. {
  145. global = (_mxml_global_t *)calloc(1, sizeof(_mxml_global_t));
  146. pthread_setspecific(_mxml_key, global);
  147. global->num_entity_cbs = 1;
  148. global->entity_cbs[0] = _mxml_entity_cb;
  149. global->wrap = 72;
  150. }
  151. return (global);
  152. }
  153. /*
  154. * '_mxml_init()' - Initialize global data...
  155. */
  156. static void
  157. _mxml_init(void)
  158. {
  159. pthread_key_create(&_mxml_key, _mxml_destructor);
  160. }
  161. #elif defined(_WIN32) && defined(MXML1_EXPORTS) /**** WIN32 threading ****/
  162. # include <windows.h>
  163. static DWORD _mxml_tls_index; /* Index for global storage */
  164. /*
  165. * 'DllMain()' - Main entry for library.
  166. */
  167. BOOL WINAPI /* O - Success/failure */
  168. DllMain(HINSTANCE hinst, /* I - DLL module handle */
  169. DWORD reason, /* I - Reason */
  170. LPVOID reserved) /* I - Unused */
  171. {
  172. _mxml_global_t *global; /* Global data */
  173. (void)hinst;
  174. (void)reserved;
  175. switch (reason)
  176. {
  177. case DLL_PROCESS_ATTACH : /* Called on library initialization */
  178. if ((_mxml_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES)
  179. return (FALSE);
  180. break;
  181. case DLL_THREAD_DETACH : /* Called when a thread terminates */
  182. if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL)
  183. free(global);
  184. break;
  185. case DLL_PROCESS_DETACH : /* Called when library is unloaded */
  186. if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL)
  187. free(global);
  188. TlsFree(_mxml_tls_index);
  189. break;
  190. default:
  191. break;
  192. }
  193. return (TRUE);
  194. }
  195. /*
  196. * '_mxml_global()' - Get global data.
  197. */
  198. _mxml_global_t * /* O - Global data */
  199. _mxml_global(void)
  200. {
  201. _mxml_global_t *global; /* Global data */
  202. if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) == NULL)
  203. {
  204. global = (_mxml_global_t *)calloc(1, sizeof(_mxml_global_t));
  205. global->num_entity_cbs = 1;
  206. global->entity_cbs[0] = _mxml_entity_cb;
  207. global->wrap = 72;
  208. TlsSetValue(_mxml_tls_index, (LPVOID)global);
  209. }
  210. return (global);
  211. }
  212. #else /**** No threading ****/
  213. /*
  214. * '_mxml_global()' - Get global data.
  215. */
  216. _mxml_global_t * /* O - Global data */
  217. _mxml_global(void)
  218. {
  219. static _mxml_global_t global = /* Global data */
  220. {
  221. NULL, /* error_cb */
  222. 1, /* num_entity_cbs */
  223. { _mxml_entity_cb }, /* entity_cbs */
  224. 72, /* wrap */
  225. NULL, /* custom_load_cb */
  226. NULL /* custom_save_cb */
  227. };
  228. return (&global);
  229. }
  230. #endif /* HAVE_PTHREAD_H */