deprecation.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /* Copyright (C) 2001, 2005, 2006, 2009-2012, 2016, 2018
  2. * Free Software Foundation, Inc.
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public License
  6. * as published by the Free Software Foundation; either version 3 of
  7. * the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301 USA
  18. */
  19. #ifdef HAVE_CONFIG_H
  20. # include <config.h>
  21. #endif
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include <stdarg.h>
  25. #include "libguile/_scm.h"
  26. #include "libguile/deprecation.h"
  27. #include "libguile/strings.h"
  28. #include "libguile/ports.h"
  29. #include "libguile/private-options.h"
  30. struct issued_warning {
  31. struct issued_warning *prev;
  32. const char *message;
  33. };
  34. static scm_i_pthread_mutex_t warn_lock = SCM_I_PTHREAD_MUTEX_INITIALIZER;
  35. static struct issued_warning *issued_warnings;
  36. static int print_summary = 0;
  37. void
  38. scm_c_issue_deprecation_warning (const char *msg)
  39. {
  40. if (!SCM_WARN_DEPRECATED)
  41. print_summary = 1;
  42. else
  43. {
  44. struct issued_warning *iw;
  45. scm_i_pthread_mutex_lock (&warn_lock);
  46. for (iw = issued_warnings; iw; iw = iw->prev)
  47. if (!strcmp (iw->message, msg))
  48. {
  49. msg = NULL;
  50. break;
  51. }
  52. if (msg)
  53. {
  54. msg = strdup (msg);
  55. iw = malloc (sizeof (struct issued_warning));
  56. if (msg == NULL || iw == NULL)
  57. /* Nothing sensible to do if you can't allocate this small
  58. amount of memory. */
  59. abort ();
  60. iw->message = msg;
  61. iw->prev = issued_warnings;
  62. issued_warnings = iw;
  63. }
  64. scm_i_pthread_mutex_unlock (&warn_lock);
  65. /* All this dance is to avoid printing to a port inside a mutex,
  66. which could recurse and deadlock. */
  67. if (msg)
  68. {
  69. if (scm_gc_running_p)
  70. fprintf (stderr, "%s\n", msg);
  71. else
  72. {
  73. scm_puts (msg, scm_current_warning_port ());
  74. scm_newline (scm_current_warning_port ());
  75. }
  76. }
  77. }
  78. }
  79. void
  80. scm_c_issue_deprecation_warning_fmt (const char *msg, ...)
  81. {
  82. va_list ap;
  83. char buf[512];
  84. va_start (ap, msg);
  85. vsnprintf (buf, 511, msg, ap);
  86. va_end (ap);
  87. buf[511] = '\0';
  88. scm_c_issue_deprecation_warning (buf);
  89. }
  90. SCM_DEFINE(scm_issue_deprecation_warning,
  91. "issue-deprecation-warning", 0, 0, 1,
  92. (SCM msgs),
  93. "Output @var{msgs} to @code{(current-error-port)} when this "
  94. "is the first call to @code{issue-deprecation-warning} with "
  95. "this specific @var{msgs}. Do nothing otherwise. "
  96. "The argument @var{msgs} should be a list of strings; "
  97. "they are printed in turn, each one followed by a newline.")
  98. #define FUNC_NAME s_scm_issue_deprecation_warning
  99. {
  100. if (!SCM_WARN_DEPRECATED)
  101. print_summary = 1;
  102. else
  103. {
  104. SCM nl = scm_from_utf8_string ("\n");
  105. SCM msgs_nl = SCM_EOL;
  106. char *c_msgs;
  107. while (scm_is_pair (msgs))
  108. {
  109. if (!scm_is_null (msgs_nl))
  110. msgs_nl = scm_cons (nl, msgs_nl);
  111. msgs_nl = scm_cons (SCM_CAR (msgs), msgs_nl);
  112. msgs = SCM_CDR (msgs);
  113. }
  114. msgs_nl = scm_string_append (scm_reverse_x (msgs_nl, SCM_EOL));
  115. c_msgs = scm_to_locale_string (msgs_nl);
  116. scm_c_issue_deprecation_warning (c_msgs);
  117. free (c_msgs);
  118. }
  119. return SCM_UNSPECIFIED;
  120. }
  121. #undef FUNC_NAME
  122. static void
  123. print_deprecation_summary (void)
  124. {
  125. if (print_summary)
  126. {
  127. fputs ("\n"
  128. "Some deprecated features have been used. Set the environment\n"
  129. "variable GUILE_WARN_DEPRECATED to \"detailed\" and rerun the\n"
  130. "program to get more information. Set it to \"no\" to suppress\n"
  131. "this message.\n", stderr);
  132. }
  133. }
  134. SCM_DEFINE(scm_include_deprecated_features,
  135. "include-deprecated-features", 0, 0, 0,
  136. (),
  137. "Return @code{#t} iff deprecated features should be included "
  138. "in public interfaces.")
  139. #define FUNC_NAME s_scm_include_deprecated_features
  140. {
  141. return scm_from_bool (SCM_ENABLE_DEPRECATED == 1);
  142. }
  143. #undef FUNC_NAME
  144. void
  145. scm_init_deprecation ()
  146. {
  147. const char *level = getenv ("GUILE_WARN_DEPRECATED");
  148. if (level == NULL)
  149. level = SCM_WARN_DEPRECATED_DEFAULT;
  150. if (!strcmp (level, "detailed"))
  151. SCM_WARN_DEPRECATED = 1;
  152. else if (!strcmp (level, "no"))
  153. SCM_WARN_DEPRECATED = 0;
  154. else
  155. {
  156. SCM_WARN_DEPRECATED = 0;
  157. atexit (print_deprecation_summary);
  158. }
  159. #include "libguile/deprecation.x"
  160. }
  161. /*
  162. Local Variables:
  163. c-file-style: "gnu"
  164. End:
  165. */