merge from 1.8 branch
[bpt/guile.git] / ice-9 / slib.scm
CommitLineData
7ebe6c76
JB
1;;;; slib.scm --- definitions needed to get SLIB to work with Guile
2;;;;
cd5fea8d 3;;;; Copyright (C) 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
a482f2cc 4;;;;
73be1d9e
MV
5;;;; This library is free software; you can redistribute it and/or
6;;;; modify it under the terms of the GNU Lesser General Public
7;;;; License as published by the Free Software Foundation; either
8;;;; version 2.1 of the License, or (at your option) any later version.
a482f2cc 9;;;;
73be1d9e
MV
10;;;; This library is distributed in the hope that it will be useful,
11;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
a482f2cc 12;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
73be1d9e 13;;;; Lesser General Public License for more details.
a482f2cc 14;;;;
73be1d9e
MV
15;;;; You should have received a copy of the GNU Lesser General Public
16;;;; License along with this library; if not, write to the Free Software
92205699 17;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
7ebe6c76 18;;;;
3267d4a1 19(define-module (ice-9 slib)
1a179b03
MD
20 :export (slib:load slib:load-source defmacro:load
21 implementation-vicinity library-vicinity home-vicinity
22 scheme-implementation-type scheme-implementation-version
509a787a 23 output-port-width output-port-height array-indexes
9b2416ea
KR
24 make-random-state
25 -1+ <? <=? =? >? >=?
26 require slib:error slib:exit slib:warn slib:eval
1a179b03
MD
27 defmacro:eval logical:logand logical:logior logical:logxor
28 logical:lognot logical:ash logical:logcount logical:integer-length
29 logical:bit-extract logical:integer-expt logical:ipow-by-squaring
30 slib:eval-load slib:tab slib:form-feed difftime offset-time
31 software-type)
e35275e2 32 :replace (delete-file open-file provide provided? system)
3267d4a1 33 :no-backtrace)
1a179b03 34
0f2d19dd
JB
35\f
36
37(define (eval-load <filename> evl)
38 (if (not (file-exists? <filename>))
39 (set! <filename> (string-append <filename> (scheme-file-suffix))))
40 (call-with-input-file <filename>
41 (lambda (port)
42 (let ((old-load-pathname *load-pathname*))
43 (set! *load-pathname* <filename>)
75a97b92 44 (do ((o (read port) (read port)))
0f2d19dd
JB
45 ((eof-object? o))
46 (evl o))
47 (set! *load-pathname* old-load-pathname)))))
48
49\f
50
51(define slib:exit quit)
52(define slib:error error)
7ed9feb0 53(define slib:warn warn)
21c2a33a
MD
54(define slib:eval (lambda (x) (eval x slib-module)))
55(define defmacro:eval (lambda (x) (eval x (interaction-environment))))
0f2d19dd
JB
56(define logical:logand logand)
57(define logical:logior logior)
58(define logical:logxor logxor)
59(define logical:lognot lognot)
60(define logical:ash ash)
61(define logical:logcount logcount)
62(define logical:integer-length integer-length)
63(define logical:bit-extract bit-extract)
64(define logical:integer-expt integer-expt)
0f2d19dd
JB
65(define slib:eval-load eval-load)
66(define slib:tab #\tab)
67(define slib:form-feed #\page)
68
ed218d98
MV
69(define slib-module (current-module))
70
71(define (defined? symbol)
72 (module-defined? slib-module symbol))
73
1a179b03
MD
74;;; *FEATURES* should be set to a list of symbols describing features
75;;; of this implementation. Suggestions for features are:
70a459e3 76(set! *features*
1a179b03
MD
77 (append
78 '(
79 source ;can load scheme source files
80 ;(slib:load-source "filename")
81; compiled ;can load compiled files
82 ;(slib:load-compiled "filename")
83
84 ;; Scheme report features
85
86; rev5-report ;conforms to
87 eval ;R5RS two-argument eval
88; values ;R5RS multiple values
89 dynamic-wind ;R5RS dynamic-wind
90; macro ;R5RS high level macros
91 delay ;has DELAY and FORCE
92 multiarg-apply ;APPLY can take more than 2 args.
93; rationalize
94 rev4-optional-procedures ;LIST-TAIL, STRING->LIST,
95 ;LIST->STRING, STRING-COPY,
96 ;STRING-FILL!, LIST->VECTOR,
97 ;VECTOR->LIST, and VECTOR-FILL!
98
99; rev4-report ;conforms to
100
101; ieee-p1178 ;conforms to
102
103; rev3-report ;conforms to
104
105 rev2-procedures ;SUBSTRING-MOVE-LEFT!,
106 ;SUBSTRING-MOVE-RIGHT!,
107 ;SUBSTRING-FILL!,
108 ;STRING-NULL?, APPEND!, 1+,
109 ;-1+, <?, <=?, =?, >?, >=?
110; object-hash ;has OBJECT-HASH
111
112 multiarg/and- ;/ and - can take more than 2 args.
113 with-file ;has WITH-INPUT-FROM-FILE and
114 ;WITH-OUTPUT-FROM-FILE
115; transcript ;TRANSCRIPT-ON and TRANSCRIPT-OFF
116; ieee-floating-point ;conforms to IEEE Standard 754-1985
117 ;IEEE Standard for Binary
118 ;Floating-Point Arithmetic.
119 full-continuation ;can return multiple times
120
121 ;; Other common features
122
123; srfi ;srfi-0, COND-EXPAND finds all srfi-*
124; sicp ;runs code from Structure and
125 ;Interpretation of Computer
126 ;Programs by Abelson and Sussman.
127 defmacro ;has Common Lisp DEFMACRO
128; record ;has user defined data structures
129 string-port ;has CALL-WITH-INPUT-STRING and
130 ;CALL-WITH-OUTPUT-STRING
131; sort
132; pretty-print
133; object->string
134; format ;Common-lisp output formatting
135; trace ;has macros: TRACE and UNTRACE
136; compiler ;has (COMPILER)
137; ed ;(ED) is editor
e35275e2
KR
138
139 ;; core definitions compatible, plus `make-random-state' below
1a179b03
MD
140 random
141 )
142
143 (if (defined? 'getenv)
144 '(getenv)
145 '())
146
147 (if (defined? 'current-time)
148 '(current-time)
149 '())
150
151 (if (defined? 'system)
152 '(system)
153 '())
154
1a179b03
MD
155 (if (defined? 'char-ready?)
156 '(char-ready?)
157 '())
158
1a179b03 159 *features*))
0f2d19dd 160
e35275e2
KR
161;; The array module specified by slib 3a1 is not the same as what guile
162;; provides, so we must remove `array' from the features list.
163;;
164;; The main difference is `create-array' which is similar to
165;; `make-uniform-array', but the `Ac64' etc prototype procedures incorporate
166;; an initial fill element into the prototype.
167;;
168;; Believe the array-for-each module will need to be taken from slib when
169;; the array module is taken from there, since what the array module creates
170;; won't be understood by the guile functions. So remove `array-for-each'
171;; from the features list too.
172;;
173;; Also, slib 3a1 array-for-each specifies an `array-map' which is not in
174;; guile (but could be implemented quite easily).
175;;
176;; ENHANCE-ME: It'd be nice to implement what's necessary, since the guile
177;; functions should be more efficient than the implementation in slib.
178;;
179;; FIXME: Since the *features* variable is shared by slib and the guile
180;; core, removing these feature symbols has the unhappy effect of making it
181;; look like they aren't in the core either. Let's assume that arrays have
182;; been present unconditionally long enough that no guile-specific code will
183;; bother to test. An alternative would be to make a new separate
184;; *features* variable which the slib stuff operated on, leaving the core
185;; mechanism alone. That might be a good thing anyway.
186;;
187(set! *features* (delq 'array *features*))
188(set! *features* (delq 'array-for-each *features*))
189
84269297
KR
190;; The random module in slib 3a1 provides a `random:chunk' which is used by
191;; the random-inexact module. Guile doesn't provide random:chunk so we must
192;; remove 'random from `*features*' to use the slib code.
193;;
194;; ENHANCE-ME: Maybe Guile could provide a `random:chunk', the rest of the
195;; random module is already the same as Guile.
196;;
197;; FIXME: As per the array bits above, *features* is shared by slib and the
198;; guile core, so removing 'random has the unhappy effect of making it look
199;; like this isn't in the core. Let's assume random numbers have been
200;; present unconditionally long enough that no guile-specific code will
201;; bother to test.
202;;
203(set! *features* (delq 'random *features*))
204
0f2d19dd 205
9b345f6c 206;;; FIXME: Because uers want require to search the path, this uses
096d5f90 207;;; load-from-path, which probably isn't a hot idea. slib
9b345f6c
JB
208;;; doesn't expect this function to search a path, so I expect to get
209;;; bug reports at some point complaining that the wrong file gets
210;;; loaded when something accidentally appears in the path before
211;;; slib, etc. ad nauseum. However, the right fix seems to involve
212;;; changing catalog:get in slib/require.scm, and I don't expect
213;;; Aubrey will integrate such a change. So I'm just going to punt
214;;; for the time being.
1a179b03 215(define (slib:load name)
0f2d19dd
JB
216 (save-module-excursion
217 (lambda ()
218 (set-current-module slib-module)
d1005e3c
MD
219 (let ((errinfo (catch 'system-error
220 (lambda ()
221 (load-from-path name)
222 #f)
223 (lambda args args))))
224 (if (and errinfo
225 (catch 'system-error
226 (lambda ()
227 (load-from-path
228 (string-append name ".scm"))
229 #f)
230 (lambda args args)))
c51bfd81 231 (apply throw errinfo))))))
0f2d19dd
JB
232
233(define slib:load-source slib:load)
234(define defmacro:load slib:load)
235
c51bfd81
MD
236(define slib-parent-dir
237 (let* ((path (%search-load-path "slib/require.scm")))
00f06035 238 (if path
4e15fee8 239 (substring path 0 (- (string-length path) 17))
00f06035 240 (error "Could not find slib/require.scm in " %load-path))))
c51bfd81 241
1a179b03 242(define (implementation-vicinity)
c51bfd81 243 (string-append slib-parent-dir "/"))
1a179b03 244(define (library-vicinity)
c51bfd81 245 (string-append (implementation-vicinity) "slib/"))
1a179b03 246(define home-vicinity
ad76c8d9
TP
247 (let ((home-path (getenv "HOME")))
248 (lambda () home-path)))
1a179b03
MD
249(define (scheme-implementation-type) 'guile)
250(define scheme-implementation-version version)
251;;; (scheme-implementation-home-page) should return a (string) URI
252;;; (Uniform Resource Identifier) for this scheme implementation's home
253;;; page; or false if there isn't one.
254(define (scheme-implementation-home-page)
255 "http://www.gnu.org/software/guile/guile.html")
0f2d19dd 256
e35275e2
KR
257;; legacy from r3rs, but slib says all implementations provide these
258;; ("Legacy" section of the "Miscellany" node in the manual)
259(define-public t #t)
260(define-public nil #f)
261
262;; ENHANCE-ME: Could call ioctl TIOCGWINSZ to get the size of a tty (see
263;; "man 4 tty_ioctl" on a GNU/Linux system), on systems with that.
0f2d19dd
JB
264(define (output-port-width . arg) 80)
265(define (output-port-height . arg) 24)
4b0d6055 266
e35275e2
KR
267;; slib 3a1 and up, straight from Template.scm
268(define-public (call-with-open-ports . ports)
269 (define proc (car ports))
270 (cond ((procedure? proc) (set! ports (cdr ports)))
271 (else (set! ports (reverse ports))
272 (set! proc (car ports))
273 (set! ports (reverse (cdr ports)))))
274 (let ((ans (apply proc ports)))
275 (for-each close-port ports)
276 ans))
277
278;; slib (version 3a1) requires open-file accept a symbol r, rb, w or wb for
279;; MODES, so extend the guile core open-file accordingly.
280;;
281;; slib (version 3a1) also calls open-file with strings "rb" or "wb", not
282;; sure if that's intentional, but in any case this extension continues to
283;; accept strings to make that work.
284;;
285(define-public (open-file filename modes)
286 (if (symbol? modes)
287 (set! modes (symbol->string modes)))
288 ((@ (guile) open-file) filename modes))
289
290;; returning #t/#f instead of throwing an error for failure
291(define-public (delete-file filename)
292 (catch 'system-error
293 (lambda () ((@ (guile) delete-file) filename) #t)
294 (lambda args #f)))
295
296;; Nothing special to do for this, so straight from Template.scm. Maybe
297;; "sensible-browser" for a debian system would be worth trying too (and
298;; would be good on a tty).
299(define-public (browse-url url)
300 (define (try cmd end) (zero? (system (string-append cmd url end))))
301 (or (try "netscape-remote -remote 'openURL(" ")'")
302 (try "netscape -remote 'openURL(" ")'")
303 (try "netscape '" "'&")
304 (try "netscape '" "'")))
305
1a179b03
MD
306;;; {array-for-each}
307(define (array-indexes ra)
308 (let ((ra0 (apply make-array '() (array-shape ra))))
309 (array-index-map! ra0 list)
310 ra0))
311
6001fe82
MD
312;;; {Random numbers}
313;;;
1a179b03 314(define (make-random-state . args)
6001fe82
MD
315 (let ((seed (if (null? args) *random-state* (car args))))
316 (cond ((string? seed))
317 ((number? seed) (set! seed (number->string seed)))
318 (else (let ()
319 (require 'object->string)
320 (set! seed (object->limited-string seed 50)))))
321 (seed->random-state seed)))
322
9b2416ea
KR
323;;; {rev2-procedures}
324;;;
325
326(define -1+ 1-)
327(define <? <)
328(define <=? <=)
329(define =? =)
330(define >? >)
331(define >=? >=)
332
700ffd55
KR
333;;; {system}
334;;;
700ffd55
KR
335;; If the program run is killed by a signal, the shell normally gives an
336;; exit code of 128+signum. If the shell itself is killed by a signal then
337;; we do the same 128+signum here.
338;;
339;; "stop-sig" shouldn't arise here, since system shouldn't be calling
340;; waitpid with WUNTRACED, but allow for it anyway, just in case.
341;;
e35275e2
KR
342(if (memq 'system *features*)
343 (define-public system
344 (lambda (str)
345 (let ((st ((@ (guile) system) str)))
346 (or (status:exit-val st)
347 (+ 128 (or (status:term-sig st)
348 (status:stop-sig st))))))))
700ffd55 349
0f2d19dd
JB
350;;; {Time}
351;;;
352
353(define difftime -)
354(define offset-time +)
355
356\f
0f2d19dd
JB
357(define define
358 (procedure->memoizing-macro
359 (lambda (exp env)
360 (if (= (length env) 1)
361 `(define-public ,@(cdr exp))
9123414e 362 `(define-private ,@(cdr exp))))))
0f2d19dd 363
7a0ff2f8
MD
364;;; Hack to make syncase macros work in the slib module
365(if (nested-ref the-root-module '(app modules ice-9 syncase))
366 (set-object-property! (module-local-variable (current-module) 'define)
367 '*sc-expander*
368 '(define)))
369
26ec032d 370(define (software-type)
ea4bcd7b
GB
371 "Return a symbol describing the current platform's operating system.
372This may be one of AIX, VMS, UNIX, COHERENT, WINDOWS, MS-DOS, OS/2,
373THINKC, AMIGA, ATARIST, MACH, or ACORN.
374
375Note that most varieties of Unix are considered to be simply \"UNIX\".
376That is because when a program depends on features that are not present
377on every operating system, it is usually better to test for the presence
378or absence of that specific feature. The return value of
379@code{software-type} should only be used for this purpose when there is
380no other easy or unambiguous way of detecting such features."
381 'UNIX)
0f2d19dd 382
c51bfd81 383(slib:load (in-vicinity (library-vicinity) "require.scm"))
0f2d19dd 384
1a179b03 385(define require require:require)
c51bfd81
MD
386
387;; {Extensions to the require system so that the user can add new
388;; require modules easily.}
389
390(define *vicinity-table*
391 (list
392 (cons 'implementation (implementation-vicinity))
393 (cons 'library (library-vicinity))))
394
395(define (install-require-vicinity name vicinity)
396 (let ((entry (assq name *vicinity-table*)))
397 (if entry
398 (set-cdr! entry vicinity)
399 (set! *vicinity-table*
400 (acons name vicinity *vicinity-table*)))))
401
402(define (install-require-module name vicinity-name file-name)
12ed431d
MD
403 (if (not *catalog*) ;Fix which loads catalog in slib
404 (catalog:get 'random)) ;(doesn't load the feature 'random)
c51bfd81
MD
405 (let ((entry (assq name *catalog*))
406 (vicinity (cdr (assq vicinity-name *vicinity-table*))))
407 (let ((path-name (in-vicinity vicinity file-name)))
408 (if entry
409 (set-cdr! entry path-name)
410 (set! *catalog*
411 (acons name path-name *catalog*))))))
6012c379
MV
412
413(define (make-exchanger obj)
414 (lambda (rep) (let ((old obj)) (set! obj rep) old)))