2000-05-10 04:32:00 -05:00
|
|
|
;; 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
|
2005-11-16 23:35:02 -06:00
|
|
|
;; 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
|
|
|
|
;; Boston, MA 02110-1301, USA gnu@gnu.org
|
2000-05-10 04:32:00 -05:00
|
|
|
|
2018-02-16 17:52:19 -06:00
|
|
|
(define-module (gnucash utilities))
|
2001-12-04 17:21:02 -06:00
|
|
|
|
2013-11-16 16:59:00 -06:00
|
|
|
;; Turn off the scheme compiler's "possibly unbound variable" warnings.
|
|
|
|
;; In guile 2.0 we get nearly 7500 of them loading the scheme files.
|
|
|
|
;; This is the default value for auto-compilation-options without "unbound-variable".
|
|
|
|
;; See module/ice-9/boot-9.scm */
|
|
|
|
(if (>= (string->number (major-version)) 2)
|
|
|
|
(set! %auto-compilation-options
|
|
|
|
'(#:warnings (arity-mismatch format duplicate-case-datum bad-case-datum))))
|
|
|
|
|
2006-10-15 14:02:05 -05:00
|
|
|
(use-modules (gnucash core-utils))
|
2001-12-04 17:21:02 -06:00
|
|
|
|
2019-07-05 22:14:56 -05:00
|
|
|
(eval-when (compile load eval expand)
|
|
|
|
(load-extension "libgncmod-engine" "scm_init_sw_engine_module"))
|
|
|
|
(use-modules (sw_engine))
|
|
|
|
|
2001-05-15 11:27:55 -05:00
|
|
|
;; Load the srfis (eventually, we should see where these are needed
|
|
|
|
;; and only have the use-modules statements in those files).
|
|
|
|
(use-modules (srfi srfi-1))
|
|
|
|
(use-modules (srfi srfi-8))
|
2001-08-07 18:29:04 -05:00
|
|
|
(use-modules (gnucash gnc-module))
|
2006-01-20 21:59:22 -06:00
|
|
|
|
2001-12-11 10:48:01 -06:00
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; Exports
|
|
|
|
|
2018-02-16 17:52:19 -06:00
|
|
|
;; from utilities.scm
|
2001-12-04 17:21:02 -06:00
|
|
|
(export gnc:warn)
|
|
|
|
(export gnc:error)
|
|
|
|
(export gnc:msg)
|
|
|
|
(export gnc:debug)
|
2018-05-02 19:52:59 -05:00
|
|
|
(export addto!)
|
2019-07-20 05:21:20 -05:00
|
|
|
(export sort-and-delete-duplicates)
|
2001-12-04 17:21:02 -06:00
|
|
|
|
|
|
|
;; Do this stuff very early -- but other than that, don't add any
|
|
|
|
;; executable code until the end of the file if you can help it.
|
|
|
|
;; These are needed for a guile 1.3.4 bug
|
2006-10-15 14:02:05 -05:00
|
|
|
(debug-enable 'backtrace)
|
2001-12-04 17:21:02 -06:00
|
|
|
(read-enable 'positions)
|
2006-03-13 10:54:14 -06:00
|
|
|
(debug-set! stack 200000)
|
2001-12-04 17:21:02 -06:00
|
|
|
|
2007-02-19 17:45:15 -06:00
|
|
|
(define (strify items)
|
2010-04-23 16:01:48 -05:00
|
|
|
(string-join (map (lambda (x) (format #f "~A" x)) items) ""))
|
2007-02-19 17:45:15 -06:00
|
|
|
|
2001-12-04 17:21:02 -06:00
|
|
|
(define (gnc:warn . items)
|
2007-02-19 17:45:15 -06:00
|
|
|
(gnc-scm-log-warn (strify items)))
|
2001-12-04 17:21:02 -06:00
|
|
|
|
|
|
|
(define (gnc:error . items)
|
2007-02-19 17:45:15 -06:00
|
|
|
(gnc-scm-log-error (strify items )))
|
2001-12-04 17:21:02 -06:00
|
|
|
|
|
|
|
(define (gnc:msg . items)
|
2007-02-19 17:45:15 -06:00
|
|
|
(gnc-scm-log-msg (strify items)))
|
2001-12-04 17:21:02 -06:00
|
|
|
|
2019-07-06 19:30:54 -05:00
|
|
|
;; this definition of gnc:debug is different from others because we
|
|
|
|
;; want to check loglevel is debug *once* at gnc:debug definition
|
|
|
|
;; instead of every call to gnc:debug. if loglevel isn't debug then
|
|
|
|
;; gnc:debug becomes a NOOP.
|
|
|
|
(define gnc:debug
|
|
|
|
(cond
|
|
|
|
((qof-log-check "gnc" QOF-LOG-DEBUG)
|
|
|
|
(display "debugging enabled\n")
|
|
|
|
(lambda items (gnc-scm-log-debug (strify items))))
|
|
|
|
|
|
|
|
(else
|
|
|
|
(lambda items #f))))
|
2018-02-19 15:27:44 -06:00
|
|
|
|
2019-04-21 10:15:47 -05:00
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2019-02-14 01:21:29 -06:00
|
|
|
;; the following functions are initialized to log message to tracefile
|
|
|
|
;; and will be redefined in UI initialization to display dialog
|
|
|
|
;; messages
|
2019-04-21 10:15:47 -05:00
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2019-02-14 01:21:29 -06:00
|
|
|
(define-public (gnc:gui-warn str1 str2) (gnc:warn str1))
|
|
|
|
(define-public (gnc:gui-error str1 str2) (gnc:error str1))
|
|
|
|
(define-public (gnc:gui-msg str1 str2) (gnc:msg str1))
|
|
|
|
|
2018-05-02 19:52:59 -05:00
|
|
|
(define-syntax addto!
|
|
|
|
(syntax-rules ()
|
|
|
|
((addto! alist element)
|
|
|
|
(set! alist (cons element alist)))))
|
2018-02-19 15:27:44 -06:00
|
|
|
|
2019-04-21 10:15:47 -05:00
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2019-03-29 10:36:33 -05:00
|
|
|
;; pair of utility functions for use with guile-json which requires
|
|
|
|
;; lists converted vectors to save as json arrays. traverse list
|
|
|
|
;; converting into vectors, and vice versa.
|
2019-04-21 10:15:47 -05:00
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2019-03-29 10:36:33 -05:00
|
|
|
(define-public (traverse-list->vec lst)
|
|
|
|
(cond
|
|
|
|
((list? lst) (list->vector (map traverse-list->vec lst)))
|
|
|
|
(else lst)))
|
|
|
|
|
|
|
|
(define-public (traverse-vec->list vec)
|
|
|
|
(cond
|
|
|
|
((vector? vec) (map traverse-vec->list (vector->list vec)))
|
|
|
|
(else vec)))
|
|
|
|
|
2019-04-21 10:15:47 -05:00
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; general and efficent string-replace-substring function, based on
|
|
|
|
;; function designed by Mark H Weaver, core guile developer. avoids
|
|
|
|
;; string-append which will constantly build new strings. augmented
|
|
|
|
;; with start and end indices; will selective choose to replace
|
|
|
|
;; substring if start-idx <= index <= end-idx
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(define* (string-replace-substring s substr replacement #:optional
|
|
|
|
(start 0)
|
|
|
|
(end (string-length s))
|
|
|
|
(start-idx #f)
|
|
|
|
(end-idx #f))
|
|
|
|
(let ((substr-length (string-length substr))
|
|
|
|
(start-idx (or start-idx 0))
|
|
|
|
(end-idx (or end-idx +inf.0)))
|
|
|
|
(if (zero? substr-length)
|
|
|
|
(error "string-replace-substring: empty substr")
|
|
|
|
(let loop ((start start)
|
|
|
|
(i 0)
|
|
|
|
(pieces (list (substring s 0 start))))
|
|
|
|
(let ((idx (string-contains s substr start end)))
|
|
|
|
(if idx
|
|
|
|
(loop (+ idx substr-length)
|
|
|
|
(1+ i)
|
|
|
|
(cons* (if (<= start-idx i end-idx) replacement substr)
|
|
|
|
(substring s start idx)
|
|
|
|
pieces))
|
|
|
|
(string-concatenate-reverse (cons (substring s start)
|
|
|
|
pieces))))))))
|
|
|
|
|
2018-02-19 15:27:44 -06:00
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; gnc:substring-replace
|
|
|
|
;;
|
|
|
|
;; Search for all occurrences in string "s1" of string "s2" and
|
|
|
|
;; replace them with string "s3".
|
|
|
|
;;
|
|
|
|
;; Example: (gnc:substring-replace "foobarfoobar" "bar" "xyz")
|
|
|
|
;; returns "fooxyzfooxyz".
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
|
|
(define-public (gnc:substring-replace s1 s2 s3)
|
2019-04-21 10:15:47 -05:00
|
|
|
(string-replace-substring s1 s2 s3))
|
2018-02-19 15:27:44 -06:00
|
|
|
|
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; gnc:substring-replace-from-to
|
|
|
|
;; same as gnc:substring-replace extended by:
|
|
|
|
;; start: from which occurrence onwards the replacement shall start
|
|
|
|
;; end-after: max. number times the replacement should executed
|
|
|
|
;;
|
2019-04-21 10:15:47 -05:00
|
|
|
;; Example: (gnc:substring-replace-from-to "foobarfoobarfoobar" "bar" "xyz" 2 1)
|
2018-02-19 15:27:44 -06:00
|
|
|
;; returns "foobarfooxyzfoobar".
|
|
|
|
;;
|
|
|
|
;; start=1 and end-after<=0 will call gnc:substring-replace (replace all)
|
|
|
|
;; start>1 and end-after<=0 will the replace from "start" until end of file
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
|
|
(define-public (gnc:substring-replace-from-to s1 s2 s3 start end-after)
|
2019-04-21 10:15:47 -05:00
|
|
|
(string-replace-substring
|
|
|
|
s1 s2 s3 0 (string-length s1) (max 0 (1- start))
|
|
|
|
(and (positive? end-after) (+ (max 0 (1- start)) (1- end-after)))))
|
2019-06-03 08:17:55 -05:00
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; avoid using strftime, still broken in guile-2.2. see explanation at
|
|
|
|
;; https://www.mail-archive.com/bug-guile@gnu.org/msg09778.html
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(let ((strftime-old strftime))
|
|
|
|
(set! strftime
|
|
|
|
(lambda args
|
|
|
|
(gnc:warn "strftime may be buggy. use gnc-print-time64 instead.")
|
|
|
|
(apply strftime-old args))))
|
2019-07-20 05:21:20 -05:00
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; a basic sort-and-delete-duplicates. because delete-duplicates
|
|
|
|
;; usually run in O(N^2) and if the list must be sorted, it's more
|
|
|
|
;; efficient to sort first then delete adjacent elements. guile-2.0
|
|
|
|
;; uses quicksort internally.
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(define* (sort-and-delete-duplicates lst < #:optional (= =))
|
2019-09-09 11:34:25 -05:00
|
|
|
(define (kons a b) (if (and (pair? b) (= a (car b))) b (cons a b)))
|
|
|
|
(reverse (fold kons '() (sort lst <))))
|
2019-08-15 20:32:56 -05:00
|
|
|
|
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; compatibility hack for fixing guile-2.0 string handling. this code
|
|
|
|
;; may be removed when minimum guile is 2.2 or later. see
|
|
|
|
;; https://lists.gnu.org/archive/html/guile-user/2019-04/msg00012.html
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(when (string=? (effective-version) "2.0")
|
|
|
|
;; When using Guile 2.0.x, use monkey patching to change the
|
|
|
|
;; behavior of string ports to use UTF-8 as the internal encoding.
|
|
|
|
;; Note that this is the default behavior in Guile 2.2 or later.
|
|
|
|
(let* ((mod (resolve-module '(guile)))
|
|
|
|
(orig-open-input-string (module-ref mod 'open-input-string))
|
|
|
|
(orig-open-output-string (module-ref mod 'open-output-string))
|
|
|
|
(orig-object->string (module-ref mod 'object->string))
|
|
|
|
(orig-simple-format (module-ref mod 'simple-format)))
|
|
|
|
|
|
|
|
(define (open-input-string str)
|
|
|
|
(with-fluids ((%default-port-encoding "UTF-8"))
|
|
|
|
(orig-open-input-string str)))
|
|
|
|
|
|
|
|
(define (open-output-string)
|
|
|
|
(with-fluids ((%default-port-encoding "UTF-8"))
|
|
|
|
(orig-open-output-string)))
|
|
|
|
|
|
|
|
(define (object->string . args)
|
|
|
|
(with-fluids ((%default-port-encoding "UTF-8"))
|
|
|
|
(apply orig-object->string args)))
|
|
|
|
|
|
|
|
(define (simple-format . args)
|
|
|
|
(with-fluids ((%default-port-encoding "UTF-8"))
|
|
|
|
(apply orig-simple-format args)))
|
|
|
|
|
|
|
|
(define (call-with-input-string str proc)
|
|
|
|
(proc (open-input-string str)))
|
|
|
|
|
|
|
|
(define (call-with-output-string proc)
|
|
|
|
(let ((port (open-output-string)))
|
|
|
|
(proc port)
|
|
|
|
(get-output-string port)))
|
|
|
|
|
|
|
|
(module-set! mod 'open-input-string open-input-string)
|
|
|
|
(module-set! mod 'open-output-string open-output-string)
|
|
|
|
(module-set! mod 'object->string object->string)
|
|
|
|
(module-set! mod 'simple-format simple-format)
|
|
|
|
(module-set! mod 'call-with-input-string call-with-input-string)
|
|
|
|
(module-set! mod 'call-with-output-string call-with-output-string)
|
|
|
|
|
|
|
|
(when (eqv? (module-ref mod 'format) orig-simple-format)
|
|
|
|
(module-set! mod 'format simple-format))))
|