test-unwind.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. /* Copyright (C) 2004, 2005, 2008 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
  5. * License as published by the Free Software Foundation; either
  6. * version 2.1 of the License, or (at your option) any later version.
  7. *
  8. * This library is distributed in the hope that it will be useful,
  9. * but 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 02110-1301 USA
  16. */
  17. #if HAVE_CONFIG_H
  18. # include <config.h>
  19. #endif
  20. /* This blob per the Autoconf manual (under "Particular Functions"), updated
  21. to match that of Gnulib. */
  22. #ifndef alloca
  23. # if HAVE_ALLOCA_H
  24. # include <alloca.h>
  25. # elif defined __GNUC__
  26. # define alloca __builtin_alloca
  27. # elif defined _AIX
  28. # define alloca __alloca
  29. # elif defined _MSC_VER
  30. # include <malloc.h>
  31. # define alloca _alloca
  32. # else
  33. # include <stddef.h>
  34. # ifdef __cplusplus
  35. extern "C"
  36. # endif
  37. void *alloca (size_t);
  38. # endif
  39. #endif
  40. #include <libguile.h>
  41. #include <stdlib.h>
  42. #include <stdio.h>
  43. #include <unistd.h>
  44. #ifdef HAVE_STRING_H
  45. # include <string.h>
  46. #endif
  47. void set_flag (void *data);
  48. void func1 (void);
  49. void func2 (void);
  50. void func3 (void);
  51. void func4 (void);
  52. void check_flag1 (const char *msg, void (*func)(void), int val);
  53. SCM check_flag1_body (void *data);
  54. SCM return_tag (void *data, SCM tag, SCM args);
  55. void check_cont (int rewindable);
  56. SCM check_cont_body (void *data);
  57. void close_port (SCM port);
  58. void delete_file (void *data);
  59. void check_ports (void);
  60. void check_fluid (void);
  61. int flag1, flag2, flag3;
  62. void
  63. set_flag (void *data)
  64. {
  65. int *f = (int *)data;
  66. *f = 1;
  67. }
  68. /* FUNC1 should leave flag1 zero.
  69. */
  70. void
  71. func1 ()
  72. {
  73. scm_dynwind_begin (0);
  74. flag1 = 0;
  75. scm_dynwind_unwind_handler (set_flag, &flag1, 0);
  76. scm_dynwind_end ();
  77. }
  78. /* FUNC2 should set flag1.
  79. */
  80. void
  81. func2 ()
  82. {
  83. scm_dynwind_begin (0);
  84. flag1 = 0;
  85. scm_dynwind_unwind_handler (set_flag, &flag1, SCM_F_WIND_EXPLICITLY);
  86. scm_dynwind_end ();
  87. }
  88. /* FUNC3 should set flag1.
  89. */
  90. void
  91. func3 ()
  92. {
  93. scm_dynwind_begin (0);
  94. flag1 = 0;
  95. scm_dynwind_unwind_handler (set_flag, &flag1, 0);
  96. scm_misc_error ("func3", "gratuitous error", SCM_EOL);
  97. scm_dynwind_end ();
  98. }
  99. /* FUNC4 should set flag1.
  100. */
  101. void
  102. func4 ()
  103. {
  104. scm_dynwind_begin (0);
  105. flag1 = 0;
  106. scm_dynwind_unwind_handler (set_flag, &flag1, SCM_F_WIND_EXPLICITLY);
  107. scm_misc_error ("func4", "gratuitous error", SCM_EOL);
  108. scm_dynwind_end ();
  109. }
  110. SCM
  111. check_flag1_body (void *data)
  112. {
  113. void (*f)(void) = (void (*)(void))data;
  114. f ();
  115. return SCM_UNSPECIFIED;
  116. }
  117. SCM
  118. return_tag (void *data, SCM tag, SCM args)
  119. {
  120. return tag;
  121. }
  122. void
  123. check_flag1 (const char *tag, void (*func)(void), int val)
  124. {
  125. scm_internal_catch (SCM_BOOL_T,
  126. check_flag1_body, func,
  127. return_tag, NULL);
  128. if (flag1 != val)
  129. {
  130. printf ("%s failed\n", tag);
  131. exit (1);
  132. }
  133. }
  134. SCM
  135. check_cont_body (void *data)
  136. {
  137. scm_t_dynwind_flags flags = (data? SCM_F_DYNWIND_REWINDABLE : 0);
  138. int first;
  139. SCM val;
  140. scm_dynwind_begin (flags);
  141. val = scm_make_continuation (&first);
  142. scm_dynwind_end ();
  143. return val;
  144. }
  145. void
  146. check_cont (int rewindable)
  147. {
  148. SCM res;
  149. res = scm_internal_catch (SCM_BOOL_T,
  150. check_cont_body, (void *)(long)rewindable,
  151. return_tag, NULL);
  152. /* RES is now either the created continuation, the value passed to
  153. the continuation, or a catch-tag, such as 'misc-error.
  154. */
  155. if (scm_is_true (scm_procedure_p (res)))
  156. {
  157. /* a continuation, invoke it */
  158. scm_call_1 (res, SCM_BOOL_F);
  159. }
  160. else if (scm_is_false (res))
  161. {
  162. /* the result of invoking the continuation, dynwind must be
  163. rewindable */
  164. if (rewindable)
  165. return;
  166. printf ("continuation not blocked\n");
  167. exit (1);
  168. }
  169. else
  170. {
  171. /* the catch tag, dynwind must not have been rewindable. */
  172. if (!rewindable)
  173. return;
  174. printf ("continuation didn't work\n");
  175. exit (1);
  176. }
  177. }
  178. void
  179. close_port (SCM port)
  180. {
  181. scm_close_port (port);
  182. }
  183. void
  184. delete_file (void *data)
  185. {
  186. unlink ((char *)data);
  187. }
  188. void
  189. check_ports ()
  190. {
  191. #define FILENAME_TEMPLATE "/check-ports.XXXXXX"
  192. char *filename;
  193. const char *tmpdir = getenv ("TMPDIR");
  194. if (tmpdir == NULL)
  195. tmpdir = "/tmp";
  196. filename = (char *) alloca (strlen (tmpdir) +
  197. sizeof (FILENAME_TEMPLATE) + 1);
  198. strcpy (filename, tmpdir);
  199. strcat (filename, FILENAME_TEMPLATE);
  200. if (mktemp (filename) == NULL)
  201. exit (1);
  202. scm_dynwind_begin (0);
  203. {
  204. SCM port = scm_open_file (scm_from_locale_string (filename),
  205. scm_from_locale_string ("w"));
  206. scm_dynwind_unwind_handler_with_scm (close_port, port,
  207. SCM_F_WIND_EXPLICITLY);
  208. scm_dynwind_current_output_port (port);
  209. scm_write (scm_version (), SCM_UNDEFINED);
  210. }
  211. scm_dynwind_end ();
  212. scm_dynwind_begin (0);
  213. {
  214. SCM port = scm_open_file (scm_from_locale_string (filename),
  215. scm_from_locale_string ("r"));
  216. SCM res;
  217. scm_dynwind_unwind_handler_with_scm (close_port, port,
  218. SCM_F_WIND_EXPLICITLY);
  219. scm_dynwind_unwind_handler (delete_file, filename, SCM_F_WIND_EXPLICITLY);
  220. scm_dynwind_current_input_port (port);
  221. res = scm_read (SCM_UNDEFINED);
  222. if (scm_is_false (scm_equal_p (res, scm_version ())))
  223. {
  224. printf ("ports didn't work\n");
  225. exit (1);
  226. }
  227. }
  228. scm_dynwind_end ();
  229. #undef FILENAME_TEMPLATE
  230. }
  231. void
  232. check_fluid ()
  233. {
  234. SCM f = scm_make_fluid ();
  235. SCM x;
  236. scm_fluid_set_x (f, scm_from_int (12));
  237. scm_dynwind_begin (0);
  238. scm_dynwind_fluid (f, scm_from_int (13));
  239. x = scm_fluid_ref (f);
  240. scm_dynwind_end ();
  241. if (!scm_is_eq (x, scm_from_int (13)))
  242. {
  243. printf ("setting fluid didn't work\n");
  244. exit (1);
  245. }
  246. if (!scm_is_eq (scm_fluid_ref (f), scm_from_int (12)))
  247. {
  248. printf ("resetting fluid didn't work\n");
  249. exit (1);
  250. }
  251. }
  252. static void
  253. inner_main (void *data, int argc, char **argv)
  254. {
  255. check_flag1 ("func1", func1, 0);
  256. check_flag1 ("func2", func2, 1);
  257. check_flag1 ("func3", func3, 1);
  258. check_flag1 ("func4", func4, 1);
  259. check_cont (0);
  260. check_cont (1);
  261. check_ports ();
  262. check_fluid ();
  263. exit (0);
  264. }
  265. int
  266. main (int argc, char **argv)
  267. {
  268. scm_boot_guile (argc, argv, inner_main, 0);
  269. return 0;
  270. }