core: Add current-output-port, open-output-file, set-current-output-port.
[mes.git] / module / mes / guile.mes
1 ;;; -*-scheme-*-
2
3 ;;; Mes --- Maxwell Equations of Software
4 ;;; Copyright © 2016,2017 Jan Nieuwenhuizen <janneke@gnu.org>
5 ;;;
6 ;;; This file is part of Mes.
7 ;;;
8 ;;; Mes is free software; you can redistribute it and/or modify it
9 ;;; under the terms of the GNU General Public License as published by
10 ;;; the Free Software Foundation; either version 3 of the License, or (at
11 ;;; your option) any later version.
12 ;;;
13 ;;; Mes is distributed in the hope that it will be useful, but
14 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 ;;; GNU General Public License for more details.
17 ;;;
18 ;;; You should have received a copy of the GNU General Public License
19 ;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
20
21 ;;; Commentary:
22
23 ;;; Code:
24
25 (define-macro (define-module module . rest) #t)
26 (define-macro (use-modules . rest) #t)
27 (define-macro (cond-expand-provide . rest) #t)
28
29 (define-macro (include-from-path file)
30   (let loop ((path (cons %moduledir (string-split (or (getenv "GUILE_LOAD_PATH") "") #\:))))
31     (if (getenv "MES_DEBUG") (format (current-error-port) "include-from-path: ~s [PATH:~s]\n" file path))
32     (if (null? path) (error "include-from-path: not found: " file)
33         (let ((file (string-append (car path) "/" file)))
34           (if (access? file R_OK) `(load ,file)
35               (loop (cdr path)))))))
36
37 (mes-use-module (srfi srfi-16))
38
39 (define (drain-input port)
40   (list->string
41    (let loop ((c (read-char)))
42      (if (eq? c #\*eof*) '()
43          (cons c (loop (read-char)))))))
44
45 (define (make-string n . fill)
46   (list->string (apply make-list n fill)))
47
48 (define (object->string x . rest)
49   (with-output-to-string
50     (lambda () ((if (pair? rest) (car rest) write) x))))
51
52 (define (port-filename p) "<stdin>")
53 (define (port-line p) 0)
54 (define (simple-format port format . rest) (map (lambda (x) (display x port)) rest))
55
56 (define (with-input-from-string string thunk)
57   (define save-peek-char peek-char)
58   (define save-read-char read-char)
59   (define save-unread-char unread-char)
60   (let ((tell 0)
61         (end (string-length string)))
62     (set! peek-char
63           (lambda () (if (= tell end) (integer->char -1)
64                          (string-ref string (- tell 1)))))
65     (set! read-char
66           (lambda () (if (= tell end) (integer->char -1)
67                          (begin
68                            (set! tell (1+ tell))
69                            (string-ref string (- tell 1))))))
70     (set! unread-char
71           (lambda (c) (set! tell (1- tell)) c)))
72   (let ((r (thunk)))
73     (set! peek-char save-peek-char)
74     (set! read-char save-read-char)
75     (set! unread-char save-unread-char)
76     r))
77
78 (define (with-input-from-file file thunk)
79   (let ((port (open-input-file file)))
80     (if (= port -1)
81         (error 'no-such-file file)
82         (let* ((save (current-input-port))
83                (foo (set-current-input-port port))
84                (r (thunk)))
85           (set-current-input-port save)
86           r))))
87
88 (define (with-output-to-file file thunk)
89   (let ((port (open-output-file file)))
90     (if (= port -1)
91         (error 'cannot-open file)
92         (let* ((save (current-output-port))
93                (foo (set-current-output-port port))
94                (r (thunk)))
95           (set-current-output-port save)
96           r))))
97
98 (define (with-output-to-port port thunk)
99   (let* ((save (current-output-port))
100          (foo (set-current-output-port port))
101          (r (thunk)))
102     (set-current-output-port save)
103     r))
104
105 (define open-input-string
106   (let ((save-set-current-input-port #f)
107         (string-port #f))
108     (lambda (string)
109       (set! save-set-current-input-port set-current-input-port)
110       (set! string-port (cons '*string-port* (gensym)))
111       (set! set-current-input-port
112             (let ((save-peek-char peek-char)
113                   (save-read-char read-char)
114                   (save-unread-char unread-char)
115                   (tell 0)
116                   (end (string-length string)))
117               (lambda (port)
118                 (if (not (equal? port string-port)) (save-set-current-input-port port)
119                     (begin
120                       (set! peek-char
121                             (lambda () (if (= tell end) (integer->char -1)
122                                            (string-ref string (- tell 1)))))
123                       (set! read-char
124                             (lambda () (if (= tell end) (integer->char -1)
125                                            (begin
126                                              (set! tell (1+ tell))
127                                              (string-ref string (- tell 1))))))
128                       (set! unread-char
129                             (lambda (c) (set! tell (1- tell)) c))
130                       (set! set-current-input-port
131                             (lambda (port)
132                               (save-set-current-input-port port)
133                               (set! peek-char save-peek-char)
134                               (set! read-char save-read-char)
135                               (set! unread-char save-unread-char)
136                               (set! set-current-input-port save-set-current-input-port)
137                               string-port)))))))
138       string-port)))
139
140 (define (read-string)
141   (define (append-char s c)
142     (append2 s (cons c (list))))
143   (define (read-string c p s)
144     (cond
145      ((and (eq? c #\\) (or (eq? p #\\) (eq? p #\")))
146       ((lambda (c)
147          (read-string (read-char) (peek-char) (append-char s c)))
148        (read-char)))
149      ((and (eq? c #\\) (eq? p #\n))
150       (read-char)
151       (read-string (read-char) (peek-char) (append-char s 10)))
152      ((eq? c #\*eof*) s)
153      (#t (read-string (read-char) (peek-char) (append-char s c)))))
154   (list->string (read-string (read-char) (peek-char) (list))))