Use `mkstemp' instead of `mktemp'.
[bpt/guile.git] / test-suite / standalone / test-unwind.c
CommitLineData
c291b588 1/* Copyright (C) 2004, 2005, 2008, 2009 Free Software Foundation, Inc.
eedcb08a
LC
2 *
3 * This library is free software; you can redistribute it and/or
53befeb7
NJ
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.
eedcb08a 7 *
53befeb7
NJ
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
eedcb08a
LC
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
53befeb7
NJ
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
eedcb08a
LC
17 */
18
19#if HAVE_CONFIG_H
20# include <config.h>
21#endif
22
23#include <alloca.h>
24
3c8fb18e
MV
25#include <libguile.h>
26#include <stdlib.h>
27#include <stdio.h>
c05d0e8f 28#include <unistd.h>
3c8fb18e 29
eedcb08a
LC
30#ifdef HAVE_STRING_H
31# include <string.h>
32#endif
33
34
3c8fb18e
MV
35void set_flag (void *data);
36void func1 (void);
37void func2 (void);
38void func3 (void);
39void func4 (void);
40void check_flag1 (const char *msg, void (*func)(void), int val);
41SCM check_flag1_body (void *data);
42SCM return_tag (void *data, SCM tag, SCM args);
43void check_cont (int rewindable);
44SCM check_cont_body (void *data);
c05d0e8f
MV
45void close_port (SCM port);
46void delete_file (void *data);
47void check_ports (void);
8843e1fa 48void check_fluid (void);
3c8fb18e
MV
49
50int flag1, flag2, flag3;
51
52void
53set_flag (void *data)
54{
55 int *f = (int *)data;
56 *f = 1;
57}
58
59/* FUNC1 should leave flag1 zero.
60 */
61
62void
63func1 ()
64{
661ae7ab 65 scm_dynwind_begin (0);
3c8fb18e 66 flag1 = 0;
661ae7ab
MV
67 scm_dynwind_unwind_handler (set_flag, &flag1, 0);
68 scm_dynwind_end ();
3c8fb18e
MV
69}
70
71/* FUNC2 should set flag1.
72 */
73
74void
75func2 ()
76{
661ae7ab 77 scm_dynwind_begin (0);
3c8fb18e 78 flag1 = 0;
661ae7ab
MV
79 scm_dynwind_unwind_handler (set_flag, &flag1, SCM_F_WIND_EXPLICITLY);
80 scm_dynwind_end ();
3c8fb18e
MV
81}
82
83/* FUNC3 should set flag1.
84 */
85
86void
87func3 ()
88{
661ae7ab 89 scm_dynwind_begin (0);
3c8fb18e 90 flag1 = 0;
661ae7ab 91 scm_dynwind_unwind_handler (set_flag, &flag1, 0);
3c8fb18e 92 scm_misc_error ("func3", "gratuitous error", SCM_EOL);
661ae7ab 93 scm_dynwind_end ();
3c8fb18e
MV
94}
95
96/* FUNC4 should set flag1.
97 */
98
99void
100func4 ()
101{
661ae7ab 102 scm_dynwind_begin (0);
3c8fb18e 103 flag1 = 0;
661ae7ab 104 scm_dynwind_unwind_handler (set_flag, &flag1, SCM_F_WIND_EXPLICITLY);
3c8fb18e 105 scm_misc_error ("func4", "gratuitous error", SCM_EOL);
661ae7ab 106 scm_dynwind_end ();
3c8fb18e
MV
107}
108
109SCM
110check_flag1_body (void *data)
111{
112 void (*f)(void) = (void (*)(void))data;
113 f ();
114 return SCM_UNSPECIFIED;
115}
116
117SCM
118return_tag (void *data, SCM tag, SCM args)
119{
120 return tag;
121}
122
123void
124check_flag1 (const char *tag, void (*func)(void), int val)
125{
126 scm_internal_catch (SCM_BOOL_T,
127 check_flag1_body, func,
128 return_tag, NULL);
129 if (flag1 != val)
130 {
131 printf ("%s failed\n", tag);
132 exit (1);
133 }
134}
135
136SCM
137check_cont_body (void *data)
138{
98241dc5 139 scm_t_dynwind_flags flags = (data? SCM_F_DYNWIND_REWINDABLE : 0);
3c8fb18e
MV
140 int first;
141 SCM val;
142
661ae7ab 143 scm_dynwind_begin (flags);
3c8fb18e
MV
144
145 val = scm_make_continuation (&first);
661ae7ab 146 scm_dynwind_end ();
3c8fb18e
MV
147 return val;
148}
149
150void
151check_cont (int rewindable)
152{
153 SCM res;
154
155 res = scm_internal_catch (SCM_BOOL_T,
4858610b 156 check_cont_body, (void *)(long)rewindable,
3c8fb18e
MV
157 return_tag, NULL);
158
159 /* RES is now either the created continuation, the value passed to
160 the continuation, or a catch-tag, such as 'misc-error.
161 */
162
66dd7f14 163 if (scm_is_true (scm_procedure_p (res)))
3c8fb18e
MV
164 {
165 /* a continuation, invoke it */
166 scm_call_1 (res, SCM_BOOL_F);
167 }
66dd7f14 168 else if (scm_is_false (res))
3c8fb18e 169 {
661ae7ab 170 /* the result of invoking the continuation, dynwind must be
3c8fb18e
MV
171 rewindable */
172 if (rewindable)
173 return;
174 printf ("continuation not blocked\n");
175 exit (1);
176 }
177 else
178 {
661ae7ab 179 /* the catch tag, dynwind must not have been rewindable. */
3c8fb18e
MV
180 if (!rewindable)
181 return;
182 printf ("continuation didn't work\n");
183 exit (1);
184 }
185}
c05d0e8f
MV
186
187void
188close_port (SCM port)
189{
190 scm_close_port (port);
191}
192
193void
194delete_file (void *data)
195{
196 unlink ((char *)data);
197}
198
199void
200check_ports ()
201{
eedcb08a
LC
202#define FILENAME_TEMPLATE "/check-ports.XXXXXX"
203 char *filename;
204 const char *tmpdir = getenv ("TMPDIR");
205
206 if (tmpdir == NULL)
207 tmpdir = "/tmp";
208
c291b588 209 filename = alloca (strlen (tmpdir) + sizeof (FILENAME_TEMPLATE) + 1);
eedcb08a
LC
210 strcpy (filename, tmpdir);
211 strcat (filename, FILENAME_TEMPLATE);
c05d0e8f 212
bd4b6c1a
TTN
213 /* Sanity check: Make sure that `filename' is actually writeable.
214 We used to use mktemp(3), but that is now considered a security risk. */
215 if (0 > mkstemp (filename))
c05d0e8f
MV
216 exit (1);
217
661ae7ab 218 scm_dynwind_begin (0);
c05d0e8f 219 {
ad6dec05
MV
220 SCM port = scm_open_file (scm_from_locale_string (filename),
221 scm_from_locale_string ("w"));
661ae7ab 222 scm_dynwind_unwind_handler_with_scm (close_port, port,
f1da8e4e 223 SCM_F_WIND_EXPLICITLY);
c05d0e8f 224
661ae7ab 225 scm_dynwind_current_output_port (port);
c05d0e8f
MV
226 scm_write (scm_version (), SCM_UNDEFINED);
227 }
661ae7ab 228 scm_dynwind_end ();
c05d0e8f 229
661ae7ab 230 scm_dynwind_begin (0);
c05d0e8f 231 {
ad6dec05
MV
232 SCM port = scm_open_file (scm_from_locale_string (filename),
233 scm_from_locale_string ("r"));
c05d0e8f 234 SCM res;
661ae7ab 235 scm_dynwind_unwind_handler_with_scm (close_port, port,
f1da8e4e 236 SCM_F_WIND_EXPLICITLY);
661ae7ab 237 scm_dynwind_unwind_handler (delete_file, filename, SCM_F_WIND_EXPLICITLY);
c05d0e8f 238
661ae7ab 239 scm_dynwind_current_input_port (port);
c05d0e8f 240 res = scm_read (SCM_UNDEFINED);
66dd7f14 241 if (scm_is_false (scm_equal_p (res, scm_version ())))
c05d0e8f
MV
242 {
243 printf ("ports didn't work\n");
244 exit (1);
245 }
246 }
661ae7ab 247 scm_dynwind_end ();
eedcb08a 248#undef FILENAME_TEMPLATE
c05d0e8f 249}
8843e1fa
MV
250
251void
252check_fluid ()
253{
254 SCM f = scm_make_fluid ();
255 SCM x;
256
79e9bca7 257 scm_fluid_set_x (f, scm_from_int (12));
8843e1fa 258
661ae7ab
MV
259 scm_dynwind_begin (0);
260 scm_dynwind_fluid (f, scm_from_int (13));
8843e1fa 261 x = scm_fluid_ref (f);
661ae7ab 262 scm_dynwind_end ();
8843e1fa 263
79e9bca7 264 if (!scm_is_eq (x, scm_from_int (13)))
8843e1fa
MV
265 {
266 printf ("setting fluid didn't work\n");
267 exit (1);
268 }
269
79e9bca7 270 if (!scm_is_eq (scm_fluid_ref (f), scm_from_int (12)))
8843e1fa
MV
271 {
272 printf ("resetting fluid didn't work\n");
273 exit (1);
274 }
275}
276
3c8fb18e
MV
277static void
278inner_main (void *data, int argc, char **argv)
279{
280 check_flag1 ("func1", func1, 0);
281 check_flag1 ("func2", func2, 1);
282 check_flag1 ("func3", func3, 1);
283 check_flag1 ("func4", func4, 1);
284
285 check_cont (0);
286 check_cont (1);
287
c05d0e8f
MV
288 check_ports ();
289
8843e1fa
MV
290 check_fluid ();
291
3c8fb18e
MV
292 exit (0);
293}
294
295int
296main (int argc, char **argv)
297{
298 scm_boot_guile (argc, argv, inner_main, 0);
299 return 0;
300}