;; This program is free software; you can redistribute it and/or ;; modify it under the terms of the GNU General Public License as ;; published by the Free Software Foundation; either version 2 of ;; the License, or (at your option) any later version. ;; ;; This program 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 General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, contact: ;; ;; Free Software Foundation Voice: +1-617-542-5942 ;; 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 ;; Boston, MA 02110-1301, USA gnu@gnu.org (define-module (gnucash app-utils c-interface)) (use-modules (ice-9 match)) (use-modules (gnucash core-utils) (gnucash utilities)) (export gnc:make-string-database) (export gnc:call-with-error-handling) (export gnc:apply-with-error-handling) (export gnc:eval-string-with-error-handling) (export gnc:backtrace-if-exception) (define (gnc:call-with-error-handling cmd args) (let ((captured-stack #f) (captured-error #f) (result #f)) (catch #t (lambda () ;; Execute the code in which you want to catch errors here. (cond ((procedure? cmd) (set! result (apply cmd args))) ((string? cmd) (set! result (eval-string cmd))))) (lambda (key . parameters) ;; Put the code which you want to handle an error after the ;; stack has been unwound here. (set! captured-error (call-with-output-string (lambda (port) (display-backtrace captured-stack port) (newline port) (print-exception port #f key parameters))))) (lambda (key . parameters) ;; Capture the stack here, cut the last 3 frames which are ;; make-stack, this one, and the throw handler. (set! captured-stack (make-stack #t 3)))) (list result captured-error))) ;; gnc:eval-string-with-error-handling will evaluate the input string (cmd) ;; an captures any exception that would be generated. It returns ;; a list with 2 elements: the output of the evaluation and a backtrace. ;; The first may be set if string evaluation did generate ;; output, the latter is set when an exception was caught. ;; We'll use this to wrap guile calls in C(++), allowing ;; the C(++) code to decide how to handle the errors. (define (gnc:eval-string-with-error-handling cmd) (gnc:call-with-error-handling cmd '())) ;; gnc:apply-with-error-handling will call guile's apply to run func with args ;; an captures any exception that would be generated. It returns ;; a list with 2 elements: the output of the evaluation and a backtrace. ;; The first may be set if the result of the apply did generate ;; output, the latter is set when an exception was caught. ;; We'll use this to wrap guile calls in C(++), allowing ;; the C(++) code to decide how to handle the errors. (define (gnc:apply-with-error-handling func args) (gnc:call-with-error-handling func args)) (define (gnc:backtrace-if-exception proc . args) (match (gnc:apply-with-error-handling proc args) ((result #f) result) ((_ captured-error) (display captured-error (current-error-port)) (when (defined? 'gnc:warn) (gnc:warn captured-error)) #f)))