libgeda

g_basic.c

Go to the documentation of this file.
00001 /* gEDA - GPL Electronic Design Automation
00002  * libgeda - gEDA's library
00003  * Copyright (C) 1998-2010 Ales Hvezda
00004  * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00019  */
00020 #include <config.h>
00021 #include <missing.h>
00022 
00023 #include <stdio.h>
00024 #include <sys/stat.h>
00025 #ifdef HAVE_STDLIB_H
00026 #include <stdlib.h>
00027 #endif
00028 
00029 #ifdef HAVE_UNISTD_H
00030 #include <unistd.h>
00031 #endif
00032 
00033 #ifdef HAVE_STRING_H
00034 #include <string.h>
00035 #endif
00036 
00037 #include "libgeda_priv.h"
00038 #include "libgedaguile.h"
00039 
00040 #ifdef HAVE_LIBDMALLOC
00041 #include <dmalloc.h>
00042 #endif
00043 
00044 static void process_error_stack (SCM s_stack, SCM s_key, SCM s_args, GError **err);
00045 
00046 /* Pre-unwind handler called in the context in which the exception was
00047  * thrown. */
00048 static SCM protected_pre_unwind_handler (void *data, SCM key, SCM args)
00049 {
00050   /* Capture the stack trace */
00051   *((SCM *) data) = scm_make_stack (SCM_BOOL_T, SCM_EOL);
00052 
00053   return SCM_BOOL_T;
00054 }
00055 
00056 /* Post-unwind handler called in the context of the catch expression.
00057  * This actually does the work of parsing the stack and generating log
00058  * messages. */
00059 static SCM protected_post_unwind_handler (void *data, SCM key, SCM args)
00060 { 
00061   /* The stack was captured pre-unwind */
00062   SCM s_stack = *(SCM *) data;
00063 
00064   process_error_stack (s_stack, key, args, NULL);
00065 
00066   return SCM_BOOL_F;
00067 }
00068 
00069 /* Actually carries out evaluation for protected eval */
00070 static SCM protected_body_eval (void *data)
00071 {
00072   SCM args = *((SCM *)data);
00073   return scm_eval (scm_car (args), scm_cadr (args));
00074 }
00075 
00097 SCM g_scm_eval_protected (SCM exp, SCM module_or_state)
00098 {
00099   SCM stack = SCM_BOOL_T;
00100   SCM body_data;
00101   SCM result;
00102 
00103   if (module_or_state == SCM_UNDEFINED) {
00104     body_data = scm_list_2 (exp, scm_interaction_environment ());
00105   } else {
00106     body_data = scm_list_2 (exp, module_or_state);
00107   }
00108 
00109   result = scm_c_catch (SCM_BOOL_T,
00110                         protected_body_eval,           /* catch body */
00111                         &body_data,                    /* body data */
00112                         protected_post_unwind_handler, /* post handler */
00113                         &stack,                        /* post data */
00114                         protected_pre_unwind_handler,  /* pre handler */
00115                         &stack                         /* pre data */
00116                         );
00117 
00118   scm_remember_upto_here_2 (body_data, stack);
00119 
00120   return result;
00121 }
00122 
00133 SCM g_scm_c_eval_string_protected (const gchar *str) {
00134   SCM s_str;
00135   g_return_val_if_fail ((str != NULL), SCM_BOOL_F);
00136   s_str = scm_from_utf8_string (str);
00137   return g_scm_eval_string_protected (s_str);
00138 }
00139 
00153 SCM g_scm_eval_string_protected (SCM str)
00154 {
00155   SCM expr = scm_list_2 (scm_from_utf8_symbol ("eval-string"),
00156                          str);
00157 
00158   return g_scm_eval_protected (expr, SCM_UNDEFINED);
00159 }
00160 
00161 /* Data to be passed to g_read_file()'s worker functions. */
00162 struct g_read_file_data_t
00163 {
00164   SCM stack;
00165   SCM filename;
00166   GError *err;
00167 };
00168 
00169 /* Body function for g_read_file(). Simply loads the specified
00170  * file. */
00171 SCM
00172 g_read_file__body (struct g_read_file_data_t *data)
00173 {
00174   return scm_primitive_load (data->filename);
00175 }
00176 
00177 /* Post-unwind handler for g_read_file(). Processes the stack captured
00178  * in the pre-unwind handler. */
00179 SCM
00180 g_read_file__post_handler (struct g_read_file_data_t *data, SCM key, SCM args)
00181 {
00182   process_error_stack (data->stack, key, args, &data->err);
00183   return SCM_BOOL_F;
00184 }
00185 
00186 /* Pre-unwind handler for g_read_file().  Captures the Guile stack for
00187  * processing in the post-unwind handler. */
00188 SCM
00189 g_read_file__pre_handler (struct g_read_file_data_t *data, SCM key, SCM args)
00190 {
00191   data->stack = scm_make_stack (SCM_BOOL_T, SCM_EOL);
00192   return SCM_BOOL_F;
00193 }
00194 
00207 gboolean
00208 g_read_file(TOPLEVEL *toplevel, const gchar *filename, GError **err)
00209 {
00210   struct g_read_file_data_t data;
00211 
00212   g_return_val_if_fail ((filename != NULL), FALSE);
00213 
00214   data.stack = SCM_BOOL_F;
00215   data.filename = scm_from_utf8_string (filename);
00216   data.err = NULL;
00217 
00218   scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
00219   edascm_dynwind_toplevel (toplevel);
00220 
00221   scm_c_catch (SCM_BOOL_T,
00222                (scm_t_catch_body) g_read_file__body, &data,
00223                (scm_t_catch_handler) g_read_file__post_handler, &data,
00224                (scm_t_catch_handler) g_read_file__pre_handler, &data);
00225 
00226   scm_dynwind_end ();
00227 
00228   /* If no error occurred, indicate success. */
00229   if (data.err == NULL) return TRUE;
00230 
00231   g_propagate_error (err, data.err);
00232   return FALSE;
00233 }
00234 
00235 
00243 static void
00244 process_error_stack (SCM s_stack, SCM s_key, SCM s_args, GError **err) {
00245   char *long_message;
00246   char *short_message;
00247   SCM s_port, s_subr, s_message, s_message_args, s_rest, s_location;
00248 
00249   /* Split s_args up */
00250   s_rest = s_args;
00251   s_subr = scm_car (s_rest);         s_rest = scm_cdr (s_rest);
00252   s_message = scm_car (s_rest);      s_rest = scm_cdr (s_rest);
00253   s_message_args = scm_car (s_rest); s_rest = scm_cdr (s_rest);
00254 
00255   /* Capture short error message */
00256   s_port = scm_open_output_string ();
00257   scm_display_error_message (s_message, s_message_args, s_port);
00258   short_message = scm_to_utf8_string (scm_get_output_string (s_port));
00259   scm_close_output_port (s_port);
00260 
00261   /* Capture long error message (including possible backtrace) */
00262   s_port = scm_open_output_string ();
00263   if (scm_is_true (scm_stack_p (s_stack))) {
00264     scm_puts (_("\nBacktrace:\n"), s_port);
00265     scm_display_backtrace (s_stack, s_port, SCM_BOOL_F, SCM_BOOL_F);
00266     scm_puts ("\n", s_port);
00267   }
00268 
00269   s_location = SCM_BOOL_F;
00270 #ifdef HAVE_SCM_DISPLAY_ERROR_STACK
00271   s_location = s_stack;
00272 #endif /* HAVE_SCM_DISPLAY_ERROR_STACK */
00273 #ifdef HAVE_SCM_DISPLAY_ERROR_FRAME
00274   s_location =
00275     scm_is_true (s_stack) ? scm_stack_ref (s_stack, SCM_INUM0) : SCM_BOOL_F;
00276 #endif /* HAVE_SCM_DISPLAY_ERROR_FRAME */
00277 
00278   scm_display_error (s_location, s_port, s_subr,
00279                      s_message, s_message_args, s_rest);
00280 
00281   long_message = scm_to_utf8_string (scm_get_output_string (s_port));
00282   scm_close_output_port (s_port);
00283 
00284   /* Send long message to log */
00285   s_log_message ("%s", long_message);
00286 
00287   /* Populate any GError */
00288   g_set_error (err, EDA_ERROR, EDA_ERROR_SCHEME, "%s", short_message);
00289 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines