123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 |
- /* Copyright 2004-2005,2008-2010,2013,2018-2019
- Free Software Foundation, Inc.
- This file is part of Guile.
- Guile is free software: you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Guile is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
- License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with Guile. If not, see
- <https://www.gnu.org/licenses/>. */
- #if HAVE_CONFIG_H
- # include <config.h>
- #endif
- #include <alloca.h>
- #include <libguile.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <unistd.h>
- #ifdef HAVE_STRING_H
- # include <string.h>
- #endif
- void set_flag (void *data);
- void func1 (void);
- void func2 (void);
- void func3 (void);
- void func4 (void);
- void check_flag1 (const char *msg, void (*func)(void), int val);
- SCM check_flag1_body (void *data);
- SCM return_tag (void *data, SCM tag, SCM args);
- void check_cont (int rewindable);
- SCM check_cont_body (void *data);
- void close_port (SCM port);
- void delete_file (void *data);
- void check_ports (void);
- void check_fluid (void);
- int flag1, flag2, flag3;
- void
- set_flag (void *data)
- {
- int *f = (int *)data;
- *f = 1;
- }
- /* FUNC1 should leave flag1 zero.
- */
- void
- func1 ()
- {
- scm_dynwind_begin (0);
- flag1 = 0;
- scm_dynwind_unwind_handler (set_flag, &flag1, 0);
- scm_dynwind_end ();
- }
- /* FUNC2 should set flag1.
- */
- void
- func2 ()
- {
- scm_dynwind_begin (0);
- flag1 = 0;
- scm_dynwind_unwind_handler (set_flag, &flag1, SCM_F_WIND_EXPLICITLY);
- scm_dynwind_end ();
- }
- /* FUNC3 should set flag1.
- */
- void
- func3 ()
- {
- scm_dynwind_begin (0);
- flag1 = 0;
- scm_dynwind_unwind_handler (set_flag, &flag1, 0);
- scm_misc_error ("func3", "gratuitous error", SCM_EOL);
- scm_dynwind_end ();
- }
- /* FUNC4 should set flag1.
- */
- void
- func4 ()
- {
- scm_dynwind_begin (0);
- flag1 = 0;
- scm_dynwind_unwind_handler (set_flag, &flag1, SCM_F_WIND_EXPLICITLY);
- scm_misc_error ("func4", "gratuitous error", SCM_EOL);
- scm_dynwind_end ();
- }
- SCM
- check_flag1_body (void *data)
- {
- void (*f)(void) = (void (*)(void))data;
- f ();
- return SCM_UNSPECIFIED;
- }
- SCM
- return_tag (void *data, SCM tag, SCM args)
- {
- return tag;
- }
- void
- check_flag1 (const char *tag, void (*func)(void), int val)
- {
- scm_internal_catch (SCM_BOOL_T,
- check_flag1_body, func,
- return_tag, NULL);
- if (flag1 != val)
- {
- printf ("%s failed\n", tag);
- exit (EXIT_FAILURE);
- }
- }
- SCM
- check_cont_body (void *data)
- {
- scm_t_dynwind_flags flags = (data? SCM_F_DYNWIND_REWINDABLE : 0);
- SCM val;
- scm_dynwind_begin (flags);
- val = scm_c_eval_string ("(call/cc (lambda (k) k))");
- scm_dynwind_end ();
- return val;
- }
- void
- check_cont (int rewindable)
- {
- SCM res;
-
- res = scm_internal_catch (SCM_BOOL_T,
- check_cont_body, (void *)(long)rewindable,
- return_tag, NULL);
- /* RES is now either the created continuation, the value passed to
- the continuation, or a catch-tag, such as 'misc-error.
- */
- if (scm_is_true (scm_procedure_p (res)))
- {
- /* a continuation, invoke it */
- scm_call_1 (res, SCM_BOOL_F);
- }
- else if (scm_is_false (res))
- {
- /* the result of invoking the continuation, dynwind must be
- rewindable */
- if (rewindable)
- return;
- printf ("continuation not blocked\n");
- exit (EXIT_FAILURE);
- }
- else
- {
- /* the catch tag, dynwind must not have been rewindable. */
- if (!rewindable)
- return;
- printf ("continuation didn't work\n");
- exit (EXIT_FAILURE);
- }
- }
- void
- close_port (SCM port)
- {
- scm_close_port (port);
- }
- void
- delete_file (void *data)
- {
- unlink ((char *)data);
- }
- void
- check_ports ()
- {
- #define FILENAME_TEMPLATE "/check-ports.XXXXXX"
- char *filename;
- const char *tmpdir = getenv ("TMPDIR");
- int fd;
- #ifdef __MINGW32__
- extern int mkstemp (char *);
- /* On Windows neither $TMPDIR nor /tmp can be relied on. */
- if (tmpdir == NULL)
- tmpdir = getenv ("TEMP");
- if (tmpdir == NULL)
- tmpdir = getenv ("TMP");
- if (tmpdir == NULL)
- tmpdir = "/";
- #else
- if (tmpdir == NULL)
- tmpdir = "/tmp";
- #endif
- filename = alloca (strlen (tmpdir) + sizeof (FILENAME_TEMPLATE) + 1);
- strcpy (filename, tmpdir);
- strcat (filename, FILENAME_TEMPLATE);
- /* Sanity check: Make sure that `filename' is actually writeable.
- We used to use mktemp(3), but that is now considered a security risk. */
- fd = mkstemp (filename);
- if (fd < 0)
- exit (EXIT_FAILURE);
- close (fd);
- scm_dynwind_begin (0);
- {
- SCM port = scm_open_file (scm_from_locale_string (filename),
- scm_from_locale_string ("w"));
- scm_dynwind_unwind_handler_with_scm (close_port, port,
- SCM_F_WIND_EXPLICITLY);
- scm_dynwind_current_output_port (port);
- scm_write (scm_version (), SCM_UNDEFINED);
- }
- scm_dynwind_end ();
- scm_dynwind_begin (0);
- {
- SCM port = scm_open_file (scm_from_locale_string (filename),
- scm_from_locale_string ("r"));
- SCM res;
- scm_dynwind_unwind_handler_with_scm (close_port, port,
- SCM_F_WIND_EXPLICITLY);
- scm_dynwind_unwind_handler (delete_file, filename, SCM_F_WIND_EXPLICITLY);
- scm_dynwind_current_input_port (port);
- res = scm_read (SCM_UNDEFINED);
- if (scm_is_false (scm_equal_p (res, scm_version ())))
- {
- printf ("ports didn't work\n");
- exit (EXIT_FAILURE);
- }
- }
- scm_dynwind_end ();
- #undef FILENAME_TEMPLATE
- }
- void
- check_fluid ()
- {
- SCM f = scm_make_fluid ();
- SCM x;
- scm_fluid_set_x (f, scm_from_int (12));
- scm_dynwind_begin (0);
- scm_dynwind_fluid (f, scm_from_int (13));
- x = scm_fluid_ref (f);
- scm_dynwind_end ();
- if (!scm_is_eq (x, scm_from_int (13)))
- {
- printf ("setting fluid didn't work\n");
- exit (EXIT_FAILURE);
- }
- if (!scm_is_eq (scm_fluid_ref (f), scm_from_int (12)))
- {
- printf ("resetting fluid didn't work\n");
- exit (EXIT_FAILURE);
- }
- }
- static void
- inner_main (void *data, int argc, char **argv)
- {
- check_flag1 ("func1", func1, 0);
- check_flag1 ("func2", func2, 1);
- check_flag1 ("func3", func3, 1);
- check_flag1 ("func4", func4, 1);
- check_cont (0);
- check_cont (1);
- check_ports ();
- check_fluid ();
- exit (EXIT_SUCCESS);
- }
- int
- main (int argc, char **argv)
- {
- scm_boot_guile (argc, argv, inner_main, 0);
- return 0;
- }
|