Bump gEDA version
[geda-gaf.git] / libgeda / src / g_basic.c
blob31c2e2b702ee256a8661a843c93a80b400f91b07
1 /* gEDA - GPL Electronic Design Automation
2 * libgeda - gEDA's library
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2020 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #include <config.h>
22 #include <stdio.h>
23 #include <sys/stat.h>
24 #ifdef HAVE_STDLIB_H
25 #include <stdlib.h>
26 #endif
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
32 #ifdef HAVE_STRING_H
33 #include <string.h>
34 #endif
36 #include "libgeda_priv.h"
37 #include "libgedaguile.h"
39 static void process_error_stack (SCM s_stack, SCM s_key, SCM s_args, GError **err);
41 /* Pre-unwind handler called in the context in which the exception was
42 * thrown. */
43 static SCM protected_pre_unwind_handler (void *data, SCM key, SCM args)
45 /* Capture the stack trace */
46 *((SCM *) data) = scm_make_stack (SCM_BOOL_T, SCM_EOL);
48 return SCM_BOOL_T;
51 /* Post-unwind handler called in the context of the catch expression.
52 * This actually does the work of parsing the stack and generating log
53 * messages. */
54 static SCM protected_post_unwind_handler (void *data, SCM key, SCM args)
56 /* The stack was captured pre-unwind */
57 SCM s_stack = *(SCM *) data;
59 process_error_stack (s_stack, key, args, NULL);
61 return SCM_BOOL_F;
64 /* Actually carries out evaluation for protected eval */
65 static SCM protected_body_eval (void *data)
67 SCM args = *((SCM *)data);
68 return scm_eval (scm_car (args), scm_cadr (args));
71 /*! \brief Evaluate a Scheme expression safely.
72 * \par Function Description
74 * Often a libgeda program (or libgeda itself) will need to call out
75 * to Scheme code, for example to load a Scheme initialisation (RC) file.
76 * If an error or exception caused by such code goes uncaught, it
77 * locks up the Scheme interpreter, stopping any further Scheme code
78 * from being run until the program is restarted.
80 * This function is equivalent to scm_eval (), with the important
81 * difference that any errors or exceptions caused by the evaluated
82 * expression \a exp are caught and reported via the libgeda logging
83 * mechanism. If an error occurs during evaluation, this function
84 * returns SCM_BOOL_F. If \a module_or_state is undefined, uses the
85 * current interaction environment.
87 * \param exp Expression to evaluate
88 * \param module_or_state Environment in which to evaluate \a exp
90 * \returns Evaluation results or SCM_BOOL_F if exception caught.
92 SCM g_scm_eval_protected (SCM exp, SCM module_or_state)
94 SCM stack = SCM_BOOL_T;
95 SCM body_data;
96 SCM result;
98 if (SCM_UNBNDP (module_or_state)) {
99 body_data = scm_list_2 (exp, scm_interaction_environment ());
100 } else {
101 body_data = scm_list_2 (exp, module_or_state);
104 result = scm_c_catch (SCM_BOOL_T,
105 protected_body_eval, /* catch body */
106 &body_data, /* body data */
107 protected_post_unwind_handler, /* post handler */
108 &stack, /* post data */
109 protected_pre_unwind_handler, /* pre handler */
110 &stack /* pre data */
113 scm_remember_upto_here_2 (body_data, stack);
115 return result;
118 /*! \brief Evaluate a C string as a Scheme expression safely
119 * \par Function Description
121 * Evaluates a C string like scm_c_eval_string(). Simple wrapper for
122 * g_scm_eval_string_protected().
124 * \param str String to evaluate.
126 * \returns Evaluation results or SCM_BOOL_F if exception caught.
128 SCM g_scm_c_eval_string_protected (const gchar *str) {
129 SCM s_str;
130 g_return_val_if_fail ((str != NULL), SCM_BOOL_F);
131 s_str = scm_from_utf8_string (str);
132 return g_scm_eval_string_protected (s_str);
135 /*! \brief Evaluate a string as a Scheme expression safely
136 * \par Function Description
138 * Evaluates a string similarly to scm_eval_string(), but catching
139 * any errors or exceptions and reporting them via the libgeda
140 * logging mechanism.
142 * See also g_scm_eval_protected() and g_scm_c_eval_string_protected().
144 * \param str String to evaluate.
146 * \returns Evaluation results or SCM_BOOL_F if exception caught.
148 SCM g_scm_eval_string_protected (SCM str)
150 SCM expr = scm_list_2 (scm_from_utf8_symbol ("eval-string"),
151 str);
153 return g_scm_eval_protected (expr, SCM_UNDEFINED);
156 /* Data to be passed to g_read_file()'s worker functions. */
157 struct g_read_file_data_t
159 SCM stack;
160 SCM filename;
161 GError *err;
164 /* Body function for g_read_file(). Simply loads the specified
165 * file. */
167 g_read_file__body (struct g_read_file_data_t *data)
169 return scm_primitive_load (data->filename);
172 /* Post-unwind handler for g_read_file(). Processes the stack captured
173 * in the pre-unwind handler. */
175 g_read_file__post_handler (struct g_read_file_data_t *data, SCM key, SCM args)
177 process_error_stack (data->stack, key, args, &data->err);
178 return SCM_BOOL_F;
181 /* Pre-unwind handler for g_read_file(). Captures the Guile stack for
182 * processing in the post-unwind handler. */
184 g_read_file__pre_handler (struct g_read_file_data_t *data, SCM key, SCM args)
186 data->stack = scm_make_stack (SCM_BOOL_T, SCM_EOL);
187 return SCM_BOOL_F;
190 /*! \brief Load a Scheme file, catching and logging errors.
191 * \par Function Description
192 * Loads \a filename, catching any uncaught errors and logging them.
194 * \bug Most other functions in the libgeda API return TRUE on success
195 * and FALSE on failure. g_read_file() shouldn't be an exception.
197 * \param toplevel The TOPLEVEL structure.
198 * \param filename The file name of the Scheme file to load.
199 * \param err Return location for errors, or NULL.
200 * \return TRUE on success, FALSE on failure.
202 gboolean
203 g_read_file(TOPLEVEL *toplevel, const gchar *filename, GError **err)
205 struct g_read_file_data_t data;
207 g_return_val_if_fail ((filename != NULL), FALSE);
209 data.stack = SCM_BOOL_F;
210 data.filename = scm_from_utf8_string (filename);
211 data.err = NULL;
213 scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
214 edascm_dynwind_toplevel (toplevel);
216 scm_c_catch (SCM_BOOL_T,
217 (scm_t_catch_body) g_read_file__body, &data,
218 (scm_t_catch_handler) g_read_file__post_handler, &data,
219 (scm_t_catch_handler) g_read_file__pre_handler, &data);
221 scm_dynwind_end ();
223 /* If no error occurred, indicate success. */
224 if (data.err == NULL) return TRUE;
226 g_propagate_error (err, data.err);
227 return FALSE;
231 /*! \brief Process a Scheme error into the log and/or a GError
232 * \par Function Description
233 * Process a captured Guile exception with the given \a s_key and \a
234 * s_args, and optionally the stack trace \a s_stack. The stack trace
235 * and source location are logged, and if a GError return location \a
236 * err is provided, it is populated with an informative error message.
238 static void
239 process_error_stack (SCM s_stack, SCM s_key, SCM s_args, GError **err) {
240 char *long_message;
241 char *short_message;
242 SCM s_port, s_subr, s_message, s_message_args, s_rest, s_location;
244 /* Split s_args up */
245 s_rest = s_args;
246 s_subr = scm_car (s_rest); s_rest = scm_cdr (s_rest);
247 s_message = scm_car (s_rest); s_rest = scm_cdr (s_rest);
248 s_message_args = scm_car (s_rest); s_rest = scm_cdr (s_rest);
250 /* Capture short error message */
251 s_port = scm_open_output_string ();
252 scm_display_error_message (s_message, s_message_args, s_port);
253 short_message = scm_to_utf8_string (scm_get_output_string (s_port));
254 scm_close_output_port (s_port);
256 /* Capture long error message (including possible backtrace) */
257 s_port = scm_open_output_string ();
258 if (scm_is_true (scm_stack_p (s_stack))) {
259 scm_puts (_("\nBacktrace:\n"), s_port);
260 scm_display_backtrace (s_stack, s_port, SCM_BOOL_F, SCM_BOOL_F);
261 scm_puts ("\n", s_port);
264 s_location = SCM_BOOL_F;
265 #ifdef HAVE_SCM_DISPLAY_ERROR_STACK
266 s_location = s_stack;
267 #endif /* HAVE_SCM_DISPLAY_ERROR_STACK */
268 #ifdef HAVE_SCM_DISPLAY_ERROR_FRAME
269 s_location =
270 scm_is_true (s_stack) ? scm_stack_ref (s_stack, SCM_INUM0) : SCM_BOOL_F;
271 #endif /* HAVE_SCM_DISPLAY_ERROR_FRAME */
273 scm_display_error (s_location, s_port, s_subr,
274 s_message, s_message_args, s_rest);
276 long_message = scm_to_utf8_string (scm_get_output_string (s_port));
277 scm_close_output_port (s_port);
279 /* Send long message to log */
280 s_log_message ("%s", long_message);
282 /* Populate any GError */
283 g_set_error (err, EDA_ERROR, EDA_ERROR_SCHEME, "%s", short_message);