test-unwind.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /* Copyright (C) 2004, 2005, 2008, 2009, 2010, 2013 Free Software Foundation, Inc.
  2. *
  3. * This library is free software; you can redistribute it and/or
  4. * modify it under the terms of the GNU Lesser General Public License
  5. * as published by the Free Software Foundation; either version 3 of
  6. * the License, or (at your option) any later version.
  7. *
  8. * This library is distributed in the hope that it will be useful, but
  9. * WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. * Lesser General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Lesser General Public
  14. * License along with this library; if not, write to the Free Software
  15. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  16. * 02110-1301 USA
  17. */
  18. #if HAVE_CONFIG_H
  19. # include <config.h>
  20. #endif
  21. #include <alloca.h>
  22. #include <libguile.h>
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25. #include <unistd.h>
  26. #ifdef HAVE_STRING_H
  27. # include <string.h>
  28. #endif
  29. void set_flag (void *data);
  30. void func1 (void);
  31. void func2 (void);
  32. void func3 (void);
  33. void func4 (void);
  34. void check_flag1 (const char *msg, void (*func)(void), int val);
  35. SCM check_flag1_body (void *data);
  36. SCM return_tag (void *data, SCM tag, SCM args);
  37. void check_cont (int rewindable);
  38. SCM check_cont_body (void *data);
  39. void close_port (SCM port);
  40. void delete_file (void *data);
  41. void check_ports (void);
  42. void check_fluid (void);
  43. int flag1, flag2, flag3;
  44. void
  45. set_flag (void *data)
  46. {
  47. int *f = (int *)data;
  48. *f = 1;
  49. }
  50. /* FUNC1 should leave flag1 zero.
  51. */
  52. void
  53. func1 ()
  54. {
  55. scm_dynwind_begin (0);
  56. flag1 = 0;
  57. scm_dynwind_unwind_handler (set_flag, &flag1, 0);
  58. scm_dynwind_end ();
  59. }
  60. /* FUNC2 should set flag1.
  61. */
  62. void
  63. func2 ()
  64. {
  65. scm_dynwind_begin (0);
  66. flag1 = 0;
  67. scm_dynwind_unwind_handler (set_flag, &flag1, SCM_F_WIND_EXPLICITLY);
  68. scm_dynwind_end ();
  69. }
  70. /* FUNC3 should set flag1.
  71. */
  72. void
  73. func3 ()
  74. {
  75. scm_dynwind_begin (0);
  76. flag1 = 0;
  77. scm_dynwind_unwind_handler (set_flag, &flag1, 0);
  78. scm_misc_error ("func3", "gratuitous error", SCM_EOL);
  79. scm_dynwind_end ();
  80. }
  81. /* FUNC4 should set flag1.
  82. */
  83. void
  84. func4 ()
  85. {
  86. scm_dynwind_begin (0);
  87. flag1 = 0;
  88. scm_dynwind_unwind_handler (set_flag, &flag1, SCM_F_WIND_EXPLICITLY);
  89. scm_misc_error ("func4", "gratuitous error", SCM_EOL);
  90. scm_dynwind_end ();
  91. }
  92. SCM
  93. check_flag1_body (void *data)
  94. {
  95. void (*f)(void) = (void (*)(void))data;
  96. f ();
  97. return SCM_UNSPECIFIED;
  98. }
  99. SCM
  100. return_tag (void *data, SCM tag, SCM args)
  101. {
  102. return tag;
  103. }
  104. void
  105. check_flag1 (const char *tag, void (*func)(void), int val)
  106. {
  107. scm_internal_catch (SCM_BOOL_T,
  108. check_flag1_body, func,
  109. return_tag, NULL);
  110. if (flag1 != val)
  111. {
  112. printf ("%s failed\n", tag);
  113. exit (EXIT_FAILURE);
  114. }
  115. }
  116. SCM
  117. check_cont_body (void *data)
  118. {
  119. scm_t_dynwind_flags flags = (data? SCM_F_DYNWIND_REWINDABLE : 0);
  120. SCM val;
  121. scm_dynwind_begin (flags);
  122. val = scm_c_eval_string ("(call/cc (lambda (k) k))");
  123. scm_dynwind_end ();
  124. return val;
  125. }
  126. void
  127. check_cont (int rewindable)
  128. {
  129. SCM res;
  130. res = scm_internal_catch (SCM_BOOL_T,
  131. check_cont_body, (void *)(long)rewindable,
  132. return_tag, NULL);
  133. /* RES is now either the created continuation, the value passed to
  134. the continuation, or a catch-tag, such as 'misc-error.
  135. */
  136. if (scm_is_true (scm_procedure_p (res)))
  137. {
  138. /* a continuation, invoke it */
  139. scm_call_1 (res, SCM_BOOL_F);
  140. }
  141. else if (scm_is_false (res))
  142. {
  143. /* the result of invoking the continuation, dynwind must be
  144. rewindable */
  145. if (rewindable)
  146. return;
  147. printf ("continuation not blocked\n");
  148. exit (EXIT_FAILURE);
  149. }
  150. else
  151. {
  152. /* the catch tag, dynwind must not have been rewindable. */
  153. if (!rewindable)
  154. return;
  155. printf ("continuation didn't work\n");
  156. exit (EXIT_FAILURE);
  157. }
  158. }
  159. void
  160. close_port (SCM port)
  161. {
  162. scm_close_port (port);
  163. }
  164. void
  165. delete_file (void *data)
  166. {
  167. unlink ((char *)data);
  168. }
  169. void
  170. check_ports ()
  171. {
  172. #define FILENAME_TEMPLATE "/check-ports.XXXXXX"
  173. char *filename;
  174. const char *tmpdir = getenv ("TMPDIR");
  175. #ifdef __MINGW32__
  176. extern int mkstemp (char *);
  177. /* On Windows neither $TMPDIR nor /tmp can be relied on. */
  178. if (tmpdir == NULL)
  179. tmpdir = getenv ("TEMP");
  180. if (tmpdir == NULL)
  181. tmpdir = getenv ("TMP");
  182. if (tmpdir == NULL)
  183. tmpdir = "/";
  184. #else
  185. if (tmpdir == NULL)
  186. tmpdir = "/tmp";
  187. #endif
  188. filename = alloca (strlen (tmpdir) + sizeof (FILENAME_TEMPLATE) + 1);
  189. strcpy (filename, tmpdir);
  190. strcat (filename, FILENAME_TEMPLATE);
  191. /* Sanity check: Make sure that `filename' is actually writeable.
  192. We used to use mktemp(3), but that is now considered a security risk. */
  193. if (0 > mkstemp (filename))
  194. exit (EXIT_FAILURE);
  195. scm_dynwind_begin (0);
  196. {
  197. SCM port = scm_open_file (scm_from_locale_string (filename),
  198. scm_from_locale_string ("w"));
  199. scm_dynwind_unwind_handler_with_scm (close_port, port,
  200. SCM_F_WIND_EXPLICITLY);
  201. scm_dynwind_current_output_port (port);
  202. scm_write (scm_version (), SCM_UNDEFINED);
  203. }
  204. scm_dynwind_end ();
  205. scm_dynwind_begin (0);
  206. {
  207. SCM port = scm_open_file (scm_from_locale_string (filename),
  208. scm_from_locale_string ("r"));
  209. SCM res;
  210. scm_dynwind_unwind_handler_with_scm (close_port, port,
  211. SCM_F_WIND_EXPLICITLY);
  212. scm_dynwind_unwind_handler (delete_file, filename, SCM_F_WIND_EXPLICITLY);
  213. scm_dynwind_current_input_port (port);
  214. res = scm_read (SCM_UNDEFINED);
  215. if (scm_is_false (scm_equal_p (res, scm_version ())))
  216. {
  217. printf ("ports didn't work\n");
  218. exit (EXIT_FAILURE);
  219. }
  220. }
  221. scm_dynwind_end ();
  222. #undef FILENAME_TEMPLATE
  223. }
  224. void
  225. check_fluid ()
  226. {
  227. SCM f = scm_make_fluid ();
  228. SCM x;
  229. scm_fluid_set_x (f, scm_from_int (12));
  230. scm_dynwind_begin (0);
  231. scm_dynwind_fluid (f, scm_from_int (13));
  232. x = scm_fluid_ref (f);
  233. scm_dynwind_end ();
  234. if (!scm_is_eq (x, scm_from_int (13)))
  235. {
  236. printf ("setting fluid didn't work\n");
  237. exit (EXIT_FAILURE);
  238. }
  239. if (!scm_is_eq (scm_fluid_ref (f), scm_from_int (12)))
  240. {
  241. printf ("resetting fluid didn't work\n");
  242. exit (EXIT_FAILURE);
  243. }
  244. }
  245. static void
  246. inner_main (void *data, int argc, char **argv)
  247. {
  248. check_flag1 ("func1", func1, 0);
  249. check_flag1 ("func2", func2, 1);
  250. check_flag1 ("func3", func3, 1);
  251. check_flag1 ("func4", func4, 1);
  252. check_cont (0);
  253. check_cont (1);
  254. check_ports ();
  255. check_fluid ();
  256. exit (EXIT_SUCCESS);
  257. }
  258. int
  259. main (int argc, char **argv)
  260. {
  261. scm_boot_guile (argc, argv, inner_main, 0);
  262. return 0;
  263. }