test-unwind.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /* Copyright 2004-2005,2008-2010,2013,2018-2019
  2. Free Software Foundation, Inc.
  3. This file is part of Guile.
  4. Guile is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Lesser General Public License as published
  6. by the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. Guile is distributed in the hope that it will be useful, but WITHOUT
  9. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  11. License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with Guile. If not, see
  14. <https://www.gnu.org/licenses/>. */
  15. #if HAVE_CONFIG_H
  16. # include <config.h>
  17. #endif
  18. #include <alloca.h>
  19. #include <libguile.h>
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <unistd.h>
  23. #ifdef HAVE_STRING_H
  24. # include <string.h>
  25. #endif
  26. void set_flag (void *data);
  27. void func1 (void);
  28. void func2 (void);
  29. void func3 (void);
  30. void func4 (void);
  31. void check_flag1 (const char *msg, void (*func)(void), int val);
  32. SCM check_flag1_body (void *data);
  33. SCM return_tag (void *data, SCM tag, SCM args);
  34. void check_cont (int rewindable);
  35. SCM check_cont_body (void *data);
  36. void close_port (SCM port);
  37. void delete_file (void *data);
  38. void check_ports (void);
  39. void check_fluid (void);
  40. int flag1, flag2, flag3;
  41. void
  42. set_flag (void *data)
  43. {
  44. int *f = (int *)data;
  45. *f = 1;
  46. }
  47. /* FUNC1 should leave flag1 zero.
  48. */
  49. void
  50. func1 ()
  51. {
  52. scm_dynwind_begin (0);
  53. flag1 = 0;
  54. scm_dynwind_unwind_handler (set_flag, &flag1, 0);
  55. scm_dynwind_end ();
  56. }
  57. /* FUNC2 should set flag1.
  58. */
  59. void
  60. func2 ()
  61. {
  62. scm_dynwind_begin (0);
  63. flag1 = 0;
  64. scm_dynwind_unwind_handler (set_flag, &flag1, SCM_F_WIND_EXPLICITLY);
  65. scm_dynwind_end ();
  66. }
  67. /* FUNC3 should set flag1.
  68. */
  69. void
  70. func3 ()
  71. {
  72. scm_dynwind_begin (0);
  73. flag1 = 0;
  74. scm_dynwind_unwind_handler (set_flag, &flag1, 0);
  75. scm_misc_error ("func3", "gratuitous error", SCM_EOL);
  76. scm_dynwind_end ();
  77. }
  78. /* FUNC4 should set flag1.
  79. */
  80. void
  81. func4 ()
  82. {
  83. scm_dynwind_begin (0);
  84. flag1 = 0;
  85. scm_dynwind_unwind_handler (set_flag, &flag1, SCM_F_WIND_EXPLICITLY);
  86. scm_misc_error ("func4", "gratuitous error", SCM_EOL);
  87. scm_dynwind_end ();
  88. }
  89. SCM
  90. check_flag1_body (void *data)
  91. {
  92. void (*f)(void) = (void (*)(void))data;
  93. f ();
  94. return SCM_UNSPECIFIED;
  95. }
  96. SCM
  97. return_tag (void *data, SCM tag, SCM args)
  98. {
  99. return tag;
  100. }
  101. void
  102. check_flag1 (const char *tag, void (*func)(void), int val)
  103. {
  104. scm_internal_catch (SCM_BOOL_T,
  105. check_flag1_body, func,
  106. return_tag, NULL);
  107. if (flag1 != val)
  108. {
  109. printf ("%s failed\n", tag);
  110. exit (EXIT_FAILURE);
  111. }
  112. }
  113. SCM
  114. check_cont_body (void *data)
  115. {
  116. scm_t_dynwind_flags flags = (data? SCM_F_DYNWIND_REWINDABLE : 0);
  117. SCM val;
  118. scm_dynwind_begin (flags);
  119. val = scm_c_eval_string ("(call/cc (lambda (k) k))");
  120. scm_dynwind_end ();
  121. return val;
  122. }
  123. void
  124. check_cont (int rewindable)
  125. {
  126. SCM res;
  127. res = scm_internal_catch (SCM_BOOL_T,
  128. check_cont_body, (void *)(long)rewindable,
  129. return_tag, NULL);
  130. /* RES is now either the created continuation, the value passed to
  131. the continuation, or a catch-tag, such as 'misc-error.
  132. */
  133. if (scm_is_true (scm_procedure_p (res)))
  134. {
  135. /* a continuation, invoke it */
  136. scm_call_1 (res, SCM_BOOL_F);
  137. }
  138. else if (scm_is_false (res))
  139. {
  140. /* the result of invoking the continuation, dynwind must be
  141. rewindable */
  142. if (rewindable)
  143. return;
  144. printf ("continuation not blocked\n");
  145. exit (EXIT_FAILURE);
  146. }
  147. else
  148. {
  149. /* the catch tag, dynwind must not have been rewindable. */
  150. if (!rewindable)
  151. return;
  152. printf ("continuation didn't work\n");
  153. exit (EXIT_FAILURE);
  154. }
  155. }
  156. void
  157. close_port (SCM port)
  158. {
  159. scm_close_port (port);
  160. }
  161. void
  162. delete_file (void *data)
  163. {
  164. unlink ((char *)data);
  165. }
  166. void
  167. check_ports ()
  168. {
  169. #define FILENAME_TEMPLATE "/check-ports.XXXXXX"
  170. char *filename;
  171. const char *tmpdir = getenv ("TMPDIR");
  172. int fd;
  173. #ifdef __MINGW32__
  174. extern int mkstemp (char *);
  175. /* On Windows neither $TMPDIR nor /tmp can be relied on. */
  176. if (tmpdir == NULL)
  177. tmpdir = getenv ("TEMP");
  178. if (tmpdir == NULL)
  179. tmpdir = getenv ("TMP");
  180. if (tmpdir == NULL)
  181. tmpdir = "/";
  182. #else
  183. if (tmpdir == NULL)
  184. tmpdir = "/tmp";
  185. #endif
  186. filename = alloca (strlen (tmpdir) + sizeof (FILENAME_TEMPLATE) + 1);
  187. strcpy (filename, tmpdir);
  188. strcat (filename, FILENAME_TEMPLATE);
  189. /* Sanity check: Make sure that `filename' is actually writeable.
  190. We used to use mktemp(3), but that is now considered a security risk. */
  191. fd = mkstemp (filename);
  192. if (fd < 0)
  193. exit (EXIT_FAILURE);
  194. close (fd);
  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. }