scm-5e5/0000755001705200017500000000000010752352226010036 5ustar tbtbscm-5e5/disarm.scm0000644001705200017500000001011010750211230011775 0ustar tbtb;;;; "disarm.scm", Make SCM safe for client-server applications. ;; Copyright (C) 1998 Free Software Foundation, Inc. ;; ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU Lesser General Public License as ;; published by the Free Software Foundation, either version 3 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 ;; Lesser General Public License for more details. ;; ;; You should have received a copy of the GNU Lesser General Public ;; License along with this program. If not, see ;; . ;;; Author: Aubrey Jaffer. (define (disarm name) (lambda args ;;(if (memq? name slib:features) (set! slib:features (remove name *features))) (error name 'disabled))) (define abort quit) (define restart (disarm 'restart)) (define ed (disarm 'ed)) #+vms (define vms-debug (disarm 'vms-debug)) ;; opening files (define open-file (disarm 'open-file)) (define transcript-on (disarm 'transcript-on)) #+i/o-extensions (begin (define system (disarm 'system)) (define execvp (disarm 'exec)) (define execv execvp) (define execlp execvp) (define execl execvp) (define putenv (disarm 'putenv)) (define stat (disarm 'stat)) (define reopen-file (disarm 'reopen-file)) (define duplicate-port (disarm 'duplicate-port)) (define redirect-port! (disarm 'redirect-port!)) (define opendir (disarm 'opendir)) (define mkdir (disarm 'mkdir)) (define rmdir (disarm 'rmdir)) (define chdir (disarm 'chdir)) (define rename-file (disarm 'rename-file)) (define chmod (disarm 'chmod)) (define utime (disarm 'utime)) (define umask (disarm 'umask)) (define fileno (disarm 'fileno)) (define access (disarm 'access)) ) #+posix (begin (define open-pipe (disarm 'open-pipe)) (define fork (disarm 'fork)) (define setuid (disarm 'setuid)) (define setgid (disarm 'setgid)) (define seteuid (disarm 'seteuid)) (define setegid (disarm 'setegid)) (define kill (disarm 'kill)) (define waitpid (disarm 'waitpid)) (define uname (disarm 'uname)) (define getpw (disarm 'getpw)) (define getgr (disarm 'getgr)) (define getgroups (disarm 'getgroups)) (define link (disarm 'link)) (define chown (disarm 'chown)) ) ;;#+unix ;;(begin ;; (define symlink (disarm 'symlink)) ;; (define readlink (disarm 'readlink)) ;; (define lstat (disarm 'lstat)) ;; (define nice (disarm 'nice)) ;; (define acct (disarm 'acct)) ;; (define mknod (disarm 'mknod)) ;; ) #+edit-line (error 'edit-line 'inappropriate-for-server) #+curses (error 'curses 'inappropriate-for-server) #+turtle-graphics (error 'turtle-graphics 'inappropriate-for-server) ;;#+socket ;;(begin ;; (define make-stream-socket (disarm 'make-stream-socket)) ;; (define make-stream-socketpair (disarm 'make-stream-socketpair)) ;; (define socket:connect (disarm 'socket:connect)) ;; (define socket:bind (disarm 'socket:bind)) ;; (define socket:listen (disarm 'socket:listen)) ;; (define socket:accept (disarm 'socket:accept)) ;; ) ;; load (define load (disarm 'load)) (define try-load load) (define scm:load load) (define scm:load-source load) (define link:link (disarm 'link:link)) ;; SLIB loads (define base:load load) (define slib:load load) (define slib:load-compiled load) (define slib:load-source load) (define defmacro:load load) (define macro:load load) ;;(define macwork:load load) ;;(define syncase:load load) ;;(define synclo:load load) ;;;; eval ;;(define eval (disarm 'eval)) ;;(define eval-string eval) ;;(define interaction-environment (disarm 'interaction-environment)) ;;(define scheme-report-environment (disarm 'scheme-report-environment)) ;;;; SLIB evals ;;(define base:eval eval) ;;(define slib:eval eval) ;;(define defmacro:eval eval) ;;(define macro:eval eval) ;;(define macwork:eval eval) ;;(define repl:eval eval) ;;(define syncase:eval eval) ;;(define syncase:eval-hook eval) ;;(define synclo:eval eval) scm-5e5/bytenumb.c0000644001705200017500000003003710750226347012034 0ustar tbtb/* "bytenumb.scm" Byte integer and IEEE floating-point conversions. * Copyright (C) 2007 Free Software Foundation, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see * . */ /* Author: Aubrey Jaffer */ /* For documentation see: http://cvs.savannah.gnu.org/viewcvs/slib/slib/bytenumb.scm?view=markup */ #include #include #include "scm.h" int get_bytes_length(obj) SCM obj; { array_dim *s; if (IMP(obj)) return -1; switch (TYP7(obj)) { case tc7_string: case tc7_VfixN8: case tc7_VfixZ8: return LENGTH(obj); case tc7_smob: if (!ARRAYP(obj)) return -1; if (1 != ARRAY_NDIM(obj)) return -1; s = ARRAY_DIMS(obj); if (1 != s[0].inc) return -1; return s[0].ubnd - s[0].lbnd; default: return -1; } } static char s_wrong_length[] = "wrong length"; static SCM list_of_0; char * get_bytes(obj, minlen, s_name) SCM obj; int minlen; const char *s_name; { ASRTER(NIMP(obj) && (TYP7(obj)==tc7_string || TYP7(obj)==tc7_VfixN8 || TYP7(obj)==tc7_VfixZ8), obj, ARG1, s_name); { int byvlen = get_bytes_length(obj); ASRTER(byvlen >= minlen, obj, s_wrong_length, s_name); return (char*)scm_addr(cons(obj, list_of_0), s_name); } } static char s_bytes_to_integer[] = "bytes->integer"; SCM scm_bytes_to_integer(sbyts, sn) SCM sbyts; SCM sn; { long n = INUM(sn); if (!(n)) return INUM0; { int cnt = abs(n); char *byts = get_bytes(sbyts, cnt, s_bytes_to_integer); int iu = 0, id = cnt - sizeof(BIGDIG); sizet ndigs = (cnt + sizeof(BIGDIG) - 1) / sizeof(BIGDIG); int negp = (0x80 & byts[0]) && (0 > n); SCM retval = mkbig(ndigs, negp); BIGDIG *digs = BDIGITS(retval), carry = 1; if (negp) for (; iu < ndigs; iu++) { int j = 0; unsigned long dig = 0; for (; j < sizeof(BIGDIG); j++) { dig = (dig<<8) + (0xFF ^ ((id + j >= 0) ? (((unsigned char *)byts)[id + j]) : 255)); /* printf("byts[%d + %d] = %lx\n", id, j, 0xFF & dig); */ } dig = dig + carry; digs[iu] = dig; carry = dig >> (8 * sizeof(BIGDIG)); /* printf("id = %d; iu = %d; dig = %04lx\n", id, iu, dig); */ id = id - sizeof(BIGDIG); } else for (; iu < ndigs; iu++) { int j = 0; BIGDIG dig = 0; for (; j < sizeof(BIGDIG); j++) { dig = (dig<<8) + ((id + j >= 0) ? (((unsigned char *)byts)[id + j]) : 0); } digs[iu] = dig; /* printf("id = %d; iu = %d; dig = %04x\n", id, iu, dig); */ id = id - sizeof(BIGDIG); } return normbig(retval); } } static char s_integer_to_bytes[] = "integer->bytes"; SCM scm_integer_to_bytes(sn, slen) SCM sn; SCM slen; { ASRTER(INUMP(slen), slen, ARG2, s_integer_to_bytes); { int len = INUM(slen); SCM sbyts = make_string(scm_iabs(slen), MAKICHR(0)); char *byts = CHARS(sbyts); if (INUMP(sn)) { int idx = -1 + (abs(len)); long n = num2long(sn, (char *)ARG1, s_integer_to_bytes); if ((0 > n) && (0 > len)) { long res = -1 - n; while (!(0 > idx)) { byts[idx--] = 0xFF ^ (res % 0x100); res = res>>8; } } else { unsigned long res = n; while (!(0 > idx)) { byts[idx--] = res % 0x100; res = res>>8; } } } else { ASRTER(NIMP(sn) && BIGP(sn), sn, ARG1, s_integer_to_bytes); { BIGDIG *digs = BDIGITS(sn), borrow = 1; sizet ndigs = NUMDIGS(sn); int iu = 0, id = abs(len) - 1; unsigned long dig; if ((0 > len) && (TYP16(sn)==tc16_bigneg)) for (; 0 <= id ; iu++) { sizet j = sizeof(BIGDIG); dig = (iu < ndigs) ? digs[iu] : 0; dig = dig ^ ((1 << (8 * sizeof(BIGDIG))) - 1); /* printf("j = %d; id = %d; iu = %d; dig = %04x; borrow = %d\n", j, id, iu, dig, borrow); */ for (; 0 < j-- && 0 <= id;) { /* printf("byts[%d] = %02x\n", id, 0xFF & dig); */ int dg = (0xFF & dig) + borrow; borrow = dg >> 8; ((unsigned char *)byts)[id--] = dg; dig = (dig)>>8; } } else for (; 0 <= id ; iu++) { BIGDIG dig = (iu < ndigs) ? digs[iu] : 0; sizet j = sizeof(BIGDIG); /* printf("j = %d; id = %d; iu = %d; dig = %04x\n", j, id, iu, dig); */ for (; 0 < j-- && 0 <= id;) { /* printf("byts[%d] = %02x\n", id, 0xFF & dig); */ ((unsigned char *)byts)[id--] = 0xFF & dig; dig = (dig>>8); } } } } return sbyts; } } static char s_bytes_to_ieee_float[] = "bytes->ieee-float"; SCM scm_bytes_to_ieee_float(sbyts) SCM sbyts; { char *byts = get_bytes(sbyts, 4, s_bytes_to_ieee_float); int len = LENGTH(sbyts); int s = (1<<(7)) & ((((unsigned char*)(byts))[0])); int e = ((0x7f&((((unsigned char*)(byts))[0])))<<1) + ((0x80&((((unsigned char*)(byts))[1])))>>7); float f = (((unsigned char*)(byts))[ -1 + (len)]); int idx = -2 + (len); while (!((idx)<=1)) { { int T_idx = -1 + (idx); f = ((((unsigned char*)(byts))[idx])) + ((f) / 0x100); idx = T_idx; } } f = ((0x7f&((((unsigned char*)(byts))[1]))) + ((f) / 0x100)) / 0x80; if ((0<(e)) && ((e)<0xff)) return makdbl(ldexpf((s ? -1 : 1) * (1 + (f)), (e) - 0x7f), 0.0); else if (!(e)) if (!(f)) return flo0; else return makdbl(ldexpf((s ? -1 : 1) * (f), -126), 0.0); else if (f) return scm_narn; else return makdbl((s ? -(1.0) : 1.0) / 0.0, 0.0); } static char s_bytes_to_ieee_double[] = "bytes->ieee-double"; SCM scm_bytes_to_ieee_double(sbyts) SCM sbyts; { char *byts = get_bytes(sbyts, 8, s_bytes_to_ieee_double); int len = LENGTH(sbyts); int s = (1<<(7)) & ((((unsigned char*)(byts))[0])); int e = ((0x7f&((((unsigned char*)(byts))[0])))<<4) + ((0xf0&((((unsigned char*)(byts))[1])))>>4); double f = (((unsigned char*)(byts))[ -1 + (len)]); int idx = -2 + (len); while (!((idx)<=1)) { { int T_idx = -1 + (idx); f = ((((unsigned char*)(byts))[idx])) + ((f) / 0x100); idx = T_idx; } } f = ((0xf&((((unsigned char*)(byts))[1]))) + ((f) / 0x100)) / 0x10; if ((0<(e)) && ((e)<0x7ff)) return makdbl(ldexp((s ? -1 : 1) * (1 + (f)), (e) - 0x3ff), 0.0); else if (!(e)) if (!(f)) return flo0; else return makdbl(ldexp((s ? -1 : 1) * (f), -1022), 0.0); else if (f) return scm_narn; else return makdbl((s ? -(1.0) : 1.0) / 0.0, 0.0); } static char s_ieee_float_to_bytes[] = "ieee-float->bytes"; SCM scm_ieee_float_to_bytes(in_flt) SCM in_flt; { double dbl = num2dbl(in_flt, (char *)ARG1, s_ieee_float_to_bytes); float flt = (float) dbl; SCM sbyts = make_string(MAKINUM(4), MAKICHR(0)); char *byts = CHARS(sbyts); int s = flt < 0.0; int scl = 0x7f; flt = fabs(flt); if (0.0==flt) { if (s) byts[0] = 0x80; return sbyts; } else if (flt != flt) { byts[0] = 0x7f; byts[1] = 0xc0; return sbyts; } else goto L_scale; L_out: { float T_flt = 0x80 * (flt); int val = (int)(floor(0x80 * (flt))); int idx = 1; float flt = T_flt; while (!((idx) > 3)) { byts[idx] = val; { float T_flt = 0x100 * ((flt) - (val)); int T_val = (int)(floor(0x100 * ((flt) - (val)))); idx = 1 + (idx); flt = T_flt; val = T_val; } } byts[1] = (0x80 & (scl<<7)) | (0x7f & (((unsigned char*)(byts))[1])); byts[0] = (s ? 0x80 : 0) + ((scl)>>1); return sbyts; } L_scale: if (!(scl)) { flt = (flt)/2; goto L_out; } else if ((flt)>=0x10) { float flt16 = (flt) / 0x10; if ((flt16)==(flt)) { byts[0] = s ? 0xff : 0x7f; byts[1] = 0x80; return sbyts; } else { flt = flt16; scl = (scl) + 4; goto L_scale; } } else if ((flt) >= 2) { flt = (flt) / 2; scl = (scl) + 1; goto L_scale; } else if (((scl) >= 4) && ((0x10 * (flt))<1)) { flt = (flt) * 0x10; scl = (scl)+ -4; goto L_scale; } else if ((flt)<1) { flt = (flt) * 2; scl = (scl) + -1; goto L_scale; } else { flt = -1+(flt); goto L_out; } } static char s_ieee_double_to_bytes[] = "ieee-double->bytes"; SCM scm_ieee_double_to_bytes(in_flt) SCM in_flt; { double flt = num2dbl(in_flt, (char *)ARG1, s_ieee_double_to_bytes); SCM sbyts = make_string(MAKINUM(8), MAKICHR(0)); char *byts = CHARS(sbyts); int s = flt < 0.0; int scl = 0x3ff; flt = fabs(flt); if (0.0==flt) { if (s) byts[0] = 0x80; return sbyts; } else if (flt != flt) { byts[0] = 0x7f; byts[1] = 0xf8; return sbyts; } else goto L_scale; L_out: { double T_flt = 0x10 * (flt); int val = (int)(floor(0x10 * (flt))); int idx = 1; double flt = T_flt; while (!((idx) > 7)) { byts[idx] = val; { double T_flt = 0x100 * (flt - val); int T_val = (int)floor(0x100 * (flt - val)); idx = 1 + (idx); flt = T_flt; val = T_val; } } byts[1] = (0xf0 & (scl<<4)) | (0x0f & (((unsigned char*)(byts))[1])); byts[0] = (s ? 0x80 : 0) + ((scl)>>4); return sbyts; } L_scale: if (!(scl)) { flt = (flt) / 2; goto L_out; } else if ((flt) >= 0x10) { double flt16 = (flt) / 0x10; if ((flt16)==(flt)) { byts[0] = s ? 0xff : 0x7f; byts[1] = 0xf0; return sbyts; } else { flt = flt16; scl = (scl) + 4; goto L_scale; } } else if ((flt) >= 2) { flt = (flt) / 2; scl = (scl) + 1; goto L_scale; } else if (((scl) >= 4) && ((0x10 * flt) < 1)) { flt = (flt) * 0x10; scl = (scl) + -4; goto L_scale; } else if ((flt) < 1) { flt = (flt) * 2; scl = (scl) + -1; goto L_scale; } else { flt = -1 + (flt); goto L_out; } } static char s_integer_byte_collate_M[] = "integer-byte-collate!"; SCM scm_integer_byte_collate_M(byte_vector) SCM byte_vector; { char* bv = get_bytes(byte_vector, 1, s_integer_byte_collate_M); bv[0] = 0x80^(bv[0]); return byte_vector; } static char s_ieee_byte_collate_M[] = "ieee-byte-collate!"; SCM scm_ieee_byte_collate_M(byte_vector) SCM byte_vector; { char* byv = get_bytes(byte_vector, 4, s_ieee_byte_collate_M); int byvlen = get_bytes_length(byte_vector); if (0x80&(byv[0])) { int idx = -1 + byvlen; while (!(0 > (idx))) { byv[idx] = 0xff^(byv[idx]); idx = -1+(idx); } } else byv[0] = 0x80^(byv[0]); return byte_vector; } static char s_ieee_byte_decollate_M[] = "ieee-byte-decollate!"; SCM scm_ieee_byte_decollate_M(byte_vector) SCM byte_vector; { char* byv = get_bytes(byte_vector, 4, s_ieee_byte_collate_M); int byvlen = get_bytes_length(byte_vector); if (!(0x80&(byv[0]))) { int idx = -1 + byvlen; while (!(0 > (idx))) { byv[idx] = 0xff^(byv[idx]); idx = -1+(idx); } } else byv[0] = 0x80^(byv[0]); return byte_vector; } static iproc subr1s[] = { {s_bytes_to_ieee_float, scm_bytes_to_ieee_float}, {s_bytes_to_ieee_double, scm_bytes_to_ieee_double}, {s_ieee_float_to_bytes, scm_ieee_float_to_bytes}, {s_ieee_double_to_bytes, scm_ieee_double_to_bytes}, {s_integer_byte_collate_M, scm_integer_byte_collate_M}, {s_ieee_byte_collate_M, scm_ieee_byte_collate_M}, {s_ieee_byte_decollate_M, scm_ieee_byte_decollate_M}, {0, 0}}; void init_bytenumb() { list_of_0 = cons(INUM0, EOL); scm_gc_protect(list_of_0); make_subr(s_bytes_to_integer, tc7_subr_2, scm_bytes_to_integer); make_subr(s_integer_to_bytes, tc7_subr_2, scm_integer_to_bytes); init_iprocs(subr1s, tc7_subr_1); scm_ldstr("\n\ (define (integer-byte-collate byte-vector)\n\ (integer-byte-collate! (bytes-copy byte-vector)))\n\ (define (ieee-byte-collate byte-vector)\n\ (ieee-byte-collate! (bytes-copy byte-vector)))\n\ (define (ieee-byte-decollate byte-vector)\n\ (ieee-byte-decollate! (bytes-copy byte-vector)))\n\ "); /* add_feature("byte-number"); */ } scm-5e5/Init5e5.scm0000644001705200017500000014656010750526465012006 0ustar tbtb;;;; "Init.scm", Scheme initialization code for SCM. ;; Copyright (C) 1991-2008 Free Software Foundation, Inc. ;; ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU Lesser General Public License as ;; published by the Free Software Foundation, either version 3 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 ;; Lesser General Public License for more details. ;; ;; You should have received a copy of the GNU Lesser General Public ;; License along with this program. If not, see ;; . ;;; Author: Aubrey Jaffer. (define (scheme-implementation-type) 'scm) (define (scheme-implementation-version) "5e5") (define (scheme-implementation-home-page) "http://swiss.csail.mit.edu/~jaffer/SCM") ;@ (define in-vicinity string-append) ;@ (define (user-vicinity) (case (software-type) ((vms) "[.]") (else ""))) ;@ (define vicinity:suffix? (let ((suffi (case (software-type) ((amiga) '(#\: #\/)) ((macos thinkc) '(#\:)) ((ms-dos windows atarist os/2) '(#\\ #\/)) ((nosve) '(#\: #\.)) ((unix coherent plan9) '(#\/)) ((vms) '(#\: #\])) (else (slib:warn "require.scm" 'unknown 'software-type (software-type)) "/")))) (lambda (chr) (and (memv chr suffi) #t)))) ;@ (define (pathname->vicinity pathname) (let loop ((i (- (string-length pathname) 1))) (cond ((negative? i) "") ((vicinity:suffix? (string-ref pathname i)) (substring pathname 0 (+ i 1))) (else (loop (- i 1)))))) (define (program-vicinity) (if *load-pathname* (pathname->vicinity *load-pathname*) (slib:error 'program-vicinity " called; use slib:load to load"))) ;@ (define sub-vicinity (case (software-type) ((vms) (lambda (vic name) (let ((l (string-length vic))) (if (or (zero? (string-length vic)) (not (char=? #\] (string-ref vic (- l 1))))) (string-append vic "[" name "]") (string-append (substring vic 0 (- l 1)) "." name "]"))))) (else (let ((*vicinity-suffix* (case (software-type) ((nosve) ".") ((macos thinkc) ":") ((ms-dos windows atarist os/2) "\\") ((unix coherent plan9 amiga) "/")))) (lambda (vic name) (string-append vic name *vicinity-suffix*)))))) ;@ (define (make-vicinity ) ) ;@ (define with-load-pathname (let ((exchange (lambda (new) (let ((old *load-pathname*)) (set! *load-pathname* new) old)))) (lambda (path thunk) (let ((old #f)) (dynamic-wind (lambda () (set! old (exchange path))) thunk (lambda () (exchange old))))))) (define slib:features (append '(ed getenv tmpnam abort transcript with-file ieee-p1178 rev4-report rev4-optional-procedures hash object-hash delay dynamic-wind fluid-let multiarg-apply multiarg/and- logical defmacro string-port source current-time sharp:semi math-integer ;math-real and srfi-94 provided in "Transcen.scm" vicinity srfi-59 srfi-96 srfi-23 srfi-60) ;logical (if (defined? *features*) *features* slib:features))) (if (defined? *features*) (set! *features* slib:features)) (define eval (let ((@eval @eval) (@copy-tree @copy-tree)) (lambda (x) (@eval (@copy-tree x))))) (define (exec-self) (require 'i/o-extensions) (execv (execpath) (if *script* (cons (car (program-arguments)) (cons "\\" (member *script* (program-arguments)))) (program-arguments)))) (define (display-file file . port) (call-with-input-file file (lambda (inport) (do ((c (read-char inport) (read-char inport))) ((eof-object? c)) (apply write-char c port))))) (define (terms) (display-file (in-vicinity (implementation-vicinity) "COPYING"))) ;;; Read integer up to first non-digit (define (read:try-number port . ic) (define chr0 (char->integer #\0)) (let loop ((arg (and (not (null? ic)) (- (char->integer (car ic)) chr0)))) (let ((c (peek-char port))) (cond ((eof-object? c) #f) ((char-numeric? c) (loop (+ (* 10 (or arg 0)) (- (char->integer (read-char port)) chr0)))) (else arg))))) (define (read-array-type port) (define (bomb pc wid) (error 'array 'syntax? (symbol-append "#" rank "A" pc wid))) (case (char-downcase (peek-char port)) ((#\:) (read-char port) (let ((typ (let loop ((arg '())) (if (= 4 (length arg)) (string->symbol (list->string (reverse arg))) (let ((c (read-char port))) (and (not (eof-object? c)) (loop (cons (char-downcase c) arg)))))))) (define wid (and typ (not (eq? 'bool typ)) (read:try-number port))) (define (check-suffix chrs) (define chr (read-char port)) (if (and (char? chr) (not (memv (char-downcase chr) chrs))) (error 'array-type? (symbol-append ":" typ wid chr)))) (define prot (assq typ '((floc (128 . +64.0i) (64 . +64.0i) (32 . +32.0i) (16 . +32.0i)) (flor (128 . 64.0) (64 . 64.0) (32 . 32.0) (16 . 32.0)) (fixz (64 . -64) (32 . -32) (16 . -16) (8 . -8)) (fixn (64 . 64) (32 . 32) (16 . 16) (8 . 8)) (char . #\a) (bool . #t)))) (if prot (set! prot (cdr prot))) (cond ((pair? prot) (set! prot (assv wid (cdr prot))) (if (pair? prot) (set! prot (cdr prot))) (if wid (check-suffix (if (and (inexact? prot) (real? prot)) '(#\b #\d) '(#\b))))) (prot) (else (check-suffix '()))) prot)) ((#\\) (read-char port) #\a) ((#\t) (read-char port) #t) ((#\c #\r) (let* ((pc (read-char port)) (wid (read:try-number port))) (case wid ((64 32) (case pc ((#\c) (* +i wid)) (else (exact->inexact wid)))) (else (bomb pc wid))))) ((#\s #\u) (let* ((pc (read-char port)) (wid (read:try-number port))) (case (or wid (peek-char port)) ((32 16 8) (case pc ((#\s) (- wid)) (else wid))) (else (bomb pc wid))))) (else #f))) ;;; We come into read:array with number or #f for RANK. (define (read:array rank dims port) (define (make-it rank dims typ) (list->uniform-array (cond (rank) ((null? dims) 1) (else (length dims))) typ (read port))) (let loop ((dims dims)) (define dim (read:try-number port)) (if dim (loop (cons dim dims)) (case (peek-char port) ((#\*) (read-char port) (loop dims)) ((#\: #\\ #\t #\c #\r #\s #\u #\T #\C #\R #\S #\U) (make-it rank dims (read-array-type port))) (else (make-it rank dims #f)))))) ;;; read-macros valid for LOAD and READ. (define (read:sharp c port reader) ; ignore reader (case c ;; Used in "implcat" and "slibcat" ((#\+) (if (slib:provided? (read port)) (read port) (begin (read port) (if #f #f)))) ;; Used in "implcat" and "slibcat" ((#\-) (if (slib:provided? (read port)) (begin (read port) (if #f #f)) (read port))) ((#\a #\A) (read:array #f '() port)) ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9) (let* ((num (read:try-number port c)) (chr (peek-char port))) (case chr ((#\a #\A) (read-char port) (read:array num '() port)) ((#\*) (read-char port) (read:array #f (list num) port)) (else (read:array 1 (list num) port)) ;;(else (error 'sharp 'syntax? (symbol-append "#" num chr))) ))) (else (error "unknown # object" c)))) ;;; read-macros valid only in LOAD. (define (load:sharp c port reader) ;reader used only for #. (case c ((#\') (read port)) ((#\.) (eval (reader port))) ((#\!) (let skip ((metarg? #f)) (let ((c (read-char port))) (case c ((#\newline) (if metarg? (skip #t))) ((#\\) (skip #t)) ((#\!) (cond ((eqv? #\# (peek-char port)) (read-char port) (if #f #f)) (else (skip metarg?)))) (else (if (char? c) (skip metarg?) c)))))) ;; Make #; convert the rest of the line to a (comment ...) form. ;; "build.scm" uses this. ((#\;) (let skip-semi () (cond ((eqv? #\; (peek-char port)) (read-char port) (skip-semi)) (else (require 'line-i/o) `(comment ,(read-line port)))))) ((#\?) (case (read port) ((line) (port-line port)) ((column) (port-column port)) ((file) (port-filename port)) (else #f))) (else (read:sharp c port read)))) ;;; We can assume TOK has at least 2 characters. (define char:sharp (letrec ((numeric-1 (lambda (tok radix) (numeric (substring tok 1 (string-length tok)) radix))) (numeric (lambda (tok radix) (cond ((string->number tok radix) => integer->char)))) (compose (lambda (modifier tok) (and (char=? #\- (string-ref tok 1)) (if (= 3 (string-length tok)) (modifier (string-ref tok 2)) (let ((c (char:sharp (substring tok 2 (string-length tok))))) (and c (modifier c))))))) (control (lambda (c) (and (char? c) (if (eqv? c #\?) (integer->char 127) (integer->char (logand #o237 (char->integer c))))))) (meta (lambda (c) (and (char? c) (integer->char (logior 128 (char->integer c))))))) (lambda (tok) (case (string-ref tok 0) ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7) (numeric tok 8)) ((#\O #\o) (numeric-1 tok 8)) ((#\D #\d) (numeric-1 tok 10)) ((#\X #\x) (numeric-1 tok 16)) ((#\C #\c) (compose control tok)) ((#\^) (and (= 2 (string-length tok)) (control (string-ref tok 1)))) ((#\M #\m) (compose meta tok)))))) ;;;; Function used to accumulate comments before a definition. (define comment (let ((*accumulated-comments* '())) (lambda args (cond ((null? args) (let ((ans (apply string-append (map (lambda (comment) (string-append (or comment "") "\n")) (reverse *accumulated-comments*))))) (set! *accumulated-comments* '()) (if (equal? "" ans) "no-comment" ;#f (substring ans 0 (+ -1 (string-length ans)))))) (else (set! *accumulated-comments* (append (reverse args) *accumulated-comments*))))))) (define : ':) ;for /bin/sh hack. (define !#(if #f #f)) ;for scsh hack. ;;;; Here are some Revised^2 Scheme functions: (define 1+ (let ((+ +)) (lambda (n) (+ n 1)))) (define -1+ (let ((+ +)) (lambda (n) (+ n -1)))) (define 1- -1+) (define ? >) (define >=? >=) (define t #t) (define nil #f) (define identity cr) (cond ((defined? defsyntax) (defsyntax define-syntax (the-macro defsyntax))) (else (define defsyntax define) (define the-macro identity))) (defsyntax sequence (the-macro begin)) (define copy-tree @copy-tree) ;;; VMS does something strange when output is sent to both ;;; CURRENT-OUTPUT-PORT and CURRENT-ERROR-PORT. (case (software-type) ((vms) (set-current-error-port (current-output-port)))) ;;; OPEN_READ, OPEN_WRITE, and OPEN_BOTH are used to request the proper ;;; mode to open files in. MS-DOS does carriage return - newline ;;; translation if not opened in `b' mode. (define open_read (case (software-type) ((ms-dos windows atarist) 'rb) (else 'r))) (define open_write (case (software-type) ((ms-dos windows) 'wbc) ((atarist) 'wb) (else 'w))) (define open_both (case (software-type) ((ms-dos windows) 'r+bc) ((atarist) 'r+b) (else 'r+))) (define ((make-moder str) mode) (if (symbol? mode) (string->symbol (string-append (symbol->string mode) str)) (string-append mode str))) (define _ionbf (make-moder "0")) (define _tracked (make-moder "?")) (define _exclusive (make-moder "x")) (define could-not-open #f) (define (open-output-file str) (or (open-file str open_write) (and (procedure? could-not-open) (could-not-open) #f) (error "OPEN-OUTPUT-FILE couldn't open file " str))) (define (open-input-file str) (or (open-file str open_read) (and (procedure? could-not-open) (could-not-open) #f) (error "OPEN-INPUT-FILE couldn't open file " str))) (define (string-index str chr) (define len (string-length str)) (do ((pos 0 (+ 1 pos))) ((or (>= pos len) (char=? chr (string-ref str pos))) (and (< pos len) pos)))) (if (not (defined? try-create-file)) (define (try-create-file str modes . perms) (if (symbol? modes) (set! modes (symbol->string modes))) (let ((idx (string-index modes #\x))) (cond ((slib:in-catalog? 'i/o-extensions) (require 'i/o-extensions) (apply try-create-file str modes perms)) ((not idx) (warn "not exclusive modes?" modes str) (try-open-file str modes)) (else (set! modes (string-append (substring modes 0 idx) (substring modes (+ 1 idx) (string-length modes)))) (cond ((not (string-index modes #\w)) (warn 'try-create-file "not writing?" modes str) (try-open-file str modes)) (else (cond ((and (not (null? perms)) (not (eqv? #o666 (car perms)))) (warn "perms?" (car perms) str))) (cond ((file-exists? str) #f) (else (try-open-file str modes)))))))))) (if (not (defined? file-position)) (define (file-position . args) #f)) (if (not (defined? file-set-position)) (define file-set-position file-position)) (define close-input-port close-port) (define close-output-port close-port) (define (call-with-open-ports . ports) (define proc (car ports)) (cond ((procedure? proc) (set! ports (cdr ports))) (else (set! ports (reverse ports)) (set! proc (car ports)) (set! ports (reverse (cdr ports))))) (let ((ans (apply proc ports))) (for-each close-port ports) ans)) (define (call-with-input-file str proc) (call-with-open-ports (open-input-file str) proc)) (define (call-with-output-file str proc) (call-with-open-ports (open-output-file str) proc)) (define (with-input-from-port port thunk) (dynamic-wind (lambda () (set! port (set-current-input-port port))) thunk (lambda () (set! port (set-current-input-port port))))) (define (with-output-to-port port thunk) (dynamic-wind (lambda () (set! port (set-current-output-port port))) thunk (lambda () (set! port (set-current-output-port port))))) (define (with-error-to-port port thunk) (dynamic-wind (lambda () (set! port (set-current-error-port port))) thunk (lambda () (set! port (set-current-error-port port))))) (define (with-input-from-file file thunk) (let* ((nport (open-input-file file)) (ans (with-input-from-port nport thunk))) (close-port nport) ans)) (define (with-output-to-file file thunk) (let* ((nport (open-output-file file)) (ans (with-output-to-port nport thunk))) (close-port nport) ans)) (define (with-error-to-file file thunk) (let* ((nport (open-output-file file)) (ans (with-error-to-port nport thunk))) (close-port nport) ans)) (define (call-with-outputs thunk proc) (define stdout #f) (define stderr #f) (define status #f) (set! stdout (call-with-output-string (lambda (stdout) (set! stderr (call-with-output-string (lambda (stderr) (call-with-current-continuation (lambda (escape) (dynamic-wind (lambda () (set! status #f) (set! stdout (set-current-output-port stdout)) (set! stderr (set-current-error-port stderr))) (lambda () (set! status (list (thunk)))) (lambda () (set! stdout (set-current-output-port stdout)) (set! stderr (set-current-error-port stderr)) (if (not status) (escape #f)))))))))))) (apply proc stdout stderr (or status '()))) (define browse-url (case (software-type) ((unix coherent plan9) (lambda (url) (define (try cmd end) (zero? (system (string-append cmd url end)))) (or (try "netscape-remote -remote 'openURL(" ")'") (try "netscape -remote 'openURL(" ")'") (try "netscape '" "'&") (try "netscape '" "'")))) (else (lambda (url) (slib:warn 'define (software-type) 'case 'of 'browse-url 'in *load-pathname*))))) (define (warn . args) (define cep (current-error-port)) (if (defined? print-call-stack) (print-call-stack cep)) (perror "WARN") (errno 0) (display "WARN:" cep) (for-each (lambda (x) (display #\space cep) (write x cep)) args) (newline cep) (force-output cep)) (define (error . args) (define cep (current-error-port)) (if (defined? print-call-stack) (print-call-stack cep)) (perror "ERROR") (errno 0) (display "ERROR:" cep) (for-each (lambda (x) (display #\space cep) (write x cep)) args) (newline cep) (force-output cep) (abort)) (define set-errno errno) (define slib:exit quit) (define exit quit) (define (print . args) (define result #f) (for-each (lambda (x) (set! result x) (write x) (display #\space)) args) (newline) result) (define (pprint . args) (define result #f) (for-each (lambda (x) (set! result x) (pretty-print x)) args) result) (define (pp . args) (for-each pretty-print args) (if #f #f)) (if (not (defined? file-exists?)) (define (file-exists? str) (let ((port (open-file str open_read))) (errno 0) (and port (close-port port) #t)))) (define (file-readable? str) (let ((port (open-file str open_read))) (errno 0) (and port (char-ready? port) (do ((c (read-char port) (and (char-ready? port) (read-char port))) (i 0 (+ 1 i)) (l '() (cons c l))) ((or (not c) (eof-object? c) (<= 2 i)) (if (null? l) #f (list->string (reverse l)))))))) (define difftime -) (define offset-time +) (if (not (defined? ed)) (define (ed . args) (system (apply string-append (or (getenv "EDITOR") "ed") (map (lambda (s) (string-append " " s)) args))))) (if (not (defined? output-port-width)) (define (output-port-width . arg) 80)) (if (not (defined? output-port-height)) (define (output-port-height . arg) 24)) (if (not (defined? last-pair)) (define (last-pair l) (if (pair? (cdr l)) (last-pair (cdr l)) l))) (define slib:error error) (define slib:warn warn) (define slib:tab #\tab) (define slib:form-feed #\page) (define slib:eval eval) (define (make-exchanger . pair) (lambda (rep) (swap-car! pair rep))) ;;;; Load. (define load:indent 0) (define (load:pre file) (define cep (current-error-port)) (cond ((> (verbose) 1) (display (string-append ";" (make-string load:indent #\space) "loading " file) cep) (set! load:indent (modulo (+ 2 load:indent) 16)) (newline cep))) (force-output cep)) (define (load:post filesuf) (define cep (current-error-port)) (errno 0) (cond ((> (verbose) 1) (set! load:indent (modulo (+ -2 load:indent) 16)) (display (string-append ";" (make-string load:indent #\space) "done loading " filesuf) cep) (newline cep) (force-output cep)))) ;;; Here for backward compatibility (define scheme-file-suffix (case (software-type) ((NOSVE) (lambda () "_scm")) (else (lambda () ".scm")))) (define (has-suffix? str suffix) (let ((sufl (string-length suffix)) (sl (string-length str))) (and (> sl sufl) (string=? (substring str (- sl sufl) sl) suffix)))) (define *load-reader* #f) (define (scm:load file . libs) (define filesuf file) (define hss (has-suffix? file (scheme-file-suffix))) (load:pre file) (or (and (defined? link:link) (not hss) (or (let ((s2 (file-readable? file))) (and s2 (not (equal? "#!" s2)) (apply link:link file libs))) (and link:able-suffix (let* ((fs (string-append file link:able-suffix)) (fs2 (file-readable? fs))) (and fs2 (apply link:link fs libs) (set! filesuf fs) #t) )))) (and (null? libs) (try-load file *load-reader*)) ;;HERE is where the suffix gets specified (and (not hss) (errno 0) ; clean up error from TRY-LOAD above (set! filesuf (string-append file (scheme-file-suffix))) (try-load filesuf *load-reader*)) (and (procedure? could-not-open) (could-not-open) #f) (begin (set! load:indent 0) (error "LOAD couldn't find file " file))) (load:post filesuf)) (define load scm:load) (define slib:load load) (define (scm:load-source file) (define sfs (scheme-file-suffix)) (define filesuf file) (load:pre file) (or (and (or (try-load file *load-reader*) ;;HERE is where the suffix gets specified (and (not (has-suffix? file sfs)) (begin (set! filesuf (string-append file sfs)) (try-load filesuf *load-reader*))))) (and (procedure? could-not-open) (could-not-open) #f) (error "LOAD couldn't find file " file)) (load:post filesuf)) (define slib:load-source scm:load-source) ;;; This is the vicinity where this file resides. (define implementation-vicinity #f) ;;; (library-vicinity) should be defined to be the pathname of the ;;; directory where files of Scheme library functions reside. (define library-vicinity #f) ;;; (home-vicinity) should return the vicinity of the user's HOME ;;; directory, the directory which typically contains files which ;;; customize a computer environment for a user. (define home-vicinity #f) (if (not (defined? getpw)) (define read-line (if (defined? read-line) read-line (lambda port (let* ((chr (apply read-char port))) (if (eof-object? chr) chr (do ((chr chr (apply read-char port)) (clist '() (cons chr clist))) ((or (eof-object? chr) (char=? #\newline chr)) (list->string (reverse clist)))))))))) (if (not (defined? getpw)) (define string-index (if (defined? string-index) string-index (lambda (str chr) (define len (string-length str)) (do ((pos 0 (+ 1 pos))) ((or (>= pos len) (char=? chr (string-ref str pos))) (and (< pos len) pos))))))) (define (login->home-directory login) (cond ((defined? getpw) (let ((pwvect (getpw login))) (and pwvect (vector-ref pwvect 5)))) ((not (file-exists? "/etc/passwd")) #f) (else (call-with-input-file "/etc/passwd" (lambda (iprt) (let tryline () (define line (read-line iprt)) (define (get-field) (define idx (string-index line #\:)) (and idx (let ((fld (substring line 0 idx))) (set! line (substring line (+ 1 idx) (string-length line))) fld))) (cond ((eof-object? line) #f) ((string-index line #\:) => (lambda (idx) (define name (substring line 0 idx)) (cond ((equal? login name) (do ((ans (get-field) (get-field)) (cnt 4 (+ -1 cnt))) ((or (negative? cnt) (not ans)) ans))) (else (tryline)))))))))))) (define (getlogin) (or (getenv "USER") (getenv "LOGNAME"))) ;;; If the environment variable SCHEME_LIBRARY_PATH is undefined, use ;;; (implementation-vicinity) as (library-vicinity). "require.scm", ;;; the first file loaded from (library-vicinity), can redirect it. (define (set-vicinities! init-file) (set! implementation-vicinity (let ((vic (substring init-file 0 (- (string-length init-file) (string-length "Init.scm") (string-length (scheme-implementation-version)))))) (lambda () vic))) (let ((library-path (getenv "SCHEME_LIBRARY_PATH"))) (if library-path (set! library-vicinity (lambda () library-path)) (let ((filename (in-vicinity (implementation-vicinity) "require.scm"))) (or (try-load filename) (try-load (in-vicinity (implementation-vicinity) "requires.scm")) (error "Can't load" filename)) (if (not library-vicinity) (error "Can't find library-vicinity"))))) (set! home-vicinity (let ((home (getenv "HOME"))) (and (not home) login->home-directory (let ((login (getlogin))) (and login (set! home (login->home-directory login))))) (and home (case (software-type) ((unix coherent plan9 ms-dos) ;V7 unix has a / on HOME (if (not (eqv? #\/ (string-ref home (+ -1 (string-length home))))) (set! home (string-append home "/")))))) (lambda () home)))) ;;; SET-VICINITIES! is also called from BOOT-TAIL (set-vicinities! *load-pathname*) ;;;; Initialize SLIB (load (in-vicinity (library-vicinity) "require")) ;;; This enables line-numbering for SLIB loads. (define *slib-load-reader* (and (defined? read-numbered) read-numbered)) ;;; DO NOT MOVE! SLIB:LOAD-SOURCE and SLIB:LOAD must be defined after ;;; "require.scm" is loaded. (define (slib:load-source file) (fluid-let ((*load-reader* *slib-load-reader*)) (scm:load-source file))) (define (slib:load file . libs) (fluid-let ((*load-reader* *slib-load-reader*)) (apply scm:load file libs))) ;;; Legacy grease (if (not (defined? slib:in-catalog?)) (define slib:in-catalog? require:feature->path)) ;;; Dynamic link-loading (cond ((or (defined? dyn:link) (defined? vms:dynamic-link-call)) (load (in-vicinity (implementation-vicinity) "Link")))) ;;; Redefine to ease transition from *features* to slib:features. (define (provide feature) (cond ((not (memq feature slib:features)) (set! slib:features (cons feature slib:features)) (if (defined? *features*) (set! *features* slib:features))))) (cond ((defined? link:link) (define (slib:load-compiled . args) (cond ((symbol? (car args)) (require (car args)) (apply slib:load-compiled (cdr args))) ((apply link:link args) (if (defined? *features*) (set! slib:features *features*))) (else (error "Couldn't link files " args)))) (provide 'compiled))) ;;; Complete the function set for feature STRING-CASE. (cond ((defined? string-upcase!) (define (string-upcase str) (string-upcase! (string-copy str))) (define (string-downcase str) (string-downcase! (string-copy str))) (define (string-capitalize str) (string-capitalize! (string-copy str))) (define string-ci->symbol (let ((s2cis (if (equal? "x" (symbol->string 'x)) string-downcase string-upcase))) (lambda (str) (string->symbol (s2cis str))))) (define symbol-append (let ((s2cis (if (equal? "x" (symbol->string 'x)) string-downcase string-upcase))) (lambda args (string->symbol (apply string-append (map (lambda (obj) (cond ((char? obj) (string obj)) ((string? obj) (s2cis obj)) ((number? obj) (s2cis (number->string obj))) ((symbol? obj) (symbol->string obj)) ((not obj) "") (else (error 'wrong-type-to 'symbol-append obj)))) args)))))) (define (StudlyCapsExpand nstr . delimitr) (set! delimitr (cond ((null? delimitr) "-") ((char? (car delimitr)) (string (car delimitr))) (else (car delimitr)))) (do ((idx (+ -1 (string-length nstr)) (+ -1 idx))) ((> 1 idx) nstr) (cond ((and (> idx 1) (char-upper-case? (string-ref nstr (+ -1 idx))) (char-lower-case? (string-ref nstr idx))) (set! nstr (string-append (substring nstr 0 (+ -1 idx)) delimitr (substring nstr (+ -1 idx) (string-length nstr))))) ((and (char-lower-case? (string-ref nstr (+ -1 idx))) (char-upper-case? (string-ref nstr idx))) (set! nstr (string-append (substring nstr 0 idx) delimitr (substring nstr idx (string-length nstr)))))))) (provide 'string-case))) ;;;; Bit order and lamination ;;(define (logical:ones deg) (lognot (ash -1 deg))) ;;; New with SRFI-60 (define (rotate-bit-field n count start end) (define width (- end start)) (set! count (modulo count width)) (let ((mask (lognot (ash -1 width)))) (define azn (logand mask (arithmetic-shift n (- start)))) (logior (arithmetic-shift (logior (logand mask (arithmetic-shift azn count)) (arithmetic-shift azn (- count width))) start) (logand (lognot (ash mask start)) n)))) ;;; Legacy ;;(define (logical:rotate k count len) (rotate-bit-field k count 0 len)) (define (log2-binary-factors n) (+ -1 (integer-length (logand n (- n))))) (define (bit-reverse k n) (do ((m (if (negative? n) (lognot n) n) (arithmetic-shift m -1)) (k (+ -1 k) (+ -1 k)) (rvs 0 (logior (arithmetic-shift rvs 1) (logand 1 m)))) ((negative? k) (if (negative? n) (lognot rvs) rvs)))) (define (reverse-bit-field n start end) (define width (- end start)) (let ((mask (lognot (ash -1 width)))) (define zn (logand mask (arithmetic-shift n (- start)))) (logior (arithmetic-shift (bit-reverse width zn) start) (logand (lognot (ash mask start)) n)))) (define (integer->list k . len) (if (null? len) (do ((k k (arithmetic-shift k -1)) (lst '() (cons (odd? k) lst))) ((<= k 0) lst)) (do ((idx (+ -1 (car len)) (+ -1 idx)) (k k (arithmetic-shift k -1)) (lst '() (cons (odd? k) lst))) ((negative? idx) lst)))) (define (list->integer bools) (do ((bs bools (cdr bs)) (acc 0 (+ acc acc (if (car bs) 1 0)))) ((null? bs) acc))) (define (booleans->integer . bools) (list->integer bools)) ;;;; SRFI-60 aliases (define arithmetic-shift ash) (define bitwise-ior logior) (define bitwise-xor logxor) (define bitwise-and logand) (define bitwise-not lognot) ;;(define bit-count logcount) ;Aliases bit-vector function ;;BITWISE-BIT-COUNT returns negative count for negative inputs. (define bit-set? logbit?) (define any-bits-set? logtest) (define first-set-bit log2-binary-factors) (define bitwise-merge bitwise-if) (define @case-aux (let ((integer-jump-table 1) (char-jump-table 2)) (lambda (keys actions else-action) (let ((n (length keys))) (define (every-key pred) (let test ((keys keys)) (or (null? keys) (and (pred (car keys)) (test (cdr keys)))))) (define (jump-table keys) (let ((minkey (apply min keys)) (maxkey (apply max keys))) (and (< (- maxkey minkey) (* 4 n)) (let ((actv (make-vector (+ 2 (- maxkey minkey)) else-action))) (for-each (lambda (key action) (vector-set! actv (+ 1 (- key minkey)) action)) keys actions) (list integer-jump-table minkey actv))))) (cond ((< n 5) #f) ((every-key integer?) (jump-table keys)) ((every-key char?) (let* ((int-keys (map char->integer keys))) (cond ((jump-table int-keys) => (lambda (x) (cons char-jump-table (cons (integer->char (cadr x)) (cddr x))))) (else #f))))))))) ;;;defmacro from dorai@cs.rice.edu (heavily hacked by jaffer): (define *defmacros* '()) (define (defmacro? m) (and (assq m *defmacros*) #t)) (define defmacro:transformer (lambda (f) (procedure->memoizing-macro (lambda (exp env) (@copy-tree (apply f (remove-line-numbers! (cdr exp)))))))) (define defmacro:get-destructuring-bind-pairs (lambda (s e) (let loop ((s s) (e e) (r '())) (cond ((pair? s) (loop (car s) `(car ,e) (loop (cdr s) `(cdr ,e) r))) ((null? s) r) ((symbol? s) (cons `(,s ,e) r)) (else (error 'destructuring-bind "illegal syntax")))))) (defsyntax destructuring-bind (let ((destructuring-bind-transformer (lambda (s x . ff) (let ((tmp (gentemp))) `(let ((,tmp ,x)) (let ,(defmacro:get-destructuring-bind-pairs s tmp) ,@ff)))))) (set! *defmacros* (acons 'destructuring-bind destructuring-bind-transformer *defmacros*)) (defmacro:transformer destructuring-bind-transformer))) (defsyntax defmacro:simple-defmacro (let ((defmacro-transformer (lambda (name parms . body) `(defsyntax ,name (let ((transformer (lambda ,parms ,@body))) (set! *defmacros* (acons ',name transformer *defmacros*)) (defmacro:transformer transformer)))))) (set! *defmacros* (acons 'defmacro defmacro-transformer *defmacros*)) (defmacro:transformer defmacro-transformer))) (defmacro:simple-defmacro defmacro (name . body) (define (expn name pattern body) (let ((args (gentemp))) `(defmacro:simple-defmacro ,name ,args (destructuring-bind ,pattern ,args ,@body)))) (if (pair? name) (expn (car name) (cdr name) body) (expn name (car body) (cdr body)))) (define (macroexpand-1 e) (if (pair? e) (let ((a (car e))) (cond ((symbol? a) (set! a (assq a *defmacros*)) (if a (apply (cdr a) (cdr e)) e)) (else e))) e)) (define (macroexpand e) (if (pair? e) (let ((a (car e))) (cond ((symbol? a) (set! a (assq a *defmacros*)) (if a (macroexpand (apply (cdr a) (cdr e))) e)) (else e))) e)) (define gentemp (let ((*gensym-counter* -1)) (lambda () (set! *gensym-counter* (+ *gensym-counter* 1)) (string->symbol (string-append "scm:G" (number->string *gensym-counter*)))))) (define defmacro:eval slib:eval) (define defmacro:load load) ;; slib:eval-load definition moved to "slib/require.scm" ;;;; Autoloads for SLIB procedures. (define (trace-all . args) (require 'debug) (apply trace-all args)) (define (track-all . args) (require 'debug) (apply track-all args)) (define (stack-all . args) (require 'debug) (apply stack-all args)) (define (break-all . args) (require 'debug) (apply break-all args)) (define (pretty-print . args) (require 'pretty-print) (apply pretty-print args)) ;;; (require 'transcript) would get us SLIB transcript -- not what we want. (define (transcript-on arg) (load (in-vicinity (implementation-vicinity) (string-append "Tscript" (scheme-file-suffix)))) (transcript-on arg)) (define (transcript-off) (error "No transcript active")) ;;;; Macros. ;;; Trace gets re-defmacroed when tracef autoloads. (defmacro trace x (cond ((null? x) '()) (else (require 'trace) `(trace ,@x)))) (defmacro track x (cond ((null? x) '()) (else (require 'track) `(track ,@x)))) (defmacro stack x (cond ((null? x) '()) (else (require 'stack) `(stack ,@x)))) (defmacro break x (cond ((null? x) '()) (else (require 'break) `(break ,@x)))) (defmacro defvar (var val) `(if (not (defined? ,var)) (define ,var ,val))) (defmacro defconst (name value) (cond ((list? name) `(defconst ,(car name) (lambda ,(cdr name) ,value))) (else (cond ((not (slib:eval `(defined? ,name)))) ((and (symbol? name) (equal? (slib:eval value) (slib:eval name)))) (else (error 'trying-to-defconst name 'to-different-value value))) `(define ,name ,value)))) (defmacro qase (key . clauses) `(case ,key ,@(map (lambda (clause) (if (list? (car clause)) (cons (apply append (map (lambda (elt) (case elt ((unquote) '(unquote)) ((unquote-splicing) '(unquote-splicing)) (else (eval (list 'quasiquote (list elt)))))) (car clause))) (cdr clause)) clause)) clauses))) (defmacro (casev . args) `(qase ,@args)) (defmacro fluid-let (clauses . body) (let ((ids (map car clauses)) (temp (gentemp)) (swap (gentemp))) `(let* ((,temp (list ,@(map cadr clauses))) (,swap (lambda () (set! ,temp (set! ,ids ,temp))))) (dynamic-wind ,swap (lambda () ,@body) ,swap)))) (define (scm:print-binding sexp frame) (cond ((not (null? (cdr sexp))) (display "In") (for-each (lambda (exp) (display #\space) (display exp)) (cdr sexp)) (display ": "))) (do ((vars (car frame) (cdr vars)) (vals (cdr frame) (cdr vals))) ((not (pair? vars)) (cond ((not (null? vars)) (write vars) (display " := ") (write (car vals)))) (newline)) (write (car vars)) (display " = ") (write (car vals)) (display "; "))) (define print-args (procedure->memoizing-macro (lambda (sexp env) (define (fix-list frm) (cond ((pair? frm) (cons (car frm) (fix-list (cdr frm)))) ((null? frm) '()) ((symbol? frm) (list frm)) (else '()))) (define frm (car env)) `(scm:print-binding ',sexp ,(cond ((symbol? frm) `(list ',frm ,frm)) ((list? frm) `(list ',frm ,@frm)) ((pair? frm) (let ((jlp (fix-list frm))) `(list ',(if (symbol? (cdr (last-pair frm))) frm jlp) ,@jlp)))))))) (cond ((defined? stack-trace) ;;#+breakpoint-error;; remove line to enable breakpointing on calls to ERROR (define error (letrec ((oerror error) (nerror (lambda args (dynamic-wind (lambda () (set! error oerror)) (lambda () (define cep (current-error-port)) (if (defined? print-call-stack) (print-call-stack cep)) (perror "ERROR") (errno 0) (display "ERROR: " cep) (if (not (null? args)) (begin (display (car args) cep) (for-each (lambda (x) (display #\space cep) (write x cep)) (cdr args)))) (newline cep) (cond ((stack-trace) (newline cep))) (display " * Breakpoint established: (continue ) to return." cep) (newline cep) (force-output cep) (require 'debug) (apply breakpoint args)) (lambda () (set! error nerror)))))) nerror)) (define (user-interrupt . args) (define cep (current-error-port)) (newline cep) (if (defined? print-call-stack) (print-call-stack cep)) (display "ERROR: user interrupt" cep) (newline cep) (cond ((stack-trace) (newline cep))) (display " * Breakpoint established: (continue ) to return." cep) (newline cep) (force-output cep) (require 'debug) (apply breakpoint args)) )) (cond ((and (inexact? (string->number "0.0")) (not (defined? exp))) (or (and (defined? usr:lib) (usr:lib "m") (load (in-vicinity (implementation-vicinity) "Transcen") (usr:lib "m"))) (load (in-vicinity (implementation-vicinity) "Transcen")))) (else (define (infinite? z) #f) (define finite? number?) (define inexact->exact identity) (define exact->inexact identity) (define round->exact identity) (define floor->exact identity) (define ceiling->exact identity) (define truncate->exact identity) (define expt integer-expt))) (define (numerator q) (if (not (rational? q)) (error 'numerator q)) (do ((num q (* 2 num))) ((integer? num) num))) (define (denominator q) (if (not (rational? q)) (error 'denominator q)) (do ((num q (* 2 num)) (den (- q q -1) (* 2 den))) ((integer? num) den))) ;@ (define (integer-log base k) (define (ilog m b k) (cond ((< k b) k) (else (set! n (+ n m)) (let ((q (ilog (+ m m) (* b b) (quotient k b)))) (cond ((< q b) q) (else (set! n (+ m n)) (quotient q b))))))) (define n 1) (define (eigt? k j) (and (exact? k) (integer? k) (> k j))) (cond ((not (and (eigt? base 1) (eigt? k 0))) (slib:error 'integer-log base k)) ((< k base) 0) (else (ilog 1 base (quotient k base)) n))) ;;;; http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/lisp/code/math/isqrt/isqrt.txt ;;; Akira Kurihara ;;; School of Mathematics ;;; Japan Women's University ;@ (define integer-sqrt (let ((table '#(0 1 1 1 2 2 2 2 2 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4)) (square (lambda (x) (* x x)))) (lambda (n) (define (isqrt n) (if (> n 24) (let* ((len/4 (quotient (- (integer-length n) 1) 4)) (top (isqrt (ash n (* -2 len/4)))) (init (ash top len/4)) (q (quotient n init)) (iter (quotient (+ init q) 2))) (cond ((odd? q) iter) ((< (remainder n init) (square (- iter init))) (- iter 1)) (else iter))) (vector-ref table n))) (if (and (exact? n) (integer? n) (not (negative? n))) (isqrt n) (slib:error 'integer-sqrt n))))) (if (defined? array?) (begin (define (array-null? array) (zero? (apply * (map (lambda (bnd) (- 1 (apply - bnd))) (array-shape array))))) (define (create-array prot . args) (if (array-null? prot) (dimensions->uniform-array args (array-prototype prot)) (dimensions->uniform-array args (array-prototype prot) (apply array-ref prot (map car (array-shape prot)))))) (define make-array create-array) (define (list->array rank proto lst) (list->uniform-array rank (array-prototype proto) lst)) (define (vector->array vect prototype . dimensions) (define vdx (vector-length vect)) (if (not (eqv? vdx (apply * dimensions))) (slib:error 'vector->array vdx '<> (cons '* dimensions))) (let ((ra (apply make-array prototype dimensions))) (define (v2ra dims idxs) (cond ((null? dims) (set! vdx (+ -1 vdx)) (apply array-set! ra (vector-ref vect vdx) (reverse idxs))) (else (do ((idx (+ -1 (car dims)) (+ -1 idx))) ((negative? idx) vect) (v2ra (cdr dims) (cons idx idxs)))))) (v2ra dimensions '()) ra)) (define (array->vector ra) (define dims (array-dimensions ra)) (let* ((vdx (apply * dims)) (vect (make-vector vdx))) (define (ra2v dims idxs) (if (null? dims) (let ((val (apply array-ref ra (reverse idxs)))) (set! vdx (+ -1 vdx)) (vector-set! vect vdx val) vect) (do ((idx (+ -1 (car dims)) (+ -1 idx))) ((negative? idx) vect) (ra2v (cdr dims) (cons idx idxs))))) (ra2v dims '()))) (define (make-uniform-wrapper prot) (if (string? prot) (set! prot (string->number prot))) (if prot (lambda opt (if (null? opt) (list->uniform-array 1 prot '()) (list->uniform-array 0 prot (car opt)))) vector)) (define Ac64 (make-uniform-wrapper "+64i")) (define Ac32 (make-uniform-wrapper "+32i")) (define Ar64 (make-uniform-wrapper "64.")) (define Ar32 (make-uniform-wrapper "32.")) (define As64 (make-uniform-wrapper -64)) (define As32 (make-uniform-wrapper -32)) (define As16 (make-uniform-wrapper -16)) (define As8 (make-uniform-wrapper -8)) (define Au64 (make-uniform-wrapper 64)) (define Au32 (make-uniform-wrapper 32)) (define Au16 (make-uniform-wrapper 16)) (define Au8 (make-uniform-wrapper 8)) (define At1 (make-uniform-wrapper #t)) ;;; New SRFI-58 names ;; flonums (define A:floC128b Ac64) (define A:floC64b Ac64) (define A:floC32b Ac32) (define A:floC16b Ac32) (define A:floR128b Ar64) (define A:floR64b Ar64) (define A:floR32b Ar32) (define A:floR16b Ar32) ;; decimal flonums (define A:floQ128d Ar64) (define A:floQ64d Ar64) (define A:floQ32d Ar32) ;; fixnums (define A:fixZ64b As64) (define A:fixZ32b As32) (define A:fixZ16b As16) (define A:fixZ8b As8) (define A:fixN64b Au64) (define A:fixN32b Au32) (define A:fixN16b Au16) (define A:fixN8b Au8) (define A:bool At1) (define (array-shape a) (let ((dims (array-dimensions a))) (if (pair? dims) (map (lambda (ind) (if (number? ind) (list 0 (+ -1 ind)) ind)) dims) dims))) (define array=? equal?) (provide 'srfi-47) (provide 'srfi-58) (provide 'srfi-63) )) (define (alarm-interrupt) (alarm 0)) (if (defined? setitimer) (begin (define profile-alarm #f) (define (profile-alarm-interrupt) (profile-alarm 0)) (define virtual-alarm #f) (define (virtual-alarm-interrupt) (virtual-alarm 0)) (define milli-alarm #f) (let ((make-alarm (lambda (sym) (and (setitimer sym 0 0) ;DJGPP supports only REAL and PROFILE (lambda (value . interval) (cadr (setitimer sym value (if (pair? interval) (car interval) 0)))))))) (set! profile-alarm (make-alarm 'profile)) (set! virtual-alarm (make-alarm 'virtual)) (set! milli-alarm (make-alarm 'real))))) ;;;; Initialize statically linked add-ons (cond ((defined? scm_init_extensions) (scm_init_extensions) (if (defined? *features*) (set! slib:features *features*)) (set! scm_init_extensions #f))) ;;; Use *argv* instead of (program-arguments), to allow option ;;; processing to be done on it. "ScmInit.scm" must ;;; (set! *argv* (program-arguments)) ;;; if it wants to alter the arguments which BOOT-TAIL processes. (define *argv* #f) (if (not (defined? *syntax-rules*)) (define *syntax-rules* #f)) (if (not (defined? *interactive*)) (define *interactive* #f)) (define (boot-tail dumped?) (cond ((not *argv*) (set! *argv* (program-arguments)) (cond (dumped? (set-vicinities! dumped?) (verbose (if (and (isatty? (current-input-port)) (isatty? (current-output-port))) (if (<= (length *argv*) 1) 2 1) 0)))) (cond ((provided? 'getopt) (set! *optind* 1) (set! *optarg* #f))))) ;;; This loads the user's initialization file, or files named in ;;; program arguments. (or *script* (eq? (software-type) 'THINKC) (member "-no-init-file" (program-arguments)) (member "--no-init-file" (program-arguments)) (try-load (in-vicinity (or (home-vicinity) (user-vicinity)) (string-append "ScmInit") (scheme-file-suffix)) *load-reader*) (errno 0)) ;; Include line numbers in loaded code. (if (defined? read-numbered) (set! *load-reader* read-numbered)) (cond ((and (> (length *argv*) 1) (char=? #\- (string-ref (cadr *argv*) 0))) (require 'getopt) ;;; (else ;;; (define *optind* 1) ;;; (define getopt:opt #f) ;;; (define (getopt optstring) #f)) (let* ((simple-opts "muvqibs") (arg-opts '("a kbytes" "-version" "-help" "-no-symbol-case-fold" "no-init-file" "-no-init-file" "p number" "h feature" "r feature" "d filename" "f filename" "l filename" "c string" "e string" "o filename")) (opts (apply string-append ":" simple-opts (map (lambda (o) (string-append (string (string-ref o 0)) ":")) arg-opts))) (didsomething #f) (moreopts #t) (exe-name (symbol->string (scheme-implementation-type))) (up-name (apply string (map char-upcase (string->list exe-name))))) (define (do-thunk thunk) (if *interactive* (thunk) (let ((complete #f)) (dynamic-wind (lambda () #f) (lambda () (thunk) (set! complete #t)) (lambda () (if (not complete) (close-port (current-input-port)))))))) (define (do-string-arg) (require 'string-port) (do-thunk (lambda () ((if *syntax-rules* macro:eval eval) (call-with-input-string (string-append "(begin " *optarg* ")") read)))) (set! didsomething #t)) (define (do-load file) (do-thunk (lambda () (cond (*syntax-rules* (require 'macro) (macro:load file)) (else (load file))))) (set! didsomething #t)) (define (usage preopt opt postopt success?) (define cep (if success? (current-output-port) (current-error-port))) (define indent (make-string 6 #\space)) (define i 3) (cond ((char? opt) (set! opt (string opt))) ;;((symbol? opt) (set! opt (symbol->string opt))) ) (display (string-append preopt opt postopt) cep) (newline cep) (display (string-append "Usage: " exe-name " [-a kbytes] [-" simple-opts "]") cep) (for-each (lambda (o) (display (string-append " [-" o "]") cep) (set! i (+ 1 i)) (cond ((zero? (modulo i 5)) (newline cep) (display indent cep)))) (cdr arg-opts)) (display " [-- | -s | -] [file] [args...]" cep) (newline cep) (if success? (display success? cep) (quit #f))) ;; -a int => ignore (handled by scm_init_from_argv) ;; -c str => (eval str) ;; -e str => (eval str) ;; -d str => (require 'databases) (open-database str) ;; -f str => (load str) ;; -l str => (load str) ;; -r sym => (require sym) ;; -h sym => (provide sym) ;; -o str => (dump str) ;; -p int => (verbose int) ;; -m => (set! *syntax-rules* #t) ;; -u => (set! *syntax-rules* #f) ;; -v => (verbose 3) ;; -q => (verbose 0) ;; -i => (set! *interactive* #t) ;; -b => (set! *interactive* #f) ;; -s => set argv, don't execute first one ;; --no-symbol-case-fold => symbols preserve character case ;; -no-init-file => don't load init file ;; --no-init-file => don't load init file ;; --help => print and exit ;; --version => print and exit ;; -- => last option (let loop ((option (getopt-- opts))) (case option ((#\a) (cond ((> *optind* 3) (usage "scm: option `-" getopt:opt "' must be first" #f)) ((or (not (exact? (string->number *optarg*))) (not (<= 1 (string->number *optarg*) 10000))) ;; This size limit should match scm.c ^^ (usage "scm: option `-" getopt:opt (string-append *optarg* "' unreasonable") #f)))) ((#\e #\c) (do-string-arg)) ;sh-like ((#\f #\l) (do-load *optarg*)) ;(set-car! *argv* *optarg*) ((#\d) (require 'databases) (open-database *optarg*)) ((#\o) (require 'dump) (if (< *optind* (length *argv*)) (dump *optarg* #t) (dump *optarg*))) ((#\r) (do-thunk (lambda () (if (and (= 1 (string-length *optarg*)) (char-numeric? (string-ref *optarg* 0))) (case (string-ref *optarg* 0) ((#\2) (require 'r2rs)) ((#\3) (require 'r3rs)) ((#\4) (require 'r4rs)) ((#\5) (require 'r5rs) (set! *syntax-rules* #t)) (else (require (string->symbol *optarg*)))) (require (string->symbol *optarg*)))))) ((#\h) (do-thunk (lambda () (provide (string->symbol *optarg*))))) ((#\p) (verbose (string->number *optarg*))) ((#\q) (verbose 0)) ((#\v) (verbose 3)) ((#\i) (set! *interactive* #t) ;sh-like (verbose (max 2 (verbose)))) ((#\b) (set! didsomething #t) (set! *interactive* #f)) ((#\s) (set! moreopts #f) ;sh-like (set! didsomething #t) (set! *interactive* #t)) ((#\m) (set! *syntax-rules* #t)) ((#\u) (set! *syntax-rules* #f)) ((#\n) (if (not (string=? "o-init-file" *optarg*)) (usage "scm: unrecognized option `-n" *optarg* "'" #f))) ((#\:) (usage "scm: option `-" getopt:opt "' requires an argument" #f)) ((#\?) (usage "scm: unrecognized option `-" getopt:opt "'" #f)) ((#f) (set! moreopts #f) ;sh-like (cond ((and (< *optind* (length *argv*)) (string=? "-" (list-ref *argv* *optind*))) (set! *optind* (+ 1 *optind*))))) (else (or (cond ((not (string? option)) #f) ((string-ci=? "no-init-file" option)) ((string-ci=? "no-symbol-case-fold" option)) ((string-ci=? "version" option) (display (string-append exe-name " " (scheme-implementation-version) " Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. " up-name " may be distributed under the terms of" " the GNU General Public Licence; certain other uses are permitted as well." " For details, see the file `COPYING', which is included in the " up-name " distribution. There is no warranty, to the extent permitted by law. " )) (cond ((execpath) => (lambda (path) (display " This executable was loaded from ") (write path) (newline)))) (quit #t)) ((string-ci=? "help" option) (usage "This is " up-name ", a Scheme interpreter." (let ((sihp (scheme-implementation-home-page))) (if sihp (string-append "Latest info: " sihp " ") ""))) (quit #t)) (else #f)) (usage "scm: unknown option `--" option "'" #f)))) (cond ((and moreopts (< *optind* (length *argv*))) (loop (getopt-- opts))) ((< *optind* (length *argv*)) ;No more opts (set! *argv* (list-tail *argv* *optind*)) (set! *optind* 1) (cond ((and (not didsomething) *script*) (do-load *script*) (set! *optind* (+ 1 *optind*)))) (cond ((and (> (verbose) 2) (not (= (+ -1 *optind*) (length *argv*)))) (display "scm: extra command arguments unused:" (current-error-port)) (for-each (lambda (x) (display (string-append " " x) (current-error-port))) (list-tail *argv* (+ -1 *optind*))) (newline (current-error-port))))) ((and (not didsomething) (= *optind* (length *argv*))) (set! *interactive* #t))))) (cond ((not *interactive*) (quit)) ((and *syntax-rules* (not (provided? 'macro))) (require 'repl) (require 'macro) (let* ((oquit quit)) (set! quit (lambda () (repl:quit))) (set! exit quit) (repl:top-level macro:eval) (oquit)))) ;;otherwise, fall into natural SCM repl. ) (else (errno 0) (set! *interactive* #t) (for-each load (cdr (program-arguments)))))) scm-5e5/requires.scm0000644001705200017500000000140610722100222012362 0ustar tbtb;;; "require.scm" Trampoline to slib/require.scm (define library-vicinity (let* ((vl (case (software-type) ((amiga) '(#\: #\/)) ((ms-dos windows atarist os/2) '(#\\ #\/)) ((macos thinkc) '(#\:)) ((nosve) '(#\: #\.)) ((unix coherent plan9) '(#\/)) ((vms) '(#\: #\])))) (iv (implementation-vicinity)) (vc (and (positive? (string-length iv)) (string-ref iv (+ -1 (string-length iv))))) (vs (if (memv vc vl) (string vc) "/")) (lv (let loop ((pos (+ -2 (string-length iv)))) (cond ((or (< pos 0) (not vs)) (string-append iv ".." vs "slib" vs)) ((memv (string-ref iv pos) vl) (string-append (substring iv 0 (+ 1 pos)) "slib" vs)) (else (loop (- pos 1))))))) (lambda () lv))) scm-5e5/scm.h0000644001705200017500000012473310750224617011003 0ustar tbtb/* "scm.h" SCM data types and external functions. * Copyright (C) 1990-2006 Free Software Foundation, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see * . */ #ifdef __cplusplus extern "C" { #endif #ifdef _WIN32 # include #endif #ifdef _WIN32_WCE # include #endif #ifdef hpux # ifndef __GNUC__ # define const /**/ # endif #endif #ifdef PLAN9 # include # include /* Simple imitation of some Unix system calls */ # define exit(val) exits("") # define getcwd getwd /* we have our own isatty */ int isatty (int); #endif typedef long SCM; typedef struct {SCM car, cdr;} cell; typedef struct {long sname;SCM (*cproc)();} subr; typedef struct {long sname;double (*dproc)();} dsubr; typedef struct {const char *string;SCM (*cproc)();} iproc; typedef struct {const char *name;} subr_info; #include #include "scmfig.h" #ifdef _WIN32 # ifdef SCM_WIN_DLL # define SCM_DLL_EXPORT __declspec(dllexport) # define SCM_EXPORT SCM_DLL_EXPORT # else # define SCM_DLL_EXPORT /**/ # define SCM_EXPORT extern # endif #else # define SCM_DLL_EXPORT /**/ # define SCM_EXPORT extern #endif typedef struct { sizet eltsize; sizet len; sizet alloclen; sizet maxlen; const char *what; char *elts;} scm_gra; #ifdef USE_ANSI_PROTOTYPES # define P(s) s #else # define P(s) () #endif #ifndef STDC_HEADERS int isatty P((int)); #endif typedef struct { SCM (*mark)P((SCM)); sizet (*free)P((CELLPTR)); int (*print)P((SCM exp, SCM port, int writing)); SCM (*equalp)P((SCM, SCM)); } smobfuns; typedef struct { char *name; SCM (*mark)P((SCM ptr)); int (*free)P((FILE *p)); int (*print)P((SCM exp, SCM port, int writing)); SCM (*equalp)P((SCM, SCM)); int (*fputc)P((int c, FILE *p)); /* int (*fputs)P((char *s, FILE *p)); */ /* sizet (*fwrite)P((char *s, sizet siz, sizet num, FILE *p)); */ int (*fputs)P((const char *s, FILE *p)); sizet (*fwrite)P((const void *s, sizet siz, sizet num, FILE *p)); int (*fflush)P((FILE *stream)); int (*fgetc)P((FILE *p)); int (*fclose)P((FILE *p)); int (*ungetc)P((int c, SCM p)); } ptobfuns; typedef struct { SCM data; SCM port; long flags; long line; int unread; short col; short colprev; } port_info; typedef struct { SCM v; sizet base; } array; typedef struct { long lbnd; long ubnd; long inc; } array_dim; #ifdef FLOATS typedef struct {char *string;double (*cproc)P((double));} dblproc; # ifdef SINGLES # ifdef CDR_DOUBLES typedef struct {SCM type;double num;} flo; # else typedef struct {SCM type;float num;} flo; # endif # endif typedef struct {SCM type;double *real;} dbl; #endif /* Conditionals should always expect immediates */ /* GCC __builtin_expect() is stubbed in scmfig.h */ #define IMP(x) SCM_EXPECT_TRUE(6 & PTR2INT(x)) #define NIMP(x) (!IMP(x)) #define INUMP(x) SCM_EXPECT_TRUE(2 & PTR2INT(x)) #define NINUMP(x) (!INUMP(x)) #define INUM0 ((SCM) 2) #define ICHRP(x) ((0xff & PTR2INT(x))==0xf4) #define ICHR(x) ((unsigned char)((x)>>8)) #define MAKICHR(x) (((x)<<8)+0xf4L) #define ILOC00 (0x000000fcL) #define ILOCP(n) ((0xff & PTR2INT(n))==PTR2INT(ILOC00)) #define MAKILOC(if, id) (ILOC00 + (((long)id)<<8) + (((long)if)<<16)) #define IDIST(n) ((PTR2INT(n)>>8) & 0x7f) #define IFRAME(n) ((PTR2INT(n)>>16)) #define ICDRP(n) (ICDR & (n)) #define ICDR (1L<<15) /* ISYMP tests for ISPCSYM and ISYM */ #define ISYMP(n) ((0x187 & PTR2INT(n))==4) /* IFLAGP tests for ISPCSYM, ISYM and IFLAG */ #define IFLAGP(n) ((0x87 & PTR2INT(n))==4) #define ISYMNUM(n) ((PTR2INT((n)>>9)) & 0x7f) #define ISYMVAL(n) (PTR2INT((n)>>16)) #define MAKISYMVAL(isym, val) ((isym) | ((long)(val) <<16)) #define ISYMCHARS(n) (isymnames[ISYMNUM(n)]) #define MAKSPCSYM(n) (((n)<<9)+((n)<<3)+4L) #define MAKISYM(n) (((n)<<9)+0x74L) #define MAKIFLAG(n) (((n)<<9)+0x174L) /* This is to make the print representation of some evaluated code, as in backtraces, make a little more sense. */ #define MAKSPCSYM2(work, look) ((127L & (work)) | ((127L<<9) & (look))) SCM_EXPORT char *isymnames[]; #define NUM_ISPCSYM 14 #define IM_AND MAKSPCSYM(0) #define IM_BEGIN MAKSPCSYM(1) #define IM_CASE MAKSPCSYM(2) #define IM_COND MAKSPCSYM(3) #define IM_DO MAKSPCSYM(4) #define IM_IF MAKSPCSYM(5) #define IM_LAMBDA MAKSPCSYM(6) #define IM_LET MAKSPCSYM(7) #define IM_LETSTAR MAKSPCSYM(8) #define IM_LETREC MAKSPCSYM(9) #define IM_OR MAKSPCSYM(10) #define IM_QUOTE MAKSPCSYM(11) #define IM_SET MAKSPCSYM(12) #define IM_FUNCALL MAKSPCSYM(13) #define s_and (ISYMCHARS(IM_AND)+2) #define s_begin (ISYMCHARS(IM_BEGIN)+2) #define s_case (ISYMCHARS(IM_CASE)+2) #define s_cond (ISYMCHARS(IM_COND)+2) #define s_do (ISYMCHARS(IM_DO)+2) #define s_if (ISYMCHARS(IM_IF)+2) #define s_lambda (ISYMCHARS(IM_LAMBDA)+2) #define s_let (ISYMCHARS(IM_LET)+2) #define s_letstar (ISYMCHARS(IM_LETSTAR)+2) #define s_letrec (ISYMCHARS(IM_LETREC)+2) #define s_or (ISYMCHARS(IM_OR)+2) #define s_quote (ISYMCHARS(IM_QUOTE)+2) #define s_set (ISYMCHARS(IM_SET)+2) #define s_define (ISYMCHARS(IM_DEFINE)+2) #define s_delay (ISYMCHARS(IM_DELAY)+2) #define s_quasiquote (ISYMCHARS(IM_QUASIQUOTE)+2) #define s_let_syntax (ISYMCHARS(IM_LET_SYNTAX)+2) SCM_EXPORT SCM i_dot, i_quote, i_quasiquote, i_unquote, i_uq_splicing; #define s_apply (ISYMCHARS(IM_APPLY)+2) /* each symbol defined here must have a unique number which corresponds to it's position in isymnames[] in repl.c */ /* These are used for dispatch in eval.c */ #define IM_APPLY MAKISYM(14) #define IM_FARLOC_CAR MAKISYM(15) #define IM_FARLOC_CDR MAKISYM(16) #define IM_DELAY MAKISYM(17) #define IM_QUASIQUOTE MAKISYM(18) #define IM_EVAL_FOR_APPLY MAKISYM(19) #define IM_LET_SYNTAX MAKISYM(20) #define IM_ACRO_CALL MAKISYM(21) #define IM_LINUM MAKISYM(22) #define IM_DEFINE MAKISYM(23) #define IM_EVAL_VALUES MAKISYM(24) /* These are not used for dispatch. */ #define IM_UNQUOTE MAKISYM(25) #define IM_UQ_SPLICING MAKISYM(26) #define IM_ELSE MAKISYM(27) #define IM_ARROW MAKISYM(28) #define IM_VALUES_TOKEN MAKISYM(29) #define IM_KEYWORD MAKISYM(30) #define NUM_ISYMS 31 #define SCM_MAKE_LINUM(n) (IM_LINUM | ((unsigned long)(n))<<16) #define SCM_LINUM(x) ((unsigned long)(x)>>16) #define SCM_LINUMP(x) ((0xffffL & (x))==IM_LINUM) #define BOOL_F MAKIFLAG(NUM_ISYMS+0) #define BOOL_T MAKIFLAG(NUM_ISYMS+1) #define UNDEFINED MAKIFLAG(NUM_ISYMS+2) #define EOF_VAL MAKIFLAG(NUM_ISYMS+3) #ifdef SICP # define EOL BOOL_F #else # define EOL MAKIFLAG(NUM_ISYMS+4) #endif #define UNSPECIFIED MAKIFLAG(NUM_ISYMS+5) #define NUM_IFLAGS NUM_ISYMS+6 /* Now some unnamed flags used as magic cookies by scm_top_level. */ /* Argument n can range from -4 to 16 */ #ifdef SHORT_INT # define COOKIE(n) (n) # define UNCOOK(f) (f) #else # define COOKIE(n) MAKIFLAG(NUM_IFLAGS+4+n) # define UNCOOK(f) (ISYMNUM(f)-(NUM_IFLAGS+4)) #endif #define FALSEP(x) (BOOL_F==(x)) #define NFALSEP(x) (BOOL_F != (x)) /* BOOL_NOT returns the other boolean. The order of ^s here is important for Borland C++. */ #define BOOL_NOT(x) ((x) ^ (BOOL_T ^ BOOL_F)) #define NULLP(x) (EOL==(x)) #define NNULLP(x) (EOL != (x)) #define UNBNDP(x) (UNDEFINED==(x)) #define CELLP(x) (!NCELLP(x)) #define NCELLP(x) ((sizeof(cell)-1) & PTR2INT(x)) #define GCMARKP(x) (1 & PTR2INT(CDR(x))) #define GC8MARKP(x) (0x80 & PTR2INT(CAR(x))) #define SETGCMARK(x) CDR(x) |= 1; #define CLRGCMARK(x) CDR(x) &= ~1L; #define SETGC8MARK(x) CAR(x) |= 0x80; #define CLRGC8MARK(x) CAR(x) &= ~0x80L; #define TYP3(x) (7 & PTR2INT(CAR(x))) #define TYP7(x) (0x7f & PTR2INT(CAR(x))) #define TYP7S(x) (0x7d & PTR2INT(CAR(x))) #define TYP16(x) (0xffff & PTR2INT(CAR(x))) #define TYP16S(x) (0xfeff & PTR2INT(CAR(x))) #define GCTYP16(x) (0xff7f & PTR2INT(CAR(x))) #define NCONSP(x) (1 & PTR2INT(CAR(x))) #define CONSP(x) (!NCONSP(x)) #define ECONSP(x) (CONSP(x) || (1==TYP3(x))) #define NECONSP(x) (NCONSP(x) && (1 != TYP3(x))) #define SCM_GLOCP(x) (tc3_cons_gloc==(7 & PTR2INT(x))) #define CAR(x) (((cell *)(SCM2PTR(x)))->car) #define CDR(x) (((cell *)(SCM2PTR(x)))->cdr) #define GCCDR(x) (~1L & CDR(x)) #define SETCDR(x, v) CDR(x) = (SCM)(v) #ifdef _M_ARM /* MS CLARM compiler bug workaround. */ volatile SCM MS_CLARM_dumy; # define CODE(x) (MS_CLARM_dumy = (CAR(x)-tc3_closure)) #else # define CODE(x) (CAR(x)-tc3_closure) #endif #define CLOSUREP(x) (TYP3(x)==tc3_closure) #define SETCODE(x, e) CAR(x) = (e)+tc3_closure #define ENV(x) ((~7L & CDR(x)) ? (~7L & CDR(x)) : EOL) #define GCENV ENV #define ARGC(x) ((6L & CDR(x))>>1) #ifdef CAUTIOUS # define SCM_ESTK_FRLEN 4 #else # define SCM_ESTK_FRLEN 3 #endif #define SCM_ESTK_BASE 4 #define SCM_ESTK_PARENT(v) (VELTS(v)[0]) #define SCM_ESTK_PARENT_WRITABLEP(v) (VELTS(v)[1]) #define SCM_ESTK_PARENT_INDEX(v) (VELTS(v)[2]) SCM_EXPORT long tc16_env, tc16_ident; #define ENVP(x) (tc16_env==TYP16(x)) #define SCM_ENV_FORMALS CAR #ifdef MACRO # define M_IDENTP(x) (tc16_ident==TYP16(x)) # define M_IDENT_LEXP(x) ((tc16_ident | (1L<<16))==CAR(x)) # define IDENTP(x) (SYMBOLP(x) || M_IDENTP(x)) # define IDENT_PARENT(x) (M_IDENT_LEXP(x) ? CAR(CDR(x)) : CDR(x)) # define IDENT_ENV(x) (M_IDENT_LEXP(x) ? CDR(CDR(x)) : BOOL_F) #else # define IDENTP SYMBOLP # define M_IDENTP(x) (0) #endif /* markers for various static environment frame types */ /* FIXME these need to be exported somehow to Scheme */ #ifdef CAUTIOUS # define SCM_ENV_FILENAME MAKINUM(1) # define SCM_ENV_PROCNAME MAKINUM(2) #endif #define SCM_ENV_DOC MAKINUM(3) #define SCM_ENV_ANNOTATION MAKINUM(4) #define SCM_ENV_CONSTANT MAKINUM(5) #define SCM_ENV_SYNTAX MAKINUM(6) #define SCM_ENV_END MAKINUM(7) #define PORTP(x) (TYP7(x)==tc7_port) #define OPPORTP(x) (((0x7f | OPN) & CAR(x))==(tc7_port | OPN)) #define OPINPORTP(x) (((0x7f | OPN | RDNG) & CAR(x))==(tc7_port | OPN | RDNG)) #define OPOUTPORTP(x) (((0x7f | OPN | WRTNG) & CAR(x))==(tc7_port | OPN | WRTNG)) #define OPIOPORTP(x) (((0x7f | OPN | RDNG | WRTNG) & CAR(x))==(tc7_port | OPN | RDNG | WRTNG)) #define FPORTP(x) (TYP16S(x)==tc7_port) #define OPFPORTP(x) (((0xfeff | OPN) & CAR(x))==(tc7_port | OPN)) #define OPINFPORTP(x) (((0xfeff | OPN | RDNG) & CAR(x))==(tc7_port | OPN | RDNG)) #define OPOUTFPORTP(x) (((0xfeff | OPN | WRTNG) & CAR(x))==(tc7_port | OPN | WRTNG)) #define INPORTP(x) (((0x7f | RDNG) & CAR(x))==(tc7_port | RDNG)) #define OUTPORTP(x) (((0x7f | WRTNG) & CAR(x))==(tc7_port | WRTNG)) #define OPENP(x) (OPN & CAR(x)) #define CLOSEDP(x) (!OPENP(x)) #define STREAM(x) ((FILE *)(CDR(x))) #define SETSTREAM SETCDR #define CRDYP(port) ((CAR(port) & CRDY) && (EOF != CGETUN(port))) #define CLRDY(port) (CAR(port) &= (SCM_PORTFLAGS(port) | (~0xf0000))) #define CGETUN(port) (scm_port_table[SCM_PORTNUM(port)].unread) #define tc_socket (tc7_port | OPN) #define SOCKP(x) (((0x7f | OPN | RDNG | WRTNG) & CAR(x))==(tc_socket)) #define SOCKTYP(x) (INUM(SCM_PORTDATA(x))) #define DIRP(x) (NIMP(x) && (TYP16(x)==(tc16_dir))) #define OPDIRP(x) (NIMP(x) && (CAR(x)==(tc16_dir | OPN))) #ifdef FLOATS # define INEXP(x) (TYP16(x)==tc16_flo) # define CPLXP(x) (CAR(x)==tc_dblc) # define REAL(x) (*(((dbl *) (SCM2PTR(x)))->real)) # define IMAG(x) (*((double *)(CHARS(x)+sizeof(double)))) /* ((&REAL(x))[1]) */ # ifdef SINGLES # define REALP(x) ((~REAL_PART & CAR(x))==tc_flo) # define SINGP(x) SCM_EXPECT_TRUE(CAR(x)==tc_flo) # define FLO(x) (((flo *)(SCM2PTR(x)))->num) # define REALPART(x) (SINGP(x)?0.0+FLO(x):REAL(x)) # else /* SINGLES */ # define REALP(x) (CAR(x)==tc_dblr) # define REALPART REAL # endif /* SINGLES */ #endif #ifdef FLOATS # define NUMBERP(x) (INUMP(x) || (NIMP(x) && NUMP(x))) #else # ifdef BIGDIG # define NUMBERP(x) (INUMP(x) || (NIMP(x) && NUMP(x))) # else # define NUMBERP INUMP # endif #endif #define NUMP(x) ((0xfcff & PTR2INT(CAR(x)))==tc7_smob) #define BIGP(x) (TYP16S(x)==tc16_bigpos) #define BIGSIGN(x) (0x0100 & PTR2INT(CAR(x))) #define BDIGITS(x) ((BIGDIG *)(CDR(x))) #define NUMDIGS(x) ((sizet)(((unsigned long)CAR(x))>>16)) #define MAKE_NUMDIGS(v, t) ((((v)+0L)<<16)+(t)) #define SETNUMDIGS(x, v, t) CAR(x) = MAKE_NUMDIGS(v, t) #define SNAME(x) ((char *)(subrs[NUMDIGS(x)].name)) #define SUBRF(x) (((subr *)(SCM2PTR(x)))->cproc) #define DSUBRF(x) (((dsubr *)(SCM2PTR(x)))->dproc) #define CCLO_SUBR(x) (VELTS(x)[0]) #define CCLO_LENGTH NUMDIGS #define CXR_OP SMOBNUM #define SYMBOLP(x) (TYP7S(x)==tc7_ssymbol) #define STRINGP(x) (TYP7(x)==tc7_string) #define NSTRINGP(x) (!STRINGP(x)) #define BYTESP(x) (TYP7(x)==tc7_VfixN8) #define VECTORP(x) (TYP7(x)==tc7_vector) #define NVECTORP(x) (!VECTORP(x)) #define LENGTH(x) (((unsigned long)CAR(x))>>8) #define LENGTH_MAX (((unsigned long)-1L)>>8) #define MAKE_LENGTH(v, t) ((((v)+0L)<<8) + (t)) #define SETLENGTH(x, v, t) CAR(x) = MAKE_LENGTH(v, t) #define CHARS(x) ((char *)(CDR(x))) #define UCHARS(x) ((unsigned char *)(CDR(x))) #define VELTS(x) ((SCM *)CDR(x)) #define SETCHARS SETCDR #define SETVELTS SETCDR SCM_EXPORT long tc16_array; #define ARRAYP(a) (tc16_array==TYP16(a)) #define ARRAY_V(a) (((array *)CDR(a))->v) /*#define ARRAY_NDIM(x) NUMDIGS(x)*/ #define ARRAY_NDIM(x) ((sizet)(CAR(x)>>17)) #define ARRAY_CONTIGUOUS 0x10000 #define ARRAY_CONTP(x) (ARRAY_CONTIGUOUS & PTR2INT(CAR(x))) #define ARRAY_BASE(a) (((array *)CDR(a))->base) #define ARRAY_DIMS(a) ((array_dim *)(CHARS(a)+sizeof(array))) #define FREEP(x) (CAR(x)==tc_free_cell) #define NFREEP(x) (!FREEP(x)) #define SMOBNUM(x) (0x0ff & (CAR(x)>>8)) #define PTOBNUM(x) (0x0ff & (CAR(x)>>8)) #define SCM_PORTNUM(x) ((int)(((unsigned long)CAR(x))>>20)) #define SCM_PORTNUM_MAX ((int)((0x7fffUL<<20)>>20)) #define SCM_PORTFLAGS(x) (scm_port_table[SCM_PORTNUM(x)].flags) #define SCM_PORTDATA(x) (scm_port_table[SCM_PORTNUM(x)].data) #define SCM_SETFLAGS(x, flags) (CAR(x) = (CAR(x) & ~0x0f0000L) | (flags)) /* This is used (only) for closing ports. */ #define SCM_SET_PTOBNUM(x, typ) (CAR(x)=(typ)|(CAR(x) & ~0x0ffffL)) #define DIGITS '0':case '1':case '2':case '3':case '4':\ case '5':case '6':case '7':case '8':case '9' /* Aggregated types for dispatch in switch statements. */ #define tcs_cons_inum 2: case 6:case 10:case 14:\ case 18:case 22:case 26:case 30:\ case 34:case 38:case 42:case 46:\ case 50:case 54:case 58:case 62:\ case 66:case 70:case 74:case 78:\ case 82:case 86:case 90:case 94:\ case 98:case 102:case 106:case 110:\ case 114:case 118:case 122:case 126 #define tcs_cons_iloc 124 #define tcs_cons_ispcsym 4:case 12:case 20:case 28:\ case 36:case 44:case 52:case 60:\ case 68:case 76:case 84:case 92:\ case 100:case 108 #define tcs_cons_chflag 116 /* char *or* flag */ #define tcs_cons_imcar tcs_cons_inum:\ case tcs_cons_iloc:\ case tcs_cons_ispcsym:\ case tcs_cons_chflag #define tcs_cons_nimcar 0:case 8:case 16:case 24:\ case 32:case 40:case 48:case 56:\ case 64:case 72:case 80:case 88:\ case 96:case 104:case 112:case 120 #define tcs_cons_gloc 1:case 9:case 17:case 25:\ case 33:case 41:case 49:case 57:\ case 65:case 73:case 81:case 89:\ case 97:case 105:case 113:case 121 #define tcs_closures 3:case 11:case 19:case 27:\ case 35:case 43:case 51:case 59:\ case 67:case 75:case 83:case 91:\ case 99:case 107:case 115:case 123 #define tcs_subrs tc7_asubr:case tc7_subr_0:case tc7_subr_1:case tc7_cxr:\ case tc7_subr_3:case tc7_subr_2:case tc7_rpsubr:case tc7_subr_1o:\ case tc7_subr_2o:case tc7_lsubr_2:case tc7_lsubr #define tcs_symbols tc7_ssymbol:case tc7_msymbol #define tcs_bignums tc16_bigpos:case tc16_bigneg #define tcs_uves tc7_string:case tc7_Vbool:case tc7_VfixN8:case tc7_VfixZ8:\ case tc7_VfixN16:case tc7_VfixZ16:case tc7_VfixN32:case tc7_VfixZ32:\ case tc7_VfloR32:case tc7_VfloC32:case tc7_VfloR64:case tc7_VfloC64 #define tc3_cons_nimcar 0 #define tc3_cons_imcar 2:case 4:case 6 #define tc3_cons_gloc 1 #define tc3_closure 3 #define tc3_tc7_types 5:case 7 #define tc7_ssymbol 5 #define tc7_msymbol 7 #define tc7_string 13 #define tc7_vector 15 #define tc7_Vbool 21 /* 23 */ #define tc7_VfixN8 29 #define tc7_VfixZ8 31 #define tc7_VfixN16 37 #define tc7_VfixZ16 39 #define tc7_VfixN32 45 #define tc7_VfixZ32 47 #define tc7_VfloR32 53 #define tc7_VfloC32 55 #define tc7_VfloR64 61 #define tc7_VfloC64 63 /* 69 */ #define tc7_port 71 #define tc7_contin 77 #define tc7_specfun 79 #define tc7_subr_0 85 #define tc7_subr_1 87 #define tc7_cxr 93 #define tc7_subr_3 95 #define tc7_subr_2 101 #define tc7_asubr 103 #define tc7_subr_1o 109 #define tc7_subr_2o 111 #define tc7_lsubr_2 117 #define tc7_lsubr 119 #define tc7_rpsubr 125 #define tc7_smob 127 #define tc_free_cell 127 #define tc_broken_heart (tc_free_cell+0x10000) #define tc16_apply (tc7_specfun | (0L<<8)) #define tc16_call_cc (tc7_specfun | (1L<<8)) #define tc16_cclo (tc7_specfun | (2L<<8)) #define tc16_eval (tc7_specfun | (3L<<8)) #define tc16_values (tc7_specfun | (4L<<8)) #define tc16_call_wv (tc7_specfun | (5L<<8)) #define tc16_flo 0x017f #define tc_flo 0x017fL #define REAL_PART (1L<<16) #define IMAG_PART (2L<<16) #define tc_dblr (tc16_flo|REAL_PART) #define tc_dblc (tc16_flo|REAL_PART|IMAG_PART) #define tc16_bigpos 0x027f #define tc16_bigneg 0x037f /* The first four flags fit in the car of a port cell, remaining flags only in the port table */ #define OPN (1L<<16) #define RDNG (2L<<16) #define WRTNG (4L<<16) #define CRDY (8L<<16) #define TRACKED (16L<<16) #define BINARY (32L<<16) #define BUF0 (64L<<16) #define EXCLUSIVE (128L<<16) /* LSB is used for gc mark */ SCM_EXPORT scm_gra subrs_gra; #define subrs ((subr_info *)(subrs_gra.elts)) /* SCM_EXPORT sizet numsmob, numptob; SCM_EXPORT smobfuns *smobs; SCM_EXPORT ptobfuns *ptobs; SCM_EXPORT ptobfuns pipob; */ SCM_EXPORT scm_gra smobs_gra; #define numsmob (smobs_gra.len) #define smobs ((smobfuns *)(smobs_gra.elts)) SCM_EXPORT scm_gra ptobs_gra; #define numptob (ptobs_gra.len) #define ptobs ((ptobfuns *)(ptobs_gra.elts)) SCM_EXPORT port_info *scm_port_table; #define tc16_fport (tc7_port + 0*256L) #define tc16_pipe (tc7_port + 1*256L) #define tc16_strport (tc7_port + 2*256L) #define tc16_sfport (tc7_port + 3*256L) SCM_EXPORT long tc16_dir; SCM_EXPORT long tc16_clport; SCM_EXPORT SCM sys_protects[]; #define cur_inp sys_protects[0] #define cur_outp sys_protects[1] #define cur_errp sys_protects[2] #define def_inp sys_protects[3] #define def_outp sys_protects[4] #define def_errp sys_protects[5] #define sys_errp sys_protects[6] #define sys_safep sys_protects[7] #define listofnull sys_protects[8] #define undefineds sys_protects[9] #define nullvect sys_protects[10] #define nullstr sys_protects[11] #define progargs sys_protects[12] #define loadports sys_protects[13] #define rootcont sys_protects[14] #define dynwinds sys_protects[15] #define list_unspecified sys_protects[16] #define f_evapply sys_protects[17] #define eval_env sys_protects[18] #define f_apply_closure sys_protects[19] #define flo0 sys_protects[20] #define scm_uprotects sys_protects[21] #define scm_narn sys_protects[22] #define NUM_PROTECTS 23 /* now for connects between source files */ /* SCM_EXPORT sizet num_finals; SCM_EXPORT void (**finals)P((void)); SCM_EXPORT sizet num_finals; */ SCM_EXPORT scm_gra finals_gra; #define num_finals (finals_gra.len) #define finals ((void (**)())(finals_gra.elts)) SCM_EXPORT unsigned char upcase[], downcase[]; SCM_EXPORT SCM symhash; SCM_EXPORT int symhash_dim; SCM_EXPORT long heap_cells; SCM_EXPORT CELLPTR heap_org; SCM_EXPORT VOLATILE SCM freelist; SCM_EXPORT long gc_cells_collected, gc_malloc_collected, gc_ports_collected; SCM_EXPORT long gc_syms_collected; SCM_EXPORT long cells_allocated, lcells_allocated, mallocated, lmallocated; SCM_EXPORT long mtrigger; SCM_EXPORT SCM *loc_loadpath; SCM_EXPORT SCM *loc_errobj; SCM_EXPORT SCM loadport; SCM_EXPORT char *errjmp_bad; SCM_EXPORT VOLATILE int ints_disabled; SCM_EXPORT int output_deferred, gc_hook_pending, gc_hook_active; SCM_EXPORT unsigned long SIG_deferred; SCM_EXPORT SCM exitval; SCM_EXPORT int cursinit; SCM_EXPORT unsigned int poll_count, tick_count; SCM_EXPORT int dumped; SCM_EXPORT char *execpath; SCM_EXPORT char s_no_execpath[]; SCM_EXPORT int scm_verbose; #define verbose (scm_verbose+0) SCM_EXPORT const char dirsep[]; /* strings used in several source files */ SCM_EXPORT char s_write[], s_newline[], s_system[]; SCM_EXPORT char s_make_string[], s_make_vector[], s_list[], s_op_pipe[]; #define s_string (s_make_string+5) #define s_vector (s_make_vector+5) #define s_pipe (s_op_pipe+5) SCM_EXPORT char s_make_sh_array[]; SCM_EXPORT char s_array_fill[]; #define s_array (s_make_sh_array+12) SCM_EXPORT char s_ccl[]; #define s_limit (s_ccl+10) SCM_EXPORT char s_close_port[]; #define s_port_type (s_close_port+6) SCM_EXPORT char s_call_cc[]; #define s_cont (s_call_cc+18) SCM_EXPORT char s_try_create_file[]; SCM_EXPORT char s_badenv[]; SCM_EXPORT void (*init_user_scm) P((void)); /* function prototypes */ SCM_EXPORT void (* deferred_proc) P((void)); SCM_EXPORT void process_signals P((void)); SCM_EXPORT int handle_it P((int i)); SCM_EXPORT SCM must_malloc_cell P((long len, SCM c, const char *what)); SCM_EXPORT void must_realloc_cell P((SCM z, long olen, long len, const char *what)); SCM_EXPORT char *must_malloc P((long len, const char *what)); SCM_EXPORT char *must_realloc P((char *where, long olen, long len, const char *what)); SCM_EXPORT void must_free P((char *obj, sizet len)); SCM_EXPORT void scm_protect_temp P((SCM *ptr)); SCM_EXPORT long ilength P((SCM sx)); SCM_EXPORT SCM hash P((SCM obj, SCM n)); SCM_EXPORT SCM hashv P((SCM obj, SCM n)); SCM_EXPORT SCM hashq P((SCM obj, SCM n)); SCM_EXPORT SCM obhash P((SCM obj)); SCM_EXPORT SCM obunhash P((SCM obj)); SCM_EXPORT unsigned long strhash P((unsigned char *str, sizet len, unsigned long n)); SCM_EXPORT unsigned long hasher P((SCM obj, unsigned long n, sizet d)); SCM_EXPORT SCM lroom P((SCM args)); SCM_EXPORT void lfflush P((SCM port)); SCM_EXPORT SCM scm_force_output P((SCM port)); SCM_EXPORT void scm_init_gra P((scm_gra *gra, sizet eltsize, sizet len, sizet maxlen, const char *what)); SCM_EXPORT int scm_grow_gra P((scm_gra *gra, char *elt)); SCM_EXPORT void scm_trim_gra P((scm_gra *gra)); SCM_EXPORT void scm_free_gra P((scm_gra *gra)); SCM_EXPORT long newsmob P((smobfuns *smob)); SCM_EXPORT long newptob P((ptobfuns *ptob)); SCM_EXPORT SCM scm_port_entry P((FILE *stream, long ptype, long flags)); SCM_EXPORT SCM scm_open_ports P((void)); SCM_EXPORT void prinport P((SCM exp, SCM port, char *type)); SCM_EXPORT SCM repl P((void)); SCM_EXPORT void repl_report P((void)); SCM_EXPORT void growth_mon P((char *obj, long size, char *units, int grewp)); SCM_EXPORT void gc_start P((const char *what)); SCM_EXPORT void gc_end P((void)); SCM_EXPORT void gc_mark P((SCM p)); SCM_EXPORT void scm_gc_hook P((void)); SCM_EXPORT SCM scm_gc_protect P((SCM obj)); SCM_EXPORT SCM scm_add_finalizer P((SCM value, SCM finalizer)); SCM_EXPORT void scm_run_finalizers P((int exiting)); SCM_EXPORT void scm_egc_start P((void)); SCM_EXPORT void scm_egc_end P((void)); SCM_EXPORT void heap_report P((void)); SCM_EXPORT void gra_report P((void)); SCM_EXPORT void exit_report P((void)); SCM_EXPORT void stack_report P((void)); SCM_EXPORT SCM scm_stack_trace P((SCM contin)); SCM_EXPORT SCM scm_scope_trace P((SCM env)); SCM_EXPORT SCM scm_frame_trace P((SCM contin, SCM nf)); SCM_EXPORT SCM scm_frame2env P((SCM contin, SCM nf)); SCM_EXPORT SCM scm_frame_eval P((SCM contin, SCM nf, SCM expr)); SCM_EXPORT void scm_iprin1 P((SCM exp, SCM port, int writing)); SCM_EXPORT void scm_intprint P((long n, int radix, SCM port)); SCM_EXPORT void scm_iprlist P((char *hdr, SCM exp, int tlr, SCM port, int writing)); SCM_EXPORT SCM scm_env_lookup P((SCM var, SCM stenv)); SCM_EXPORT SCM scm_env_rlookup P((SCM addr, SCM stenv, const char *what)); SCM_EXPORT SCM scm_env_getprop P((SCM prop, SCM env)); SCM_EXPORT SCM scm_env_addprop P((SCM prop, SCM val, SCM env)); SCM_EXPORT long num_frames P((SCM estk, int i)); SCM_EXPORT SCM *estk_frame P((SCM estk, int i, int nf)); SCM_EXPORT SCM *cont_frame P((SCM contin, int nf)); SCM_EXPORT SCM stacktrace1 P((SCM estk, int i)); SCM_EXPORT void scm_princode P((SCM code, SCM env, SCM port, int writing)); SCM_EXPORT void scm_princlosure P((SCM proc, SCM port, int writing)); SCM_EXPORT void lputc P((int c, SCM port)); SCM_EXPORT void lputs P((const char *s, SCM port)); SCM_EXPORT sizet lfwrite P((char *ptr, sizet size, sizet nitems, SCM port)); SCM_EXPORT int lgetc P((SCM port)); SCM_EXPORT void lungetc P((int c, SCM port)); SCM_EXPORT char *grow_tok_buf P((SCM tok_buf)); SCM_EXPORT long mode_bits P((char *modes, char *cmodes)); SCM_EXPORT long time_in_msec P((long x)); SCM_EXPORT SCM my_time P((void)); SCM_EXPORT SCM your_time P((void)); SCM_EXPORT void init_iprocs P((iproc *subra, int type)); SCM_EXPORT void final_scm P((int)); SCM_EXPORT void init_sbrk P((void)); SCM_EXPORT int init_buf0 P((FILE *inport)); SCM_EXPORT void scm_init_from_argv P((int argc, const char * const *argv, char *script_arg, int iverbose, int buf0stdin)); SCM_EXPORT void init_signals P((void)); SCM_EXPORT SCM scm_top_level P((char *initpath, SCM (*toplvl_fun)())); SCM_EXPORT void restore_signals P((void)); SCM_EXPORT void free_storage P((void)); SCM_EXPORT char *dld_find_executable P((const char* command)); SCM_EXPORT char *scm_find_execpath P((int argc, const char * const *argv, const char *script_arg)); SCM_EXPORT void init_scm P((int iverbose, int buf0stdin, long init_heap_size)); SCM_EXPORT void scm_init_INITS P((void)); SCM_EXPORT SCM scm_init_extensions P((void)); SCM_EXPORT void ignore_signals P((void)); SCM_EXPORT void unignore_signals P((void)); SCM_EXPORT void add_feature P((char *str)); SCM_EXPORT int raprin1 P((SCM exp, SCM port, int writing)); SCM_EXPORT SCM markcdr P((SCM ptr)); #define mark0 (0) /*SCM mark0 P((SCM ptr)); */ SCM_EXPORT SCM equal0 P((SCM ptr1, SCM ptr2)); SCM_EXPORT sizet free0 P((CELLPTR ptr)); SCM_EXPORT void scm_warn P((char *str1, char *str2, SCM obj)); SCM_EXPORT void everr P((SCM exp, SCM env, SCM arg, const char *pos, const char *s_subr, int codep)); SCM_EXPORT void wta P((SCM arg, const char *pos, const char *s_subr)); SCM_EXPORT void scm_experr P((SCM arg, const char *pos, const char *s_subr)); SCM_EXPORT SCM intern P((char *name, sizet len)); SCM_EXPORT SCM sysintern P((const char *name, SCM val)); SCM_EXPORT SCM sym2vcell P((SCM sym)); SCM_EXPORT SCM makstr P((long len)); SCM_EXPORT SCM scm_maksubr P((const char *name, int type, SCM (*fcn)())); SCM_EXPORT SCM make_subr P((const char *name, int type, SCM (*fcn)())); SCM_EXPORT SCM make_synt P((const char *name, long flags, SCM (*fcn)())); SCM_EXPORT SCM make_gsubr P((const char *name, int req, int opt, int rst, SCM (*fcn)())); SCM_EXPORT SCM closure P((SCM code, int nargs)); SCM_EXPORT SCM makprom P((SCM code)); SCM_EXPORT SCM force P((SCM x)); SCM_EXPORT SCM makarb P((SCM name)); SCM_EXPORT SCM tryarb P((SCM arb)); SCM_EXPORT SCM relarb P((SCM arb)); SCM_EXPORT SCM ceval P((SCM x, SCM static_env, SCM env)); SCM_EXPORT SCM scm_wrapcode P((SCM code, SCM env)); SCM_EXPORT SCM scm_current_env P((void)); SCM_EXPORT SCM prolixity P((SCM arg)); SCM_EXPORT SCM gc_for_newcell P((void)); SCM_EXPORT void gc_for_open_files P((void)); SCM_EXPORT SCM gc P((SCM arg)); SCM_EXPORT SCM tryload P((SCM filename, SCM reader)); SCM_EXPORT SCM acons P((SCM w, SCM x, SCM y)); SCM_EXPORT SCM cons2 P((SCM w, SCM x, SCM y)); SCM_EXPORT SCM resizuve P((SCM vect, SCM len)); SCM_EXPORT SCM lnot P((SCM x)); SCM_EXPORT SCM booleanp P((SCM obj)); SCM_EXPORT SCM eq P((SCM x, SCM y)); SCM_EXPORT SCM equal P((SCM x, SCM y)); SCM_EXPORT SCM consp P((SCM x)); SCM_EXPORT SCM cons P((SCM x, SCM y)); SCM_EXPORT SCM nullp P((SCM x)); SCM_EXPORT SCM setcar P((SCM pair, SCM value)); SCM_EXPORT SCM setcdr P((SCM pair, SCM value)); SCM_EXPORT SCM listp P((SCM x)); SCM_EXPORT SCM list P((SCM objs)); SCM_EXPORT SCM length P((SCM x)); SCM_EXPORT SCM append P((SCM args)); SCM_EXPORT SCM reverse P((SCM lst)); SCM_EXPORT SCM list_ref P((SCM lst, SCM k)); SCM_EXPORT SCM memq P((SCM x, SCM lst)); SCM_EXPORT SCM member P((SCM x, SCM lst)); SCM_EXPORT SCM memv P((SCM x, SCM lst)); SCM_EXPORT SCM assq P((SCM x, SCM alist)); SCM_EXPORT SCM assoc P((SCM x, SCM alist)); SCM_EXPORT SCM symbolp P((SCM x)); SCM_EXPORT SCM symbol2string P((SCM s)); SCM_EXPORT SCM string2symbol P((SCM s)); SCM_EXPORT SCM string_copy P((SCM s)); SCM_EXPORT SCM numberp P((SCM x)); SCM_EXPORT SCM exactp P((SCM x)); SCM_EXPORT SCM inexactp P((SCM x)); SCM_EXPORT SCM eqp P((SCM x, SCM y)); SCM_EXPORT SCM lessp P((SCM x, SCM y)); SCM_EXPORT SCM greaterp P((SCM x, SCM y)); SCM_EXPORT SCM leqp P((SCM x, SCM y)); SCM_EXPORT SCM greqp P((SCM x, SCM y)); SCM_EXPORT SCM zerop P((SCM z)); SCM_EXPORT SCM positivep P((SCM x)); SCM_EXPORT SCM negativep P((SCM x)); SCM_EXPORT SCM oddp P((SCM n)); SCM_EXPORT SCM evenp P((SCM n)); SCM_EXPORT SCM lmax P((SCM x, SCM y)); SCM_EXPORT SCM lmin P((SCM x, SCM y)); SCM_EXPORT SCM sum P((SCM x, SCM y)); SCM_EXPORT SCM difference P((SCM x, SCM y)); SCM_EXPORT SCM product P((SCM x, SCM y)); SCM_EXPORT SCM divide P((SCM x, SCM y)); SCM_EXPORT SCM lquotient P((SCM x, SCM y)); SCM_EXPORT SCM scm_iabs P((SCM x)); SCM_EXPORT SCM scm_abs P((SCM x)); SCM_EXPORT SCM lremainder P((SCM x, SCM y)); SCM_EXPORT SCM modulo P((SCM x, SCM y)); SCM_EXPORT SCM lgcd P((SCM x, SCM y)); SCM_EXPORT SCM llcm P((SCM n1, SCM n2)); SCM_EXPORT SCM number2string P((SCM x, SCM radix)); SCM_EXPORT SCM istring2number P((char *str, long len, long radix)); SCM_EXPORT SCM string2number P((SCM str, SCM radix)); SCM_EXPORT SCM istr2flo P((char *str, long len, long radix)); SCM_EXPORT SCM mkbig P((sizet nlen, int sign)); SCM_EXPORT SCM mkstrport P((SCM pos, SCM str, long modes, char *caller)); SCM_EXPORT SCM mksafeport P((int maxlen, SCM port)); SCM_EXPORT int reset_safeport P((SCM sfp, int maxlen, SCM port)); SCM_EXPORT SCM long2big P((long n)); SCM_EXPORT SCM ulong2big P((unsigned long n)); SCM_EXPORT SCM big2inum P((SCM b, sizet l)); SCM_EXPORT sizet iint2str P((long num, int rad, char *p)); SCM_EXPORT SCM floequal P((SCM x, SCM y)); SCM_EXPORT SCM uve_equal P((SCM u, SCM v)); SCM_EXPORT SCM uve_read P((SCM v, SCM port)); SCM_EXPORT SCM uve_write P((SCM v, SCM port)); SCM_EXPORT SCM raequal P((SCM ra0, SCM ra1)); SCM_EXPORT SCM array_equal P((SCM u, SCM v)); SCM_EXPORT SCM array_rank P((SCM ra)); SCM_EXPORT int rafill P((SCM ra, SCM fill, SCM ignore)); SCM_EXPORT SCM uve_fill P((SCM uve, SCM fill)); SCM_EXPORT SCM array_fill P((SCM ra, SCM fill)); SCM_EXPORT SCM array_prot P((SCM ra)); SCM_EXPORT SCM array_rank P((SCM ra)); SCM_EXPORT SCM array_contents P((SCM ra, SCM strict)); SCM_EXPORT int bigprint P((SCM exp, SCM port, int writing)); SCM_EXPORT int floprint P((SCM sexp, SCM port, int writing)); SCM_EXPORT SCM istr2int P((char *str, long len, long radix)); SCM_EXPORT SCM istr2bve P((char *str, long len)); SCM_EXPORT void scm_ipruk P((char *hdr, SCM ptr, SCM port)); SCM_EXPORT SCM charp P((SCM x)); SCM_EXPORT SCM char_lessp P((SCM x, SCM y)); SCM_EXPORT SCM chci_eq P((SCM x, SCM y)); SCM_EXPORT SCM chci_lessp P((SCM x, SCM y)); SCM_EXPORT SCM char_alphap P((SCM chr)); SCM_EXPORT SCM char_nump P((SCM chr)); SCM_EXPORT SCM char_whitep P((SCM chr)); SCM_EXPORT SCM char_upperp P((SCM chr)); SCM_EXPORT SCM char_lowerp P((SCM chr)); SCM_EXPORT SCM char2int P((SCM chr)); SCM_EXPORT SCM int2char P((SCM n)); SCM_EXPORT SCM char_upcase P((SCM chr)); SCM_EXPORT SCM char_downcase P((SCM chr)); SCM_EXPORT SCM stringp P((SCM x)); SCM_EXPORT SCM string P((SCM chrs)); SCM_EXPORT SCM make_string P((SCM k, SCM chr)); SCM_EXPORT SCM string2list P((SCM str)); SCM_EXPORT SCM st_length P((SCM str)); SCM_EXPORT SCM st_ref P((SCM str, SCM k)); SCM_EXPORT SCM st_set P((SCM str, SCM k, SCM chr)); SCM_EXPORT SCM st_equal P((SCM s1, SCM s2)); SCM_EXPORT SCM stci_equal P((SCM s1, SCM s2)); SCM_EXPORT SCM st_lessp P((SCM s1, SCM s2)); SCM_EXPORT SCM stci_lessp P((SCM s1, SCM s2)); SCM_EXPORT SCM substring P((SCM str, SCM start, SCM end)); SCM_EXPORT SCM st_append P((SCM args)); SCM_EXPORT SCM vectorp P((SCM x)); SCM_EXPORT SCM vector_length P((SCM v)); SCM_EXPORT SCM vector P((SCM l)); SCM_EXPORT SCM vector_ref P((SCM v, SCM k)); SCM_EXPORT SCM vector_set P((SCM v, SCM k, SCM obj)); SCM_EXPORT SCM make_vector P((SCM k, SCM fill)); SCM_EXPORT SCM vector2list P((SCM v)); SCM_EXPORT SCM for_each P((SCM proc, SCM arg1, SCM args)); SCM_EXPORT SCM procedurep P((SCM obj)); SCM_EXPORT SCM apply P((SCM proc, SCM arg1, SCM args)); SCM_EXPORT SCM scm_cvapply P((SCM proc, long n, SCM *argv)); SCM_EXPORT int scm_arity_check P((SCM proc, long argc, const char *what)); SCM_EXPORT SCM map P((SCM proc, SCM arg1, SCM args)); SCM_EXPORT SCM scm_make_cont P((void)); SCM_EXPORT SCM copytree P((SCM obj)); SCM_EXPORT SCM eval P((SCM obj)); SCM_EXPORT SCM scm_values P((SCM arg1, SCM arg2, SCM rest, const char *what)); SCM_EXPORT SCM scm_eval_values P((SCM x, SCM static_env, SCM env)); SCM_EXPORT SCM identp P((SCM obj)); SCM_EXPORT SCM ident2sym P((SCM id)); SCM_EXPORT SCM ident_eqp P((SCM id1, SCM id2, SCM env)); SCM_EXPORT int scm_nullenv_p P((SCM env)); SCM_EXPORT SCM env2tree P((SCM env)); SCM_EXPORT SCM renamed_ident P((SCM id, SCM env)); SCM_EXPORT SCM scm_check_linum P((SCM x, SCM *linum)); SCM_EXPORT SCM scm_add_linum P((SCM linum, SCM x)); SCM_EXPORT SCM input_portp P((SCM x)); SCM_EXPORT SCM output_portp P((SCM x)); SCM_EXPORT SCM cur_input_port P((void)); SCM_EXPORT SCM cur_output_port P((void)); SCM_EXPORT SCM i_setbuf0 P((SCM port)); SCM_EXPORT SCM try_open_file P((SCM filename, SCM modes)); SCM_EXPORT SCM open_file P((SCM filename, SCM modes)); SCM_EXPORT SCM open_pipe P((SCM pipestr, SCM modes)); SCM_EXPORT SCM close_port P((SCM port)); SCM_EXPORT SCM scm_file_position P((SCM port, SCM pos)); #define file_position(port) scm_file_position(port, BOOL_F) #define file_set_position scm_file_position SCM_EXPORT SCM scm_read P((SCM port)); SCM_EXPORT SCM scm_read_char P((SCM port)); SCM_EXPORT SCM scm_peek_char P((SCM port)); SCM_EXPORT SCM eof_objectp P((SCM x)); SCM_EXPORT int scm_io_error P((SCM port, const char *what)); SCM_EXPORT SCM scm_write P((SCM obj, SCM port)); SCM_EXPORT SCM scm_display P((SCM obj, SCM port)); SCM_EXPORT SCM scm_newline P((SCM port)); SCM_EXPORT SCM scm_write_char P((SCM chr, SCM port)); SCM_EXPORT SCM scm_port_line P((SCM port)); SCM_EXPORT SCM scm_port_col P((SCM port)); SCM_EXPORT void scm_line_msg P((SCM file, SCM linum, SCM port)); SCM_EXPORT void scm_err_line P((const char *what, SCM file, SCM linum, SCM port)); SCM_EXPORT SCM lgetenv P((SCM nam)); SCM_EXPORT SCM prog_args P((void)); SCM_EXPORT SCM makacro P((SCM code)); SCM_EXPORT SCM makmacro P((SCM code)); SCM_EXPORT SCM makmmacro P((SCM code)); SCM_EXPORT SCM makidmacro P((SCM code)); SCM_EXPORT void poll_routine P((void)); SCM_EXPORT void tick_signal P((void)); SCM_EXPORT void stack_check P((void)); SCM_EXPORT SCM list2ura P((SCM ndim, SCM prot, SCM lst)); SCM_EXPORT SCM make_ra P((int ndim)); SCM_EXPORT SCM makflo P((float x)); SCM_EXPORT SCM arrayp P((SCM v, SCM prot)); SCM_EXPORT SCM aset P((SCM v, SCM obj, SCM args)); SCM_EXPORT SCM aref P((SCM v, SCM args)); SCM_EXPORT SCM scm_array_ref P((SCM args)); SCM_EXPORT SCM cvref P((SCM v, sizet pos, SCM last)); SCM_EXPORT SCM quit P((SCM n)); #ifdef CAREFUL_INTS SCM_EXPORT void ints_viol P((ints_infot *info, int sense)); SCM_EXPORT void ints_warn P((char *s1, char* s2, char *fname, int linum)); #endif SCM_EXPORT void add_final P((void (*final)(void))); SCM_EXPORT SCM makcclo P((SCM proc, long len)); SCM_EXPORT SCM make_uve P((long k, SCM prot)); SCM_EXPORT long scm_prot2type P((SCM prot)); SCM_EXPORT long aind P((SCM ra, SCM args, const char *what)); SCM_EXPORT SCM scm_eval_string P((SCM str)); SCM_EXPORT SCM scm_load_string P((SCM str)); SCM_EXPORT SCM scm_unexec P((const SCM pathname)); SCM_EXPORT SCM scm_logbitp P((SCM index, SCM j1)); SCM_EXPORT SCM scm_logtest P((SCM x, SCM y)); SCM_EXPORT SCM scm_logxor P((SCM x, SCM y)); SCM_EXPORT SCM scm_logand P((SCM x, SCM y)); SCM_EXPORT SCM scm_logior P((SCM x, SCM y)); SCM_EXPORT SCM scm_lognot P((SCM n)); SCM_EXPORT SCM scm_intexpt P((SCM z1, SCM z2)); SCM_EXPORT SCM scm_ash P((SCM n, SCM cnt)); SCM_EXPORT SCM scm_bitfield P((SCM n, SCM start, SCM end)); SCM_EXPORT SCM scm_logcount P((SCM n)); SCM_EXPORT SCM scm_intlength P((SCM n)); SCM_EXPORT SCM scm_copybit P((SCM index, SCM j1, SCM bit)); SCM_EXPORT SCM scm_bitif P((SCM mask, SCM n0, SCM n1)); SCM_EXPORT SCM scm_copybitfield P((SCM to, SCM start, SCM rest)); /* Defined in "rope.c" */ SCM_EXPORT SCM long2num P((long n)); SCM_EXPORT SCM ulong2num P((unsigned long n)); SCM_EXPORT unsigned char num2uchar P((SCM num, char *pos, char *s_caller)); SCM_EXPORT signed char num2char P((SCM num, char *pos, char *s_caller)); SCM_EXPORT unsigned short num2ushort P((SCM num, char *pos, char *s_caller)); SCM_EXPORT short num2short P((SCM num, char *pos, char *s_caller)); SCM_EXPORT unsigned long num2ulong P((SCM num, char *pos, char *s_caller)); SCM_EXPORT long num2long P((SCM num, char *pos, char *s_caller)); SCM_EXPORT double num2dbl P((SCM num, char *pos, char *s_caller)); SCM_EXPORT SCM makfromstr P((const char *src, sizet len)); SCM_EXPORT SCM makfromstrs P((int argc, const char * const *argv)); SCM_EXPORT SCM makfrom0str P((const char *scr)); SCM_EXPORT char **makargvfrmstrs P((SCM args, const char *s_v)); SCM_EXPORT void must_free_argv P((char **argv)); SCM_EXPORT SCM scm_evstr P((char *str)); SCM_EXPORT void scm_ldstr P((char *str)); SCM_EXPORT int scm_ldfile P((char *path)); SCM_EXPORT int scm_ldprog P((char *path)); SCM_EXPORT unsigned long scm_addr P((SCM args, const char *name)); SCM_EXPORT unsigned long scm_base_addr P((SCM v, const char *name)); SCM_EXPORT int scm_cell_p P((SCM x)); #ifdef FLOATS SCM_EXPORT SCM makdbl P((double x, double y)); SCM_EXPORT SCM dbl2big P((double d)); SCM_EXPORT double big2dbl P((SCM b)); SCM_EXPORT double scm_truncate P((double x)); SCM_EXPORT double scm_round P((double x)); SCM_EXPORT double floident P((double x)); #endif #ifdef BIGDIG SCM_EXPORT void longdigs P((long x, BIGDIG digs[DIGSPERLONG])); SCM_EXPORT SCM adjbig P((SCM b, sizet nlen)); SCM_EXPORT SCM normbig P((SCM b)); SCM_EXPORT SCM copybig P((SCM b, int sign)); SCM_EXPORT SCM addbig P((BIGDIG *x, sizet nx, int xsgn, SCM bigy, int sgny)); SCM_EXPORT SCM mulbig P((BIGDIG *x, sizet nx, BIGDIG *y, sizet ny, int sgn)); SCM_EXPORT unsigned int divbigdig P((BIGDIG *ds, sizet h, BIGDIG div)); SCM_EXPORT SCM divbigint P((SCM x, long z, int sgn, int mode)); SCM_EXPORT SCM divbigbig P((BIGDIG *x, sizet nx, BIGDIG *y, sizet ny, int sgn, int modes)); SCM_EXPORT long pseudolong P((long x)); #endif SCM_EXPORT int bigcomp P((SCM x, SCM y)); SCM_EXPORT SCM bigequal P((SCM x, SCM y)); SCM_EXPORT int scm_bigdblcomp P((SCM b, double d)); /* "script.c" functions */ SCM_EXPORT char * scm_cat_path P((char *str1, const char *str2, long n)); SCM_EXPORT char * scm_try_path P((char *path)); SCM_EXPORT char * script_find_executable P((const char *command)); SCM_EXPORT char ** script_process_argv P((int argc, const char **argv)); SCM_EXPORT int script_count_argv P((const char **argv)); SCM_EXPORT char * find_impl_file P((const char *exec_path, const char *generic_name, const char *initname, const char *sep)); /* environment cache functions */ SCM_EXPORT void scm_ecache_report P((void)); SCM_EXPORT void scm_estk_reset P((sizet size)); SCM_EXPORT void scm_env_cons P((SCM x, SCM y)); SCM_EXPORT void scm_env_cons2 P((SCM w, SCM x, SCM y)); SCM_EXPORT void scm_env_cons3 P((SCM v, SCM w, SCM x, SCM y)); SCM_EXPORT void scm_env_v2lst P((long argc, SCM *argv)); SCM_EXPORT void scm_extend_env P((void)); SCM_EXPORT void scm_egc P((void)); /* Global state for environment cache */ SCM_EXPORT CELLPTR scm_ecache; SCM_EXPORT VOLATILE long scm_ecache_index, scm_ecache_len; SCM_EXPORT SCM scm_env, scm_env_tmp; SCM_EXPORT SCM scm_egc_roots[]; SCM_EXPORT VOLATILE long scm_egc_root_index; SCM_EXPORT SCM scm_estk; SCM_EXPORT SCM *scm_estk_v, *scm_estk_ptr; SCM_EXPORT long scm_estk_size; #ifndef RECKLESS SCM_EXPORT SCM scm_trace, scm_trace_env; #endif #ifdef RECKLESS # define ASRTER(_cond, _arg, _pos, _subr) ; # define ASRTGO(_cond, _label) ; #else # define ASRTER(_cond, _arg, _pos, _subr) if (SCM_EXPECT_FALSE(!(_cond))) wta(_arg, (char *)(_pos), _subr); # define ASRTGO(_cond, _label) if (SCM_EXPECT_FALSE(!(_cond))) goto _label; #endif #define ARGn 1 #define ARG1 2 #define ARG2 3 #define ARG3 4 #define ARG4 5 #define ARG5 6 /* following must match entry indexes in errmsgs[] */ #define WNA 7 #define OVFLOW 8 #define OUTOFRANGE 9 #define NALLOC 10 #define THRASH 11 #define EXIT 12 #define HUP_SIGNAL 13 #define INT_SIGNAL 14 #define FPE_SIGNAL 15 #define BUS_SIGNAL 16 #define SEGV_SIGNAL 17 #define ALRM_SIGNAL 18 #define VTALRM_SIGNAL 19 #define PROF_SIGNAL 20 #define EVAL(x, env, venv) (IMP(x)?(x):ceval((x), (SCM)(env), (SCM)(venv))) #define SIDEVAL(x, env, venv) if (NIMP(x)) ceval((x), (SCM)(env), (SCM)(venv)) #define NEWCELL(_into) {if (IMP(freelist)) _into = gc_for_newcell();\ else {_into = freelist;freelist = CDR(freelist);++cells_allocated;}} /* #define NEWCELL(_into) {DEFER_INTS;if (IMP(freelist)) _into = gc_for_newcell();\ else {_into = freelist;freelist = CDR(freelist);++cells_allocated;}\ ALLOW_INTS;} */ #ifdef __cplusplus } #endif scm-5e5/COPYING.LESSER0000644001705200017500000001673110746015031012066 0ustar tbtb GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. scm-5e5/continue.c0000644001705200017500000001757110750224111012026 0ustar tbtb/* "continue.c" Scheme Continuations for C. * Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1997 Free Software Foundation, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see * . */ /* Author: Aubrey Jaffer */ /* "setjump.h" contains definitions for the `other' field (type CONTINUATION_OTHER) the struct Continuation. "setjump.h" must #include "continue.h". CONTINUATION_OTHER defaults to `long' */ #define IN_CONTINUE_C #ifdef USE_CONTINUE_H # include "continue.h" #else # include "setjump.h" #endif /* For platforms with short integers, we use thrown_value instead of the value returned from setjump so that any (long) value can be returned. */ #ifdef SHORT_INT long thrown_value; #endif /* stack_size() returns the number of units of size STACKITEM which fit between @var{start} and the current top of stack. No check is done in this routine to ensure that @var{start} is actually in the current stack segment. */ long stack_size(start) STACKITEM *start; { STACKITEM stack; #ifdef STACK_GROWS_UP return &stack - start; #else return start - &stack; #endif /* def STACK_GROWS_UP */ } /* make_root_continuation() allocates (malloc) storage for a CONTINUATION near the current extent of stack. This newly allocated CONTINUATION is returned if successful, 0 if not. After make_root_continuation() returns, the calling routine still needs to `setjump(new_continuation->jmpbuf)' in order to complete the capture of this continuation. */ #ifndef __ia64__ CONTINUATION *make_root_continuation(stack_base) STACKITEM *stack_base; { CONTINUATION *cont; cont = (CONTINUATION *)malloc(sizeof(CONTINUATION)); if (!cont) return 0; cont->length = 0; cont->stkbse = stack_base; cont->parent = cont; return cont; } /* make_continuation() allocates storage for the current continuation, copying (or encapsulating) the stack state from parent_cont->stkbse to the current top of stack. The newly allocated CONTINUATION is returned if successful, 0 if not. After make_continuation() returns, the calling routine still needs to `setjump(new_continuation->jmpbuf)' in order to complete the capture of this continuation. */ /* Note: allocating local (stack) storage for the CONTINUATION would not work; Think about it. */ CONTINUATION *make_continuation(parent_cont) CONTINUATION *parent_cont; { CONTINUATION *cont; # ifdef CHEAP_CONTINUATIONS cont = (CONTINUATION *)malloc(sizeof(CONTINUATION)); if (!cont) return 0; cont->length = 0; cont->stkbse = parent_cont->stkbse; # else long j; register STACKITEM *src, *dst; FLUSH_REGISTER_WINDOWS; j = stack_size(parent_cont->stkbse); cont = (CONTINUATION *)malloc((sizeof(CONTINUATION) + j*sizeof(STACKITEM))); if (!cont) return 0; cont->length = j; cont->stkbse = parent_cont->stkbse; src = cont->stkbse; # ifdef STACK_GROWS_UP src += parent_cont->length; # else src -= parent_cont->length + cont->length; # endif/* ndef STACK_GROWS_UP */ dst = (STACKITEM *)(cont + 1); for (j = cont->length; 0 <= --j; ) *dst++ = *src++; # endif /* ndef CHEAP_CONTINUATIONS */ cont->parent = parent_cont; return cont; } #endif /* free_continuation() is trivial, but who knows what the future holds. */ void free_continuation(cont) CONTINUATION *cont; { free(cont); } /* Final routine involved in throw()ing to a continuation. After ensuring that there is sufficient room on the stack for the saved continuation, dynthrow() copies the continuation onto the stack and longjump()s into it. The routine does not return. */ /* If you use conservative GC and your Sparc(SUN-4) heap is growing out of control: You are experiencing a GC problem peculiar to the Sparc. The problem is that SCM doesn't know how to clear register windows. Every location which is not reused still gets marked at GC time. This causes lots of stuff which should be collected to not be. This will be a problem with any *conservative* GC until we find what instruction will clear the register windows. This problem is exacerbated by using lots of make-CONTINUATION. Possibly adding the following before the thrown_value = val; line might help to clear out unused stack above the continuation (a small part of the problem). #ifdef sparc bzero((void *)&a, sizeof(STACKITEM) * (((STACKITEM *)&a) - (dst - cont->length))) #endif Let me know if you try it. */ /* SCM_GROWTH is how many `long's to grow the stack by when we need room. */ #define SCM_GROWTH 100 #ifndef __ia64__ void dynthrow(a) long *a; { register CONTINUATION *cont = (CONTINUATION *)(a[0]); long val = a[1]; # ifndef CHEAP_CONTINUATIONS register long j; register STACKITEM *src, *dst = cont->stkbse; # ifdef STACK_GROWS_UP # ifndef hpux if (a[2] && (a - ((long *)a[3]) < SCM_GROWTH)) puts("grow_throw: check if long growth[]; being optimized out"); # endif /* if (a[2]) fprintf(stderr, " ct = %ld, dist = %ld\n", a[2], (((long *)a[3]) - a)); */ if (PTR_GE(dst + (cont->length), (STACKITEM *)&a)) grow_throw(a); # else # ifndef hpux if (a[2] && (((long *)a[3]) - a < SCM_GROWTH)) puts("grow_throw: check if long growth[]; being optimized out"); # endif /* if (a[2]) fprintf(stderr, " ct = %ld, dist = %ld\n", a[2], (((long *)a[3]) - a)); */ dst -= cont->length; if (PTR_LE(dst, (STACKITEM *)&a)) grow_throw(a); # endif/* def STACK_GROWS_UP */ FLUSH_REGISTER_WINDOWS; src = (STACKITEM *)(cont + 1); for (j = cont->length;0 <= --j;) *dst++ = *src++; # endif /* ndef CHEAP_CONTINUATIONS */ # ifdef SHORT_INT thrown_value = val; longjump(cont->jmpbuf, 1); # else longjump(cont->jmpbuf, val); # endif } /* grow_throw() grows the stack by SCM_GROWTH long words. If the "sizeof growth" assignment is not sufficient to restrain your overly optimistic compiler, the stack will grow by much less and grow_throw() and dynthrow() will waste time calling each other. To fix this you will have to compile grow_throw() in a separate file so the compiler won't be able to guess that the growth array isn't all used. */ # ifndef CHEAP_CONTINUATIONS void grow_throw(a) /* Grow the stack so that there is room */ long *a; /* to copy in the continuation. Then */ { /* retry the throw. */ long growth[SCM_GROWTH]; growth[0] = a[0]; growth[1] = a[1]; growth[2] = a[2] + 1; growth[3] = (long) a; growth[SCM_GROWTH-1] = sizeof growth; dynthrow(growth); } # endif /* ndef CHEAP_CONTINUATIONS */ #endif /* throw_to_continuation() restores the stack in effect when @var{cont} was made and resumes @var{cont}'s processor state. If the stack cannot be resotred because @var{cont} and @var{root_cont} do not have the same stkbase, @code{throw_to_continuation() returns. */ /* Note: If 2 or more @var{cont}s share a parent continuation and if the values of stack allocated variables in that parent continuation are changed, the results are unspecified. This is because the parent continuation may or may not be reloaded, depending on what other throws have intervened. */ void throw_to_continuation(cont, val, root_cont) CONTINUATION *cont; long val; CONTINUATION *root_cont; { long a[3]; a[0] = (long)cont; a[1] = val; a[2] = 0; if (cont->stkbse != root_cont->stkbse) return; /* Stale continuation */ dynthrow(a); } scm-5e5/scmhob.h0000644001705200017500000001117110750225413011456 0ustar tbtb/* "scmhob.h" is a header file for scheme source compiled with hobbit5x * Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997 Free Software Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see * . */ /* Author: Tanel Tammet */ #include "scm.h" #define STBL_VECTOR_SET(v,k,o) (v[((long)INUM(k))] = o) #define STBL_VECTOR_REF(v,k) (v[((long)INUM(k))]) #define CHAR_LESSP(x,y) ((ICHR(x) < ICHR(y)) ? BOOL_T : BOOL_F) #define CHAR_LEQP(x,y) ((ICHR(x) <= ICHR(y)) ? BOOL_T : BOOL_F) #define CHCI_EQ(x,y) ((upcase[ICHR(x)]==upcase[ICHR(y)]) ? BOOL_T : BOOL_F) #define CHCI_LESSP(x,y) ((upcase[ICHR(x)] < upcase[ICHR(y)]) ? BOOL_T : BOOL_F) #define CHCI_LEQP(x,y) ((upcase[ICHR(x)] <= upcase[ICHR(y)]) ? BOOL_T : BOOL_F) #define CHAR_ALPHAP(chr) ((isascii(ICHR(chr)) && isalpha(ICHR(chr))) ? BOOL_T : BOOL_F) #define CHAR_NUMP(chr) ((isascii(ICHR(chr)) && isdigit(ICHR(chr))) ? BOOL_T : BOOL_F) #define CHAR_WHITEP(chr) ((isascii(ICHR(chr)) && isspace(ICHR(chr))) ? BOOL_T : BOOL_F) #define CHAR_UPPERP(chr) ((isascii(ICHR(chr)) && isupper(ICHR(chr))) ? BOOL_T : BOOL_F) #define CHAR_LOWERP(chr) ((isascii(ICHR(chr)) && islower(ICHR(chr))) ? BOOL_T : BOOL_F) #define CHAR2INT(chr) MAKINUM(ICHR(chr)) #define INT2CHAR(n) MAKICHR(INUM(n)) #define CHAR_UPCASE(chr) MAKICHR(upcase[ICHR(chr)]) #define CHAR_DOWNCASE(chr) MAKICHR(downcase[ICHR(chr)]) #define ST_LENGTH(str) MAKINUM(LENGTH(str)) #define ST_REF(str,k) MAKICHR(CHARS(str)[INUM(k)]) #define VECTOR_LENGTH(v) MAKINUM(LENGTH(v)) #ifdef FLOATS #include #endif #ifdef BIGDIG #define PRE_TRANSC_FUN(x) (INUMP(x) ? (double) INUM(x) : (REALP(x) ? (double) REALPART(x) : (double) big2dbl(x))) #else #define PRE_TRANSC_FUN(x) (INUMP(x) ? (double) INUM(x) : (double) REALPART(x)) #endif #define SIN_FUN(x) (makdbl( sin( PRE_TRANSC_FUN(x)), 0.0)) #define COS_FUN(x) (makdbl( cos( PRE_TRANSC_FUN(x)), 0.0)) #define TAN_FUN(x) (makdbl( tan( PRE_TRANSC_FUN(x)), 0.0)) #define ASIN_FUN(x) (makdbl( asin( PRE_TRANSC_FUN(x)), 0.0)) #define ACOS_FUN(x) (makdbl( acos( PRE_TRANSC_FUN(x)), 0.0)) #define ATAN_FUN(x) (makdbl( atan( PRE_TRANSC_FUN(x)), 0.0)) #define SINH_FUN(x) (makdbl( sinh( PRE_TRANSC_FUN(x)), 0.0)) #define COSH_FUN(x) (makdbl( cosh( PRE_TRANSC_FUN(x)), 0.0)) #define TANH_FUN(x) (makdbl( tanh( PRE_TRANSC_FUN(x)), 0.0)) #define ASINH_FUN(x) (makdbl( asinh( PRE_TRANSC_FUN(x)), 0.0)) #define ACOSH_FUN(x) (makdbl( acosh( PRE_TRANSC_FUN(x)), 0.0)) #define ATANH_FUN(x) (makdbl( atanh( PRE_TRANSC_FUN(x)), 0.0)) #define SQRT_FUN(x) (makdbl( sqrt( PRE_TRANSC_FUN(x)), 0.0)) #define EXPT_FUN(x,y) (makdbl( pow(( PRE_TRANSC_FUN(x)), ( PRE_TRANSC_FUN(y))), 0.0)) #define EXP_FUN(x) (makdbl( exp( PRE_TRANSC_FUN(x)), 0.0)) #define LOG_FUN(x) (makdbl( log( PRE_TRANSC_FUN(x)), 0.0)) #define ABS_FUN(x) (makdbl( fabs( PRE_TRANSC_FUN(x)), 0.0)) #define EX2IN_FUN(x) (makdbl( PRE_TRANSC_FUN(x), 0.0)) #define FLOOR_FUN(x) (makdbl( floor( PRE_TRANSC_FUN(x)), 0.0)) #define CEILING_FUN(x) (makdbl( ceil( PRE_TRANSC_FUN(x)), 0.0)) #define TRUNCATE_FUN(x) (makdbl( ltrunc( PRE_TRANSC_FUN(x)), 0.0)) #define ROUND_FUN(x) (makdbl(round( PRE_TRANSC_FUN(x)), 0.0)) /* the following defs come from the #ifdef HOBBIT part of scm.h */ #define SBOOL(x) ((x) ? BOOL_T : BOOL_F) #define BOOLEAN_P(x) ((x)==BOOL_T || (x)==BOOL_F) #define CHAR_P ICHRP #define SYMBOL_P(x) (ISYMP(x) || (!(IMP(x)) && SYMBOLP(x))) #define VECTOR_P(x) (!(IMP(x)) && VECTORP(x)) #define PAIR_P(x) (!(IMP(x)) && CONSP(x)) #define NUMBER_P INUMP #define INTEGER_P INUMP #define STRING_P(x) (!(IMP(x)) && STRINGP(x)) #define NULL_P NULLP #define ZERO_P(x) ((x)==INUM0) #define POSITIVE_P(x) ((x) > INUM0) #define NEGATIVE_P(x) ((x) < INUM0) #define NOT(x) ((x)==BOOL_F ? BOOL_T : BOOL_F) #define SET_CAR(x,y) (CAR(x) = (SCM)(y)) #define SET_CDR(x,y) (CDR(x) = (SCM)(y)) #define VECTOR_SET(v,k,o) (VELTS(v)[((long)INUM(k))] = o) #define VECTOR_REF(v,k) (VELTS(v)[((long)INUM(k))]) #define GLOBAL(x) (*(x)) #define append2(lst1,lst2) (append(cons2(lst1,lst2,EOL))) #define procedure_pred_(x) (BOOL_T==procedurep(x)) /* new for hobbit5 - scm5 */ /* SCM intp(SCM); SCM eqv(SCM,SCM); */ scm-5e5/split.scm0000644001705200017500000000432110750220563011671 0ustar tbtb;;;; "split.scm", split input, output, and error streams into windows. ;; Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. ;; ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU Lesser General Public License as ;; published by the Free Software Foundation, either version 3 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 ;; Lesser General Public License for more details. ;; ;; You should have received a copy of the GNU Lesser General Public ;; License along with this program. If not, see ;; . ;;; Author: Aubrey Jaffer. (require 'curses) (define *stdscr* (initscr)) (nocbreak) (echo) (nl) (define subwindow-height (max 2 (quotient (output-port-height) 5))) (define *output-window* (newwin (- (output-port-height) (* 2 subwindow-height) 2) (output-port-width) 0 0)) (define *input-window* (newwin subwindow-height (output-port-width) (- (output-port-height) (* 2 subwindow-height) 1) 0)) (define *error-window* (newwin subwindow-height (output-port-width) (- (output-port-height) subwindow-height) 0)) (wmove *stdscr* (- (output-port-height) subwindow-height 1) 0) (wstandout *stdscr*) (display (make-string (output-port-width) #\-) *stdscr*) (wmove *stdscr* (- (output-port-height) (* 2 subwindow-height) 2) 0) (display (make-string (output-port-width) #\-) *stdscr*) (wstandend *stdscr*) (touchwin *stdscr*) (force-output *stdscr*) (scrollok *output-window* #t) (scrollok *input-window* #t) (scrollok *error-window* #t) (define *default-output-port* (set-current-output-port *output-window*)) (define *default-input-port* (set-current-input-port *input-window*)) (define *default-error-port* (set-current-error-port *error-window*)) (leaveok *output-window* #t) (leaveok *input-window* #f) (leaveok *error-window* #t) (define (unsplit) (cond ((endwin) (set-current-output-port *default-output-port*) (set-current-input-port *default-input-port*) (set-current-error-port *default-error-port*)))) scm-5e5/r4rstest.scm0000644001705200017500000011201510750211043012321 0ustar tbtb;;;;"r4rstest.scm": Test R4RS correctness of scheme implementations. ;; Copyright (C) 1991, 1992, 1993, 1994, 1995, 2000, 2003, 2004, 2006, 2007 Free Software Foundation, Inc. ;; ;; 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 3 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, see ;; . ;;;;"r4rstest.scm": Test R4RS correctness of scheme implementations. ;;; Author: Aubrey Jaffer ;;; Home-page: http://swiss.csail.mit.edu/~jaffer/Scheme ;;; Current version: http://swiss.csail.mit.edu/ftpdir/scm/r4rstest.scm ;;; CVS Head: ;;; http://savannah.gnu.org/cgi-bin/viewcvs/scm/scm/r4rstest.scm?rev=HEAD&only_with_tag=HEAD&content-type=text/vnd.viewcvs-markup ;;; This includes examples from ;;; William Clinger and Jonathan Rees, editors. ;;; Revised^4 Report on the Algorithmic Language Scheme ;;; and the IEEE specification. ;;; The input tests read this file expecting it to be named "r4rstest.scm". ;;; Files `tmp1', `tmp2' and `tmp3' will be created in the course of running ;;; these tests. You may need to delete them in order to run ;;; "r4rstest.scm" more than once. ;;; There are three optional tests: ;;; (TEST-CONT) tests multiple returns from call-with-current-continuation ;;; ;;; (TEST-SC4) tests procedures required by R4RS but not by IEEE ;;; ;;; (TEST-DELAY) tests DELAY and FORCE, which are not required by ;;; either standard. ;;; If you are testing a R3RS version which does not have `list?' do: ;;; (define list? #f) ;;; send corrections or additions to agj @ alum.mit.edu (define cur-section '())(define errs '()) (define SECTION (lambda args (display "SECTION") (write args) (newline) (set! cur-section args) #t)) (define record-error (lambda (e) (set! errs (cons (list cur-section e) errs)))) (define test (lambda (expect fun . args) (write (cons fun args)) (display " ==> ") ((lambda (res) (write res) (newline) (cond ((not (equal? expect res)) (record-error (list res expect (cons fun args))) (display " BUT EXPECTED ") (write expect) (newline) #f) (else #t))) (if (procedure? fun) (apply fun args) (car args))))) (define (report-errs) (newline) (if (null? errs) (display "Passed all tests") (begin (display "errors were:") (newline) (display "(SECTION (got expected (call)))") (newline) (for-each (lambda (l) (write l) (newline)) errs))) (newline)) (SECTION 2 1);; test that all symbol characters are supported. '(+ - ... !.. $.+ %.- &.! *.: /:. :+. <-. =. >. ?. ~. _. ^.) (SECTION 3 4) (define disjoint-type-functions (list boolean? char? null? number? pair? procedure? string? symbol? vector?)) (define type-examples (list #t #f #\a '() 9739 '(test) record-error "test" "" 'test '#() '#(a b c) )) (define i 1) (for-each (lambda (x) (display (make-string i #\space)) (set! i (+ 3 i)) (write x) (newline)) disjoint-type-functions) (define type-matrix (map (lambda (x) (let ((t (map (lambda (f) (f x)) disjoint-type-functions))) (write t) (write x) (newline) t)) type-examples)) (set! i 0) (define j 0) (for-each (lambda (x y) (set! j (+ 1 j)) (set! i 0) (for-each (lambda (f) (set! i (+ 1 i)) (cond ((and (= i j)) (cond ((not (f x)) (test #t f x)))) ((f x) (test #f f x))) (cond ((and (= i j)) (cond ((not (f y)) (test #t f y)))) ((f y) (test #f f y)))) disjoint-type-functions)) (list #t #\a '() 9739 '(test) record-error "test" 'car '#(a b c)) (list #f #\newline '() -3252 '(t . t) car "" 'nil '#())) (SECTION 4 1 2) (test '(quote a) 'quote (quote 'a)) (test '(quote a) 'quote ''a) (SECTION 4 1 3) (test 12 (if #f + *) 3 4) (SECTION 4 1 4) (test 8 (lambda (x) (+ x x)) 4) (define reverse-subtract (lambda (x y) (- y x))) (test 3 reverse-subtract 7 10) (define add4 (let ((x 4)) (lambda (y) (+ x y)))) (test 10 add4 6) (test '(3 4 5 6) (lambda x x) 3 4 5 6) (test '(5 6) (lambda (x y . z) z) 3 4 5 6) (SECTION 4 1 5) (test 'yes 'if (if (> 3 2) 'yes 'no)) (test 'no 'if (if (> 2 3) 'yes 'no)) (test '1 'if (if (> 3 2) (- 3 2) (+ 3 2))) (SECTION 4 1 6) (define x 2) (test 3 'define (+ x 1)) (set! x 4) (test 5 'set! (+ x 1)) (SECTION 4 2 1) (test 'greater 'cond (cond ((> 3 2) 'greater) ((< 3 2) 'less))) (test 'equal 'cond (cond ((> 3 3) 'greater) ((< 3 3) 'less) (else 'equal))) (test 2 'cond (cond ((assv 'b '((a 1) (b 2))) => cadr) (else #f))) (test 'composite 'case (case (* 2 3) ((2 3 5 7) 'prime) ((1 4 6 8 9) 'composite))) (test 'consonant 'case (case (car '(c d)) ((a e i o u) 'vowel) ((w y) 'semivowel) (else 'consonant))) (test #t 'and (and (= 2 2) (> 2 1))) (test #f 'and (and (= 2 2) (< 2 1))) (test '(f g) 'and (and 1 2 'c '(f g))) (test #t 'and (and)) (test #t 'or (or (= 2 2) (> 2 1))) (test #t 'or (or (= 2 2) (< 2 1))) (test #f 'or (or #f #f #f)) (test #f 'or (or)) (test '(b c) 'or (or (memq 'b '(a b c)) (+ 3 0))) (SECTION 4 2 2) (test 6 'let (let ((x 2) (y 3)) (* x y))) (test 35 'let (let ((x 2) (y 3)) (let ((x 7) (z (+ x y))) (* z x)))) (test 70 'let* (let ((x 2) (y 3)) (let* ((x 7) (z (+ x y))) (* z x)))) (test #t 'letrec (letrec ((even? (lambda (n) (if (zero? n) #t (odd? (- n 1))))) (odd? (lambda (n) (if (zero? n) #f (even? (- n 1)))))) (even? 88))) (define x 34) (test 5 'let (let ((x 3)) (define x 5) x)) (test 34 'let x) (test 6 'let (let () (define x 6) x)) (test 34 'let x) (test 34 'let (let ((x x)) x)) (test 7 'let* (let* ((x 3)) (define x 7) x)) (test 34 'let* x) (test 8 'let* (let* () (define x 8) x)) (test 34 'let* x) (test 9 'letrec (letrec () (define x 9) x)) (test 34 'letrec x) (test 10 'letrec (letrec ((x 3)) (define x 10) x)) (test 34 'letrec x) (define (s x) (if x (let () (set! s x) (set! x s)))) (SECTION 4 2 3) (define x 0) (test 6 'begin (begin (set! x (begin (begin 5))) (begin ((begin +) (begin x) (begin (begin 1)))))) (SECTION 4 2 4) (test '#(0 1 2 3 4) 'do (do ((vec (make-vector 5)) (i 0 (+ i 1))) ((= i 5) vec) (vector-set! vec i i))) (test 25 'do (let ((x '(1 3 5 7 9))) (do ((x x (cdr x)) (sum 0 (+ sum (car x)))) ((null? x) sum)))) (test 1 'let (let foo () 1)) (test '((6 1 3) (-5 -2)) 'let (let loop ((numbers '(3 -2 1 6 -5)) (nonneg '()) (neg '())) (cond ((null? numbers) (list nonneg neg)) ((negative? (car numbers)) (loop (cdr numbers) nonneg (cons (car numbers) neg))) (else (loop (cdr numbers) (cons (car numbers) nonneg) neg))))) ;;From: Allegro Petrofsky (test -1 'let (let ((f -)) (let f ((n (f 1))) n))) (SECTION 4 2 6) (test '(list 3 4) 'quasiquote `(list ,(+ 1 2) 4)) (test '(list a (quote a)) 'quasiquote (let ((name 'a)) `(list ,name ',name))) (test '(a 3 4 5 6 b) 'quasiquote `(a ,(+ 1 2) ,@(map abs '(4 -5 6)) b)) (test '((foo 7) . cons) 'quasiquote `((foo ,(- 10 3)) ,@(cdr '(c)) . ,(car '(cons)))) ;;; sqt is defined here because not all implementations are required to ;;; support it. (define (sqt x) (do ((i 0 (+ i 1))) ((> (* i i) x) (- i 1)))) (test '#(10 5 2 4 3 8) 'quasiquote `#(10 5 ,(sqt 4) ,@(map sqt '(16 9)) 8)) (test 5 'quasiquote `,(+ 2 3)) (test '(a `(b ,(+ 1 2) ,(foo 4 d) e) f) 'quasiquote `(a `(b ,(+ 1 2) ,(foo ,(+ 1 3) d) e) f)) (test '(a `(b ,x ,'y d) e) 'quasiquote (let ((name1 'x) (name2 'y)) `(a `(b ,,name1 ,',name2 d) e))) (test '(list 3 4) 'quasiquote (quasiquote (list (unquote (+ 1 2)) 4))) (test '`(list ,(+ 1 2) 4) 'quasiquote '(quasiquote (list (unquote (+ 1 2)) 4))) (SECTION 5 2 1) (define (tprint x) #t) (test #t 'tprint (tprint 56)) (define add3 (lambda (x) (+ x 3))) (test 6 'define (add3 3)) (define first car) (test 1 'define (first '(1 2))) (define foo (lambda () 9)) (test 9 'define (foo)) (define foo foo) (test 9 'define (foo)) (define foo (let ((foo foo)) (lambda () (+ 1 (foo))))) (test 10 'define (foo)) (define old-+ +) (begin (begin (begin) (begin (begin (begin) (define + (lambda (x y) (list y x))) (begin))) (begin)) (begin) (begin (begin (begin) (test '(3 6) add3 6) (begin)))) (set! + old-+) (test 9 add3 6) (begin) (begin (begin)) (begin (begin (begin (begin)))) (SECTION 5 2 2) (test 45 'define (let ((x 5)) (begin (begin (begin) (begin (begin (begin) (define foo (lambda (y) (bar x y))) (begin))) (begin)) (begin) (begin) (begin (define bar (lambda (a b) (+ (* a b) a)))) (begin)) (begin) (begin (foo (+ x 3))))) (define x 34) (define (foo) (define x 5) x) (test 5 foo) (test 34 'define x) (define foo (lambda () (define x 5) x)) (test 5 foo) (test 34 'define x) (define (foo x) ((lambda () (define x 5) x)) x) (test 88 foo 88) (test 4 foo 4) (test 34 'define x) (test 99 'internal-define (letrec ((foo (lambda (arg) (or arg (and (procedure? foo) (foo 99)))))) (define bar (foo #f)) (foo #f))) (test 77 'internal-define (letrec ((foo 77) (bar #f) (retfoo (lambda () foo))) (define baz (retfoo)) (retfoo))) (SECTION 6 1) (test #f not #t) (test #f not 3) (test #f not (list 3)) (test #t not #f) (test #f not '()) (test #f not (list)) (test #f not 'nil) ;(test #t boolean? #f) ;(test #f boolean? 0) ;(test #f boolean? '()) (SECTION 6 2) (test #t eqv? 'a 'a) (test #f eqv? 'a 'b) (test #t eqv? 2 2) (test #t eqv? '() '()) (test #t eqv? '10000 '10000) (test #f eqv? (cons 1 2)(cons 1 2)) (test #f eqv? (lambda () 1) (lambda () 2)) (test #f eqv? #f 'nil) (let ((p (lambda (x) x))) (test #t eqv? p p)) (define gen-counter (lambda () (let ((n 0)) (lambda () (set! n (+ n 1)) n)))) (let ((g (gen-counter))) (test #t eqv? g g)) (test #f eqv? (gen-counter) (gen-counter)) (letrec ((f (lambda () (if (eqv? f g) 'f 'both))) (g (lambda () (if (eqv? f g) 'g 'both)))) (test #f eqv? f g)) (test #t eq? 'a 'a) (test #f eq? (list 'a) (list 'a)) (test #t eq? '() '()) (test #t eq? car car) (let ((x '(a))) (test #t eq? x x)) (let ((x '#())) (test #t eq? x x)) (let ((x (lambda (x) x))) (test #t eq? x x)) (define test-eq?-eqv?-agreement (lambda (obj1 obj2) (cond ((eq? (eq? obj1 obj2) (eqv? obj1 obj2))) (else (record-error (list #f #t (list 'test-eq?-eqv?-agreement obj1 obj2))) (display "eqv? and eq? disagree about ") (write obj1) (display #\space) (write obj2) (newline))))) (test-eq?-eqv?-agreement '#f '#f) (test-eq?-eqv?-agreement '#t '#t) (test-eq?-eqv?-agreement '#t '#f) (test-eq?-eqv?-agreement '(a) '(a)) (test-eq?-eqv?-agreement '(a) '(b)) (test-eq?-eqv?-agreement car car) (test-eq?-eqv?-agreement car cdr) (test-eq?-eqv?-agreement (list 'a) (list 'a)) (test-eq?-eqv?-agreement (list 'a) (list 'b)) (test-eq?-eqv?-agreement '#(a) '#(a)) (test-eq?-eqv?-agreement '#(a) '#(b)) (test-eq?-eqv?-agreement "abc" "abc") (test-eq?-eqv?-agreement "abc" "abz") (test #t equal? 'a 'a) (test #t equal? '(a) '(a)) (test #t equal? '(a (b) c) '(a (b) c)) (test #t equal? "abc" "abc") (test #t equal? 2 2) (test #t equal? (make-vector 5 'a) (make-vector 5 'a)) (SECTION 6 3) (test '(a b c d e) 'dot '(a . (b . (c . (d . (e . ())))))) (define x (list 'a 'b 'c)) (define y x) (and list? (test #t list? y)) (set-cdr! x 4) (test '(a . 4) 'set-cdr! x) (test #t eqv? x y) (test '(a b c . d) 'dot '(a . (b . (c . d)))) (and list? (test #f list? y)) (and list? (let ((x (list 'a))) (set-cdr! x x) (test #f 'list? (list? x)))) ;(test #t pair? '(a . b)) ;(test #t pair? '(a . 1)) ;(test #t pair? '(a b c)) ;(test #f pair? '()) ;(test #f pair? '#(a b)) (test '(a) cons 'a '()) (test '((a) b c d) cons '(a) '(b c d)) (test '("a" b c) cons "a" '(b c)) (test '(a . 3) cons 'a 3) (test '((a b) . c) cons '(a b) 'c) (test 'a car '(a b c)) (test '(a) car '((a) b c d)) (test 1 car '(1 . 2)) (test '(b c d) cdr '((a) b c d)) (test 2 cdr '(1 . 2)) (test '(a 7 c) list 'a (+ 3 4) 'c) (test '() list) (test 3 length '(a b c)) (test 3 length '(a (b) (c d e))) (test 0 length '()) (test '(x y) append '(x) '(y)) (test '(a b c d) append '(a) '(b c d)) (test '(a (b) (c)) append '(a (b)) '((c))) (test '() append) (test '(a b c . d) append '(a b) '(c . d)) (test 'a append '() 'a) (test '(c b a) reverse '(a b c)) (test '((e (f)) d (b c) a) reverse '(a (b c) d (e (f)))) (test 'c list-ref '(a b c d) 2) (test '(a b c) memq 'a '(a b c)) (test '(b c) memq 'b '(a b c)) (test '#f memq 'a '(b c d)) (test '#f memq (list 'a) '(b (a) c)) (test '((a) c) member (list 'a) '(b (a) c)) (test '(101 102) memv 101 '(100 101 102)) (define e '((a 1) (b 2) (c 3))) (test '(a 1) assq 'a e) (test '(b 2) assq 'b e) (test #f assq 'd e) (test #f assq (list 'a) '(((a)) ((b)) ((c)))) (test '((a)) assoc (list 'a) '(((a)) ((b)) ((c)))) (test '(5 7) assv 5 '((2 3) (5 7) (11 13))) (SECTION 6 4) ;(test #t symbol? 'foo) (test #t symbol? (car '(a b))) ;(test #f symbol? "bar") ;(test #t symbol? 'nil) ;(test #f symbol? '()) ;(test #f symbol? #f) ;;; But first, what case are symbols in? Determine the standard case: (define char-standard-case char-upcase) (if (string=? (symbol->string 'A) "a") (set! char-standard-case char-downcase)) (test #t 'standard-case (string=? (symbol->string 'a) (symbol->string 'A))) (test #t 'standard-case (or (string=? (symbol->string 'a) "A") (string=? (symbol->string 'A) "a"))) (define (str-copy s) (let ((v (make-string (string-length s)))) (do ((i (- (string-length v) 1) (- i 1))) ((< i 0) v) (string-set! v i (string-ref s i))))) (define (string-standard-case s) (set! s (str-copy s)) (do ((i 0 (+ 1 i)) (sl (string-length s))) ((>= i sl) s) (string-set! s i (char-standard-case (string-ref s i))))) (test (string-standard-case "flying-fish") symbol->string 'flying-fish) (test (string-standard-case "martin") symbol->string 'Martin) (test "Malvina" symbol->string (string->symbol "Malvina")) (test #t 'standard-case (eq? 'a 'A)) (define x (string #\a #\b)) (define y (string->symbol x)) (string-set! x 0 #\c) (test "cb" 'string-set! x) (test "ab" symbol->string y) (test y string->symbol "ab") (test #t eq? 'mISSISSIppi 'mississippi) (test #f 'string->symbol (eq? 'bitBlt (string->symbol "bitBlt"))) (test 'JollyWog string->symbol (symbol->string 'JollyWog)) (SECTION 6 5 5) (test #t number? 3) (test #t complex? 3) (test #t real? 3) (test #t rational? 3) (test #t integer? 3) (test #t exact? 3) (test #f inexact? 3) (test 1 expt 0 0) (test 0 expt 0 1) (test 0 expt 0 256) ;;(test 0 expt 0 -255) (test 1 expt -1 256) (test -1 expt -1 255) (test 1 expt -1 -256) (test -1 expt -1 -255) (test 1 expt 256 0) (test 1 expt -256 0) (test 256 expt 256 1) (test -256 expt -256 1) (test 8 expt 2 3) (test -8 expt -2 3) (test 9 expt 3 2) (test 9 expt -3 2) (test #t = 22 22 22) (test #t = 22 22) (test #f = 34 34 35) (test #f = 34 35) (test #t > 3 -6246) (test #f > 9 9 -2424) (test #t >= 3 -4 -6246) (test #t >= 9 9) (test #f >= 8 9) (test #t < -1 2 3 4 5 6 7 8) (test #f < -1 2 3 4 4 5 6 7) (test #t <= -1 2 3 4 5 6 7 8) (test #t <= -1 2 3 4 4 5 6 7) (test #f < 1 3 2) (test #f >= 1 3 2) (test #t zero? 0) (test #f zero? 1) (test #f zero? -1) (test #f zero? -100) (test #t positive? 4) (test #f positive? -4) (test #f positive? 0) (test #f negative? 4) (test #t negative? -4) (test #f negative? 0) (test #t odd? 3) (test #f odd? 2) (test #f odd? -4) (test #t odd? -1) (test #f even? 3) (test #t even? 2) (test #t even? -4) (test #f even? -1) (test 38 max 34 5 7 38 6) (test -24 min 3 5 5 330 4 -24) (test 7 + 3 4) (test '3 + 3) (test 0 +) (test 4 * 4) (test 1 *) (test -1 - 3 4) (test -3 - 3) (test 7 abs -7) (test 7 abs 7) (test 0 abs 0) (test 5 quotient 35 7) (test -5 quotient -35 7) (test -5 quotient 35 -7) (test 5 quotient -35 -7) (test 1 modulo 13 4) (test 1 remainder 13 4) (test 3 modulo -13 4) (test -1 remainder -13 4) (test -3 modulo 13 -4) (test 1 remainder 13 -4) (test -1 modulo -13 -4) (test -1 remainder -13 -4) (test 0 modulo 0 86400) (test 0 modulo 0 -86400) (define (divtest n1 n2) (= n1 (+ (* n2 (quotient n1 n2)) (remainder n1 n2)))) (test #t divtest 238 9) (test #t divtest -238 9) (test #t divtest 238 -9) (test #t divtest -238 -9) (test 4 gcd 0 4) (test 4 gcd -4 0) (test 4 gcd 32 -36) (test 0 gcd) (test 288 lcm 32 -36) (test 1 lcm) (SECTION 6 5 5) ;;; Implementations which don't allow division by 0 can have fragile ;;; string->number. (define (test-string->number str) (define ans (string->number str)) (cond ((not ans) #t) ((number? ans) #t) (else ans))) (for-each (lambda (str) (test #t test-string->number str)) '("+#.#" "-#.#" "#.#" "1/0" "-1/0" "0/0" "+1/0i" "-1/0i" "0/0i" "0/0-0/0i" "1/0-1/0i" "-1/0+1/0i" "#i" "#e" "#" "#i0/0")) (cond ((number? (string->number "1+1i")) ;More kawa bait (test #t number? (string->number "#i-i")) (test #t number? (string->number "#i+i")) (test #t number? (string->number "#i2+i")))) ;;;;From: fred@sce.carleton.ca (Fred J Kaudel) ;;; Modified by jaffer. (define (test-inexact) (define f3.9 (string->number "3.9")) (define f4.0 (string->number "4.0")) (define f-3.25 (string->number "-3.25")) (define f.25 (string->number ".25")) (define f4.5 (string->number "4.5")) (define f3.5 (string->number "3.5")) (define f0.0 (string->number "0.0")) (define f0.8 (string->number "0.8")) (define f1.0 (string->number "1.0")) (define f1e300 (and (string->number "1+3i") (string->number "1e300"))) (define f1e-300 (and (string->number "1+3i") (string->number "1e-300"))) (define wto write-test-obj) (define lto load-test-obj) (newline) (display ";testing inexact numbers; ") (newline) (SECTION 6 2) (test #f eqv? 1 f1.0) (test #f eqv? 0 f0.0) (test #t eqv? f0.0 f0.0) (cond ((= f0.0 (- f0.0)) (test #t eqv? f0.0 (- f0.0)) (test #t equal? f0.0 (- f0.0)))) (cond ((= f0.0 (* -5 f0.0)) (test #t eqv? f0.0 (* -5 f0.0)) (test #t equal? f0.0 (* -5 f0.0)))) (SECTION 6 5 5) (and f1e300 (let ((f1e300+1e300i (make-rectangular f1e300 f1e300))) (test f1.0 'magnitude (/ (magnitude f1e300+1e300i) (* f1e300 (sqrt 2)))) (test f.25 / f1e300+1e300i (* 4 f1e300+1e300i)))) (and f1e-300 (let ((f1e-300+1e-300i (make-rectangular f1e-300 f1e-300))) (test f1.0 'magnitude (round (/ (magnitude f1e-300+1e-300i) (* f1e-300 (sqrt 2))))) (test f.25 / f1e-300+1e-300i (* 4 f1e-300+1e-300i)))) (test #t = f0.0 f0.0) (test #t = f0.0 (- f0.0)) (test #t = f0.0 (* -5 f0.0)) (test #t inexact? f3.9) (test #t 'max (inexact? (max f3.9 4))) (test f4.0 max f3.9 4) (test f4.0 exact->inexact 4) (test f4.0 exact->inexact 4.0) (test 4 inexact->exact 4) (test 4 inexact->exact 4.0) (test (- f4.0) round (- f4.5)) (test (- f4.0) round (- f3.5)) (test (- f4.0) round (- f3.9)) (test f0.0 round f0.0) (test f0.0 round f.25) (test f1.0 round f0.8) (test f4.0 round f3.5) (test f4.0 round f4.5) ;;(test f1.0 expt f0.0 f0.0) ;;(test f1.0 expt f0.0 0) ;;(test f1.0 expt 0 f0.0) (test f0.0 expt f0.0 f1.0) (test f0.0 expt f0.0 1) (test f0.0 expt 0 f1.0) (test f1.0 expt -25 f0.0) (test f1.0 expt f-3.25 f0.0) (test f1.0 expt f-3.25 0) ;;(test f0.0 expt f0.0 f-3.25) (test (atan 1) atan 1 1) (set! write-test-obj (list f.25 f-3.25)) ;.25 inexact errors less likely. (set! load-test-obj (list 'define 'foo (list 'quote write-test-obj))) (test #t call-with-output-file "tmp3" (lambda (test-file) (write-char #\; test-file) (display #\; test-file) (display ";" test-file) (write write-test-obj test-file) (newline test-file) (write load-test-obj test-file) (output-port? test-file))) (check-test-file "tmp3") (set! write-test-obj wto) (set! load-test-obj lto) (let ((x (string->number "4195835.0")) (y (string->number "3145727.0"))) (test #t 'pentium-fdiv-bug (> f1.0 (- x (* (/ x y) y))))) (report-errs)) (define (test-inexact-printing) (let ((f0.0 (string->number "0.0")) (f0.5 (string->number "0.5")) (f1.0 (string->number "1.0")) (f2.0 (string->number "2.0"))) (define log2 (let ((l2 (log 2))) (lambda (x) (/ (log x) l2)))) (define (slow-frexp x) (if (zero? x) (list f0.0 0) (let* ((l2 (log2 x)) (e (floor (log2 x))) (e (if (= l2 e) (inexact->exact e) (+ (inexact->exact e) 1))) (f (/ x (expt 2 e)))) (list f e)))) (define float-precision (let ((mantissa-bits (do ((i 0 (+ i 1)) (eps f1.0 (* f0.5 eps))) ((= f1.0 (+ f1.0 eps)) i))) (minval (do ((x f1.0 (* f0.5 x))) ((zero? (* f0.5 x)) x)))) (lambda (x) (apply (lambda (f e) (let ((eps (cond ((= f1.0 f) (expt f2.0 (+ 1 (- e mantissa-bits)))) ((zero? f) minval) (else (expt f2.0 (- e mantissa-bits)))))) (if (zero? eps) ;Happens if gradual underflow. minval eps))) (slow-frexp x))))) (define (float-print-test x) (define (testit number) (eqv? number (string->number (number->string number)))) (let ((eps (float-precision x)) (all-ok? #t)) (do ((j -100 (+ j 1))) ((or (not all-ok?) (> j 100)) all-ok?) (let* ((xx (+ x (* j eps))) (ok? (testit xx))) (cond ((not ok?) (display "Number readback failure for ") (display `(+ ,x (* ,j ,eps))) (newline) (display xx) (newline) (set! all-ok? #f)) ;; (else (display xx) (newline)) ))))) (define (mult-float-print-test x) (let ((res #t)) (for-each (lambda (mult) (or (float-print-test (* mult x)) (set! res #f))) (map string->number '("1.0" "10.0" "100.0" "1.0e20" "1.0e50" "1.0e100" "0.1" "0.01" "0.001" "1.0e-20" "1.0e-50" "1.0e-100"))) res)) (SECTION 6 5 6) (test #t 'float-print-test (float-print-test f0.0)) (test #t 'mult-float-print-test (mult-float-print-test f1.0)) (test #t 'mult-float-print-test (mult-float-print-test (string->number "3.0"))) (test #t 'mult-float-print-test (mult-float-print-test (string->number "7.0"))) (test #t 'mult-float-print-test (mult-float-print-test (string->number "3.1415926535897931"))) (test #t 'mult-float-print-test (mult-float-print-test (string->number "2.7182818284590451"))))) (define (test-bignum) (define tb (lambda (n1 n2) (= n1 (+ (* n2 (quotient n1 n2)) (remainder n1 n2))))) (define b3-3 (string->number "33333333333333333333")) (define b3-2 (string->number "33333333333333333332")) (define b3-0 (string->number "33333333333333333330")) (define b2-0 (string->number "2177452800")) (newline) (display ";testing bignums; ") (newline) (SECTION 6 5 7) (test 0 modulo b3-3 3) (test 0 modulo b3-3 -3) (test 0 remainder b3-3 3) (test 0 remainder b3-3 -3) (test 2 modulo b3-2 3) (test -1 modulo b3-2 -3) (test 2 remainder b3-2 3) (test 2 remainder b3-2 -3) (test 1 modulo (- b3-2) 3) (test -2 modulo (- b3-2) -3) (test -2 remainder (- b3-2) 3) (test -2 remainder (- b3-2) -3) (test 3 modulo 3 b3-3) (test b3-0 modulo -3 b3-3) (test 3 remainder 3 b3-3) (test -3 remainder -3 b3-3) (test (- b3-0) modulo 3 (- b3-3)) (test -3 modulo -3 (- b3-3)) (test 3 remainder 3 (- b3-3)) (test -3 remainder -3 (- b3-3)) (test 0 modulo (- b2-0) 86400) (test 0 modulo b2-0 -86400) (test 0 modulo b2-0 86400) (test 0 modulo (- b2-0) -86400) (test 0 modulo 0 (- b2-0)) (test #t 'remainder (tb (string->number "281474976710655325431") 65535)) (test #t 'remainder (tb (string->number "281474976710655325430") 65535)) (let ((n (string->number "30414093201713378043612608166064768844377641568960512"))) (and n (exact? n) (do ((pow3 1 (* 3 pow3)) (cnt 21 (+ -1 cnt))) ((negative? cnt) (zero? (modulo n pow3)))))) (SECTION 6 5 8) (test "281474976710655325431" number->string (string->number "281474976710655325431")) (report-errs)) (define (test-numeric-predicates) (let* ((big-ex (expt 2 150)) (big-inex (exact->inexact big-ex))) (newline) (display ";testing bignum-inexact comparisons;") (newline) (SECTION 6 5 5) (test #f = (+ big-ex 1) big-inex (- big-ex 1)) (test #f = big-inex (+ big-ex 1) (- big-ex 1)) (test #t < (- (inexact->exact big-inex) 1) big-inex (+ (inexact->exact big-inex) 1)))) (SECTION 6 5 9) (test "0" number->string 0) (test "100" number->string 100) (test "100" number->string 256 16) (test 100 string->number "100") (test 256 string->number "100" 16) (test #f string->number "") (test #f string->number ".") (test #f string->number "d") (test #f string->number "D") (test #f string->number "i") (test #f string->number "I") (test #f string->number "3i") (test #f string->number "3I") (test #f string->number "33i") (test #f string->number "33I") (test #f string->number "3.3i") (test #f string->number "3.3I") (test #f string->number "-") (test #f string->number "+") (test #t 'string->number (or (not (string->number "80000000" 16)) (positive? (string->number "80000000" 16)))) (test #t 'string->number (or (not (string->number "-80000000" 16)) (negative? (string->number "-80000000" 16)))) (SECTION 6 6) (test #t eqv? '#\ #\Space) (test #t eqv? #\space '#\Space) (test #t char? #\a) (test #t char? #\() (test #t char? #\space) (test #t char? '#\newline) (test #f char=? #\A #\B) (test #f char=? #\a #\b) (test #f char=? #\9 #\0) (test #t char=? #\A #\A) (test #t char? #\A #\B) (test #f char>? #\a #\b) (test #t char>? #\9 #\0) (test #f char>? #\A #\A) (test #t char<=? #\A #\B) (test #t char<=? #\a #\b) (test #f char<=? #\9 #\0) (test #t char<=? #\A #\A) (test #f char>=? #\A #\B) (test #f char>=? #\a #\b) (test #t char>=? #\9 #\0) (test #t char>=? #\A #\A) (test #f char-ci=? #\A #\B) (test #f char-ci=? #\a #\B) (test #f char-ci=? #\A #\b) (test #f char-ci=? #\a #\b) (test #f char-ci=? #\9 #\0) (test #t char-ci=? #\A #\A) (test #t char-ci=? #\A #\a) (test #t char-ci? #\A #\B) (test #f char-ci>? #\a #\B) (test #f char-ci>? #\A #\b) (test #f char-ci>? #\a #\b) (test #t char-ci>? #\9 #\0) (test #f char-ci>? #\A #\A) (test #f char-ci>? #\A #\a) (test #t char-ci<=? #\A #\B) (test #t char-ci<=? #\a #\B) (test #t char-ci<=? #\A #\b) (test #t char-ci<=? #\a #\b) (test #f char-ci<=? #\9 #\0) (test #t char-ci<=? #\A #\A) (test #t char-ci<=? #\A #\a) (test #f char-ci>=? #\A #\B) (test #f char-ci>=? #\a #\B) (test #f char-ci>=? #\A #\b) (test #f char-ci>=? #\a #\b) (test #t char-ci>=? #\9 #\0) (test #t char-ci>=? #\A #\A) (test #t char-ci>=? #\A #\a) (test #t char-alphabetic? #\a) (test #t char-alphabetic? #\A) (test #t char-alphabetic? #\z) (test #t char-alphabetic? #\Z) (test #f char-alphabetic? #\0) (test #f char-alphabetic? #\9) (test #f char-alphabetic? #\space) (test #f char-alphabetic? #\;) (test #f char-numeric? #\a) (test #f char-numeric? #\A) (test #f char-numeric? #\z) (test #f char-numeric? #\Z) (test #t char-numeric? #\0) (test #t char-numeric? #\9) (test #f char-numeric? #\space) (test #f char-numeric? #\;) (test #f char-whitespace? #\a) (test #f char-whitespace? #\A) (test #f char-whitespace? #\z) (test #f char-whitespace? #\Z) (test #f char-whitespace? #\0) (test #f char-whitespace? #\9) (test #t char-whitespace? #\space) (test #f char-whitespace? #\;) (test #f char-upper-case? #\0) (test #f char-upper-case? #\9) (test #f char-upper-case? #\space) (test #f char-upper-case? #\;) (test #f char-lower-case? #\0) (test #f char-lower-case? #\9) (test #f char-lower-case? #\space) (test #f char-lower-case? #\;) (test #\. integer->char (char->integer #\.)) (test #\A integer->char (char->integer #\A)) (test #\a integer->char (char->integer #\a)) (test #\A char-upcase #\A) (test #\A char-upcase #\a) (test #\a char-downcase #\A) (test #\a char-downcase #\a) (SECTION 6 7) (test #t string? "The word \"recursion\\\" has many meanings.") ;(test #t string? "") (define f (make-string 3 #\*)) (test "?**" 'string-set! (begin (string-set! f 0 #\?) f)) (test "abc" string #\a #\b #\c) (test "" string) (test 3 string-length "abc") (test #\a string-ref "abc" 0) (test #\c string-ref "abc" 2) (test 0 string-length "") (test "" substring "ab" 0 0) (test "" substring "ab" 1 1) (test "" substring "ab" 2 2) (test "a" substring "ab" 0 1) (test "b" substring "ab" 1 2) (test "ab" substring "ab" 0 2) (test "foobar" string-append "foo" "bar") (test "foo" string-append "foo") (test "foo" string-append "foo" "") (test "foo" string-append "" "foo") (test "" string-append) (test "" make-string 0) (test #t string=? "" "") (test #f string? "" "") (test #t string<=? "" "") (test #t string>=? "" "") (test #t string-ci=? "" "") (test #f string-ci? "" "") (test #t string-ci<=? "" "") (test #t string-ci>=? "" "") (test #f string=? "A" "B") (test #f string=? "a" "b") (test #f string=? "9" "0") (test #t string=? "A" "A") (test #t string? "A" "B") (test #f string>? "a" "b") (test #t string>? "9" "0") (test #f string>? "A" "A") (test #t string<=? "A" "B") (test #t string<=? "a" "b") (test #f string<=? "9" "0") (test #t string<=? "A" "A") (test #f string>=? "A" "B") (test #f string>=? "a" "b") (test #t string>=? "9" "0") (test #t string>=? "A" "A") (test #f string-ci=? "A" "B") (test #f string-ci=? "a" "B") (test #f string-ci=? "A" "b") (test #f string-ci=? "a" "b") (test #f string-ci=? "9" "0") (test #t string-ci=? "A" "A") (test #t string-ci=? "A" "a") (test #t string-ci? "A" "B") (test #f string-ci>? "a" "B") (test #f string-ci>? "A" "b") (test #f string-ci>? "a" "b") (test #t string-ci>? "9" "0") (test #f string-ci>? "A" "A") (test #f string-ci>? "A" "a") (test #t string-ci<=? "A" "B") (test #t string-ci<=? "a" "B") (test #t string-ci<=? "A" "b") (test #t string-ci<=? "a" "b") (test #f string-ci<=? "9" "0") (test #t string-ci<=? "A" "A") (test #t string-ci<=? "A" "a") (test #f string-ci>=? "A" "B") (test #f string-ci>=? "a" "B") (test #f string-ci>=? "A" "b") (test #f string-ci>=? "a" "b") (test #t string-ci>=? "9" "0") (test #t string-ci>=? "A" "A") (test #t string-ci>=? "A" "a") (SECTION 6 8) (test #t vector? '#(0 (2 2 2 2) "Anna")) ;(test #t vector? '#()) (test '#(a b c) vector 'a 'b 'c) (test '#() vector) (test 3 vector-length '#(0 (2 2 2 2) "Anna")) (test 0 vector-length '#()) (test 8 vector-ref '#(1 1 2 3 5 8 13 21) 5) (test '#(0 ("Sue" "Sue") "Anna") 'vector-set (let ((vec (vector 0 '(2 2 2 2) "Anna"))) (vector-set! vec 1 '("Sue" "Sue")) vec)) (test '#(hi hi) make-vector 2 'hi) (test '#() make-vector 0) (test '#() make-vector 0 'a) (SECTION 6 9) (test #t procedure? car) ;(test #f procedure? 'car) (test #t procedure? (lambda (x) (* x x))) (test #f procedure? '(lambda (x) (* x x))) (test #t call-with-current-continuation procedure?) (test 7 apply + (list 3 4)) (test 7 apply (lambda (a b) (+ a b)) (list 3 4)) (test 17 apply + 10 (list 3 4)) (test '() apply list '()) (define compose (lambda (f g) (lambda args (f (apply g args))))) (test 30 (compose sqt *) 12 75) (test '(b e h) map cadr '((a b) (d e) (g h))) (test '(5 7 9) map + '(1 2 3) '(4 5 6)) (test '(1 2 3) map + '(1 2 3)) (test '(1 2 3) map * '(1 2 3)) (test '(-1 -2 -3) map - '(1 2 3)) (test '#(0 1 4 9 16) 'for-each (let ((v (make-vector 5))) (for-each (lambda (i) (vector-set! v i (* i i))) '(0 1 2 3 4)) v)) (test -3 call-with-current-continuation (lambda (exit) (for-each (lambda (x) (if (negative? x) (exit x))) '(54 0 37 -3 245 19)) #t)) (define list-length (lambda (obj) (call-with-current-continuation (lambda (return) (letrec ((r (lambda (obj) (cond ((null? obj) 0) ((pair? obj) (+ (r (cdr obj)) 1)) (else (return #f)))))) (r obj)))))) (test 4 list-length '(1 2 3 4)) (test #f list-length '(a b . c)) (test '() map cadr '()) ;;; This tests full conformance of call-with-current-continuation. It ;;; is a separate test because some schemes do not support call/cc ;;; other than escape procedures. I am indebted to ;;; raja@copper.ucs.indiana.edu (Raja Sooriamurthi) for fixing this ;;; code. The function leaf-eq? compares the leaves of 2 arbitrary ;;; trees constructed of conses. (define (next-leaf-generator obj eot) (letrec ((return #f) (cont (lambda (x) (recur obj) (set! cont (lambda (x) (return eot))) (cont #f))) (recur (lambda (obj) (if (pair? obj) (for-each recur obj) (call-with-current-continuation (lambda (c) (set! cont c) (return obj))))))) (lambda () (call-with-current-continuation (lambda (ret) (set! return ret) (cont #f)))))) (define (leaf-eq? x y) (let* ((eot (list 'eot)) (xf (next-leaf-generator x eot)) (yf (next-leaf-generator y eot))) (letrec ((loop (lambda (x y) (cond ((not (eq? x y)) #f) ((eq? eot x) #t) (else (loop (xf) (yf))))))) (loop (xf) (yf))))) (define (test-cont) (newline) (display ";testing continuations; ") (newline) (SECTION 6 9) (test #t leaf-eq? '(a (b (c))) '((a) b c)) (test #f leaf-eq? '(a (b (c))) '((a) b c d)) (report-errs)) ;;; Test Optional R4RS DELAY syntax and FORCE procedure (define (test-delay) (newline) (display ";testing DELAY and FORCE; ") (newline) (SECTION 6 9) (test 3 'delay (force (delay (+ 1 2)))) (test '(3 3) 'delay (let ((p (delay (+ 1 2)))) (list (force p) (force p)))) (test 2 'delay (letrec ((a-stream (letrec ((next (lambda (n) (cons n (delay (next (+ n 1))))))) (next 0))) (head car) (tail (lambda (stream) (force (cdr stream))))) (head (tail (tail a-stream))))) (letrec ((count 0) (p (delay (begin (set! count (+ count 1)) (if (> count x) count (force p))))) (x 5)) (test 6 force p) (set! x 10) (test 6 force p)) (test 3 'force (letrec ((p (delay (if c 3 (begin (set! c #t) (+ (force p) 1))))) (c #f)) (force p))) (report-errs)) (SECTION 6 10 1) (test #t input-port? (current-input-port)) (test #t output-port? (current-output-port)) (test #t call-with-input-file "r4rstest.scm" input-port?) (define this-file (open-input-file "r4rstest.scm")) (test #t input-port? this-file) (SECTION 6 10 2) (test #\; peek-char this-file) (test #\; read-char this-file) (test '(define cur-section '()) read this-file) (test #\( peek-char this-file) (test '(define errs '()) read this-file) (close-input-port this-file) (close-input-port this-file) (define (check-test-file name) (define test-file (open-input-file name)) (test #t 'input-port? (call-with-input-file name (lambda (test-file) (test load-test-obj read test-file) (test #t eof-object? (peek-char test-file)) (test #t eof-object? (read-char test-file)) (input-port? test-file)))) (test #\; read-char test-file) (test #\; read-char test-file) (test #\; read-char test-file) (test write-test-obj read test-file) (test load-test-obj read test-file) (close-input-port test-file)) (SECTION 6 10 3) (define write-test-obj '(#t #f a () 9739 -3 . #((test) "te \" \" st" "" test #() b c))) (define load-test-obj (list 'define 'foo (list 'quote write-test-obj))) (test #t call-with-output-file "tmp1" (lambda (test-file) (write-char #\; test-file) (display #\; test-file) (display ";" test-file) (write write-test-obj test-file) (newline test-file) (write load-test-obj test-file) (output-port? test-file))) (check-test-file "tmp1") (define test-file (open-output-file "tmp2")) (write-char #\; test-file) (display #\; test-file) (display ";" test-file) (write write-test-obj test-file) (newline test-file) (write load-test-obj test-file) (test #t output-port? test-file) (close-output-port test-file) (check-test-file "tmp2") (define (test-sc4) (newline) (display ";testing scheme 4 functions; ") (newline) (SECTION 6 7) (test '(#\P #\space #\l) string->list "P l") (test '() string->list "") (test "1\\\"" list->string '(#\1 #\\ #\")) (test "" list->string '()) (SECTION 6 8) (test '(dah dah didah) vector->list '#(dah dah didah)) (test '() vector->list '#()) (test '#(dididit dah) list->vector '(dididit dah)) (test '#() list->vector '()) (SECTION 6 10 4) (load "tmp1") (test write-test-obj 'load foo) (report-errs)) (report-errs) (let ((have-inexacts? (and (string->number "0.0") (inexact? (string->number "0.0")))) (have-bignums? (let ((n (string->number "1427247692705959881058285969449495136382746625"))) (and n (exact? n))))) (cond (have-inexacts? (test-inexact) (test-inexact-printing))) (if have-bignums? (test-bignum)) (if (and have-inexacts? have-bignums?) (test-numeric-predicates))) (newline) (display "To fully test continuations, Scheme 4, and DELAY/FORCE do:") (newline) (display "(test-cont) (test-sc4) (test-delay)") (newline) "last item in file" scm-5e5/Tscript.scm0000644001705200017500000000463510750217336012202 0ustar tbtb;;;; "Tscript.scm" transcript-on and transcript-off. ;; Copyright (C) 1999 Free Software Foundation, Inc. ;; ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU Lesser General Public License as ;; published by the Free Software Foundation, either version 3 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 ;; Lesser General Public License for more details. ;; ;; You should have received a copy of the GNU Lesser General Public ;; License along with this program. If not, see ;; . ;;; Author: Radey Shouman (define transcript-on #f) (define transcript-off #f) (let ((*transcript-stack* '())) (define (trans-on filename) (let ((trans (open-output-file filename)) (inp (current-input-port)) (outp (current-output-port)) (errp (current-error-port))) (define (clone-port port) (make-soft-port (vector (and (output-port? port) (lambda (c) (write-char c port) (write-char c trans))) (and (output-port? port) (lambda (s) (display s port) (display s trans))) (and (output-port? port) (lambda () (force-output port) (force-output trans))) (and (input-port? port) (lambda () (let ((c (read-char port))) (if (eof-object? c) (close-output-port trans) (write-char c trans)) c))) (lambda () (close-port port))) (if (input-port? port) (if (output-port? port) "r+" "r") "w"))) (set! *transcript-stack* (cons (list trans (current-input-port) (current-output-port) (current-error-port)) *transcript-stack*)) (set-current-input-port (clone-port inp)) (set-current-output-port (clone-port outp)) (set-current-error-port (clone-port errp)))) (define (trans-off) (cond ((pair? *transcript-stack*) (apply (lambda (trans inp outp errp) (close-port trans) (set-current-input-port inp) (set-current-output-port outp) (set-current-error-port errp)) (car *transcript-stack*)) (set! *transcript-stack* (cdr *transcript-stack*))) (else (error "No transcript active")))) (set! transcript-on trans-on) (set! transcript-off trans-off)) (provide 'transcript) scm-5e5/setjump.mar0000644001705200017500000000220710647032750012227 0ustar tbtb .title setjump and longjump ; The VAX C runtime library uses the $unwind utility for ; implementing longjmp. That fails if your program does not ; follow normal stack decipline. This is a dirty implementation ; of setjmp and longjmp that does not have that problem. The ; names longjmp and setjmp are avoided so that the code can be ; linked with the vax c runtime library without name clashes. ; This code was contributed by an anonymous reviewer from ; comp.sources.reviewed. .entry setjump,^M movl 4(ap),r0 movq r2,(r0)+ movq r4,(r0)+ movq r6,(r0)+ movq r8,(r0)+ movq r10,(r0)+ movl fp,(r0)+ movo 4(fp),(r0)+ movq 20(fp),(r0) clrl r0 ret .entry longjump,^M movl 4(ap),r0 movq (r0)+,r2 movq (r0)+,r4 movq (r0)+,r6 movq (r0)+,r8 movq (r0)+,r10 movl (r0)+,r1 movo (r0)+,4(r1) movq (r0),20(r1) movl 8(ap),r0 movl r1,fp ret .end scm-5e5/unexec.c0000644001705200017500000010366510750241211011471 0ustar tbtb/* Copyright (C) 1985,86,87,88,92,93,94 Free Software Foundation, Inc. This file is part of GNU Emacs. GNU Emacs 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 3 of the License, or (at your option) any later version. GNU Emacs 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 GNU Emacs. If not, see . */ /* * unexec.c - Convert a running program into an a.out file. * * Author: Spencer W. Thomas * Computer Science Dept. * University of Utah * Date: Tue Mar 2 1982 * Modified heavily since then. * * Synopsis: * unexec (new_name, a_name, data_start, bss_start, entry_address) * char *new_name, *a_name; * unsigned data_start, bss_start, entry_address; * * Takes a snapshot of the program and makes an a.out format file in the * file named by the string argument new_name. * If a_name is non-NULL, the symbol table will be taken from the given file. * On some machines, an existing a_name file is required. * * The boundaries within the a.out file may be adjusted with the data_start * and bss_start arguments. Either or both may be given as 0 for defaults. * * Data_start gives the boundary between the text segment and the data * segment of the program. The text segment can contain shared, read-only * program code and literal data, while the data segment is always unshared * and unprotected. Data_start gives the lowest unprotected address. * The value you specify may be rounded down to a suitable boundary * as required by the machine you are using. * * Specifying zero for data_start means the boundary between text and data * should not be the same as when the program was loaded. * If NO_REMAP is defined, the argument data_start is ignored and the * segment boundaries are never changed. * * Bss_start indicates how much of the data segment is to be saved in the * a.out file and restored when the program is executed. It gives the lowest * unsaved address, and is rounded up to a page boundary. The default when 0 * is given assumes that the entire data segment is to be stored, including * the previous data and bss as well as any additional storage allocated with * break (2). * * The new file is set up to start at entry_address. * * If you make improvements I'd like to get them too. * harpo!utah-cs!thomas, thomas@Utah-20 * */ /* Modified to support SysVr3 shared libraries by James Van Artsdalen * of Dell Computer Corporation. james@bigtex.cactus.org. */ /* There are several compilation parameters affecting unexec: * COFF Define this if your system uses COFF for executables. * COFF_ENCAPSULATE Define this if you are using the GNU coff encapsulated a.out format. This is closer to a.out than COFF. You should *not* define COFF if you define COFF_ENCAPSULATE Otherwise we assume you use Berkeley format. * NO_REMAP Define this if you do not want to try to save Emacs's pure data areas as part of the text segment. Saving them as text is good because it allows users to share more. However, on machines that locate the text area far from the data area, the boundary cannot feasibly be moved. Such machines require NO_REMAP. Also, remapping can cause trouble with the built-in startup routine /lib/crt0.o, which defines `environ' as an initialized variable. Dumping `environ' as pure does not work! So, to use remapping, you must write a startup routine for your machine in Emacs's crt0.c. If NO_REMAP is defined, Emacs uses the system's crt0.o. * SECTION_ALIGNMENT Some machines that use COFF executables require that each section start on a certain boundary *in the COFF file*. Such machines should define SECTION_ALIGNMENT to a mask of the low-order bits that must be zero on such a boundary. This mask is used to control padding between segments in the COFF file. If SECTION_ALIGNMENT is not defined, the segments are written consecutively with no attempt at alignment. This is right for unmodified system V. * SEGMENT_MASK Some machines require that the beginnings and ends of segments *in core* be on certain boundaries. For most machines, a page boundary is sufficient. That is the default. When a larger boundary is needed, define SEGMENT_MASK to a mask of the bits that must be zero on such a boundary. * A_TEXT_OFFSET(HDR) Some machines count the a.out header as part of the size of the text segment (a_text); they may actually load the header into core as the first data in the text segment. Some have additional padding between the header and the real text of the program that is counted in a_text. For these machines, define A_TEXT_OFFSET(HDR) to examine the header structure HDR and return the number of bytes to add to `a_text' before writing it (above and beyond the number of bytes of actual program text). HDR's standard fields are already correct, except that this adjustment to the `a_text' field has not yet been made; thus, the amount of offset can depend on the data in the file. * A_TEXT_SEEK(HDR) If defined, this macro specifies the number of bytes to seek into the a.out file before starting to write the text segment. * EXEC_MAGIC For machines using COFF, this macro, if defined, is a value stored into the magic number field of the output file. * ADJUST_EXEC_HEADER This macro can be used to generate statements to adjust or initialize nonstandard fields in the file header * ADDR_CORRECT(ADDR) Macro to correct an int which is the bit pattern of a pointer to a byte into an int which is the number of a byte. This macro has a default definition which is usually right. This default definition is a no-op on most machines (where a pointer looks like an int) but not on all machines. */ #ifndef emacs #define PERROR(arg) perror (arg); return -1 #else #define IN_UNEXEC #include #define PERROR(file) report_error (file, new) #endif #ifndef CANNOT_DUMP /* all rest of file! */ #ifdef COFF_ENCAPSULATE int need_coff_header = 1; #include /* The location might be a poor assumption */ #else #ifdef MSDOS #if __DJGPP__ > 1 #include /* for O_RDONLY, O_RDWR */ #include /* for _crt0_startup_flags and its bits */ static int save_djgpp_startup_flags; #endif #include #define filehdr external_filehdr #define scnhdr external_scnhdr #define syment external_syment #define auxent external_auxent #define n_numaux e_numaux #define n_type e_type struct aouthdr { unsigned short magic; /* type of file */ unsigned short vstamp; /* version stamp */ unsigned long tsize; /* text size in bytes, padded to FW bdry*/ unsigned long dsize; /* initialized data " " */ unsigned long bsize; /* uninitialized data " " */ unsigned long entry; /* entry pt. */ unsigned long text_start;/* base of text used for this file */ unsigned long data_start;/* base of data used for this file */ }; #else /* not MSDOS */ #include #endif /* not MSDOS */ #endif /* Define getpagesize if the system does not. Note that this may depend on symbols defined in a.out.h. */ #include "getpagesize.h" #ifndef makedev /* Try to detect types.h already loaded */ #include #endif /* makedev */ #include #include #include #include /* Must be after sys/types.h for USG and BSD4_1*/ #ifdef USG5 #include #endif #ifndef O_RDONLY #define O_RDONLY 0 #endif #ifndef O_RDWR #define O_RDWR 2 #endif extern char *start_of_text (); /* Start of text */ extern char *start_of_data (); /* Start of initialized data */ #ifdef COFF static long block_copy_start; /* Old executable start point */ static struct filehdr f_hdr; /* File header */ static struct aouthdr f_ohdr; /* Optional file header (a.out) */ long bias; /* Bias to add for growth */ long lnnoptr; /* Pointer to line-number info within file */ #define SYMS_START block_copy_start static long text_scnptr; static long data_scnptr; #else /* not COFF */ #ifdef HPUX extern void *sbrk (); #else #if 0 /* Some systems with __STDC__ compilers still declare this `char *' in some header file, and our declaration conflicts. The return value is always cast, so it should be harmless to leave it undefined. Hopefully machines with different size pointers and ints declare sbrk in a header file. */ #ifdef __STDC__ extern void *sbrk (); #else extern char *sbrk (); #endif /* __STDC__ */ #endif #endif /* HPUX */ #define SYMS_START ((long) N_SYMOFF (ohdr)) /* Some machines override the structure name for an a.out header. */ #ifndef EXEC_HDR_TYPE #define EXEC_HDR_TYPE struct exec #endif #ifdef HPUX #ifdef HP9000S200_ID #define MY_ID HP9000S200_ID #else #include #define MY_ID MYSYS #endif /* no HP9000S200_ID */ static MAGIC OLDMAGIC = {MY_ID, SHARE_MAGIC}; static MAGIC NEWMAGIC = {MY_ID, DEMAND_MAGIC}; #define N_TXTOFF(x) TEXT_OFFSET(x) #define N_SYMOFF(x) LESYM_OFFSET(x) static EXEC_HDR_TYPE hdr, ohdr; #else /* not HPUX */ #if defined (USG) && !defined (IBMAIX) && !defined (IRIS) && !defined (COFF_ENCAPSULATE) && !defined (LINUX) static struct bhdr hdr, ohdr; #define a_magic fmagic #define a_text tsize #define a_data dsize #define a_bss bsize #define a_syms ssize #define a_trsize rtsize #define a_drsize rdsize #define a_entry entry #define N_BADMAG(x) \ (((x).fmagic)!=OMAGIC && ((x).fmagic)!=NMAGIC &&\ ((x).fmagic)!=FMAGIC && ((x).fmagic)!=IMAGIC) #define NEWMAGIC FMAGIC #else /* IRIS or IBMAIX or not USG */ static EXEC_HDR_TYPE hdr, ohdr; #define NEWMAGIC ZMAGIC #endif /* IRIS or IBMAIX not USG */ #endif /* not HPUX */ static int unexec_text_start; static int unexec_data_start; #ifdef COFF_ENCAPSULATE /* coffheader is defined in the GNU a.out.encap.h file. */ struct coffheader coffheader; #endif #endif /* not COFF */ static int pagemask; /* Correct an int which is the bit pattern of a pointer to a byte into an int which is the number of a byte. This is a no-op on ordinary machines, but not on all. */ #ifndef ADDR_CORRECT /* Let m-*.h files override this definition */ #define ADDR_CORRECT(x) ((char *)(x) - (char*)0) #endif #ifdef emacs #include "lisp.h" static report_error (file, fd) char *file; int fd; { if (fd) close (fd); report_file_error ("Cannot unexec", Fcons (build_string (file), Qnil)); } #endif /* emacs */ #define ERROR0(msg) report_error_1 (new, msg, 0, 0); return -1 #define ERROR1(msg,x) report_error_1 (new, msg, x, 0); return -1 #define ERROR2(msg,x,y) report_error_1 (new, msg, x, y); return -1 static report_error_1 (fd, msg, a1, a2) int fd; char *msg; int a1, a2; { close (fd); #ifdef emacs error (msg, a1, a2); #else fprintf (stderr, msg, a1, a2); fprintf (stderr, "\n"); #endif } static int make_hdr (); static int copy_text_and_data (); static int copy_sym (); static void mark_x (); /* **************************************************************** * unexec * * driving logic. */ unexec (new_name, a_name, data_start, bss_start, entry_address) char *new_name, *a_name; unsigned data_start, bss_start, entry_address; { int new, a_out = -1; if (a_name && (a_out = open (a_name, O_RDONLY)) < 0) { PERROR (a_name); } if ((new = creat (new_name, 0666)) < 0) { PERROR (new_name); } if (make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) < 0 || copy_text_and_data (new, a_out) < 0 || copy_sym (new, a_out, a_name, new_name) < 0 #ifdef COFF #ifndef COFF_BSD_SYMBOLS || adjust_lnnoptrs (new, a_out, new_name) < 0 #endif #endif ) { close (new); /* unlink (new_name); /* Failed, unlink new a.out */ return -1; } close (new); if (a_out >= 0) close (a_out); mark_x (new_name); return 0; } /* **************************************************************** * make_hdr * * Make the header in the new a.out from the header in core. * Modify the text and data sizes. */ static int make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) int new, a_out; unsigned data_start, bss_start, entry_address; char *a_name; char *new_name; { int tem; #ifdef COFF auto struct scnhdr f_thdr; /* Text section header */ auto struct scnhdr f_dhdr; /* Data section header */ auto struct scnhdr f_bhdr; /* Bss section header */ auto struct scnhdr scntemp; /* Temporary section header */ register int scns; #endif /* COFF */ #ifdef USG_SHARED_LIBRARIES extern unsigned int bss_end; #else unsigned int bss_end; #endif pagemask = getpagesize () - 1; /* Adjust text/data boundary. */ #ifdef NO_REMAP data_start = (int) start_of_data (); #else /* not NO_REMAP */ if (!data_start) data_start = (int) start_of_data (); #endif /* not NO_REMAP */ data_start = ADDR_CORRECT (data_start); #ifdef SEGMENT_MASK data_start = data_start & ~SEGMENT_MASK; /* (Down) to segment boundary. */ #else data_start = data_start & ~pagemask; /* (Down) to page boundary. */ #endif bss_end = ADDR_CORRECT (sbrk (0)) + pagemask; bss_end &= ~ pagemask; /* Adjust data/bss boundary. */ if (bss_start != 0) { bss_start = (ADDR_CORRECT (bss_start) + pagemask); /* (Up) to page bdry. */ bss_start &= ~ pagemask; if (bss_start > bss_end) { ERROR1 ("unexec: Specified bss_start (%u) is past end of program", bss_start); } } else bss_start = bss_end; if (data_start > bss_start) /* Can't have negative data size. */ { ERROR2 ("unexec: data_start (%u) can't be greater than bss_start (%u)", data_start, bss_start); } #ifdef COFF /* Salvage as much info from the existing file as possible */ if (a_out >= 0) { if (read (a_out, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr)) { PERROR (a_name); } block_copy_start += sizeof (f_hdr); if (f_hdr.f_opthdr > 0) { if (read (a_out, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr)) { PERROR (a_name); } block_copy_start += sizeof (f_ohdr); } /* Loop through section headers, copying them in */ lseek (a_out, sizeof (f_hdr) + f_hdr.f_opthdr, 0); for (scns = f_hdr.f_nscns; scns > 0; scns--) { if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp)) { PERROR (a_name); } if (scntemp.s_scnptr > 0L) { if (block_copy_start < scntemp.s_scnptr + scntemp.s_size) block_copy_start = scntemp.s_scnptr + scntemp.s_size; } if (strcmp (scntemp.s_name, ".text") == 0) { f_thdr = scntemp; } else if (strcmp (scntemp.s_name, ".data") == 0) { f_dhdr = scntemp; } else if (strcmp (scntemp.s_name, ".bss") == 0) { f_bhdr = scntemp; } } } else { ERROR0 ("can't build a COFF file from scratch yet"); } /* Now we alter the contents of all the f_*hdr variables to correspond to what we want to dump. */ #ifdef USG_SHARED_LIBRARIES /* The amount of data we're adding to the file is distance from the * end of the original .data space to the current end of the .data * space. */ bias = bss_start - (f_ohdr.data_start + f_dhdr.s_size); #endif f_hdr.f_flags |= (F_RELFLG | F_EXEC); #ifdef TPIX f_hdr.f_nscns = 3; #endif #ifdef EXEC_MAGIC f_ohdr.magic = EXEC_MAGIC; #endif #ifndef NO_REMAP f_ohdr.text_start = (long) start_of_text (); f_ohdr.tsize = data_start - f_ohdr.text_start; f_ohdr.data_start = data_start; #endif /* NO_REMAP */ f_ohdr.dsize = bss_start - f_ohdr.data_start; f_ohdr.bsize = bss_end - bss_start; #ifndef KEEP_OLD_TEXT_SCNPTR /* On some machines, the old values are right. ??? Maybe on all machines with NO_REMAP. */ f_thdr.s_size = f_ohdr.tsize; f_thdr.s_scnptr = sizeof (f_hdr) + sizeof (f_ohdr); f_thdr.s_scnptr += (f_hdr.f_nscns) * (sizeof (f_thdr)); #endif /* KEEP_OLD_TEXT_SCNPTR */ #ifdef ADJUST_TEXT_SCNHDR_SIZE /* On some machines, `text size' includes all headers. */ f_thdr.s_size -= f_thdr.s_scnptr; #endif /* ADJUST_TEST_SCNHDR_SIZE */ lnnoptr = f_thdr.s_lnnoptr; #ifdef SECTION_ALIGNMENT /* Some systems require special alignment of the sections in the file itself. */ f_thdr.s_scnptr = (f_thdr.s_scnptr + SECTION_ALIGNMENT) & ~SECTION_ALIGNMENT; #endif /* SECTION_ALIGNMENT */ #ifdef TPIX f_thdr.s_scnptr = 0xd0; #endif text_scnptr = f_thdr.s_scnptr; #ifdef ADJUST_TEXTBASE text_scnptr = sizeof (f_hdr) + sizeof (f_ohdr) + (f_hdr.f_nscns) * (sizeof (f_thdr)); #endif #ifndef KEEP_OLD_PADDR f_dhdr.s_paddr = f_ohdr.data_start; #endif /* KEEP_OLD_PADDR */ f_dhdr.s_vaddr = f_ohdr.data_start; f_dhdr.s_size = f_ohdr.dsize; f_dhdr.s_scnptr = f_thdr.s_scnptr + f_thdr.s_size; #ifdef SECTION_ALIGNMENT /* Some systems require special alignment of the sections in the file itself. */ f_dhdr.s_scnptr = (f_dhdr.s_scnptr + SECTION_ALIGNMENT) & ~SECTION_ALIGNMENT; #endif /* SECTION_ALIGNMENT */ #ifdef DATA_SECTION_ALIGNMENT /* Some systems require special alignment of the data section only. */ f_dhdr.s_scnptr = (f_dhdr.s_scnptr + DATA_SECTION_ALIGNMENT) & ~DATA_SECTION_ALIGNMENT; #endif /* DATA_SECTION_ALIGNMENT */ data_scnptr = f_dhdr.s_scnptr; #ifndef KEEP_OLD_PADDR f_bhdr.s_paddr = f_ohdr.data_start + f_ohdr.dsize; #endif /* KEEP_OLD_PADDR */ f_bhdr.s_vaddr = f_ohdr.data_start + f_ohdr.dsize; f_bhdr.s_size = f_ohdr.bsize; f_bhdr.s_scnptr = 0L; #ifndef USG_SHARED_LIBRARIES bias = f_dhdr.s_scnptr + f_dhdr.s_size - block_copy_start; #endif if (f_hdr.f_symptr > 0L) { f_hdr.f_symptr += bias; } if (f_thdr.s_lnnoptr > 0L) { f_thdr.s_lnnoptr += bias; } #ifdef ADJUST_EXEC_HEADER ADJUST_EXEC_HEADER; #endif /* ADJUST_EXEC_HEADER */ if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr)) { PERROR (new_name); } if (write (new, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr)) { PERROR (new_name); } #ifndef USG_SHARED_LIBRARIES if (write (new, &f_thdr, sizeof (f_thdr)) != sizeof (f_thdr)) { PERROR (new_name); } if (write (new, &f_dhdr, sizeof (f_dhdr)) != sizeof (f_dhdr)) { PERROR (new_name); } if (write (new, &f_bhdr, sizeof (f_bhdr)) != sizeof (f_bhdr)) { PERROR (new_name); } #else /* USG_SHARED_LIBRARIES */ /* The purpose of this code is to write out the new file's section * header table. * * Scan through the original file's sections. If the encountered * section is one we know (.text, .data or .bss), write out the * correct header. If it is a section we do not know (such as * .lib), adjust the address of where the section data is in the * file, and write out the header. * * If any section precedes .text or .data in the file, this code * will not adjust the file pointer for that section correctly. */ /* This used to use sizeof (f_ohdr) instead of .f_opthdr. .f_opthdr is said to be right when there is no optional header. */ lseek (a_out, sizeof (f_hdr) + f_hdr.f_opthdr, 0); for (scns = f_hdr.f_nscns; scns > 0; scns--) { if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp)) PERROR (a_name); if (!strcmp (scntemp.s_name, f_thdr.s_name)) /* .text */ { if (write (new, &f_thdr, sizeof (f_thdr)) != sizeof (f_thdr)) PERROR (new_name); } else if (!strcmp (scntemp.s_name, f_dhdr.s_name)) /* .data */ { if (write (new, &f_dhdr, sizeof (f_dhdr)) != sizeof (f_dhdr)) PERROR (new_name); } else if (!strcmp (scntemp.s_name, f_bhdr.s_name)) /* .bss */ { if (write (new, &f_bhdr, sizeof (f_bhdr)) != sizeof (f_bhdr)) PERROR (new_name); } else { if (scntemp.s_scnptr) scntemp.s_scnptr += bias; if (write (new, &scntemp, sizeof (scntemp)) != sizeof (scntemp)) PERROR (new_name); } } #endif /* USG_SHARED_LIBRARIES */ return (0); #else /* if not COFF */ /* Get symbol table info from header of a.out file if given one. */ if (a_out >= 0) { #ifdef COFF_ENCAPSULATE if (read (a_out, &coffheader, sizeof coffheader) != sizeof coffheader) { PERROR(a_name); } if (coffheader.f_magic != COFF_MAGIC) { ERROR1("%s doesn't have legal coff magic number\n", a_name); } #endif if (read (a_out, &ohdr, sizeof hdr) != sizeof hdr) { PERROR (a_name); } if (N_BADMAG (ohdr)) { ERROR1 ("invalid magic number in %s", a_name); } hdr = ohdr; } else { #ifdef COFF_ENCAPSULATE /* We probably could without too much trouble. The code is in gld * but I don't have that much time or incentive. */ ERROR0 ("can't build a COFF file from scratch yet"); #else #ifdef MSDOS /* Demacs 1.1.1 91/10/16 HIRANO Satoshi */ bzero ((void *)&hdr, sizeof hdr); #else bzero (&hdr, sizeof hdr); #endif #endif } unexec_text_start = (long) start_of_text (); unexec_data_start = data_start; /* Machine-dependent fixup for header, or maybe for unexec_text_start */ #ifdef ADJUST_EXEC_HEADER ADJUST_EXEC_HEADER; #endif /* ADJUST_EXEC_HEADER */ hdr.a_trsize = 0; hdr.a_drsize = 0; if (entry_address != 0) hdr.a_entry = entry_address; hdr.a_bss = bss_end - bss_start; hdr.a_data = bss_start - data_start; #ifdef NO_REMAP hdr.a_text = ohdr.a_text; #else /* not NO_REMAP */ hdr.a_text = data_start - unexec_text_start; #ifdef A_TEXT_OFFSET hdr.a_text += A_TEXT_OFFSET (ohdr); #endif #endif /* not NO_REMAP */ #ifdef COFF_ENCAPSULATE /* We are encapsulating BSD format within COFF format. */ { struct coffscn *tp, *dp, *bp; tp = &coffheader.scns[0]; dp = &coffheader.scns[1]; bp = &coffheader.scns[2]; tp->s_size = hdr.a_text + sizeof(struct exec); dp->s_paddr = data_start; dp->s_vaddr = data_start; dp->s_size = hdr.a_data; bp->s_paddr = dp->s_vaddr + dp->s_size; bp->s_vaddr = bp->s_paddr; bp->s_size = hdr.a_bss; coffheader.tsize = tp->s_size; coffheader.dsize = dp->s_size; coffheader.bsize = bp->s_size; coffheader.text_start = tp->s_vaddr; coffheader.data_start = dp->s_vaddr; } if (write (new, &coffheader, sizeof coffheader) != sizeof coffheader) { PERROR(new_name); } #endif /* COFF_ENCAPSULATE */ if (write (new, &hdr, sizeof hdr) != sizeof hdr) { PERROR (new_name); } #if 0 /* This #ifndef caused a bug on Linux when using QMAGIC. */ /* This adjustment was done above only #ifndef NO_REMAP, so only undo it now #ifndef NO_REMAP. */ /* #ifndef NO_REMAP */ #endif #ifdef A_TEXT_OFFSET hdr.a_text -= A_TEXT_OFFSET (ohdr); #endif return 0; #endif /* not COFF */ } /* **************************************************************** * copy_text_and_data * * Copy the text and data segments from memory to the new a.out */ static int copy_text_and_data (new, a_out) int new, a_out; { register char *end; register char *ptr; #ifdef COFF #ifdef USG_SHARED_LIBRARIES int scns; struct scnhdr scntemp; /* Temporary section header */ /* The purpose of this code is to write out the new file's section * contents. * * Step through the section table. If we know the section (.text, * .data) do the appropriate thing. Otherwise, if the section has * no allocated space in the file (.bss), do nothing. Otherwise, * the section has space allocated in the file, and is not a section * we know. So just copy it. */ lseek (a_out, sizeof (struct filehdr) + sizeof (struct aouthdr), 0); for (scns = f_hdr.f_nscns; scns > 0; scns--) { if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp)) PERROR ("temacs"); if (!strcmp (scntemp.s_name, ".text")) { lseek (new, (long) text_scnptr, 0); ptr = (char *) f_ohdr.text_start; end = ptr + f_ohdr.tsize; write_segment (new, ptr, end); } else if (!strcmp (scntemp.s_name, ".data")) { lseek (new, (long) data_scnptr, 0); ptr = (char *) f_ohdr.data_start; end = ptr + f_ohdr.dsize; write_segment (new, ptr, end); } else if (!scntemp.s_scnptr) ; /* do nothing - no data for this section */ else { char page[BUFSIZ]; int size, n; long old_a_out_ptr = lseek (a_out, 0, 1); lseek (a_out, scntemp.s_scnptr, 0); for (size = scntemp.s_size; size > 0; size -= sizeof (page)) { n = size > sizeof (page) ? sizeof (page) : size; if (read (a_out, page, n) != n || write (new, page, n) != n) PERROR ("emacs"); } lseek (a_out, old_a_out_ptr, 0); } } #else /* COFF, but not USG_SHARED_LIBRARIES */ #ifdef MSDOS #if __DJGPP__ >= 2 /* Dump the original table of exception handlers, not the one where our exception hooks are registered. */ __djgpp_exception_toggle (); /* Switch off startup flags that might have been set at runtime and which might change the way that dumped Emacs works. */ save_djgpp_startup_flags = _crt0_startup_flags; _crt0_startup_flags &= ~(_CRT0_FLAG_NO_LFN | _CRT0_FLAG_NEARPTR); #endif #endif lseek (new, (long) text_scnptr, 0); ptr = (char *) f_ohdr.text_start; #ifdef HEADER_INCL_IN_TEXT /* For Gould UTX/32, text starts after headers */ ptr = (char *) (ptr + text_scnptr); #endif /* HEADER_INCL_IN_TEXT */ end = ptr + f_ohdr.tsize; write_segment (new, ptr, end); lseek (new, (long) data_scnptr, 0); ptr = (char *) f_ohdr.data_start; end = ptr + f_ohdr.dsize; write_segment (new, ptr, end); #ifdef MSDOS #if __DJGPP__ >= 2 /* Restore our exception hooks. */ __djgpp_exception_toggle (); /* Restore the startup flags. */ _crt0_startup_flags = save_djgpp_startup_flags; #endif #endif #endif /* USG_SHARED_LIBRARIES */ #else /* if not COFF */ /* Some machines count the header as part of the text segment. That is to say, the header appears in core just before the address that start_of_text returns. For them, N_TXTOFF is the place where the header goes. We must adjust the seek to the place after the header. Note that at this point hdr.a_text does *not* count the extra A_TEXT_OFFSET bytes, only the actual bytes of code. */ #ifdef A_TEXT_SEEK lseek (new, (long) A_TEXT_SEEK (hdr), 0); #else lseek (new, (long) N_TXTOFF (hdr), 0); #endif /* no A_TEXT_SEEK */ #ifdef RISCiX /* Acorn's RISC-iX has a wacky way of initialising the position of the heap. * There is a little table in crt0.o that is filled at link time with * the min and current brk positions, among other things. When start * runs, it copies the table to where these parameters live during * execution. This data is in text space, so it cannot be modified here * before saving the executable, so the data is written manually. In * addition, the table does not have a label, and the nearest accessible * label (mcount) is not prefixed with a '_', thus making it inaccessible * from within C programs. To overcome this, emacs's executable is passed * through the command 'nm %s | fgrep mcount' into a pipe, and the * resultant output is then used to find the address of 'mcount'. As far as * is possible to determine, in RISC-iX releases prior to 1.2, the negative * offset of the table from mcount is 0x2c, whereas from 1.2 onwards it is * 0x30. bss_end has been rounded up to page boundary. This solution is * based on suggestions made by Kevin Welton and Steve Hunt of Acorn, and * avoids the need for a custom version of crt0.o for emacs which has its * table in data space. */ { char command[1024]; char errbuf[1024]; char address_text[32]; int proforma[4]; FILE *pfile; char *temp_ptr; char c; int mcount_address, mcount_offset, count; extern char *_execname; /* The use of _execname is incompatible with RISCiX 1.1 */ sprintf (command, "nm %s | fgrep mcount", _execname); if ( (pfile = popen(command, "r")) == NULL) { sprintf (errbuf, "Could not open pipe"); PERROR (errbuf); } count=0; while ( ((c=getc(pfile)) != EOF) && (c != ' ') && (count < 31)) address_text[count++]=c; address_text[count]=0; if ((count == 0) || pclose(pfile) != NULL) { sprintf (errbuf, "Failed to execute the command '%s'\n", command); PERROR (errbuf); } sscanf(address_text, "%x", &mcount_address); ptr = (char *) unexec_text_start; mcount_offset = (char *)mcount_address - ptr; #ifdef RISCiX_1_1 #define EDATA_OFFSET 0x2c #else #define EDATA_OFFSET 0x30 #endif end = ptr + mcount_offset - EDATA_OFFSET; write_segment (new, ptr, end); proforma[0] = bss_end; /* becomes _edata */ proforma[1] = bss_end; /* becomes _end */ proforma[2] = bss_end; /* becomes _minbrk */ proforma[3] = bss_end; /* becomes _curbrk */ write (new, proforma, 16); temp_ptr = ptr; ptr = end + 16; end = temp_ptr + hdr.a_text; write_segment (new, ptr, end); } #else /* !RISCiX */ ptr = (char *) unexec_text_start; end = ptr + hdr.a_text; write_segment (new, ptr, end); #endif /* RISCiX */ ptr = (char *) unexec_data_start; end = ptr + hdr.a_data; /* This lseek is certainly incorrect when A_TEXT_OFFSET and I believe it is a no-op otherwise. Let's see if its absence ever fails. */ /* lseek (new, (long) N_TXTOFF (hdr) + hdr.a_text, 0); */ write_segment (new, ptr, end); #endif /* not COFF */ return 0; } write_segment (new, ptr, end) int new; register char *ptr, *end; { register int i, nwrite, ret; char buf[80]; extern int errno; /* This is the normal amount to write at once. It is the size of block that NFS uses. */ int writesize = 1 << 13; int pagesize = getpagesize (); char zeros[1 << 13]; bzero (zeros, sizeof (zeros)); for (i = 0; ptr < end;) { /* Distance to next multiple of writesize. */ nwrite = (((int) ptr + writesize) & -writesize) - (int) ptr; /* But not beyond specified end. */ if (nwrite > end - ptr) nwrite = end - ptr; ret = write (new, ptr, nwrite); /* If write gets a page fault, it means we reached a gap between the old text segment and the old data segment. This gap has probably been remapped into part of the text segment. So write zeros for it. */ if (ret == -1 #ifdef EFAULT && errno == EFAULT #endif ) { /* Write only a page of zeros at once, so that we we don't overshoot the start of the valid memory in the old data segment. */ if (nwrite > pagesize) nwrite = pagesize; write (new, zeros, nwrite); } #if 0 /* Now that we have can ask `write' to write more than a page, it is legit for write do less than the whole amount specified. */ else if (nwrite != ret) { sprintf (buf, "unexec write failure: addr 0x%x, fileno %d, size 0x%x, wrote 0x%x, errno %d", ptr, new, nwrite, ret, errno); PERROR (buf); } #endif i += nwrite; ptr += nwrite; } } /* **************************************************************** * copy_sym * * Copy the relocation information and symbol table from the a.out to the new */ static int copy_sym (new, a_out, a_name, new_name) int new, a_out; char *a_name, *new_name; { char page[1024]; int n; if (a_out < 0) return 0; #ifdef COFF if (SYMS_START == 0L) return 0; #endif /* COFF */ #ifdef COFF if (lnnoptr) /* if there is line number info */ lseek (a_out, lnnoptr, 0); /* start copying from there */ else #endif /* COFF */ lseek (a_out, SYMS_START, 0); /* Position a.out to symtab. */ while ((n = read (a_out, page, sizeof page)) > 0) { if (write (new, page, n) != n) { PERROR (new_name); } } if (n < 0) { PERROR (a_name); } return 0; } /* **************************************************************** * mark_x * * After successfully building the new a.out, mark it executable */ static void mark_x (name) char *name; { struct stat sbuf; int um; int new = 0; /* for PERROR */ um = umask (777); umask (um); if (stat (name, &sbuf) == -1) { PERROR (name); } sbuf.st_mode |= 0111 & ~um; if (chmod (name, sbuf.st_mode) == -1) PERROR (name); } #ifdef COFF #ifndef COFF_BSD_SYMBOLS /* * If the COFF file contains a symbol table and a line number section, * then any auxiliary entries that have values for x_lnnoptr must * be adjusted by the amount that the line number section has moved * in the file (bias computed in make_hdr). The #@$%&* designers of * the auxiliary entry structures used the absolute file offsets for * the line number entry rather than an offset from the start of the * line number section! * * When I figure out how to scan through the symbol table and pick out * the auxiliary entries that need adjustment, this routine will * be fixed. As it is now, all such entries are wrong and sdb * will complain. Fred Fish, UniSoft Systems Inc. */ /* This function is probably very slow. Instead of reopening the new file for input and output it should copy from the old to the new using the two descriptors already open (WRITEDESC and READDESC). Instead of reading one small structure at a time it should use a reasonable size buffer. But I don't have time to work on such things, so I am installing it as submitted to me. -- RMS. */ adjust_lnnoptrs (writedesc, readdesc, new_name) int writedesc; int readdesc; char *new_name; { register int nsyms; register int new; #if defined (amdahl_uts) || defined (pfa) SYMENT symentry; AUXENT auxentry; #else struct syment symentry; union auxent auxentry; #endif if (!lnnoptr || !f_hdr.f_symptr) return 0; #ifdef MSDOS if ((new = writedesc) < 0) #else if ((new = open (new_name, O_RDWR)) < 0) #endif { PERROR (new_name); return -1; } lseek (new, f_hdr.f_symptr, 0); for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++) { read (new, &symentry, SYMESZ); if (symentry.n_numaux) { read (new, &auxentry, AUXESZ); nsyms++; if (ISFCN (symentry.n_type) || symentry.n_type == 0x2400) { auxentry.x_sym.x_fcnary.x_fcn.x_lnnoptr += bias; lseek (new, -AUXESZ, 1); write (new, &auxentry, AUXESZ); } } } #ifndef MSDOS close (new); #endif return 0; } #endif /* COFF_BSD_SYMBOLS */ #endif /* COFF */ #endif /* not CANNOT_DUMP */ scm-5e5/scl.c0000644001705200017500000021037710750224507010773 0ustar tbtb/* "scl.c" non-IEEE utility functions and non-integer arithmetic. * Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1997, 2005, 2006 Free Software Foundation, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see * . */ /* Authors: Jerry D. Hedden and Aubrey Jaffer */ #include "scm.h" #ifdef FLOATS # ifndef PLAN9 # include # endif static double big2scaldbl P((SCM b, int expt)); static SCM bigdblop P((int op, SCM b, double re, double im)); static SCM inex_divbigbig P((SCM a, SCM b)); static int apx_log10 P((double x)); static double lpow10 P((double x, int n)); static sizet idbl2str P((double f, char *a)); static sizet iflo2str P((SCM flt, char *str)); static void safe_add_1 P((double f, double *fsum)); static long scm_twos_power P((SCM n)); static char s_makrect[] = "make-rectangular", s_makpolar[] = "make-polar", s_magnitude[] = "magnitude", s_angle[] = "angle", s_real_part[] = "real-part", s_imag_part[] = "imag-part", s_in2ex[] = "inexact->exact",s_ex2in[] = "exact->inexact"; static char s_expt[] = "real-expt", s_atan2[] = "$atan2"; #endif static char s_memv[] = "memv", s_assv[] = "assv"; SCM sys_protects[NUM_PROTECTS]; sizet num_protects = NUM_PROTECTS; char s_inexactp[] = "inexact?"; static char s_zerop[] = "zero?", s_abs[] = "abs", s_positivep[] = "positive?", s_negativep[] = "negative?"; static char s_lessp[] = "<", s_grp[] = ">"; static char s_leqp[] = "<=", s_greqp[] = ">="; #define s_eqp (&s_leqp[1]) static char s_max[] = "max", s_min[] = "min"; char s_sum[] = "+", s_difference[] = "-", s_product[] = "*", s_divide[] = "/"; static char s_number2string[] = "number->string", s_str2number[] = "string->number"; static char s_list_tail[] = "list-tail"; static char s_str2list[] = "string->list"; static char s_st_copy[] = "string-copy", s_st_fill[] = "string-fill!"; static char s_vect2list[] = "vector->list", s_ve_fill[] = "vector-fill!"; static char s_intexpt[] = "integer-expt"; static char str_inf0[] = "inf.0"; /*** NUMBERS -> STRINGS ***/ #ifdef FLOATS static int dbl_mant_dig = 0; static double max_dbl_int; /* Integers less than or equal to max_dbl_int are representable exactly as doubles. */ static double dbl_eps; double dbl_prec(x) double x; { int expt; double frac = frexp(x, &expt); # ifdef DBL_MIN_EXP if (0.0==x || expt < DBL_MIN_EXP) /* gradual underflow */ return ldexp(1.0, - dbl_mant_dig) * ldexp(1.0, DBL_MIN_EXP); # endif if (1.0==frac) return ldexp(1.0, expt - dbl_mant_dig + 1); return ldexp(1.0, expt - dbl_mant_dig); } static double llog2 = 0.3010299956639812; /* log10(2) */ static int apx_log10(x) double x; { int expt; frexp(x, &expt); expt -= 1; if (expt >= 0) return (int)(expt * llog2); return -((int)(-expt * llog2)); } static double p10[] = {1.0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7}; static double lpow10(x, n) double x; int n; { if (n >= 0) { while (n > 7) { x *= 1e8; n -= 8; } return x*p10[n]; } while (n < -7) { x /= 1e8; n += 8; } return x/p10[-n]; } int inf2str(f, a) double f; char *a; { sizet ch = 0; if (f < 0.0) a[ch++] = '-'; else if (f > 0.0) a[ch++] = '+'; else { a[ch++] = '0'; a[ch++] = '/'; a[ch++] = '0'; return ch; } while (str_inf0[ch - 1]) { a[ch] = str_inf0[ch - 1]; ch++; } /* # ifdef COMPACT_INFINITY_NOTATION */ /* else a[ch++] = '0'; */ /* # else */ /* a[ch++] = (f != f) ? '0' : '1'; */ /* # endif */ /* a[ch++] = '/'; a[ch++] = '0'; */ return ch; } /* DBL2STR_FUZZ is a somewhat arbitrary guard against round off error in scaling f and fprec. */ # define DBL2STR_FUZZ 0.9 int dblprec; static sizet idbl2str(f, a) double f; char *a; { double fprec = dbl_prec(f); int efmt, dpt, d, i, exp; sizet ch = 0; if (f==0.0) {exp = 0; goto zero;} /*{a[0]='0'; a[1]='.'; a[2]='0'; return 3;}*/ if (f==2*f) return inf2str(f, a); if (f < 0.0) {f = -f;a[ch++]='-';} else if (f > 0.0) ; else return inf2str(f, a); exp = apx_log10(f); f = lpow10(f, -exp); fprec = lpow10(fprec, -exp); # ifdef DBL_MIN_10_EXP /* Prevent random unnormalized values, as from make-uniform-vector, from causing infinite loops, but try to print gradually underflowing numbers. */ while (f < 1.0) { f *= 10.0; fprec *= 10.0; if (exp-- < DBL_MIN_10_EXP - DBL_DIG - 1) return inf2str(f, a); } while (f > 10.0) { f /= 10.0; fprec /= 10.0; if (exp++ > DBL_MAX_10_EXP) return inf2str(f, a); } # else while (f < 1.0) {f *= 10.0; fprec *= 10.0; exp--;} while (f > 10.0) {f /= 10.0; fprec /= 10.0; exp++;} # endif fprec *= 0.5; if (f+fprec >= 10.0) {f = 1.0; exp++;} zero: # ifdef ENGNOT dpt = (exp+9999)%3; exp -= dpt++; efmt = 1; # else efmt = (exp < -3) || (exp > dblprec+2); if (!efmt) if (exp < 0) { a[ch++] = '0'; a[ch++] = '.'; dpt = exp; while (++dpt) a[ch++] = '0'; } else dpt = exp+1; else dpt = 1; # endif for (i = 30; i--;) { /* printf(" f = %.20g, fprec = %.20g, i = %d\n", f, fprec, i); */ d = f; f -= d; a[ch++] = d+'0'; if (f < fprec && f < DBL2STR_FUZZ*fprec) break; if ((f + fprec) >= 1.0 && (f + DBL2STR_FUZZ*fprec) >= 1.0) { a[ch-1]++; break; } f *= 10.0; fprec *= 10.0; if (!(--dpt)) a[ch++] = '.'; } if (dpt > 0) # ifndef ENGNOT if ((dpt > 4) && (exp > 6)) { d = (a[0]=='-'?2:1); for (i = ch++; i > d; i--) a[i] = a[i-1]; a[d] = '.'; efmt = 1; } else # endif { while (--dpt) a[ch++] = '0'; a[ch++] = '.'; } if (a[ch-1]=='.') a[ch++]='0'; /* trailing zero */ if (efmt && exp) { a[ch++] = 'e'; if (exp < 0) { exp = -exp; a[ch++] = '-'; } for (i = 10; i <= exp; i *= 10); for (i /= 10; i; i /= 10) { a[ch++] = exp/i + '0'; exp %= i; } } return ch; } static sizet iflo2str(flt, str) SCM flt; char *str; { sizet i; # ifdef SINGLES if (SINGP(flt)) i = idbl2str(FLO(flt), str); else # endif i = idbl2str(REAL(flt), str); if (scm_narn==flt) return i; if (CPLXP(flt)) { if (!(0 > IMAG(flt))) str[i++] = '+'; i += idbl2str(IMAG(flt), &str[i]); str[i++] = 'i'; } return i; } #endif /* FLOATS */ sizet iuint2str(num, rad, p) unsigned long num; int rad; char *p; { sizet j; register int i = 1, d; register unsigned long n = num; for (n /= rad;n > 0;n /= rad) i++; j = i; n = num; while (i--) { d = n % rad; n /= rad; p[i] = d + ((d < 10) ? '0' : 'a' - 10); } return j; } sizet iint2str(num, rad, p) long num; int rad; char *p; { if ((num < 0) && !(rad < 0)) { *p++ = '-'; return 1 + iuint2str((unsigned long) -num, rad, p); } return iuint2str((unsigned long) num, rad < 0 ? -rad : rad, p); } #ifdef BIGDIG static SCM big2str(b, radix) SCM b; register unsigned int radix; { SCM t = copybig(b, 0); /* sign of temp doesn't matter */ register BIGDIG *ds = BDIGITS(t); sizet i = NUMDIGS(t); sizet j = radix==16 ? (BITSPERDIG*i)/4+2 : radix >= 10 ? (BITSPERDIG*i*241L)/800+2 : (BITSPERDIG*i)+2; sizet k = 0; sizet radct = 0; sizet ch; /* jeh */ BIGDIG radpow = 1, radmod = 0; SCM ss = makstr((long)j); char *s = CHARS(ss), c; scm_protect_temp(&t); while ((long) radpow * radix < BIGRAD) { radpow *= radix; radct++; } s[0] = tc16_bigneg==TYP16(b) ? '-' : '+'; while ((i || radmod) && j) { if (k==0) { radmod = (BIGDIG)divbigdig(ds, i, radpow); k = radct; if (!ds[i-1]) i--; } c = radmod % radix; radmod /= radix; k--; s[--j] = c < 10 ? c + '0' : c + 'a' - 10; } ch = s[0]=='-' ? 1 : 0; /* jeh */ if (ch < j) { /* jeh */ for (i = j;j < LENGTH(ss);j++) s[ch+j-i] = s[j]; /* jeh */ resizuve(ss, (SCM)MAKINUM(ch+LENGTH(ss)-i)); /* jeh */ } return ss; } #endif SCM number2string(x, radix) SCM x, radix; { if (UNBNDP(radix)) radix=MAKINUM(10L); else ASRTER(INUMP(radix), radix, ARG2, s_number2string); #ifdef FLOATS if (NINUMP(x)) { char num_buf[FLOBUFLEN]; # ifdef BIGDIG ASRTGO(NIMP(x), badx); if (BIGP(x)) return big2str(x, (unsigned int)INUM(radix)); # ifndef RECKLESS if (!(INEXP(x))) badx: wta(x, (char *)ARG1, s_number2string); # endif # else ASRTER(NIMP(x) && INEXP(x), x, ARG1, s_number2string); # endif return makfromstr(num_buf, iflo2str(x, num_buf)); } #else # ifdef BIGDIG if (NINUMP(x)) { ASRTER(NIMP(x) && BIGP(x), x, ARG1, s_number2string); return big2str(x, (unsigned int)INUM(radix)); } # else ASRTER(INUMP(x), x, ARG1, s_number2string); # endif #endif { char num_buf[INTBUFLEN]; return makfromstr(num_buf, iint2str(INUM(x), (int)INUM(radix), num_buf)); } } /* These print routines are stubbed here so that repl.c doesn't need FLOATS or BIGDIGs conditionals */ int floprint(sexp, port, writing) SCM sexp; SCM port; int writing; { #ifdef FLOATS if (!errjmp_bad) { char num_buf[FLOBUFLEN]; lfwrite(num_buf, (sizet)sizeof(char), iflo2str(sexp, num_buf), port); return !0; } else #endif scm_ipruk("float", sexp, port); return !0; } int bigprint(exp, port, writing) SCM exp; SCM port; int writing; { #ifdef BIGDIG if (!errjmp_bad) { exp = big2str(exp, (unsigned int)10); lfwrite(CHARS(exp), (sizet)sizeof(char), (sizet)LENGTH(exp), port); return !0; } else #endif scm_ipruk("bignum", exp, port); return !0; } /*** END nums->strs ***/ /*** STRINGS -> NUMBERS ***/ #ifdef BIGDIG SCM istr2int(str, len, radix) char *str; long len; register long radix; { sizet j; register sizet k, blen = 1; sizet i = 0; int c; SCM res; register BIGDIG *ds; register unsigned long t2; if (0 >= len) return BOOL_F; /* zero length */ if (10==radix) j = 1+(84*len)/(BITSPERDIG*25); else j = (8 < radix) ? 1+(4*len)/BITSPERDIG : 1+(3*len)/BITSPERDIG; switch (str[0]) { /* leading sign */ case '-': case '+': if (++i==len) return BOOL_F; /* bad if lone `+' or `-' */ } res = mkbig(j, '-'==str[0]); ds = BDIGITS(res); for (k = j;k--;) ds[k] = 0; do { switch (c = str[i++]) { case DIGITS: c = c - '0'; goto accumulate; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': c = c-'A'+10; goto accumulate; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': c = c-'a'+10; accumulate: if (c >= radix) return BOOL_F; /* bad digit for radix */ k = 0; t2 = c; moretodo: while(k < blen) { /* printf("k = %d, blen = %d, t2 = %ld, ds[k] = %d\n", k, blen, t2, ds[k]);*/ t2 += ds[k]*radix; ds[k++] = BIGLO(t2); t2 = BIGDN(t2); } ASRTER(blen <= j, (SCM)MAKINUM(blen), OVFLOW, "bignum"); if (t2) {blen++; goto moretodo;} break; default: return BOOL_F; /* not a digit */ } } while (i < len); if (blen * BITSPERDIG/CHAR_BIT <= sizeof(SCM)) if (INUMP(res = big2inum(res, blen))) return res; if (j==blen) return res; return adjbig(res, blen); } #else SCM istr2int(str, len, radix) register char *str; long len; register long radix; { register long n = 0, ln; register int c; register int i = 0; int lead_neg = 0; if (0 >= len) return BOOL_F; /* zero length */ switch (*str) { /* leading sign */ case '-': lead_neg = 1; case '+': if (++i==len) return BOOL_F; /* bad if lone `+' or `-' */ } do { switch (c = str[i++]) { case DIGITS: c = c - '0'; goto accumulate; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': c = c-'A'+10; goto accumulate; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': c = c-'a'+10; accumulate: if (c >= radix) return BOOL_F; /* bad digit for radix */ ln = n; n = n * radix - c; if (n > ln # ifdef hpux || (-n > -MOST_NEGATIVE_FIXNUM) /* workaround for HP700 cc bug */ # endif ) goto ovfl; break; default: return BOOL_F; /* not a digit */ } } while (i < len); if (lead_neg) { if (n < MOST_NEGATIVE_FIXNUM) goto ovfl; } else { if (n < -MOST_POSITIVE_FIXNUM) goto ovfl; n = -n; } return MAKINUM(n); ovfl: /* overflow scheme integer */ return BOOL_F; } #endif #ifdef FLOATS # ifdef BIGDIG static char twostab[] = {4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0}; static long scm_twos_power(n) SCM n; { long d, c = 0; int d4; # ifdef BIGDIG if (NINUMP(n)) { BIGDIG *ds; int i = 0; ds = BDIGITS(n); while (0==(d = ds[i++])) c += BITSPERDIG; goto out; } # endif d = INUM(n); if (0==d) return 0; out: do { d4 = 15 & d; c += twostab[d4]; d >>= 4; } while (0==d4); return c; } # endif /* def BIGDIG */ SCM istr2flo(str, len, radix) register char *str; register long len; register long radix; { register int c, i = 0; double lead_sgn = 0.0; double res = 0.0, tmp = 0.0; int flg = 0; int point = 0; SCM second; if (i >= len) return BOOL_F; /* zero length */ switch (*str) { /* leading sign */ case '-': lead_sgn = -1.0; i++; break; case '+': lead_sgn = 1.0; i++; break; } if (i==len) return BOOL_F; /* bad if lone `+' or `-' */ if (6==len && ('+'==str[0] || '-'==str[0])) if (0==strcmp(str_inf0, &str[1])) return makdbl(1./0. * ('+'==str[0] ? 1 : -1), 0.0); if (str[i]=='i' || str[i]=='I') { /* handle `+i' and `-i' */ if (lead_sgn==0.0) return BOOL_F; /* must have leading sign */ if (++i < len) return BOOL_F; /* `i' not last character */ return makdbl(0.0, lead_sgn); } /* # ifdef COMPACT_INFINITY_NOTATION */ if (0.0 != lead_sgn && str[i]=='/') { res = 1; flg = 1; goto out1; } /* # endif */ do { /* check initial digits */ switch (c = str[i]) { case DIGITS: c = c - '0'; goto accum1; case 'D': case 'E': case 'F': if (radix==10) goto out1; /* must be exponent */ case 'A': case 'B': case 'C': c = c-'A'+10; goto accum1; case 'd': case 'e': case 'f': if (radix==10) goto out1; case 'a': case 'b': case 'c': c = c-'a'+10; accum1: if (c >= radix) return BOOL_F; /* bad digit for radix */ res = res * radix + c; flg = 1; /* res is valid */ break; default: goto out1; } } while (++i < len); out1: /* if true, then we did see a digit above, and res is valid */ if (i==len) goto done; /* By here, must have seen a digit, or must have next char be a `.' with radix==10 */ if (!flg) if (!(str[i]=='.' && radix==10)) return BOOL_F; while (str[i]=='#') { /* optional sharps */ res *= radix; if (++i==len) goto done; } if (str[i]=='/') { while (++i < len) { switch (c = str[i]) { case DIGITS: c = c - '0'; goto accum2; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': c = c-'A'+10; goto accum2; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': c = c-'a'+10; accum2: if (c >= radix) return BOOL_F; tmp = tmp * radix + c; break; default: goto out2; } } out2: /* if (tmp==0.0) return BOOL_F; /\* `slash zero' not allowed *\/ */ if (i < len) while (str[i]=='#') { /* optional sharps */ tmp *= radix; if (++i==len) break; } res /= tmp; goto done; } if (str[i]=='.') { /* decimal point notation */ if (radix != 10) return BOOL_F; /* must be radix 10 */ while (++i < len) { switch (c = str[i]) { case DIGITS: point--; res = res*10.0 + c-'0'; flg = 1; break; default: goto out3; } } out3: if (!flg) return BOOL_F; /* no digits before or after decimal point */ if (i==len) goto adjust; while (str[i]=='#') { /* ignore remaining sharps */ if (++i==len) goto adjust; } } switch (str[i]) { /* exponent */ case 'd': case 'D': case 'e': case 'E': case 'f': case 'F': case 'l': case 'L': case 's': case 'S': { int expsgn = 1, expon = 0; if (radix != 10) return BOOL_F; /* only in radix 10 */ if (++i==len) return BOOL_F; /* bad exponent */ switch (str[i]) { case '-': expsgn=(-1); case '+': if (++i==len) return BOOL_F; /* bad exponent */ } if (str[i] < '0' || str[i] > '9') return BOOL_F; /* bad exponent */ do { switch (c = str[i]) { case DIGITS: expon = expon*10 + c-'0'; /* if (expon > MAXEXP) */ /* if (1==expsgn || expon > (MAXEXP + dblprec + 1)) */ /* return BOOL_F; /\* exponent too large *\/ */ break; default: goto out4; } } while (++i < len); out4: point += expsgn*expon; } } adjust: if (point >= 0) while (point--) res *= 10.0; else # ifdef _UNICOS while (point++) res *= 0.1; # else while (point++) res /= 10.0; # endif done: /* at this point, we have a legitimate floating point result */ if (lead_sgn==-1.0) res = -res; if (i==len) return makdbl(res, 0.0); if (str[i]=='i' || str[i]=='I') { /* pure imaginary number */ if (lead_sgn==0.0) return BOOL_F; /* must have leading sign */ if (++i < len) return BOOL_F; /* `i' not last character */ return makdbl(0.0, res); } switch (str[i++]) { case '-': lead_sgn = -1.0; break; case '+': lead_sgn = 1.0; break; case '@': { /* polar input for complex number */ /* get a `real' for angle */ second = istr2flo(&str[i], (long)(len-i), radix); if (IMP(second)) return BOOL_F; if (!(INEXP(second))) return BOOL_F; /* not `real' */ if (CPLXP(second)) return BOOL_F; /* not `real' */ tmp = REALPART(second); return makdbl(res*cos(tmp), res*sin(tmp)); } default: return BOOL_F; } /* at this point, last char must be `i' */ if (str[len-1] != 'i' && str[len-1] != 'I') return BOOL_F; /* handles `x+i' and `x-i' */ if (i==(len-1)) return makdbl(res, lead_sgn); /* get a `ureal' for complex part */ second = istr2flo(&str[i], (long)((len-i)-1), radix); if (IMP(second)) return BOOL_F; if (!(INEXP(second))) return BOOL_F; /* not `ureal' */ if (CPLXP(second)) return BOOL_F; /* not `ureal' */ tmp = REALPART(second); if (tmp < 0.0) return BOOL_F; /* not `ureal' */ return makdbl(res, (lead_sgn*tmp)); } #endif /* FLOATS */ SCM istring2number(str, len, radix) char *str; long len; long radix; { int i = 0; char ex = 0; char ex_p = 0, rx_p = 0; /* Only allow 1 exactness and 1 radix prefix */ SCM res; if (len==1) if (*str=='+' || *str=='-') /* Catches lone `+' and `-' for speed */ return BOOL_F; while ((len-i) >= 2 && str[i]=='#' && ++i) switch (str[i++]) { case 'b': case 'B': if (rx_p++) return BOOL_F; radix = 2; break; case 'o': case 'O': if (rx_p++) return BOOL_F; radix = 8; break; case 'd': case 'D': if (rx_p++) return BOOL_F; radix = 10; break; case 'x': case 'X': if (rx_p++) return BOOL_F; radix = 16; break; case 'i': case 'I': if (ex_p++) return BOOL_F; ex = 2; break; case 'e': case 'E': if (ex_p++) return BOOL_F; ex = 1; break; default: return BOOL_F; } switch (ex) { case 1: return istr2int(&str[i], len-i, radix); case 0: res = istr2int(&str[i], len-i, radix); if (NFALSEP(res)) return res; #ifdef FLOATS case 2: return istr2flo(&str[i], len-i, radix); #endif } return BOOL_F; } SCM string2number(str, radix) SCM str, radix; { if (UNBNDP(radix)) radix=MAKINUM(10L); else ASRTER(INUMP(radix), radix, ARG2, s_str2number); ASRTER(NIMP(str) && STRINGP(str), str, ARG1, s_str2number); return istring2number(CHARS(str), LENGTH(str), INUM(radix)); } /*** END strs->nums ***/ #ifdef FLOATS SCM makdbl (x, y) double x, y; { SCM z; if ((y==0.0) && (x==0.0)) return flo0; # ifndef _MSC_VER # ifndef SINGLESONLY if ((y != y) || (x != x) || (y==(2 * y) && (y != 0.0))) return scm_narn; if ((x==(2 * x)) && (x != 0.0)) y = 0.0; # endif # endif DEFER_INTS; if (y==0.0) { # ifdef SINGLES float fx = x; /* David Yeh changed this so that MSVC works */ # ifndef SINGLESONLY if ((-FLTMAX < x) && (x < FLTMAX) && ( (double)fx == x) ) # endif { NEWCELL(z); CAR(z) = tc_flo; FLO(z) = x; ALLOW_INTS; return z; } # endif /* def SINGLES */ z = must_malloc_cell(1L*sizeof(double), (SCM)tc_dblr, "real"); } else { z = must_malloc_cell(2L*sizeof(double), (SCM)tc_dblc, "complex"); IMAG(z) = y; } REAL(z) = x; ALLOW_INTS; return z; } #endif /* FLOATS */ #ifndef INUMS_ONLY SCM eqv(x, y) SCM x, y; { if (x==y) return BOOL_T; if (IMP(x)) return BOOL_F; if (IMP(y)) return BOOL_F; /* this ensures that types and length are the same. */ if (CAR(x) != CAR(y)) return BOOL_F; if (NUMP(x)) { # ifdef BIGDIG if (BIGP(x)) return (0==bigcomp(x, y)) ? BOOL_T : BOOL_F; # endif # ifdef FLOATS return floequal(x, y); # endif } return BOOL_F; } SCM memv(x, lst) /* m.borza 12.2.91 */ SCM x, lst; { for (;NIMP(lst);lst = CDR(lst)) { ASRTGO(CONSP(lst), badlst); if (NFALSEP(eqv(CAR(lst), x))) return lst; } # ifndef RECKLESS if (!(NULLP(lst))) badlst: wta(lst, (char *)ARG2, s_memv); # endif return BOOL_F; } SCM assv(x, alist) /* m.borza 12.2.91 */ SCM x, alist; { SCM tmp; for (;NIMP(alist);alist = CDR(alist)) { ASRTGO(CONSP(alist), badlst); tmp = CAR(alist); ASRTGO(NIMP(tmp) && CONSP(tmp), badlst); if (NFALSEP(eqv(CAR(tmp), x))) return tmp; } # ifndef RECKLESS if (!(NULLP(alist))) badlst: wta(alist, (char *)ARG2, s_assv); # endif return BOOL_F; } #endif SCM list_tail(lst, k) SCM lst, k; { register long i; ASRTER(INUMP(k), k, ARG2, s_list_tail); i = INUM(k); while (i-- > 0) { ASRTER(NIMP(lst) && CONSP(lst), lst, ARG1, s_list_tail); lst = CDR(lst); } return lst; } SCM string2list(str) SCM str; { long i; SCM res = EOL; unsigned char *src; ASRTER(NIMP(str) && STRINGP(str), str, ARG1, s_str2list); src = UCHARS(str); for (i = LENGTH(str)-1;i >= 0;i--) res = cons((SCM)MAKICHR(src[i]), res); return res; } SCM string_copy(str) SCM str; { ASRTER(NIMP(str) && STRINGP(str), str, ARG1, s_st_copy); return makfromstr(CHARS(str), (sizet)LENGTH(str)); } SCM string_fill(str, chr) SCM str, chr; { register char *dst, c; register long k; ASRTER(NIMP(str) && STRINGP(str), str, ARG1, s_st_fill); ASRTER(ICHRP(chr), chr, ARG2, s_st_fill); c = ICHR(chr); dst = CHARS(str); for (k = LENGTH(str)-1;k >= 0;k--) dst[k] = c; return UNSPECIFIED; } SCM vector2list(v) SCM v; { SCM res = EOL; long i; SCM *data; ASRTER(NIMP(v) && VECTORP(v), v, ARG1, s_vect2list); data = VELTS(v); for (i = LENGTH(v)-1;i >= 0;i--) res = cons(data[i], res); return res; } SCM vector_fill(v, fill) SCM v, fill; { register long i; register SCM *data; ASRTER(NIMP(v) && VECTORP(v), v, ARG1, s_ve_fill); data = VELTS(v); for (i = LENGTH(v)-1;i >= 0;i--) data[i] = fill; return UNSPECIFIED; } static SCM vector_equal(x, y) SCM x, y; { long i; for (i = LENGTH(x)-1;i >= 0;i--) if (FALSEP(equal(VELTS(x)[i], VELTS(y)[i]))) return BOOL_F; return BOOL_T; } #ifdef BIGDIG SCM bigequal(x, y) SCM x, y; { if (0==bigcomp(x, y)) return BOOL_T; return BOOL_F; } #endif #ifdef FLOATS SCM floequal(x, y) SCM x, y; { if ((REALPART(x) != REALPART(y))) return BOOL_F; if (CPLXP(x)) return (CPLXP(y) && (IMAG(x)==IMAG(y))) ? BOOL_T : BOOL_F; return CPLXP(y) ? BOOL_F : BOOL_T; } #endif SCM equal(x, y) SCM x, y; { CHECK_STACK; tailrecurse: POLL; if (x==y) return BOOL_T; if (IMP(x)) return BOOL_F; if (IMP(y)) return BOOL_F; if (CONSP(x) && CONSP(y)) { if (FALSEP(equal(CAR(x), CAR(y)))) return BOOL_F; x = CDR(x); y = CDR(y); goto tailrecurse; } /* this ensures that types and length are the same. */ if (CAR(x) != CAR(y)) return BOOL_F; switch (TYP7(x)) { default: return BOOL_F; case tc7_string: return st_equal(x, y); case tc7_vector: return vector_equal(x, y); case tc7_smob: { int i = SMOBNUM(x); if (!(i < numsmob)) return BOOL_F; if (smobs[i].equalp) return (smobs[i].equalp)(x, y); else return BOOL_F; } case tc7_Vbool: case tc7_VfixN8: case tc7_VfixZ8: case tc7_VfixN16: case tc7_VfixZ16: case tc7_VfixN32: case tc7_VfixZ32: case tc7_VfloR32: case tc7_VfloC32: case tc7_VfloC64: case tc7_VfloR64: { SCM (*pred)() = smobs[0x0ff & (tc16_array>>8)].equalp; if (pred) return (*pred)(x, y); else return BOOL_F; } } } SCM numberp(obj) SCM obj; { if (INUMP(obj)) return BOOL_T; #ifdef FLOATS if (NIMP(obj) && NUMP(obj)) return BOOL_T; #else # ifdef BIGDIG if (NIMP(obj) && NUMP(obj)) return BOOL_T; # endif #endif return BOOL_F; } #ifdef FLOATS SCM scm_complex_p(obj) SCM obj; { if (obj==scm_narn) return BOOL_F; return numberp(obj); } # ifdef BIGDIG int scm_bigdblcomp(b, d) SCM b; double d; { sizet dlen, blen; int dneg = d < 0 ? 1 : 0; int bneg = BIGSIGN(b) ? 1 : 0; if (bneg < dneg) return -1; if (bneg > dneg) return 1; frexp(d, &dlen); blen = INUM(scm_intlength(b)); if (blen > dlen) return dneg ? 1 : -1; if (blen < dlen) return dneg ? -1 : 1; if ((blen <= dbl_mant_dig) || (blen - scm_twos_power(b)) <= dbl_mant_dig) { double bd = big2dbl(b); if (bd > d) return -1; if (bd < d) return 1; return 0; } return bigcomp(b, dbl2big(d)); } # endif SCM realp(x) SCM x; { if (INUMP(x)) return BOOL_T; if (IMP(x)) return BOOL_F; if (REALP(x)) return BOOL_T; # ifdef BIGDIG if (BIGP(x)) return BOOL_T; # endif return BOOL_F; } SCM scm_rationalp(x) SCM x; { if (INUMP(x)) return BOOL_T; if (IMP(x)) return BOOL_F; if (REALP(x)) { float y = REALPART(x); if (y==2*y && y != 0.0) return BOOL_F; return BOOL_T; } # ifdef BIGDIG if (BIGP(x)) return BOOL_T; # endif return BOOL_F; } SCM intp(x) SCM x; { double r; if (INUMP(x)) return BOOL_T; if (IMP(x)) return BOOL_F; # ifdef BIGDIG if (BIGP(x)) return BOOL_T; # endif if (!INEXP(x)) return BOOL_F; if (CPLXP(x)) return BOOL_F; r = REALPART(x); if (r != floor(r)) return BOOL_F; if (r==2*r && r != 0.0) return BOOL_F; return BOOL_T; } #endif /* FLOATS */ SCM inexactp(x) SCM x; { #ifdef FLOATS if (NIMP(x) && INEXP(x)) return BOOL_T; #endif return BOOL_F; } SCM eqp(x, y) SCM x, y; { #ifdef FLOATS SCM t; if (NINUMP(x)) { # ifdef BIGDIG # ifndef RECKLESS if (!(NIMP(x))) badx: wta(x, (char *)ARG1, s_eqp); # endif if (BIGP(x)) { if (INUMP(y)) return BOOL_F; ASRTGO(NIMP(y), bady); if (BIGP(y)) return (0==bigcomp(x, y)) ? BOOL_T : BOOL_F; ASRTGO(INEXP(y), bady); bigreal: return (REALP(y) && (0==scm_bigdblcomp(x, REALPART(y)))) ? BOOL_T : BOOL_F; } ASRTGO(INEXP(x), badx); # else ASRTER(NIMP(x) && INEXP(x), x, ARG1, s_eqp); # endif if (INUMP(y)) {t = x; x = y; y = t; goto realint;} # ifdef BIGDIG ASRTGO(NIMP(y), bady); if (BIGP(y)) {t = x; x = y; y = t; goto bigreal;} ASRTGO(INEXP(y), bady); # else ASRTGO(NIMP(y) && INEXP(y), bady); # endif if (x==y) return BOOL_T; return floequal(x, y); } if (NINUMP(y)) { # ifdef BIGDIG ASRTGO(NIMP(y), bady); if (BIGP(y)) return BOOL_F; # ifndef RECKLESS if (!(INEXP(y))) bady: wta(y, (char *)ARG2, s_eqp); # endif # else # ifndef RECKLESS if (!(NIMP(y) && INEXP(y))) bady: wta(y, (char *)ARG2, s_eqp); # endif # endif realint: return (REALP(y) && (((double)INUM(x))==REALPART(y))) ? BOOL_T : BOOL_F; } #else # ifdef BIGDIG if (NINUMP(x)) { ASRTER(NIMP(x) && BIGP(x), x, ARG1, s_eqp); if (INUMP(y)) return BOOL_F; ASRTGO(NIMP(y) && BIGP(y), bady); return (0==bigcomp(x, y)) ? BOOL_T : BOOL_F; } if (NINUMP(y)) { # ifndef RECKLESS if (!(NIMP(y) && BIGP(y))) bady: wta(y, (char *)ARG2, s_eqp); # endif return BOOL_F; } # else ASRTER(INUMP(x), x, ARG1, s_eqp); ASRTER(INUMP(y), y, ARG2, s_eqp); # endif #endif return ((long)x==(long)y) ? BOOL_T : BOOL_F; } SCM lessp(x, y) SCM x, y; { #ifdef FLOATS if (NINUMP(x)) { # ifdef BIGDIG # ifndef RECKLESS if (!(NIMP(x))) badx: wta(x, (char *)ARG1, s_lessp); # endif if (BIGP(x)) { if (INUMP(y)) return BIGSIGN(x) ? BOOL_T : BOOL_F; ASRTGO(NIMP(y), bady); if (BIGP(y)) return (1==bigcomp(x, y)) ? BOOL_T : BOOL_F; ASRTGO(REALP(y), bady); return (1==scm_bigdblcomp(x, REALPART(y))) ? BOOL_T : BOOL_F; } ASRTGO(REALP(x), badx); # else ASRTER(NIMP(x) && REALP(x), x, ARG1, s_lessp); # endif if (INUMP(y)) return (REALPART(x) < ((double)INUM(y))) ? BOOL_T : BOOL_F; # ifdef BIGDIG ASRTGO(NIMP(y), bady); if (BIGP(y)) return (-1==scm_bigdblcomp(y, REALPART(x))) ? BOOL_T : BOOL_F; ASRTGO(REALP(y), bady); # else ASRTGO(NIMP(y) && REALP(y), bady); # endif return (REALPART(x) < REALPART(y)) ? BOOL_T : BOOL_F; } if (NINUMP(y)) { # ifdef BIGDIG ASRTGO(NIMP(y), bady); if (BIGP(y)) return BIGSIGN(y) ? BOOL_F : BOOL_T; # ifndef RECKLESS if (!(REALP(y))) bady: wta(y, (char *)ARG2, s_lessp); # endif # else # ifndef RECKLESS if (!(NIMP(y) && REALP(y))) bady: wta(y, (char *)ARG2, s_lessp); # endif # endif return (((double)INUM(x)) < REALPART(y)) ? BOOL_T : BOOL_F; } #else # ifdef BIGDIG if (NINUMP(x)) { ASRTER(NIMP(x) && BIGP(x), x, ARG1, s_lessp); if (INUMP(y)) return BIGSIGN(x) ? BOOL_T : BOOL_F; ASRTGO(NIMP(y) && BIGP(y), bady); return (1==bigcomp(x, y)) ? BOOL_T : BOOL_F; } if (NINUMP(y)) { # ifndef RECKLESS if (!(NIMP(y) && BIGP(y))) bady: wta(y, (char *)ARG2, s_lessp); # endif return BIGSIGN(y) ? BOOL_F : BOOL_T; } # else ASRTER(INUMP(x), x, ARG1, s_lessp); ASRTER(INUMP(y), y, ARG2, s_lessp); # endif #endif return ((long)x < (long)y) ? BOOL_T : BOOL_F; } SCM greaterp(x, y) SCM x, y; { return lessp(y, x); } SCM leqp(x, y) SCM x, y; { return BOOL_NOT(lessp(y, x)); } SCM greqp(x, y) SCM x, y; { return BOOL_NOT(lessp(x, y)); } SCM zerop(z) SCM z; { #ifdef FLOATS if (NINUMP(z)) { # ifdef BIGDIG ASRTGO(NIMP(z), badz); if (BIGP(z)) return BOOL_F; # ifndef RECKLESS if (!(INEXP(z))) badz: wta(z, (char *)ARG1, s_zerop); # endif # else ASRTER(NIMP(z) && INEXP(z), z, ARG1, s_zerop); # endif return (z==flo0) ? BOOL_T : BOOL_F; } #else # ifdef BIGDIG if (NINUMP(z)) { ASRTER(NIMP(z) && BIGP(z), z, ARG1, s_zerop); return BOOL_F; } # else ASRTER(INUMP(z), z, ARG1, s_zerop); # endif #endif return (z==INUM0) ? BOOL_T: BOOL_F; } SCM positivep(x) SCM x; { #ifdef FLOATS if (NINUMP(x)) { # ifdef BIGDIG ASRTGO(NIMP(x), badx); if (BIGP(x)) return TYP16(x)==tc16_bigpos ? BOOL_T : BOOL_F; # ifndef RECKLESS if (!(REALP(x))) badx: wta(x, (char *)ARG1, s_positivep); # endif # else ASRTER(NIMP(x) && REALP(x), x, ARG1, s_positivep); # endif return (REALPART(x) > 0.0) ? BOOL_T : BOOL_F; } #else # ifdef BIGDIG if (NINUMP(x)) { ASRTER(NIMP(x) && BIGP(x), x, ARG1, s_positivep); return TYP16(x)==tc16_bigpos ? BOOL_T : BOOL_F; } # else ASRTER(INUMP(x), x, ARG1, s_positivep); # endif #endif return (x > INUM0) ? BOOL_T : BOOL_F; } SCM negativep(x) SCM x; { #ifdef FLOATS if (NINUMP(x)) { # ifdef BIGDIG ASRTGO(NIMP(x), badx); if (BIGP(x)) return TYP16(x)==tc16_bigpos ? BOOL_F : BOOL_T; # ifndef RECKLESS if (!(REALP(x))) badx: wta(x, (char *)ARG1, s_negativep); # endif # else ASRTER(NIMP(x) && REALP(x), x, ARG1, s_negativep); # endif return (REALPART(x) < 0.0) ? BOOL_T : BOOL_F; } #else # ifdef BIGDIG if (NINUMP(x)) { ASRTER(NIMP(x) && BIGP(x), x, ARG1, s_negativep); return (TYP16(x)==tc16_bigneg) ? BOOL_T : BOOL_F; } # else ASRTER(INUMP(x), x, ARG1, s_negativep); # endif #endif return (x < INUM0) ? BOOL_T : BOOL_F; } static char s_exactprob[] = "not representable as inexact"; SCM lmax(x, y) SCM x, y; { #ifdef FLOATS SCM t; double z; #endif if (UNBNDP(y)) { #ifndef RECKLESS if (!(NUMBERP(x))) badx: wta(x, (char *)ARG1, s_max); #endif return x; } #ifdef FLOATS if (NINUMP(x)) { # ifdef BIGDIG ASRTGO(NIMP(x), badx); if (BIGP(x)) { if (INUMP(y)) return BIGSIGN(x) ? y : x; ASRTGO(NIMP(y), bady); if (BIGP(y)) return (1==bigcomp(x, y)) ? y : x; ASRTGO(REALP(y), bady); big_dbl: if (-1 != scm_bigdblcomp(x, REALPART(y))) return y; z = big2dbl(x); ASRTER(0==scm_bigdblcomp(x, z), x, s_exactprob, s_max); return makdbl(z, 0.0); } ASRTGO(REALP(x), badx); # else ASRTER(NIMP(x) && REALP(x), x, ARG1, s_max); # endif if (INUMP(y)) return (REALPART(x) < (z = INUM(y))) ? makdbl(z, 0.0) : x; # ifdef BIGDIG ASRTGO(NIMP(y), bady); if (BIGP(y)) { t = y; y = x; x = t; goto big_dbl; } ASRTGO(REALP(y), bady); # else ASRTGO(NIMP(y) && REALP(y), bady); # endif return (REALPART(x) < REALPART(y)) ? y : x; } if (NINUMP(y)) { # ifdef BIGDIG ASRTGO(NIMP(y), bady); if (BIGP(y)) return BIGSIGN(y) ? x : y; # ifndef RECKLESS if (!(REALP(y))) bady: wta(y, (char *)ARG2, s_max); # endif # else # ifndef RECKLESS if (!(NIMP(y) && REALP(y))) bady: wta(y, (char *)ARG2, s_max); # endif # endif return ((z = INUM(x)) < REALPART(y)) ? y : makdbl(z, 0.0); } #else # ifdef BIGDIG if (NINUMP(x)) { ASRTER(NIMP(x) && BIGP(x), x, ARG1, s_max); if (INUMP(y)) return BIGSIGN(x) ? y : x; ASRTGO(NIMP(y) && BIGP(y), bady); return (1==bigcomp(x, y)) ? y : x; } if (NINUMP(y)) { # ifndef RECKLESS if (!(NIMP(y) && BIGP(y))) bady: wta(y, (char *)ARG2, s_max); # endif return BIGSIGN(y) ? x : y; } # else ASRTER(INUMP(x), x, ARG1, s_max); ASRTER(INUMP(y), y, ARG2, s_max); # endif #endif return ((long)x < (long)y) ? y : x; } SCM lmin(x, y) SCM x, y; { #ifdef FLOATS SCM t; double z; #endif if (UNBNDP(y)) { #ifndef RECKLESS if (!(NUMBERP(x))) badx: wta(x, (char *)ARG1, s_min); #endif return x; } #ifdef FLOATS if (NINUMP(x)) { # ifdef BIGDIG ASRTGO(NIMP(x), badx); if (BIGP(x)) { if (INUMP(y)) return BIGSIGN(x) ? x : y; ASRTGO(NIMP(y), bady); if (BIGP(y)) return (-1==bigcomp(x, y)) ? y : x; ASRTGO(REALP(y), bady); big_dbl: if (1 != scm_bigdblcomp(x, REALPART(y))) return y; z = big2dbl(x); ASRTER(0==scm_bigdblcomp(x, z), x, s_exactprob, s_min); return makdbl(z, 0.0); } ASRTGO(REALP(x), badx); # else ASRTER(NIMP(x) && REALP(x), x, ARG1, s_min); # endif if (INUMP(y)) return (REALPART(x) > (z = INUM(y))) ? makdbl(z, 0.0) : x; # ifdef BIGDIG ASRTGO(NIMP(y), bady); if (BIGP(y)) { t = y; y = x; x = t; goto big_dbl; } ASRTGO(REALP(y), bady); # else ASRTGO(NIMP(y) && REALP(y), bady); # endif return (REALPART(x) > REALPART(y)) ? y : x; } if (NINUMP(y)) { # ifdef BIGDIG ASRTGO(NIMP(y), bady); if (BIGP(y)) return BIGSIGN(y) ? y : x; # ifndef RECKLESS if (!(REALP(y))) bady: wta(y, (char *)ARG2, s_min); # endif # else # ifndef RECKLESS if (!(NIMP(y) && REALP(y))) bady: wta(y, (char *)ARG2, s_min); # endif # endif return ((z = INUM(x)) > REALPART(y)) ? y : makdbl(z, 0.0); } #else # ifdef BIGDIG if (NINUMP(x)) { ASRTER(NIMP(x) && BIGP(x), x, ARG1, s_min); if (INUMP(y)) return BIGSIGN(x) ? x : y; ASRTGO(NIMP(y) && BIGP(y), bady); return (-1==bigcomp(x, y)) ? y : x; } if (NINUMP(y)) { # ifndef RECKLESS if (!(NIMP(y) && BIGP(y))) bady: wta(y, (char *)ARG2, s_min); # endif return BIGSIGN(y) ? y : x; } # else ASRTER(INUMP(x), x, ARG1, s_min); ASRTER(INUMP(y), y, ARG2, s_min); # endif #endif return ((long)x > (long)y) ? y : x; } SCM sum(x, y) SCM x, y; { if (UNBNDP(y)) { if (UNBNDP(x)) return INUM0; #ifndef RECKLESS if (!(NUMBERP(x))) badx: wta(x, (char *)ARG1, s_sum); #endif return x; } #ifdef FLOATS if (NINUMP(x)) { SCM t; # ifdef BIGDIG ASRTGO(NIMP(x), badx); if (BIGP(x)) { if (INUMP(y)) {t = x; x = y; y = t; goto intbig;} ASRTGO(NIMP(y), bady); if (BIGP(y)) { if (NUMDIGS(x) > NUMDIGS(y)) {t = x; x = y; y = t;} return addbig(BDIGITS(x), NUMDIGS(x), BIGSIGN(x), y, 0); } ASRTGO(INEXP(y), bady); bigreal: return makdbl(big2dbl(x)+REALPART(y), CPLXP(y)?IMAG(y):0.0); } ASRTGO(INEXP(x), badx); # else ASRTGO(NIMP(x) && INEXP(x), badx); # endif if (INUMP(y)) {t = x; x = y; y = t; goto intreal;} # ifdef BIGDIG ASRTGO(NIMP(y), bady); if (BIGP(y)) {t = x; x = y; y = t; goto bigreal;} # ifndef RECKLESS else if (!(INEXP(y))) bady: wta(y, (char *)ARG2, s_sum); # endif # else # ifndef RECKLESS if (!(NIMP(y) && INEXP(y))) bady: wta(y, (char *)ARG2, s_sum); # endif # endif { double i = 0.0; if (CPLXP(x)) i = IMAG(x); if (CPLXP(y)) i += IMAG(y); return makdbl(REALPART(x)+REALPART(y), i); } } if (NINUMP(y)) { # ifdef BIGDIG ASRTGO(NIMP(y), bady); if (BIGP(y)) intbig: { # ifndef DIGSTOOBIG long z = pseudolong(INUM(x)); return addbig((BIGDIG *)&z, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0); # else BIGDIG zdigs[DIGSPERLONG]; longdigs(INUM(x), zdigs); return addbig(zdigs, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0); # endif } ASRTGO(INEXP(y), bady); # else ASRTGO(NIMP(y) && INEXP(y), bady); # endif intreal: return makdbl(INUM(x)+REALPART(y), CPLXP(y)?IMAG(y):0.0); } #else # ifdef BIGDIG if (NINUMP(x)) { SCM t; ASRTGO(NIMP(x) && BIGP(x), badx); if (INUMP(y)) {t = x; x = y; y = t; goto intbig;} ASRTGO(NIMP(y) && BIGP(y), bady); if (NUMDIGS(x) > NUMDIGS(y)) {t = x; x = y; y = t;} return addbig(BDIGITS(x), NUMDIGS(x), BIGSIGN(x), y, 0); } if (NINUMP(y)) { # ifndef RECKLESS if (!(NIMP(y) && BIGP(y))) bady: wta(y, (char *)ARG2, s_sum); # endif intbig: { # ifndef DIGSTOOBIG long z = pseudolong(INUM(x)); return addbig((BIGDIG *)&z, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0); # else BIGDIG zdigs[DIGSPERLONG]; longdigs(INUM(x), zdigs); return addbig(zdigs, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0); # endif } } # else ASRTGO(INUMP(x), badx); ASRTER(INUMP(y), y, ARG2, s_sum); # endif #endif x = INUM(x)+INUM(y); if (FIXABLE(x)) return MAKINUM(x); #ifdef BIGDIG return long2big(x); #else # ifdef FLOATS return makdbl((double)x, 0.0); # else wta(y, (char *)OVFLOW, s_sum); # endif #endif } SCM difference(x, y) SCM x, y; { #ifdef FLOATS if (NINUMP(x)) { # ifndef RECKLESS if (!(NIMP(x))) badx: wta(x, (char *)ARG1, s_difference); # endif if (UNBNDP(y)) { # ifdef BIGDIG if (BIGP(x)) { x = copybig(x, !BIGSIGN(x)); return NUMDIGS(x) * BITSPERDIG/CHAR_BIT <= sizeof(SCM) ? big2inum(x, NUMDIGS(x)) : x; } # endif ASRTGO(INEXP(x), badx); return makdbl(-REALPART(x), CPLXP(x)?-IMAG(x):0.0); } if (INUMP(y)) return sum(x, MAKINUM(-INUM(y))); # ifdef BIGDIG ASRTGO(NIMP(y), bady); if (BIGP(x)) { if (BIGP(y)) return (NUMDIGS(x) < NUMDIGS(y)) ? addbig(BDIGITS(x), NUMDIGS(x), BIGSIGN(x), y, 0x0100) : addbig(BDIGITS(y), NUMDIGS(y), BIGSIGN(y) ^ 0x0100, x, 0); ASRTGO(INEXP(y), bady); return makdbl(big2dbl(x)-REALPART(y), CPLXP(y)?-IMAG(y):0.0); } ASRTGO(INEXP(x), badx); if (BIGP(y)) return makdbl(REALPART(x)-big2dbl(y), CPLXP(x)?IMAG(x):0.0); ASRTGO(INEXP(y), bady); # else ASRTGO(INEXP(x), badx); ASRTGO(NIMP(y) && INEXP(y), bady); # endif if (CPLXP(x)) { if (CPLXP(y)) return makdbl(REAL(x)-REAL(y), IMAG(x)-IMAG(y)); else return makdbl(REAL(x)-REALPART(y), IMAG(x)); } return makdbl(REALPART(x)-REALPART(y), CPLXP(y)?-IMAG(y):0.0); } if (UNBNDP(y)) {x = -INUM(x); goto checkx;} if (NINUMP(y)) { # ifdef BIGDIG ASRTGO(NIMP(y), bady); if (BIGP(y)) { # ifndef DIGSTOOBIG long z = pseudolong(INUM(x)); return addbig((BIGDIG *)&z, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0x0100); # else BIGDIG zdigs[DIGSPERLONG]; longdigs(INUM(x), zdigs); return addbig(zdigs, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0x0100); # endif } # ifndef RECKLESS if (!(INEXP(y))) bady: wta(y, (char *)ARG2, s_difference); # endif # else # ifndef RECKLESS if (!(NIMP(y) && INEXP(y))) bady: wta(y, (char *)ARG2, s_difference); # endif # endif return makdbl(INUM(x)-REALPART(y), CPLXP(y)?-IMAG(y):0.0); } #else # ifdef BIGDIG if (NINUMP(x)) { ASRTER(NIMP(x) && BIGP(x), x, ARG1, s_difference); if (UNBNDP(y)) { x = copybig(x, !BIGSIGN(x)); return NUMDIGS(x) * BITSPERDIG/CHAR_BIT <= sizeof(SCM) ? big2inum(x, NUMDIGS(x)) : x; } if (INUMP(y)) { # ifndef DIGSTOOBIG long z = pseudolong(INUM(y)); return addbig((BIGDIG *)&z, DIGSPERLONG, (y < 0) ? 0 : 0x0100, x, 0); # else BIGDIG zdigs[DIGSPERLONG]; longdigs(INUM(x), zdigs); return addbig(zdigs, DIGSPERLONG, (y < 0) ? 0 : 0x0100, x, 0); # endif } ASRTGO(NIMP(y) && BIGP(y), bady); return (NUMDIGS(x) < NUMDIGS(y)) ? addbig(BDIGITS(x), NUMDIGS(x), BIGSIGN(x), y, 0x0100) : addbig(BDIGITS(y), NUMDIGS(y), BIGSIGN(y) ^ 0x0100, x, 0); } if (UNBNDP(y)) {x = -INUM(x); goto checkx;} if (NINUMP(y)) { # ifndef RECKLESS if (!(NIMP(y) && BIGP(y))) bady: wta(y, (char *)ARG2, s_difference); # endif { # ifndef DIGSTOOBIG long z = pseudolong(INUM(x)); return addbig((BIGDIG *)&z, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0x0100); # else BIGDIG zdigs[DIGSPERLONG]; longdigs(INUM(x), zdigs); return addbig(zdigs, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0x0100); # endif } } # else ASRTER(INUMP(x), x, ARG1, s_difference); if (UNBNDP(y)) {x = -INUM(x); goto checkx;} ASRTER(INUMP(y), y, ARG2, s_difference); # endif #endif x = INUM(x)-INUM(y); checkx: if (FIXABLE(x)) return MAKINUM(x); #ifdef BIGDIG return long2big(x); #else # ifdef FLOATS return makdbl((double)x, 0.0); # else wta(y, (char *)OVFLOW, s_difference); # endif #endif } SCM product(x, y) SCM x, y; { if (UNBNDP(y)) { if (UNBNDP(x)) return MAKINUM(1L); #ifndef RECKLESS if (!(NUMBERP(x))) badx: wta(x, (char *)ARG1, s_product); #endif return x; } #ifdef FLOATS if (NINUMP(x)) { SCM t; # ifdef BIGDIG ASRTGO(NIMP(x), badx); if (BIGP(x)) { if (INUMP(y)) {t = x; x = y; y = t; goto intbig;} ASRTGO(NIMP(y), bady); if (BIGP(y)) return mulbig(BDIGITS(x), NUMDIGS(x), BDIGITS(y), NUMDIGS(y), BIGSIGN(x) ^ BIGSIGN(y)); ASRTGO(INEXP(y), bady); bigreal: return bigdblop('*', x, REALPART(y), CPLXP(y) ? IMAG(y) : 0.0); } ASRTGO(INEXP(x), badx); # else ASRTGO(NIMP(x) && INEXP(x), badx); # endif if (INUMP(y)) {t = x; x = y; y = t; goto intreal;} # ifdef BIGDIG ASRTGO(NIMP(y), bady); if (BIGP(y)) {t = x; x = y; y = t; goto bigreal;} # ifndef RECKLESS else if (!(INEXP(y))) bady: wta(y, (char *)ARG2, s_product); # endif # else # ifndef RECKLESS if (!(NIMP(y) && INEXP(y))) bady: wta(y, (char *)ARG2, s_product); # endif # endif if (CPLXP(x)) { if (CPLXP(y)) return makdbl(REAL(x)*REAL(y)-IMAG(x)*IMAG(y), REAL(x)*IMAG(y)+IMAG(x)*REAL(y)); else return makdbl(REAL(x)*REALPART(y), IMAG(x)*REALPART(y)); } return makdbl(REALPART(x)*REALPART(y), CPLXP(y)?REALPART(x)*IMAG(y):0.0); } if (NINUMP(y)) { # ifdef BIGDIG ASRTGO(NIMP(y), bady); if (BIGP(y)) { intbig: if (INUM0==x) return x; if (MAKINUM(1L)==x) return y; { # ifndef DIGSTOOBIG long z = pseudolong(INUM(x)); return mulbig((BIGDIG *)&z, DIGSPERLONG, BDIGITS(y), NUMDIGS(y), BIGSIGN(y) ? (x>0) : (x<0)); # else BIGDIG zdigs[DIGSPERLONG]; longdigs(INUM(x), zdigs); return mulbig(zdigs, DIGSPERLONG, BDIGITS(y), NUMDIGS(y), BIGSIGN(y) ? (x>0) : (x<0)); # endif } } ASRTGO(INEXP(y), bady); # else ASRTGO(NIMP(y) && INEXP(y), bady); # endif intreal: return makdbl(INUM(x)*REALPART(y), CPLXP(y)?INUM(x)*IMAG(y):0.0); } #else # ifdef BIGDIG if (NINUMP(x)) { ASRTGO(NIMP(x) && BIGP(x), badx); if (INUMP(y)) {SCM t = x; x = y; y = t; goto intbig;} ASRTGO(NIMP(y) && BIGP(y), bady); return mulbig(BDIGITS(x), NUMDIGS(x), BDIGITS(y), NUMDIGS(y), BIGSIGN(x) ^ BIGSIGN(y)); } if (NINUMP(y)) { # ifndef RECKLESS if (!(NIMP(y) && BIGP(y))) bady: wta(y, (char *)ARG2, s_product); # endif intbig: if (INUM0==x) return x; if (MAKINUM(1L)==x) return y; { # ifndef DIGSTOOBIG long z = pseudolong(INUM(x)); return mulbig((BIGDIG *)&z, DIGSPERLONG, BDIGITS(y), NUMDIGS(y), BIGSIGN(y) ? (x>0) : (x<0)); # else BIGDIG zdigs[DIGSPERLONG]; longdigs(INUM(x), zdigs); return mulbig(zdigs, DIGSPERLONG, BDIGITS(y), NUMDIGS(y), BIGSIGN(y) ? (x>0) : (x<0)); # endif } } # else ASRTGO(INUMP(x), badx); ASRTER(INUMP(y), y, ARG2, s_product); # endif #endif { long i, j, k; i = INUM(x); if (0==i) return x; j = INUM(y); k = i * j; y = MAKINUM(k); if (k != INUM(y) || k/i != j) #ifdef BIGDIG { int sgn = (i < 0) ^ (j < 0); # ifndef DIGSTOOBIG i = pseudolong(i); j = pseudolong(j); return mulbig((BIGDIG *)&i, DIGSPERLONG, (BIGDIG *)&j, DIGSPERLONG, sgn); # else /* DIGSTOOBIG */ BIGDIG idigs[DIGSPERLONG]; BIGDIG jdigs[DIGSPERLONG]; longdigs(i, idigs); longdigs(j, jdigs); return mulbig(idigs, DIGSPERLONG, jdigs, DIGSPERLONG, sgn); # endif } #else # ifdef FLOATS return makdbl(((double)i)*((double)j), 0.0); # else wta(y, (char *)OVFLOW, s_product); # endif #endif return y; } } /* Use "Smith's formula" to extend dynamic range */ /* David Goldberg What Every Computer Scientist Should Know About Floating-Point Arithmetic http://cch.loria.fr/documentation/IEEE754/ACM/goldberg.pdf */ SCM divide(x, y) SCM x, y; { #ifdef FLOATS double den, a = 1.0; if (NINUMP(x)) { # ifndef RECKLESS if (!(NIMP(x))) badx: wta(x, (char *)ARG1, s_divide); # endif if (UNBNDP(y)) { # ifdef BIGDIG if (BIGP(x)) return makdbl(1.0/big2dbl(x), 0.0); # endif /* reciprocal */ ASRTGO(INEXP(x), badx); if (REALP(x)) return makdbl(1.0/REALPART(x), 0.0); { y = x; a = 1.0; goto real_over_complex; } } # ifdef BIGDIG if (BIGP(x)) { SCM z; if (INUMP(y)) { z = INUM(y); ASRTER(z, y, OVFLOW, s_divide); if (1==z) return x; if (z < 0) z = -z; if (z < BIGRAD) { SCM w = copybig(x, BIGSIGN(x) ? (y>0) : (y<0)); return divbigdig(BDIGITS(w), NUMDIGS(w), (BIGDIG)z) ? bigdblop('/', x, INUM(y), 0.0) : normbig(w); } # ifndef DIGSTOOBIG z = pseudolong(z); z = divbigbig(BDIGITS(x), NUMDIGS(x), (BIGDIG *)&z, DIGSPERLONG, BIGSIGN(x) ? (y>0) : (y<0), 3); # else { BIGDIG zdigs[DIGSPERLONG]; longdigs(z, zdigs); z = divbigbig(BDIGITS(x), NUMDIGS(x), zdigs, DIGSPERLONG, BIGSIGN(x) ? (y>0) : (y<0), 3); } # endif return z ? z : bigdblop('/', x, INUM(y), 0.0); } ASRTGO(NIMP(y), bady); if (BIGP(y)) { z = divbigbig(BDIGITS(x), NUMDIGS(x), BDIGITS(y), NUMDIGS(y), BIGSIGN(x) ^ BIGSIGN(y), 3); return z ? z : inex_divbigbig(x, y); } ASRTGO(INEXP(y), bady); return bigdblop('/', x, REALPART(y), CPLXP(y) ? IMAG(y) : 0.0); } # endif ASRTGO(INEXP(x), badx); if (INUMP(y)) {den = INUM(y); goto basic_div;} # ifdef BIGDIG ASRTGO(NIMP(y), bady); if (BIGP(y)) return bigdblop('\\', y, REALPART(x), CPLXP(x) ? IMAG(x) : 0.0); ASRTGO(INEXP(y), bady); # else ASRTGO(NIMP(y) && INEXP(y), bady); # endif if (REALP(y)) { den = REALPART(y); basic_div: return makdbl(REALPART(x)/den, CPLXP(x)?IMAG(x)/den:0.0); } a = REALPART(x); if (REALP(x)) goto real_over_complex; /* Both x and y are complex */ /* Use "Smith's formula" to extend dynamic range */ { double b = IMAG(x); double c = REALPART(y); double d = IMAG(y); if ((d > 0 ? d : -d) < (c > 0 ? c : -c)) { double r = d/c; double i = c + d*r; return makdbl((a + b*r)/i, (b - a*r)/i); } { double r = c/d; double i = d + c*r; return makdbl((b + a*r)/i, (-a + b*r)/i); } } } if (UNBNDP(y)) { if ((MAKINUM(1L)==x) || (MAKINUM(-1L)==x)) return x; return makdbl(1.0/((double)INUM(x)), 0.0); } if (NINUMP(y)) { # ifdef BIGDIG ASRTGO(NIMP(y), bady); if (BIGP(y)) return bigdblop('\\', y, INUM(x), 0.0); # ifndef RECKLESS if (!(INEXP(y))) bady: wta(y, (char *)ARG2, s_divide); # endif # else # ifndef RECKLESS if (!(NIMP(y) && INEXP(y))) bady: wta(y, (char *)ARG2, s_divide); # endif # endif if (REALP(y)) return makdbl(INUM(x)/REALPART(y), 0.0); a = INUM(x); real_over_complex: /* Both x and y are complex */ /* Use "Smith's formula" to extend dynamic range */ { double c = REALPART(y); double d = IMAG(y); if ((d > 0 ? d : -d) < (c > 0 ? c : -c)) { double r = d/c; double i = c + d*r; return makdbl((a)/i, (- a*r)/i); } { double r = c/d; double i = d + c*r; return makdbl((a*r)/i, (-a)/i); } } } #else # ifdef BIGDIG if (NINUMP(x)) { SCM z; ASRTER(NIMP(x) && BIGP(x), x, ARG1, s_divide); if (UNBNDP(y)) goto ov; if (INUMP(y)) { z = INUM(y); if (!z) goto ov; if (1==z) return x; if (z < 0) z = -z; if (z < BIGRAD) { SCM w = copybig(x, BIGSIGN(x) ? (y>0) : (y<0)); if (divbigdig(BDIGITS(w), NUMDIGS(w), (BIGDIG)z)) goto ov; return w; } # ifndef DIGSTOOBIG z = pseudolong(z); z = divbigbig(BDIGITS(x), NUMDIGS(x), (BIGDIG *)&z, DIGSPERLONG, BIGSIGN(x) ? (y>0) : (y<0), 3); # else { BIGDIG zdigs[DIGSPERLONG]; longdigs(z, zdigs); z = divbigbig(BDIGITS(x), NUMDIGS(x), zdigs, DIGSPERLONG, BIGSIGN(x) ? (y>0) : (y<0), 3); } # endif } else { ASRTGO(NIMP(y) && BIGP(y), bady); z = divbigbig(BDIGITS(x), NUMDIGS(x), BDIGITS(y), NUMDIGS(y), BIGSIGN(x) ^ BIGSIGN(y), 3); } if (!z) goto ov; return z; } if (UNBNDP(y)) { if ((MAKINUM(1L)==x) || (MAKINUM(-1L)==x)) return x; goto ov; } if (NINUMP(y)) { # ifndef RECKLESS if (!(NIMP(y) && BIGP(y))) bady: wta(y, (char *)ARG2, s_divide); # endif goto ov; } # else ASRTER(INUMP(x), x, ARG1, s_divide); if (UNBNDP(y)) { if ((MAKINUM(1L)==x) || (MAKINUM(-1L)==x)) return x; goto ov; } ASRTER(INUMP(y), y, ARG2, s_divide); # endif #endif { long z = INUM(y); if ((0==z) || INUM(x)%z) goto ov; z = INUM(x)/z; if (FIXABLE(z)) return MAKINUM(z); #ifdef BIGDIG return long2big(z); #endif #ifdef FLOATS ov: return makdbl(((double)INUM(x))/((double)INUM(y)), 0.0); #else ov: wta(x, (char *)OVFLOW, s_divide); #endif } } SCM scm_intexpt(z1, z2) SCM z1, z2; { SCM acc = MAKINUM(1L); int recip = 0; #ifdef FLOATS double dacc, dz1; #endif if (INUM0==z2) return sum(acc, product(z1, INUM0)); ASRTER(INUMP(z2), z2, ARG2, s_intexpt); if (acc==z1) return z1; if (MAKINUM(-1L)==z1) return BOOL_F==evenp(z2)?z1:acc; z2 = INUM(z2); if (z2 < 0) { z2 = -z2; recip = 1; /* z1 = divide(z1, UNDEFINED); */ } if (INUMP(z1)) { long tmp, iacc = 1, iz1 = INUM(z1); #ifdef FLOATS if (recip) { dz1 = iz1; goto flocase; } #endif while (1) { if (0==z2) { acc = long2num(iacc); break; } if (0==iz1) if (0==recip) return z1; else goto overflow; if (1==z2) { tmp = iacc*iz1; if (tmp/iacc != iz1) { overflow: z1 = long2num(iz1); acc = long2num(iacc); ASRTGO(NFALSEP(z1) && NFALSEP(acc), errout); goto gencase; } acc = long2num(tmp); break; } if (z2 & 1) { tmp = iacc*iz1; if (tmp/iacc != iz1) goto overflow; iacc = tmp; z2 = z2 - 1; /* so jumping to gencase works */ } tmp = iz1*iz1; if (tmp/iz1 != iz1) goto overflow; iz1 = tmp; z2 >>= 1; } #ifndef RECKLESS if (FALSEP(acc)) errout: wta(UNDEFINED, (char *)OVFLOW, s_intexpt); #endif goto ret; } ASRTER(NIMP(z1), z1, ARG1, s_intexpt); #ifdef FLOATS if (REALP(z1)) { dz1 = REALPART(z1); flocase: dacc = 1.0; while(1) { if (0==z2) break; if (1==z2) {dacc = dacc*dz1; break;} if (z2 & 1) dacc = dacc*dz1; dz1 = dz1*dz1; z2 >>= 1; } return makdbl(recip ? 1.0/dacc : dacc, 0.0); } #endif gencase: while(1) { if (0==z2) break; if (1==z2) {acc = product(acc, z1); break;} if (z2 & 1) acc = product(acc, z1); z1 = product(z1, z1); z2 >>= 1; } ret: return recip ? divide(acc, UNDEFINED) : acc; } #ifdef FLOATS # ifndef HAVE_ATANH double asinh(x) double x; { return log(x+sqrt(x*x+1)); } double acosh(x) double x; { return log(x+sqrt(x*x-1)); } double atanh(x) double x; { return 0.5*log((1+x)/(1-x)); } # endif double scm_truncate(x) double x; { if (x < 0.0) return -floor(-x); return floor(x); } double scm_round(x) double x; { double plus_half = x + 0.5; double result = floor(plus_half); /* Adjust so that the round is towards even. */ return (plus_half==result && plus_half / 2 != floor(plus_half / 2)) ? result - 1 : result; } struct dpair {double x, y;}; void two_doubles(z1, z2, sstring, xy) SCM z1, z2; char *sstring; struct dpair *xy; { if (INUMP(z1)) xy->x = INUM(z1); else { # ifdef BIGDIG ASRTGO(NIMP(z1), badz1); if (BIGP(z1)) xy->x = big2dbl(z1); else { # ifndef RECKLESS if (!(REALP(z1))) badz1: wta(z1, (char *)ARG1, sstring); # endif xy->x = REALPART(z1);} # else {ASRTER(NIMP(z1) && REALP(z1), z1, ARG1, sstring); xy->x = REALPART(z1);} # endif } if (INUMP(z2)) xy->y = INUM(z2); else { # ifdef BIGDIG ASRTGO(NIMP(z2), badz2); if (BIGP(z2)) xy->y = big2dbl(z2); else { # ifndef RECKLESS if (!(REALP(z2))) badz2: wta(z2, (char *)ARG2, sstring); # endif xy->y = REALPART(z2);} # else { ASRTER(NIMP(z2) && REALP(z2), z2, ARG2, sstring); xy->y = REALPART(z2); } # endif } } SCM expt(z1, z2) SCM z1, z2; { struct dpair xy; two_doubles(z1, z2, s_expt, &xy); return makdbl(pow(xy.x, xy.y), 0.0); } SCM latan2(z1, z2) SCM z1, z2; { struct dpair xy; two_doubles(z1, z2, s_atan2, &xy); return makdbl(atan2(xy.x, xy.y), 0.0); } SCM makrect(z1, z2) SCM z1, z2; { struct dpair xy; two_doubles(z1, z2, s_makrect, &xy); return makdbl(xy.x, xy.y); } SCM makpolar(z1, z2) SCM z1, z2; { struct dpair xy; two_doubles(z1, z2, s_makpolar, &xy); return makdbl(xy.x*cos(xy.y), xy.x*sin(xy.y)); } SCM real_part(z) SCM z; { if (NINUMP(z)) { # ifdef BIGDIG ASRTGO(NIMP(z), badz); if (BIGP(z)) return z; # ifndef RECKLESS if (!(INEXP(z))) badz: wta(z, (char *)ARG1, s_real_part); # endif # else ASRTER(NIMP(z) && INEXP(z), z, ARG1, s_real_part); # endif if (CPLXP(z)) return makdbl(REAL(z), 0.0); } return z; } SCM imag_part(z) SCM z; { if (INUMP(z)) return INUM0; # ifdef BIGDIG ASRTGO(NIMP(z), badz); if (BIGP(z)) return INUM0; # ifndef RECKLESS if (!(INEXP(z))) badz: wta(z, (char *)ARG1, s_imag_part); # endif # else ASRTER(NIMP(z) && INEXP(z), z, ARG1, s_imag_part); # endif if (CPLXP(z)) return makdbl(IMAG(z), 0.0); return flo0; } SCM scm_abs(z) SCM z; { if (INUMP(z)) return scm_iabs(z); ASRTGO(NIMP(z), badz); # ifdef BIGDIG if (BIGP(z)) return scm_iabs(z); # endif if (!REALP(z)) badz: wta(z, (char *)ARG1, s_abs); return makdbl(fabs(REALPART(z)), 0.0); } SCM scm_magnitude(z) SCM z; { if (INUMP(z)) return scm_iabs(z); ASRTGO(NIMP(z), badz); # ifdef BIGDIG if (BIGP(z)) return scm_iabs(z); # endif if (!INEXP(z)) badz: wta(z, (char *)ARG1, s_magnitude); if (CPLXP(z)) { double i = IMAG(z), r = REAL(z); if (i < 0) i = -i; if (r < 0) r = -r; if (i < r) { double q = i / r; return makdbl(r * sqrt(1 + q * q), 0.0); } if (0.0==i) return i; { double q = r / i; return makdbl(i * sqrt(1 + q * q), 0.0); } } return makdbl(fabs(REALPART(z)), 0.0); } SCM angle(z) SCM z; { double x, y = 0.0; if (INUMP(z)) {x = (z>=INUM0) ? 1.0 : -1.0; goto do_angle;} # ifdef BIGDIG ASRTGO(NIMP(z), badz); if (BIGP(z)) {x = (TYP16(z)==tc16_bigpos) ? 1.0 : -1.0; goto do_angle;} # ifndef RECKLESS if (!(INEXP(z))) { badz: wta(z, (char *)ARG1, s_angle);} # endif # else ASRTER(NIMP(z) && INEXP(z), z, ARG1, s_angle); # endif if (REALP(z)) {x = REALPART(z); goto do_angle;} x = REAL(z); y = IMAG(z); do_angle: return makdbl(atan2(y, x), 0.0); } SCM ex2in(z) SCM z; { if (INUMP(z)) return makdbl((double)INUM(z), 0.0); ASRTGO(NIMP(z), badz); if (INEXP(z)) return z; # ifdef BIGDIG if (BIGP(z)) return makdbl(big2dbl(z), 0.0); # endif badz: wta(z, (char *)ARG1, s_ex2in); } SCM in2ex(z) SCM z; { if (INUMP(z)) return z; # ifdef BIGDIG ASRTGO(NIMP(z), badz); if (BIGP(z)) return z; # ifndef RECKLESS if (!(REALP(z))) badz: wta(z, (char *)ARG1, s_in2ex); # endif # else ASRTER(NIMP(z) && REALP(z), z, ARG1, s_in2ex); # endif # ifdef BIGDIG { double u = floor(REALPART(z)+0.5); if ((u <= MOST_POSITIVE_FIXNUM) # ifdef hpux && (-u <= -MOST_NEGATIVE_FIXNUM) /* workaround for HP700 cc bug */ # endif ) { SCM ans = MAKINUM((long)u); if (INUM(ans)==(long)u) return ans; } ASRTGO(!((u==2*u) || (u)!=(u)), badz); /* problem? */ return dbl2big(u); } # else return MAKINUM((long)floor(REALPART(z)+0.5)); # endif } #else /* ~FLOATS */ static char s_trunc[] = "truncate"; SCM numident(x) SCM x; { # ifdef BIGDIG ASRTER(INUMP(x) || (NIMP(x) && BIGP(x)), x, ARG1, s_trunc); # else ASRTER(INUMP(x), x, ARG1, s_trunc); # endif return x; } #endif /* FLOATS */ SCM scm_iabs(x) SCM x; { #ifdef BIGDIG if (NINUMP(x)) { ASRTER(NIMP(x) && BIGP(x), x, ARG1, s_abs); if (TYP16(x)==tc16_bigpos) return x; return copybig(x, 0); } #else ASRTER(INUMP(x), x, ARG1, s_abs); #endif if (INUM(x) >= 0) return x; x = -INUM(x); if (!POSFIXABLE(x)) #ifdef BIGDIG return long2big(x); #else wta(MAKINUM(-x), (char *)OVFLOW, s_abs); #endif return MAKINUM(x); } #ifdef BIGDIG # ifdef FLOATS SCM dbl2big(d) double d; /* must be integer */ { sizet i = 0; long c; BIGDIG *digits; SCM ans; double u = (d < 0)?-d:d; while (0 != floor(u)) {u /= BIGRAD;i++;} ans = mkbig(i, d < 0); digits = BDIGITS(ans); while (i--) { u *= BIGRAD; c = floor(u); u -= c; digits[i] = c; } ASRTER(0==u, INUM0, OVFLOW, "dbl2big"); return ans; } double big2dbl(b) SCM b; { double ans = 0.0; sizet i = NUMDIGS(b); BIGDIG *digits = BDIGITS(b); while (i--) ans = digits[i] + BIGRAD*ans; if (tc16_bigneg==TYP16(b)) return -ans; return ans; } static double big2scaldbl(b, expt) SCM b; int expt; { double ans = 0.0; int i = NUMDIGS(b) - 1; BIGDIG *digits = BDIGITS(b); while (i > (expt/BITSPERDIG)) { ans = digits[i] + BIGRAD*ans; i--; } ans = ldexp(ans, BITSPERDIG - expt); /* if (expt = (expt % BITSPERDIG)) { ans = (digits[i] >> expt) + (1L << (BITSPERDIG - expt))*ans; } if ((1L << (BITSPERDIG - expt - 1)) & digits[i]) ans += 1; */ if (tc16_bigneg==TYP16(b)) return -ans; return ans; } static SCM bigdblop(op, b, re, im) int op; SCM b; double re, im; { double bm = 0.0; int i = 0; if (NUMDIGS(b)*BITSPERDIG < DBL_MAX_EXP) { bm = big2dbl(b); } else { i = INUM(scm_intlength(b)); if (i < DBL_MAX_EXP) { i = 0; bm = big2dbl(b); } else { i = i + 1 - DBL_MAX_EXP; bm = big2scaldbl(b, i); } } switch (op) { case '*': return makdbl(ldexp(bm*re, i), 0.0==im ? 0.0 : ldexp(bm*im, i)); case '/': { double d = re*re + im*im; return makdbl(ldexp(bm*(re/d), i), ldexp(-bm*(im/d), i)); } case '\\': return makdbl(ldexp(re/bm, -i), 0.0==im ? 0.0 : ldexp(im/bm, -i)); default: return UNSPECIFIED; } } static SCM inex_divbigbig(a, b) SCM a, b; { double r; if ((NUMDIGS(a)*BITSPERDIG < DBL_MAX_EXP) && (NUMDIGS(b)*BITSPERDIG < DBL_MAX_EXP)) r = big2dbl(a) / big2dbl(b); else { int i = INUM(scm_intlength(a)); int j = INUM(scm_intlength(b)); i = (i > j) ? i : j; if (i < DBL_MAX_EXP) r = big2dbl(a) / big2dbl(b); else { i = i + 1 - DBL_MAX_EXP; r = big2scaldbl(a, i) / big2scaldbl(b, i); } } return makdbl(r, 0.0); } static char s_dfloat_parts[] = "double-float-parts"; SCM scm_dfloat_parts(f) SCM f; { int expt, ndig = dbl_mant_dig; double mant = frexp(num2dbl(f, (char *)ARG1, s_dfloat_parts), &expt); # ifdef DBL_MIN_EXP if (expt < DBL_MIN_EXP) ndig -= DBL_MIN_EXP - expt; # endif mant *= ldexp(1.0, ndig); expt -= ndig; return scm_values(dbl2big(mant), MAKINUM(expt), EOL, s_dfloat_parts); } static char s_make_dfloat[] = "make-double-float"; SCM scm_make_dfloat(mant, expt) SCM mant, expt; { double dmant = num2dbl(mant, (char *)ARG1, s_make_dfloat); int e = INUM(expt); ASRTER(INUMP(expt), expt, ARG2, s_make_dfloat); ASRTER((dmant < 0 ? -dmant : dmant)<=max_dbl_int, mant, OUTOFRANGE, s_make_dfloat); return makdbl(ldexp(dmant, e), 0.0); } static char s_next_dfloat[] = "next-double-float"; SCM scm_next_dfloat(f1, f2) SCM f1, f2; { int e, neg = 0; double d1 = num2dbl(f1, (char *)ARG1, s_next_dfloat); double dif = num2dbl(f2, (char *)ARG2, s_next_dfloat) - d1; double d = frexp(d1, &e), eps = dbl_eps; if (d1 < 0) {neg = 1; dif = -dif; d = -d;} if (dif > 0) { # ifdef DBL_MIN_EXP if (e < DBL_MIN_EXP) eps = ldexp(eps, DBL_MIN_EXP - e); else if (0.0==d) eps = ldexp(1.0, DBL_MIN_EXP - dbl_mant_dig); # endif d = ldexp(d + eps, e); } else if (dif < 0) { # ifdef DBL_MIN_EXP if (e < DBL_MIN_EXP) eps = ldexp(eps, DBL_MIN_EXP - e); else if (0.0==d) eps = ldexp(-1.0, DBL_MIN_EXP - dbl_mant_dig); # endif if (0.5==d) eps *= 0.5; d = ldexp(d - eps, e); } else if (0.0==dif) return f1; return makdbl(neg ? -d : d, 0.0); } # endif #endif unsigned long hasher(obj, n, d) SCM obj; unsigned long n; sizet d; { switch (7 & PTR2INT(obj)) { case 2: case 6: /* INUMP(obj) */ return INUM(obj) % n; case 4: if (ICHRP(obj)) return (unsigned)(downcase[ICHR(obj)]) % n; switch ((int) obj) { #ifndef SICP case (int) EOL: d = 256; break; #endif case (int) BOOL_T: d = 257; break; case (int) BOOL_F: d = 258; break; case (int) EOF_VAL: d = 259; break; default: d = 263; /* perhaps should be error */ } return d % n; default: return 263 % n; /* perhaps should be error */ case 0: switch TYP7(obj) { default: return 263 % n; case tc7_smob: switch TYP16(obj) { case tcs_bignums: bighash: return INUM(modulo(obj, MAKINUM(n))); default: return 263 % n; #ifdef FLOATS case tc16_flo: if (REALP(obj)) { double r = REALPART(obj); if (floor(r)==r) { obj = in2ex(obj); if (IMP(obj)) return INUM(obj) % n; goto bighash; } } obj = number2string(obj, MAKINUM(10)); #endif } case tcs_symbols: case tc7_string: return strhash(UCHARS(obj), (sizet) LENGTH(obj), n); case tc7_vector: { sizet len = LENGTH(obj); SCM *data = VELTS(obj); if (len>5) { sizet i = d/2; unsigned long h = 1; while (i--) h = ((h<<8) + (hasher(data[h % len], n, 2))) % n; return h; } else { sizet i = len; unsigned long h = (n)-1; while (i--) h = ((h<<8) + (hasher(data[i], n, d/len))) % n; return h; } } case tcs_cons_imcar: case tcs_cons_nimcar: if (d) return (hasher(CAR(obj), n, d/2)+hasher(CDR(obj), n, d/2)) % n; else return 1; case tc7_port: return ((RDNG & CAR(obj)) ? 260 : 261) % n; case tcs_closures: case tc7_contin: case tcs_subrs: return 262 % n; } } } static char s_hashv[] = "hashv", s_hashq[] = "hashq"; extern char s_obunhash[]; #define s_hash (&s_obunhash[9]) SCM hash(obj, n) SCM obj; SCM n; { ASRTER(INUMP(n) && 0 <= n, n, ARG2, s_hash); return MAKINUM(hasher(obj, INUM(n), 10)); } SCM hashv(obj, n) SCM obj; SCM n; { ASRTER(INUMP(n) && 0 <= n, n, ARG2, s_hashv); if (ICHRP(obj)) return MAKINUM((unsigned)(downcase[ICHR(obj)]) % INUM(n)); if (NIMP(obj) && NUMP(obj)) return MAKINUM(hasher(obj, INUM(n), 10)); else return MAKINUM(obj % INUM(n)); } SCM hashq(obj, n) SCM obj; SCM n; { ASRTER(INUMP(n) && 0 <= n, n, ARG2, s_hashq); return MAKINUM((((unsigned) obj) >> 1) % INUM(n)); } static iproc subr1s[] = { {"number?", numberp}, {s_inexactp, inexactp}, #ifdef FLOATS {"complex?", scm_complex_p}, {"real?", realp}, {"rational?", scm_rationalp}, {"integer?", intp}, {s_real_part, real_part}, {s_imag_part, imag_part}, {s_magnitude, scm_magnitude}, {s_angle, angle}, {s_in2ex, in2ex}, {s_ex2in, ex2in}, {s_abs, scm_abs}, # ifdef BIGDIG {s_dfloat_parts, scm_dfloat_parts}, # endif #else {"complex?", numberp}, {"real?", numberp}, {"rational?", numberp}, {"integer?", exactp}, {"floor", numident}, {"ceiling", numident}, {s_trunc, numident}, {"round", numident}, {s_abs, scm_iabs}, #endif {s_zerop, zerop}, {s_positivep, positivep}, {s_negativep, negativep}, {s_str2list, string2list}, {"list->string", string}, {s_st_copy, string_copy}, {"list->vector", vector}, {s_vect2list, vector2list}, {0, 0}}; static iproc asubrs[] = { {s_difference, difference}, {s_divide, divide}, {s_max, lmax}, {s_min, lmin}, {s_sum, sum}, {s_product, product}, {0, 0}}; static iproc subr2s[] = { #ifdef FLOATS {s_makrect, makrect}, {s_makpolar, makpolar}, {s_atan2, latan2}, {s_expt, expt}, # ifdef BIGDIG {s_make_dfloat, scm_make_dfloat}, {s_next_dfloat, scm_next_dfloat}, # endif #endif #ifdef INUMS_ONLY {s_memv, memq}, {s_assv, assq}, #else {s_memv, memv}, {s_assv, assv}, #endif {s_intexpt, scm_intexpt}, {s_list_tail, list_tail}, {s_ve_fill, vector_fill}, {s_st_fill, string_fill}, {s_hash, hash}, {s_hashv, hashv}, {s_hashq, hashq}, {0, 0}}; static iproc subr2os[] = { {s_str2number, string2number}, {s_number2string, number2string}, {0, 0}}; static iproc rpsubrs[] = { #ifdef INUMS_ONLY {"eqv?", eq}, #else {"eqv?", eqv}, #endif {s_eqp, eqp}, {s_lessp, lessp}, {s_grp, greaterp}, {s_leqp, leqp}, {s_greqp, greqp}, {0, 0}}; #ifdef FLOATS static dblproc cxrs[] = { {"floor", floor}, {"ceiling", ceil}, {"truncate", scm_truncate}, {"round", scm_round}, {"$abs", fabs}, {"real-sqrt", sqrt}, {"real-exp", exp}, {"real-ln", log}, {"real-log10", log10}, {"real-sin", sin}, {"real-cos", cos}, {"real-tan", tan}, {"real-asin", asin}, {"real-acos", acos}, {"real-atan", atan}, {"real-sinh", sinh}, {"real-cosh", cosh}, {"real-tanh", tanh}, {"real-asinh", asinh}, {"real-acosh", acosh}, {"real-atanh", atanh}, {0, 0}}; #endif #ifdef FLOATS static void safe_add_1(f, fsum) double f, *fsum; { *fsum = f + 1.0; } #endif void init_scl() { init_iprocs(subr1s, tc7_subr_1); init_iprocs(subr2os, tc7_subr_2o); init_iprocs(subr2s, tc7_subr_2); init_iprocs(asubrs, tc7_asubr); init_iprocs(rpsubrs, tc7_rpsubr); #ifdef SICP add_feature("sicp"); #endif #ifdef FLOATS init_iprocs((iproc *)cxrs, tc7_cxr); # ifdef SINGLES NEWCELL(flo0); CAR(flo0) = tc_flo; FLO(flo0) = 0.0; # else DEFER_INTS; flo0 = must_malloc_cell(1L*sizeof(double), (SCM)tc_dblr, "real"); REAL(flo0) = 0.0; ALLOW_INTS; # endif # ifndef _MSC_VER DEFER_INTS; scm_narn = must_malloc_cell(2L*sizeof(double), (SCM)tc_dblc, "complex"); REAL(scm_narn) = 0.0/0.0; IMAG(scm_narn) = 0.0/0.0; ALLOW_INTS; # endif # ifdef DBL_DIG dblprec = (DBL_DIG > 20) ? 20 : DBL_DIG; # else { /* determine floating point precision */ double f = 0.1; volatile double fsum = 1.0+f; while (fsum != 1.0) { f /= 10.0; if (++dblprec > 20) break; safe_add_1(f, &fsum); } dblprec = dblprec-1; } # endif /* DBL_DIG */ # ifdef DBL_MANT_DIG dbl_mant_dig = DBL_MANT_DIG; # else { /* means we #defined it. */ volatile double fsum = 0.0; double eps = 1.0; int i = 0; while (fsum != 1.0) { eps = 0.5 * eps; safe_add_1(eps, &fsum); i++; } dbl_mant_dig = i; } # endif /* DBL_MANT_DIG */ max_dbl_int = pow(2.0, dbl_mant_dig - 1.0); max_dbl_int = max_dbl_int + (max_dbl_int - 1.0); dbl_eps = ldexp(1.0, - dbl_mant_dig); sysintern("double-float-mantissa-length", MAKINUM(dbl_mant_dig)); #endif } scm-5e5/continue.h0000644001705200017500000001050010750222611012017 0ustar tbtb/* Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2006 Free Software Foundation, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see * . */ /* "continue.h" Scheme Continuations for C. Author: Aubrey Jaffer. */ /* If stack is not longword aligned then */ /* #define SHORT_ALIGN */ #ifdef THINK_C # define SHORT_ALIGN #endif #ifdef __MWERKS__ # ifdef __MC68K__ # define SHORT_ALIGN # endif #endif #ifdef MSDOS # ifndef _M_ARM /* arm processors need DWORD aligned data access */ # define SHORT_ALIGN # endif #endif #ifdef atarist # define SHORT_ALIGN #endif #ifdef SHORT_ALIGN typedef short STACKITEM; #else typedef long STACKITEM; #endif /* If stacks grow up then */ /* #define STACK_GROWS_UP */ #ifdef hp9000s800 # define STACK_GROWS_UP #endif #ifdef pyr # define STACK_GROWS_UP #endif #ifdef nosve # define STACK_GROWS_UP #endif #ifdef _UNICOS # define STACK_GROWS_UP #endif /* James Clark came up with this neat one instruction fix for continuations on the SPARC. It flushes the register windows so that all the state of the process is contained in the stack. */ #ifdef sparc # define FLUSH_REGISTER_WINDOWS asm("ta 3") #else # define FLUSH_REGISTER_WINDOWS /* empty */ #endif #ifdef vax # ifndef CHEAP_CONTINUATIONS typedef int jump_buf[17]; extern int setjump(jump_buf env); extern int longjump(jump_buf env, int ret); # else # include # define jump_buf jmp_buf # define setjump setjmp # define longjump longjmp # endif #else /* ndef vax */ # ifdef _CRAY1 typedef int jump_buf[112]; extern int setjump(jump_buf env); extern int longjump(jump_buf env, int ret); # else /* ndef _CRAY1 */ # ifndef PLAN9 # include # include # endif # ifdef SIG_UNBLOCK # define jump_buf sigjmp_buf # define setjump(buf) sigsetjmp((buf), !0) # define longjump siglongjmp # else # define jump_buf jmp_buf # define setjump setjmp # define longjump longjmp # endif /* ndef SIG_UNBLOCK */ # endif /* ndef _CRAY1 */ #endif /* ndef vax */ /* `other' is a CONTINUATION slot for miscellaneous data of type CONTINUATION_OTHER. */ #ifndef CONTINUATION_OTHER # define CONTINUATION_OTHER int #endif struct Continuation {jump_buf jmpbuf; long thrwval; long length; STACKITEM *stkbse; #ifdef __ia64__ long *bspbse; long bsplength; long rnat; #endif CONTINUATION_OTHER other; struct Continuation *parent; }; typedef struct Continuation CONTINUATION; #ifndef P # ifdef USE_ANSI_PROTOTYPES # define P(s) s # else # define P(s) () # endif #endif extern long thrown_value; long stack_size P((STACKITEM *start)); CONTINUATION *make_root_continuation P((STACKITEM *stack_base)); CONTINUATION *make_continuation P((CONTINUATION *parent_cont)); void free_continuation P((CONTINUATION *cont)); void dynthrow P((long *a)); void grow_throw P((long *a)); void throw_to_continuation P((CONTINUATION *cont, long val, CONTINUATION *root_cont)); /* how to get the local definition for malloc */ #ifndef STDC_HEADERS # ifndef malloc char *malloc P((sizet size)); # endif char *realloc P((char *ptr, sizet size)); #endif /* PTR_LT defines how to compare two addresses (which may not be in the same array). */ #if defined(__TURBOC__) && !defined(__TOS__) # ifdef PROT386 # define PTR_LT(x, y) (((long)(x)) < ((long)(y))) # else # define PTR_LT(x, y) ((x) < (y)) # endif #else /* not __TURBOC__ */ # ifdef nosve # define PTR_MASK 0xffffffffffff # define PTR_LT(x, y) (((int)(x)&PTR_MASK) < ((int)(y)&PTR_MASK)) # else # define PTR_LT(x, y) ((x) < (y)) # endif #endif #define PTR_GT(x, y) PTR_LT(y, x) #define PTR_LE(x, y) (!PTR_GT(x, y)) #define PTR_GE(x, y) (!PTR_LT(x, y)) scm-5e5/findexec.c0000644001705200017500000001277510750241111011767 0ustar tbtb/* "findexec.c" was part of DLD, a dynamic link/unlink editor for C. * Copyright (C) 1990 by W. Wilson Ho. * * GNU Emacs 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 3 of the * License, or (at your option) any later version. * * GNU Emacs 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 GNU Emacs. If not, see * . */ /* The author can be reached electronically by how@cs.ucdavis.edu or through physical mail at: W. Wilson Ho Division of Computer Science University of California at Davis Davis, CA 95616 Fri Sep 14 22:16:14 1990 Edgar Roeder (edgar at megamaster) * added a separate DLDPATH environment variable in dld_find_executable so that users may specify a special path for object modules. Thu Feb 3 01:46:16 1994 Aubrey Jaffer * find_exec.c (dld_find_executable): added stat check for linux so that it doesn't think directories with the same name as the program are executable. Wed Feb 21 23:06:35 1996 Aubrey Jaffer * find_exec.c: extracted for general use. Generalized to MS-DOS. */ /* Given a filename, dld_find_executable searches the directories listed in the environment variable PATH for a file with that filename. A new copy of the complete path name of that file is returned. This new string may be disposed by free() later on. */ #ifndef __MINGW32__ # ifndef PLAN9 # include # include # endif # ifdef linux # include # include # include # include /* for X_OK define */ # endif # ifdef __SVR4 # include # include # include # include /* for X_OK define */ # else # ifdef __sgi__ # include # include # include # include /* for X_OK define */ # else # ifdef PLAN9 # include # include # define getcwd getwd # define MAXPATHLEN 256 /* arbitrary? */ # define X_OK AEXEC # else # include # endif # endif # endif # ifdef __amigaos__ # include # include # include # endif # ifndef __STDC__ # define const /**/ # endif # ifdef __FreeBSD__ /* This might be same for 44bsd derived system. */ # include # include # include # include # endif # ifdef __DragonflyBSD__ /* This might be same for 44bsd derived system. */ # include # include # include # include # endif # ifdef __NetBSD__ # include # include # include # include # endif # ifdef __OpenBSD__ /* This might be same for 44bsd derived system. */ # include # include # include /* # include */ # include # endif # ifdef __alpha # include # include # include # include # endif # ifdef GO32 # include # endif # ifndef DEFAULT_PATH # define DEFAULT_PATH ".:~/bin::/usr/local/bin:/usr/new:/usr/ucb:/usr/bin:/bin:/usr/hosts" # endif static char *copy_of(s) register const char *s; { register char *p = (char *) malloc(strlen(s)+1); if (!p) return 0; *p = 0; strcpy(p, s); return p; } /* ABSOLUTE_FILENAME_P(fname): True if fname is an absolute filename */ # ifdef atarist # define ABSOLUTE_FILENAME_P(fname) ((fname[0] == '/') || \ (fname[0] && (fname[1] == ':'))) # else # define ABSOLUTE_FILENAME_P(fname) (fname[0] == '/') # endif /* atarist */ char *dld_find_executable(name) const char *name; { char *search; register char *p; char tbuf[MAXPATHLEN]; if (ABSOLUTE_FILENAME_P(name)) return access(name, X_OK) ? 0 : copy_of(name); if (strchr(name, '/')) { strcpy (tbuf, "."); /* in case getcwd doesn't work */ getcwd(tbuf, MAXPATHLEN); if ((name[0] == '.') && (name[1] == '/')) { strcat(tbuf, name + 1); } else { if ('/' != tbuf[strlen(tbuf) - 1]) strcat(tbuf, "/"); strcat(tbuf, name); } return copy_of(tbuf); } if (((search = (char *) getenv("DLDPATH")) == 0) && ((search = (char *) getenv("PATH")) == 0)) search = DEFAULT_PATH; p = search; while (*p) { register char *next = tbuf; if (p[0]=='~' && p[1]=='/' && getenv("HOME")) { strcpy(tbuf, (char *)getenv("HOME")); next = tbuf + strlen(tbuf); p++; } /* Copy directory name into [tbuf] */ while (*p && *p != ':') *next++ = *p++; *next = 0; if (*p) p++; if (tbuf[0] == '.' && tbuf[1] == 0) getcwd(tbuf, MAXPATHLEN); /* was getwd(tbuf); */ else if (tbuf[0]=='~' && tbuf[1]==0 && getenv("HOME")) strcpy(tbuf, (char *)getenv("HOME")); strcat(tbuf, "/"); strcat(tbuf, name); if (access(tbuf, X_OK) == 0) { # ifndef hpux # ifndef ultrix # ifndef __MACH__ # ifndef PLAN9 struct stat stat_temp; if (stat(tbuf, &stat_temp)) continue; if (S_IFREG != (S_IFMT & stat_temp.st_mode)) continue; # endif /* PLAN9 */ # endif /* __MACH__ */ # endif/* ultrix */ # endif /* hpux */ return copy_of(tbuf); } } return 0; } #endif /* ndef MSDOS */ scm-5e5/x.h0000644001705200017500000001001207673755441010466 0ustar tbtb/* x.c */ SCM make_xwindow(SCM display, int screen_number, Drawable win, int pxmp, int rootp); SCM make_xcolormap(SCM sdpy, Colormap cmp); SCM make_xdisplay(Display *d); SCM make_xgcontext(SCM d, int screen_number, GC gc, int rootp); SCM make_xcursor(SCM display, Cursor cursor); SCM make_xfont(SCM display, Font font, SCM name); SCM make_xvisual(XVisualInfo *vsl); SCM CCC2SCM_P(XcmsCCC ccc); SCM CCC2SCM(XcmsCCC ccc); SCM make_xevent(XEvent *e); size_t x_free_xevent(CELLPTR ptr); void scm2XPoint(int signp, SCM dat, XPoint *ipr, char *pos, char *s_caller); int scm2XColor(SCM s_dat, XColor *xclr); int scm2xpointslen(SCM sara, char *s_caller); void scm2display_screen(SCM dat, SCM optidx, struct display_screen *dspscn, char *s_caller); SCM thevalue(SCM obj); Pixmap thepxmap(SCM obj, char *s_caller); Font thefont(SCM obj, char *s_caller); Colormap thecmap(SCM obj, char *s_caller); Cursor thecsr(SCM obj, char *s_caller); int thebool(SCM obj, char *s_caller); int theint(SCM obj, char *s_caller); int theuint(SCM obj, char *s_caller); SCM x_open_display(SCM dpy_name); SCM x_display_debug(SCM sd, SCM si); SCM x_default_screen(SCM sdpy); SCM x_create_window(SCM swin, SCM spos, SCM sargs); SCM x_create_pixmap(SCM obj, SCM s_size, SCM s_depth); SCM x_window_ref(SCM oargs); SCM x_window_set(SCM args); SCM x_window_geometry(SCM swin); SCM x_window_geometry_set(SCM args); SCM x_close(SCM obj); SCM x_flush(SCM sd, SCM si); SCM x_create_colormap(SCM swin, SCM s_vis, SCM s_alloc); SCM x_recreate_colormap(SCM s_cm); SCM x_install_colormap(SCM s_cm, SCM s_flg); SCM x_alloc_color_cells(SCM scmap, SCM spxls, SCM sargs); SCM x_free_color_cells(SCM scmap, SCM spxls, SCM sargs); SCM x_find_color(SCM scmap, SCM dat); SCM x_color_set(SCM scmap, SCM s_pix, SCM dat); SCM x_color_ref(SCM scmap, SCM sidx); SCM x_map_window(SCM swin); SCM x_map_subwindows(SCM swin); SCM x_unmap_window(SCM swin); SCM x_unmap_subwindows(SCM swin); SCM x_create_gc(SCM args); SCM x_gc_set(SCM args); SCM x_copy_gc(SCM dst, SCM src, SCM args); SCM x_gc_ref(SCM oargs); SCM x_create_cursor(SCM sdpy, SCM scsr, SCM sargs); SCM x_load_font(SCM sdpy, SCM fntnam); SCM x_protocol_version(SCM sd, SCM si); SCM x_server_vendor(SCM sd, SCM si); SCM x_vendor_release(SCM sd, SCM si); int x_scm_error_handler(Display *display, XErrorEvent *xee); SCM x_q_length(SCM sd, SCM si); SCM x_pending(SCM sd, SCM si); SCM x_events_queued(SCM sd, SCM si); SCM x_next_event(SCM sd, SCM si); SCM x_peek_event(SCM sd, SCM si); SCM x_screen_count(SCM sd, SCM si); SCM x_screen_cells(SCM sd, SCM si); SCM x_screen_depth(SCM sd, SCM si); SCM x_screen_depths(SCM sd, SCM si); SCM x_screen_size(SCM sd, SCM si); SCM x_screen_dimm(SCM sd, SCM si); SCM x_screen_black(SCM sd, SCM si); SCM x_screen_white(SCM sd, SCM si); XVisualInfo *visual2visualinfo(Display *dsp, Visual *vis); SCM x_make_visual(SCM sd, SCM sdepth, SCM sclass); SCM x_visual_geometry(SCM svsl); SCM x_visual_class(SCM svsl); SCM x_root_window(SCM sdpy, SCM sscr); SCM x_default_colormap(SCM sdpy, SCM sscr); SCM x_default_gcontext(SCM sdpy, SCM sscr); SCM x_default_visual(SCM sdpy, SCM sscr); SCM x_default_ccc(SCM sdpy, SCM sscr); SCM x_propdata2scm(Atom type, int format, unsigned long nitems, unsigned char *data); SCM x_get_window_property(SCM swin, SCM sprop, SCM sargs); SCM x_list_properties(SCM swin); SCM x_clear_area(SCM swin, SCM spos, SCM sargs); SCM x_fill_rectangle(SCM swin, SCM sgc, SCM sargs); void xldraw_string(SCM sdbl, SCM sgc, SCM sargs, int (*proc)(void), char *s_caller); SCM x_draw_string(SCM sdbl, SCM sgc, SCM sargs); SCM x_image_string(SCM sdbl, SCM sgc, SCM sargs); SCM x_draw_points(SCM sdbl, SCM sgc, SCM sargs); SCM xldraw_lines(SCM sdbl, SCM sgc, SCM sargs, int funcod, char *s_caller); SCM x_draw_segments(SCM sdbl, SCM sgc, SCM sargs); SCM x_draw_lines(SCM sdbl, SCM sgc, SCM sargs); SCM x_fill_poly(SCM sdbl, SCM sgc, SCM sargs); SCM x_read_bitmap_file(SCM sdbl, SCM sfname); SCM x_make_bool(int f); SCM x_event_ref(SCM sevent, SCM sfield); SCM x_event_keysym(SCM sevent); char *xvisualclass2name(int class); void x_scm_final(void); void init_x(void); scm-5e5/ramap.c0000644001705200017500000014303010750224160011274 0ustar tbtb/* "ramap.c" Array mapping functions for APL-Scheme. * Copyright (C) 1994, 1995, 2006 Free Software Foundation, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see * . */ /* Author: Radey Shouman */ #include "scm.h" SCM sc2array P((SCM s, SCM ra, SCM prot)); typedef struct { char *name; SCM sproc; int (* vproc)(); } ra_iproc; # define BVE_REF(a, i) ((VELTS(a)[(i)/LONG_BIT] & (1L<<((i)%LONG_BIT))) ? 1 : 0) # define BVE_SET(a, i) (VELTS(a)[(i)/LONG_BIT] |= (1L<<((i)%LONG_BIT))) # define BVE_CLR(a, i) (VELTS(a)[(i)/LONG_BIT] &= ~(1L<<((i)%LONG_BIT))) /* Fast, recycling vector ref */ # define RVREF(ra, i, e) (e = cvref(ra, i, e)) /* #define RVREF(ra, i, e) (cvref(ra, i, UNDEFINED)) to turn off */ /* IVDEP means "ignore vector dependencies", meaning we guarantee that elements of vector operands are not aliased */ # ifdef _UNICOS # define IVDEP(test, line) if (test) {_Pragma("ivdep"); line} else {line} # else # define IVDEP(test, line) line # endif static sizet cind(ra, inds) SCM ra; long *inds; { sizet i; int k; if (!ARRAYP(ra)) return *inds; i = ARRAY_BASE(ra); for (k = 0; k < ARRAY_NDIM(ra); k++) i += (inds[k] - ARRAY_DIMS(ra)[k].lbnd)*ARRAY_DIMS(ra)[k].inc; return i; } /* Checker for array mapping functions: return values: 4 --> shapes, increments, and bases are the same; 3 --> shapes and increments are the same; 2 --> shapes are the same; 1 --> ras are at least as big as ra0; 0 --> no match. */ int ra_matchp(ra0, ras) SCM ra0, ras; { SCM ra1; array_dim dims; array_dim *s0 = &dims; array_dim *s1; sizet bas0 = 0; int i, ndim = 1; int exact = 2 /* 4 */; /* Don't care about values >2 (yet?) */ if (IMP(ra0)) return 0; switch TYP7(ra0) { default: return 0; case tc7_vector: case tcs_uves: s0->lbnd = 0; s0->inc = 1; s0->ubnd = (long)LENGTH(ra0) - 1; break; case tc7_smob: if (!ARRAYP(ra0)) return 0; ndim = ARRAY_NDIM(ra0); s0 = ARRAY_DIMS(ra0); bas0 = ARRAY_BASE(ra0); break; } while NIMP(ras) { ra1 = CAR(ras); switch (IMP(ra1) ? 0 : TYP7(ra1)) { default: scalar: CAR(ras) = sc2array(ra1, ra0, EOL); break; case tc7_vector: case tcs_uves: if (1 != ndim) return 0; switch (exact) { case 4: if (0 != bas0) exact = 3; case 3: if (1 != s0->inc) exact = 2; case 2: if ((0==s0->lbnd) && (s0->ubnd==LENGTH(ra1) - 1)) break; exact = 1; case 1: if (s0->lbnd < 0 || s0->ubnd >= LENGTH(ra1)) if (s0->lbnd <= s0->ubnd) return 0; } break; case tc7_smob: if (!ARRAYP(ra1)) goto scalar; if (ndim != ARRAY_NDIM(ra1)) { if (0==ARRAY_NDIM(ra1)) goto scalar; else return 0; } s1 = ARRAY_DIMS(ra1); if (bas0 != ARRAY_BASE(ra1)) exact = 3; for (i = 0; i < ndim; i++) switch (exact) { case 4: case 3: if (s0[i].inc != s1[i].inc) exact = 2; case 2: if (s0[i].lbnd==s1[i].lbnd && s0[i].ubnd==s1[i].ubnd) break; exact = 1; default: if (s0[i].lbnd < s1[i].lbnd || s0[i].ubnd > s1[i].ubnd) if (s0[i].lbnd <= s0[i].ubnd) return 0; } break; } ras = CDR(ras); } return exact; } static char s_ra_mismatch[] = "array shape mismatch"; int ramapc(cproc, data, ra0, lra, what) int (*cproc)(); SCM data, ra0, lra; const char *what; { SCM z, vra0, ra1, vra1; SCM lvra, *plvra; int k, kmax = (ARRAYP(ra0) ? ARRAY_NDIM(ra0) - 1 : 0); switch (ra_matchp(ra0, lra)) { default: case 0: wta(ra0, s_ra_mismatch, what); case 2: case 3: case 4: /* Try unrolling arrays */ if (kmax < 0) goto gencase; vra0 = (0==kmax ? ra0 : array_contents(ra0, UNDEFINED)); if (IMP(vra0)) goto gencase; if (!ARRAYP(vra0)) { vra1 = make_ra(1); ARRAY_BASE(vra1) = 0; ARRAY_DIMS(vra1)->lbnd = 0; ARRAY_DIMS(vra1)->ubnd = LENGTH(vra0) - 1; ARRAY_DIMS(vra1)->inc = 1; ARRAY_V(vra1) = vra0; vra0 = vra1; } lvra = EOL; plvra = &lvra; for (z = lra; NIMP(z); z = CDR(z)) { vra1 = ra1 = (0==kmax ? CAR(z) : array_contents(CAR(z), UNDEFINED)); if (FALSEP(ra1)) goto gencase; if (!ARRAYP(ra1)) { vra1 = make_ra(1); ARRAY_DIMS(vra1)->lbnd = ARRAY_DIMS(vra0)->lbnd; ARRAY_DIMS(vra1)->ubnd = ARRAY_DIMS(vra0)->ubnd; ARRAY_BASE(vra1) = 0; ARRAY_DIMS(vra1)->inc = 1; ARRAY_V(vra1) = ra1; } *plvra = cons(vra1, EOL); plvra = &CDR(*plvra); } return (UNBNDP(data) ? cproc(vra0, lvra) : cproc(vra0, data, lvra)); case 1: gencase: /* Have to loop over all dimensions. */ { SCM hp_indv; long auto_indv[5]; long *indv = &auto_indv[0]; if (ARRAY_NDIM(ra0) >= 5) { scm_protect_temp(&hp_indv); hp_indv = make_uve(ARRAY_NDIM(ra0)+0L, MAKINUM(-32L)); indv = (long *)VELTS(hp_indv); } vra0 = make_ra(1); if (ARRAYP(ra0)) { if (kmax < 0) { ARRAY_DIMS(vra0)->lbnd = 0; ARRAY_DIMS(vra0)->ubnd = 0; ARRAY_DIMS(vra0)->inc = 1; } else { ARRAY_DIMS(vra0)->lbnd = ARRAY_DIMS(ra0)[kmax].lbnd; ARRAY_DIMS(vra0)->ubnd = ARRAY_DIMS(ra0)[kmax].ubnd; ARRAY_DIMS(vra0)->inc = ARRAY_DIMS(ra0)[kmax].inc; } ARRAY_BASE(vra0) = ARRAY_BASE(ra0); ARRAY_V(vra0) = ARRAY_V(ra0); } else { ARRAY_DIMS(vra0)->lbnd = 0; ARRAY_DIMS(vra0)->ubnd = LENGTH(ra0) - 1; ARRAY_DIMS(vra0)->inc = 1; ARRAY_BASE(vra0) = 0; ARRAY_V(vra0) = ra0; ra0 = vra0; } lvra = EOL; plvra = &lvra; for (z = lra; NIMP(z); z = CDR(z)) { ra1 = CAR(z); vra1 = make_ra(1); ARRAY_DIMS(vra1)->lbnd = ARRAY_DIMS(vra0)->lbnd; ARRAY_DIMS(vra1)->ubnd = ARRAY_DIMS(vra0)->ubnd; if (ARRAYP(ra1)) { if (kmax >= 0) ARRAY_DIMS(vra1)->inc = ARRAY_DIMS(ra1)[kmax].inc; ARRAY_V(vra1) = ARRAY_V(ra1); } else { ARRAY_DIMS(vra1)->inc = 1; ARRAY_V(vra1) = ra1; } *plvra = cons(vra1, EOL); plvra = &CDR(*plvra); } for (k = 0; k <= kmax; k++) indv[k] = ARRAY_DIMS(ra0)[k].lbnd; k = kmax; do { if (k==kmax) { SCM y = lra; ARRAY_BASE(vra0) = cind(ra0, indv); for (z = lvra; NIMP(z); z = CDR(z), y = CDR(y)) ARRAY_BASE(CAR(z)) = cind(CAR(y), indv); if (0==(UNBNDP(data) ? cproc(vra0, lvra) : cproc(vra0, data, lvra))) return 0; k--; continue; } if (indv[k] < ARRAY_DIMS(ra0)[k].ubnd) { indv[k]++; k++; continue; } indv[k] = ARRAY_DIMS(ra0)[k].lbnd - 1; k--; } while (k >= 0); return 1; } } } SCM array_fill(ra, fill) SCM ra, fill; { ramapc(rafill, fill, ra, EOL, s_array_fill); return UNSPECIFIED; } static char s_sarray_copy[] = "serial-array:copy!"; static char s_array_copy[] = "array:copy!"; static int racp(src, dst) SCM dst, src; { long n = (ARRAY_DIMS(src)->ubnd - ARRAY_DIMS(src)->lbnd + 1); long inc_d, inc_s = ARRAY_DIMS(src)->inc; sizet i_d, i_s = ARRAY_BASE(src); dst = CAR(dst); inc_d = ARRAY_DIMS(dst)->inc; i_d = ARRAY_BASE(dst); src = ARRAY_V(src); dst = ARRAY_V(dst); switch TYP7(dst) { default: gencase: case tc7_vector: for (; n-- > 0; i_s += inc_s, i_d += inc_d) aset(dst, cvref(src, i_s, UNDEFINED), MAKINUM(i_d)); break; case tc7_string: if (tc7_string != TYP7(src)) goto gencase; for (; n-- > 0; i_s += inc_s, i_d += inc_d) CHARS(dst)[i_d] = CHARS(src)[i_s]; break; case tc7_Vbool: if (tc7_Vbool != TYP7(src)) goto gencase; if (1==inc_d && 1==inc_s && i_s%LONG_BIT==i_d%LONG_BIT && n>=LONG_BIT) { long *sv = (long *)VELTS(src); long *dv = (long *)VELTS(dst); sv += i_s/LONG_BIT; dv += i_d/LONG_BIT; if (i_s % LONG_BIT) { /* leading partial word */ *dv = (*dv & ~(~0L<<(i_s%LONG_BIT))) | (*sv & (~0L<<(i_s%LONG_BIT))); dv++; sv++; n -= LONG_BIT - (i_s % LONG_BIT); } IVDEP(src != dst, for (; n >= LONG_BIT; n -= LONG_BIT, sv++, dv++) *dv = *sv;) if (n) /* trailing partial word */ *dv = (*dv & (~0L< 0; i_s += inc_s, i_d += inc_d) if (VELTS(src)[i_s/LONG_BIT] & (1L << (i_s%LONG_BIT))) VELTS(dst)[i_d/LONG_BIT] |= (1L << (i_d%LONG_BIT)); else VELTS(dst)[i_d/LONG_BIT] &= ~(1L << (i_d%LONG_BIT)); } break; case tc7_VfixN32: case tc7_VfixZ32: { long *d = (long *)VELTS(dst), *s = (long *)VELTS(src); if (TYP7(src)==TYP7(dst)) { IVDEP(src != dst, for (; n-- > 0; i_s += inc_s, i_d += inc_d) d[i_d] = s[i_s];) } else if (tc7_VfixZ32==TYP7(dst)) for (; n-- > 0; i_s += inc_s, i_d += inc_d) d[i_d] = num2long(cvref(src, i_s, UNDEFINED), (char *)ARG2, s_array_copy); else for (; n-- > 0; i_s += inc_s, i_d += inc_d) d[i_d] = num2ulong(cvref(src, i_s, UNDEFINED), (char *)ARG2, s_array_copy); break; } # ifdef FLOATS case tc7_VfloR32: { float *d = (float *)VELTS(dst); float *s = (float *)VELTS(src); switch TYP7(src) { default: goto gencase; case tc7_VfixZ32: case tc7_VfixN32: IVDEP(src != dst, for (; n-- > 0; i_s += inc_s, i_d += inc_d) d[i_d] = ((long *)s)[i_s]; ) break; case tc7_VfloR32: IVDEP(src != dst, for (; n-- > 0; i_s += inc_s, i_d += inc_d) d[i_d] = s[i_s]; ) break; case tc7_VfloR64: IVDEP(src != dst, for (; n-- > 0; i_s += inc_s, i_d += inc_d) d[i_d] = ((double *)s)[i_s]; ) break; } break; } case tc7_VfloR64: { double *d = (double *)VELTS(dst); double *s = (double *)VELTS(src); switch TYP7(src) { default: goto gencase; case tc7_VfixZ32: case tc7_VfixN32: IVDEP(src != dst, for (; n-- > 0; i_s += inc_s, i_d += inc_d) d[i_d] = ((long *)s)[i_s]; ) break; case tc7_VfloR32: IVDEP(src != dst, for (; n-- > 0; i_s += inc_s, i_d += inc_d) d[i_d] = ((float *)s)[i_s];) break; case tc7_VfloR64: IVDEP(src != dst, for (; n-- > 0; i_s += inc_s, i_d += inc_d) d[i_d] = s[i_s];) break; } break; } case tc7_VfloC32: { float (*d)[2] = (float (*)[2])VELTS(dst); float (*s)[2] = (float (*)[2])VELTS(src); switch TYP7(src) { default: goto gencase; case tc7_VfixZ32: case tc7_VfixN32: IVDEP(src != dst, for (; n-- > 0; i_s += inc_s, i_d += inc_d) { d[i_d][0] = ((long *)s)[i_s]; d[i_d][1] = 0.0; }) break; case tc7_VfloR32: IVDEP(src != dst, for (; n-- > 0; i_s += inc_s, i_d += inc_d) { d[i_d][0] = ((float *)s)[i_s]; d[i_d][1] = 0.0; }) break; case tc7_VfloR64: IVDEP(src != dst, for (; n-- > 0; i_s += inc_s, i_d += inc_d) { d[i_d][0] = ((double *)s)[i_s]; d[i_d][1] = 0.0; }) break; case tc7_VfloC32: IVDEP(src != dst, for (; n-- > 0; i_s += inc_s, i_d += inc_d) { d[i_d][0] = s[i_s][0]; d[i_d][1] = s[i_s][1]; }) break; case tc7_VfloC64: IVDEP(src != dst, for (; n-- > 0; i_s += inc_s, i_d += inc_d) { d[i_d][0] = ((double (*)[2])s)[i_s][0]; d[i_d][1] = ((double (*)[2])s)[i_s][1]; }) break; } } case tc7_VfloC64: { double (*d)[2] = (double (*)[2])VELTS(dst); double (*s)[2] = (double (*)[2])VELTS(src); switch TYP7(src) { default: goto gencase; case tc7_VfixZ32: case tc7_VfixN32: IVDEP(src != dst, for (; n-- > 0; i_s += inc_s, i_d += inc_d) { d[i_d][0] = ((long *)s)[i_s]; d[i_d][1] = 0.0; }) break; case tc7_VfloR32: IVDEP(src != dst, for (; n-- > 0; i_s += inc_s, i_d += inc_d) { d[i_d][0] = ((float *)s)[i_s]; d[i_d][1] = 0.0; }) break; case tc7_VfloR64: IVDEP(src != dst, for (; n-- > 0; i_s += inc_s, i_d += inc_d) { d[i_d][0] = ((double *)s)[i_s]; d[i_d][1] = 0.0; }) break; case tc7_VfloC32: IVDEP(src != dst, for (; n-- > 0; i_s += inc_s, i_d += inc_d) { d[i_d][0] = ((float (*)[2])s)[i_s][0]; d[i_d][1] = ((float (*)[2])s)[i_s][1]; }) break; case tc7_VfloC64: IVDEP(src != dst, for (; n-- > 0; i_s += inc_s, i_d += inc_d) { d[i_d][0] = s[i_s][0]; d[i_d][1] = s[i_s][1]; }) break; } } # endif /* FLOATS */ } return 1; } SCM array_copy(dst, src) SCM dst; SCM src; { #ifndef RECKLESS if (INUM0==array_rank(dst)) ASRTER(NIMP(dst) && ARRAYP(dst) && INUM0==array_rank(src), dst, ARG2, s_array_copy); #endif ramapc(racp, UNDEFINED, src, cons(dst, EOL), s_array_copy); return UNSPECIFIED; } SCM ra2contig(ra, copy) SCM ra; int copy; { SCM ret; long inc = 1; sizet k, len = 1; for (k = ARRAY_NDIM(ra); k--;) len *= ARRAY_DIMS(ra)[k].ubnd - ARRAY_DIMS(ra)[k].lbnd + 1; k = ARRAY_NDIM(ra); if (ARRAY_CONTP(ra) && ((0==k) || (1==ARRAY_DIMS(ra)[k-1].inc))) { if (tc7_Vbool != TYP7(ARRAY_V(ra))) return ra; if ((len==LENGTH(ARRAY_V(ra)) && 0==ARRAY_BASE(ra) % LONG_BIT && 0==len % LONG_BIT)) return ra; } ret = make_ra(k); ARRAY_BASE(ret) = 0; while (k--) { ARRAY_DIMS(ret)[k].lbnd = ARRAY_DIMS(ra)[k].lbnd; ARRAY_DIMS(ret)[k].ubnd = ARRAY_DIMS(ra)[k].ubnd; ARRAY_DIMS(ret)[k].inc = inc; inc *= ARRAY_DIMS(ra)[k].ubnd - ARRAY_DIMS(ra)[k].lbnd + 1; } CAR(ret) |= ARRAY_CONTIGUOUS; ARRAY_V(ret) = make_uve(inc+0L, array_prot(ra)); if (copy) array_copy(ret, ra); return ret; } static char s_ura_rd[] = "uniform-array-read!"; SCM ura_read(ra, port) SCM ra, port; { SCM ret, cra; if (NIMP(ra) && ARRAYP(ra)) { cra = ra2contig(ra, 0); ret = uve_read(cra, port); if (cra != ra) array_copy(ra, cra); return ret; } else return uve_read(ra, port); } static char s_ura_wr[] = "uniform-array-write"; SCM ura_write(ra, port) SCM ra, port; { if (NIMP(ra) && ARRAYP(ra)) return uve_write(ra2contig(ra, 1), port); else return uve_write(ra, port); } static char s_sc2array[] = "scalar->array"; SCM sc2array(s, ra, prot) SCM s, ra, prot; { SCM res; ASRTER(NIMP(ra), ra, ARG2, s_sc2array); if (ARRAYP(ra)) { int k = ARRAY_NDIM(ra); res = make_ra(k); while (k--) { ARRAY_DIMS(res)[k].ubnd = ARRAY_DIMS(ra)[k].ubnd; ARRAY_DIMS(res)[k].lbnd = ARRAY_DIMS(ra)[k].lbnd; ARRAY_DIMS(res)[k].inc = 0; } ra = ARRAY_V(ra); } else { ASRTER(BOOL_T==arrayp(ra, UNDEFINED), ra, ARG2, s_sc2array); res = make_ra(1); ARRAY_DIMS(res)->ubnd = LENGTH(ra) - 1; ARRAY_DIMS(res)->lbnd = 0; ARRAY_DIMS(res)->inc = 0; } if (NIMP(s) && ARRAYP(s) && 0==ARRAY_NDIM(s)) { ARRAY_BASE(res) = ARRAY_BASE(s); ARRAY_V(res) = ARRAY_V(s); return res; } ARRAY_BASE(res) = 0; ARRAY_V(res) = make_uve(1L, NULLP(prot) ? array_prot(ra) : CAR(prot)); switch TYP7(ARRAY_V(res)) { case tc7_vector: break; case tc7_Vbool: if (BOOL_T==s || BOOL_F==s) break; goto mismatch; case tc7_string: if (ICHRP(s)) break; goto mismatch; case tc7_VfixN32: if (INUMP(s) && INUM(s)>=0) break; #ifdef BIGDIG if (NIMP(s) && tc16_bigpos==TYP16(s) && NUMDIGS(s)<=DIGSPERLONG) break; #endif goto mismatch; case tc7_VfixZ32: if (INUMP(s)) break; #ifdef BIGDIG if (NIMP(s) && BIGP(s) && NUMDIGS(s)<=DIGSPERLONG) break; #endif goto mismatch; #ifdef FLOATS case tc7_VfloR32: case tc7_VfloR64: if (NUMBERP(s) && !(NIMP(s) && CPLXP(s))) break; goto mismatch; case tc7_VfloC32: case tc7_VfloC64: if (NUMBERP(s)) break; goto mismatch; #endif mismatch: ARRAY_V(res) = make_vector(MAKINUM(1), s); return res; } aset(ARRAY_V(res), s, INUM0); return res; } /* Functions callable by ARRAY-MAP! */ int ra_eqp(ra0, ras) SCM ra0, ras; { SCM ra1 = CAR(ras), ra2 = CAR(CDR(ras)); long n = ARRAY_DIMS(ra0)->ubnd - ARRAY_DIMS(ra0)->lbnd + 1; sizet i0 = ARRAY_BASE(ra0), i1 = ARRAY_BASE(ra1), i2 = ARRAY_BASE(ra2); long inc0 = ARRAY_DIMS(ra0)->inc; long inc1 = ARRAY_DIMS(ra1)->inc; long inc2 = ARRAY_DIMS(ra2)->inc; ra0 = ARRAY_V(ra0); ra1 = ARRAY_V(ra1); ra2 = ARRAY_V(ra2); switch (TYP7(ra1)==TYP7(ra2) ? TYP7(ra1) : 0) { default: { SCM e1 = UNDEFINED, e2 = UNDEFINED; for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) if (BVE_REF(ra0, i0)) if (FALSEP(eqp(RVREF(ra1, i1, e1), RVREF(ra2, i2, e2)))) BVE_CLR(ra0, i0); break; } case tc7_VfixN32: case tc7_VfixZ32: for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) if (BVE_REF(ra0, i0)) if (VELTS(ra1)[i1] != VELTS(ra2)[i2]) BVE_CLR(ra0, i0); break; # ifdef FLOATS case tc7_VfloR32: for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) if (BVE_REF(ra0, i0)) if (((float *)VELTS(ra1))[i1] != ((float *)VELTS(ra2))[i2]) BVE_CLR(ra0, i0); break; case tc7_VfloR64: for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) if (BVE_REF(ra0, i0)) if (((double *)VELTS(ra1))[i1] != ((double *)VELTS(ra2))[i2]) BVE_CLR(ra0, i0); break; case tc7_VfloC32: for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) if (BVE_REF(ra0, i0)) if (((float *)VELTS(ra1))[2*i1] != ((float *)VELTS(ra2))[2*i2] || ((float *)VELTS(ra1))[2*i1+1] != ((float *)VELTS(ra2))[2*i2+1]) BVE_CLR(ra0, i0); break; case tc7_VfloC64: for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) if (BVE_REF(ra0, i0)) if (((double *)VELTS(ra1))[2*i1] != ((double *)VELTS(ra2))[2*i2] || ((double *)VELTS(ra1))[2*i1+1] != ((double *)VELTS(ra2))[2*i2+1]) BVE_CLR(ra0, i0); break; # endif /*FLOATS*/ } return 1; } /* opt 0 means <, nonzero means >= */ static int ra_compare(ra0, ra1, ra2, opt) SCM ra0, ra1, ra2; int opt; { long n = ARRAY_DIMS(ra0)->ubnd - ARRAY_DIMS(ra0)->lbnd + 1; sizet i0 = ARRAY_BASE(ra0), i1 = ARRAY_BASE(ra1), i2 = ARRAY_BASE(ra2); long inc0 = ARRAY_DIMS(ra0)->inc; long inc1 = ARRAY_DIMS(ra1)->inc; long inc2 = ARRAY_DIMS(ra2)->inc; ra0 = ARRAY_V(ra0); ra1 = ARRAY_V(ra1); ra2 = ARRAY_V(ra2); switch (TYP7(ra1)==TYP7(ra2) ? TYP7(ra1) : 0) { default: { SCM e1 = UNDEFINED, e2 = UNDEFINED; for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) if (BVE_REF(ra0, i0)) if (opt ? NFALSEP(lessp(RVREF(ra1, i1, e1), RVREF(ra2, i2, e2))) : FALSEP(lessp(RVREF(ra1, i1, e1), RVREF(ra2, i2, e2))) ) BVE_CLR(ra0, i0); break; } case tc7_VfixN32: for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) { if (BVE_REF(ra0, i0)) if (opt ? ((unsigned long*)VELTS(ra1))[i1] < ((unsigned long*)VELTS(ra2))[i2] : ((unsigned long*)VELTS(ra1))[i1] >= ((unsigned long*)VELTS(ra2))[i2]) BVE_CLR(ra0, i0); } break; case tc7_VfixZ32: for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) { if (BVE_REF(ra0, i0)) if (opt ? VELTS(ra1)[i1] < VELTS(ra2)[i2] : VELTS(ra1)[i1] >= VELTS(ra2)[i2]) BVE_CLR(ra0, i0); } break; # ifdef FLOATS case tc7_VfloR32: for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) if (BVE_REF(ra0, i0)) if (opt ? ((float *)VELTS(ra1))[i1] < ((float *)VELTS(ra2))[i2] : ((float *)VELTS(ra1))[i1] >= ((float *)VELTS(ra2))[i2]) BVE_CLR(ra0, i0); break; case tc7_VfloR64: for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) if (BVE_REF(ra0, i0)) if (opt ? ((double *)VELTS(ra1))[i1] < ((double *)VELTS(ra2))[i2] : ((double *)VELTS(ra1))[i1] >= ((double *)VELTS(ra2))[i2]) BVE_CLR(ra0, i0); break; # endif /*FLOATS*/ } return 1; } int ra_lessp(ra0, ras) SCM ra0, ras; { return ra_compare(ra0, CAR(ras), CAR(CDR(ras)), 0); } int ra_leqp(ra0, ras) SCM ra0, ras; { return ra_compare(ra0, CAR(CDR(ras)), CAR(ras), 1); } int ra_grp(ra0, ras) SCM ra0, ras; { return ra_compare(ra0, CAR(CDR(ras)), CAR(ras), 0); } int ra_greqp(ra0, ras) SCM ra0, ras; { return ra_compare(ra0, CAR(ras), CAR(CDR(ras)), 1); } int ra_sum(ra0, ras) SCM ra0, ras; { long n = ARRAY_DIMS(ra0)->ubnd - ARRAY_DIMS(ra0)->lbnd + 1; sizet i0 = ARRAY_BASE(ra0); long inc0 = ARRAY_DIMS(ra0)->inc; ra0 = ARRAY_V(ra0); if (NNULLP(ras)) { SCM ra1 = CAR(ras); sizet i1 = ARRAY_BASE(ra1); long inc1 = ARRAY_DIMS(ra1)->inc; ra1 = ARRAY_V(ra1); switch (TYP7(ra0)==TYP7(ra1) ? TYP7(ra0) : 0) { ovflow: wta(ra0, (char *)OVFLOW, "+"); default: { SCM e0 = UNDEFINED, e1 = UNDEFINED; for (; n-- > 0; i0 += inc0, i1 += inc1) aset(ra0, sum(RVREF(ra0, i0, e0), RVREF(ra1, i1, e1)), MAKINUM(i0)); break; } case tc7_VfixN32: { unsigned long r; unsigned long *v0 = (unsigned long *)VELTS(ra0); unsigned long *v1 = (unsigned long *)VELTS(ra1); IVDEP(ra0 != ra1, for (; n-- > 0; i0 += inc0, i1 += inc1) { r = v0[i0] + v1[i1]; ASRTGO(r >= v0[i0], ovflow); /* Will prevent vectorization */ v0[i0] = r; } ); break; } case tc7_VfixZ32: { long r, *v0 = (long *)VELTS(ra0), *v1 = (long *)VELTS(ra1); IVDEP(ra0 != ra1, for (; n-- > 0; i0 += inc0, i1 += inc1) { r = v0[i0] + v1[i1]; ASRTGO((v0[i0]>0 ? r>=0 || v1[i1]<0 : r<=0 || v1[i1]>0), ovflow); v0[i0] = r; } ); break; } # ifdef FLOATS case tc7_VfloR32: { float *v0 = (float *)VELTS(ra0); float *v1 = (float *)VELTS(ra1); IVDEP(ra0 != ra1, for (; n-- > 0; i0 += inc0, i1 += inc1) v0[i0] += v1[i1]); break; } case tc7_VfloR64: { double *v0 = (double *)VELTS(ra0); double *v1 = (double *)VELTS(ra1); IVDEP(ra0 != ra1, for (; n-- > 0; i0 += inc0, i1 += inc1) v0[i0] += v1[i1]); break; } case tc7_VfloC32: { float (*v0)[2] = (float (*)[2])VELTS(ra0); float (*v1)[2] = (float (*)[2])VELTS(ra1); IVDEP(ra0 != ra1, for (; n-- > 0; i0 += inc0, i1 += inc1) { v0[i0][0] += v1[i1][0]; v0[i0][1] += v1[i1][1]; }); break; } case tc7_VfloC64: { double (*v0)[2] = (double (*)[2])VELTS(ra0); double (*v1)[2] = (double (*)[2])VELTS(ra1); IVDEP(ra0 != ra1, for (; n-- > 0; i0 += inc0, i1 += inc1) { v0[i0][0] += v1[i1][0]; v0[i0][1] += v1[i1][1]; }); break; } # endif /* FLOATS */ } } return 1; } int ra_difference(ra0, ras) SCM ra0, ras; { long n = ARRAY_DIMS(ra0)->ubnd - ARRAY_DIMS(ra0)->lbnd + 1; sizet i0 = ARRAY_BASE(ra0); long inc0 = ARRAY_DIMS(ra0)->inc; ra0 = ARRAY_V(ra0); if (NULLP(ras)) { switch TYP7(ra0) { default: { SCM e0 = UNDEFINED; for (; n-- > 0; i0 += inc0) aset(ra0, difference(RVREF(ra0, i0, e0), UNDEFINED), MAKINUM(i0)); break; } case tc7_VfixZ32: { long *v0 = VELTS(ra0); for (; n-- > 0; i0 += inc0) v0[i0] = -v0[i0]; break; } # ifdef FLOATS case tc7_VfloR32: { float *v0 = (float *)VELTS(ra0); for (; n-- > 0; i0 += inc0) v0[i0] = -v0[i0]; break; } case tc7_VfloR64: { double *v0 = (double *)VELTS(ra0); for (; n-- > 0; i0 += inc0) v0[i0] = -v0[i0]; break; } case tc7_VfloC32: { float (*v0)[2] = (float (*)[2])VELTS(ra0); for (; n-- > 0; i0 += inc0) { v0[i0][0] = -v0[i0][0]; v0[i0][1] = -v0[i0][1]; } break; } case tc7_VfloC64: { double (*v0)[2] = (double (*)[2])VELTS(ra0); for (; n-- > 0; i0 += inc0) { v0[i0][0] = -v0[i0][0]; v0[i0][1] = -v0[i0][1]; } break; } # endif /* FLOATS */ } } else { SCM ra1 = CAR(ras); sizet i1 = ARRAY_BASE(ra1); long inc1 = ARRAY_DIMS(ra1)->inc; ra1 = ARRAY_V(ra1); switch (TYP7(ra0)==TYP7(ra1) ? TYP7(ra0) : 0) { ovflow: wta(ra0, (char *)OVFLOW, "-"); default: { SCM e0 = UNDEFINED, e1 = UNDEFINED; for (; n-- > 0; i0 += inc0, i1 += inc1) aset(ra0, difference(RVREF(ra0, i0, e0), RVREF(ra1, i1, e1)), MAKINUM(i0)); break; } case tc7_VfixN32: { unsigned long r; unsigned long *v0 = (unsigned long *)VELTS(ra0); unsigned long *v1 = (unsigned long*)VELTS(ra1); IVDEP(ra0 != ra1, for (; n-- > 0; i0 += inc0, i1 += inc1) { r = v0[i0] - v1[i1]; ASRTGO(r <= v0[i0], ovflow); v0[i0] = r; } ); break; } case tc7_VfixZ32: { long r, *v0 = VELTS(ra0), *v1 = VELTS(ra1); IVDEP(ra0 != ra1, for (; n-- > 0; i0 += inc0, i1 += inc1) { r = v0[i0] - v1[i1]; ASRTGO((v0[i0]>0 ? r>=0 || v1[i1]>0 : r<=0 || v1[i1]<0), ovflow); v0[i0] = r; } ); break; } # ifdef FLOATS case tc7_VfloR32: { float *v0 = (float *)VELTS(ra0); float *v1 = (float *)VELTS(ra1); IVDEP(ra0 != ra1, for (; n-- > 0; i0 += inc0, i1 += inc1) v0[i0] -= v1[i1]); break; } case tc7_VfloR64: { double *v0 = (double *)VELTS(ra0); double *v1 = (double *)VELTS(ra1); IVDEP(ra0 != ra1, for (; n-- > 0; i0 += inc0, i1 += inc1) v0[i0] -= v1[i1]); break; } case tc7_VfloC32: { float (*v0)[2] = (float (*)[2])VELTS(ra0); float (*v1)[2] = (float (*)[2])VELTS(ra1); IVDEP(ra0 != ra1, for (; n-- > 0; i0 += inc0, i1 += inc1) { v0[i0][0] -= v1[i1][0]; v0[i0][1] -= v1[i1][1]; }) break; } case tc7_VfloC64: { double (*v0)[2] = (double (*)[2])VELTS(ra0); double (*v1)[2] = (double (*)[2])VELTS(ra1); IVDEP(ra0 != ra1, for (; n-- > 0; i0 += inc0, i1 += inc1) { v0[i0][0] -= v1[i1][0]; v0[i0][1] -= v1[i1][1]; }) break; } # endif /* FLOATS */ } } return 1; } int ra_product(ra0, ras) SCM ra0, ras; { long n = ARRAY_DIMS(ra0)->ubnd - ARRAY_DIMS(ra0)->lbnd + 1; sizet i0 = ARRAY_BASE(ra0); long inc0 = ARRAY_DIMS(ra0)->inc; ra0 = ARRAY_V(ra0); if (NNULLP(ras)) { SCM ra1 = CAR(ras); sizet i1 = ARRAY_BASE(ra1); long inc1 = ARRAY_DIMS(ra1)->inc; ra1 = ARRAY_V(ra1); switch (TYP7(ra0)==TYP7(ra1) ? TYP7(ra0) : 0) { ovflow: wta(ra0, (char *)OVFLOW, "*"); default: { SCM e0 = UNDEFINED, e1 = UNDEFINED; for (; n-- > 0; i0 += inc0, i1 += inc1) aset(ra0, product(RVREF(ra0, i0, e0), RVREF(ra1, i1, e1)), MAKINUM(i0)); break; } case tc7_VfixN32: { unsigned long r; unsigned long *v0 = (unsigned long *)VELTS(ra0); unsigned long *v1 = (unsigned long *)VELTS(ra1); IVDEP(ra0 != ra1, for (; n-- > 0; i0 += inc0, i1 += inc1) { r = v0[i0] * v1[i1]; ASRTGO(0==v0[i0] || v1[i1]==r/v0[i0], ovflow); v0[i0] = r; } ); break; } case tc7_VfixZ32: { long r, *v0 = VELTS(ra0), *v1 =VELTS(ra1); IVDEP(ra0 != ra1, for (; n-- > 0; i0 += inc0, i1 += inc1) { r = v0[i0] * v1[i1]; ASRTGO(0==v0[i0] || v1[i1]==r/v0[i0], ovflow); v0[i0] = r; } ); break; } # ifdef FLOATS case tc7_VfloR32: { float *v0 = (float *)VELTS(ra0); float *v1 = (float *)VELTS(ra1); IVDEP(ra0 != ra1, for (; n-- > 0; i0 += inc0, i1 += inc1) v0[i0] *= v1[i1]); break; } case tc7_VfloR64: { double *v0 = (double *)VELTS(ra0); double *v1 = (double *)VELTS(ra1); IVDEP(ra0 != ra1, for (; n-- > 0; i0 += inc0, i1 += inc1) v0[i0] *= v1[i1]); break; } case tc7_VfloC32: { float (*v0)[2] = (float (*)[2])VELTS(ra0); register double r; float (*v1)[2] = (float (*)[2])VELTS(ra1); IVDEP(ra0 != ra1, for (; n-- > 0; i0 += inc0, i1 += inc1) { r = v0[i0][0]*v1[i1][0] - v0[i0][1]*v1[i1][1]; v0[i0][1] = v0[i0][0]*v1[i1][1] + v0[i0][1]*v1[i1][0]; v0[i0][0] = r; }); break; } case tc7_VfloC64: { double (*v0)[2] = (double (*)[2])VELTS(ra0); register double r; double (*v1)[2] = (double (*)[2])VELTS(ra1); IVDEP(ra0 != ra1, for (; n-- > 0; i0 += inc0, i1 += inc1) { r = v0[i0][0]*v1[i1][0] - v0[i0][1]*v1[i1][1]; v0[i0][1] = v0[i0][0]*v1[i1][1] + v0[i0][1]*v1[i1][0]; v0[i0][0] = r; }); break; } # endif /* FLOATS */ } } return 1; } int ra_divide(ra0, ras) SCM ra0, ras; { long n = ARRAY_DIMS(ra0)->ubnd - ARRAY_DIMS(ra0)->lbnd + 1; sizet i0 = ARRAY_BASE(ra0); long inc0 = ARRAY_DIMS(ra0)->inc; ra0 = ARRAY_V(ra0); if (NULLP(ras)) { switch TYP7(ra0) { default: { SCM e0 = UNDEFINED; for (; n-- > 0; i0 += inc0) aset(ra0, divide(RVREF(ra0, i0, e0), UNDEFINED), MAKINUM(i0)); break; } # ifdef FLOATS case tc7_VfloR32: { float *v0 = (float *)VELTS(ra0); for (; n-- > 0; i0 += inc0) v0[i0] = 1.0/v0[i0]; break; } case tc7_VfloR64: { double *v0 = (double *)VELTS(ra0); for (; n-- > 0; i0 += inc0) v0[i0] = 1.0/v0[i0]; break; } case tc7_VfloC32: { register double d; float (*v0)[2] = (float (*)[2])VELTS(ra0); for (; n-- > 0; i0 += inc0) { d = v0[i0][0]*v0[i0][0] + v0[i0][1]*v0[i0][1]; v0[i0][0] /= d; v0[i0][1] /= -d; } break; } case tc7_VfloC64: { register double d; double (*v0)[2] = (double (*)[2])VELTS(ra0); for (; n-- > 0; i0 += inc0) { d = v0[i0][0]*v0[i0][0] + v0[i0][1]*v0[i0][1]; v0[i0][0] /= d; v0[i0][1] /= -d; } break; } # endif /* FLOATS */ } } else { SCM ra1 = CAR(ras); sizet i1 = ARRAY_BASE(ra1); long inc1 = ARRAY_DIMS(ra1)->inc; ra1 = ARRAY_V(ra1); switch (TYP7(ra0)==TYP7(ra1) ? TYP7(ra0) : 0) { default: { SCM e0 = UNDEFINED, e1 = UNDEFINED; for (; n-- > 0; i0 += inc0, i1 += inc1) aset(ra0, divide(RVREF(ra0, i0, e0), RVREF(ra1, i1, e1)), MAKINUM(i0)); break; } # ifdef FLOATS case tc7_VfloR32: { float *v0 = (float *)VELTS(ra0); float *v1 = (float *)VELTS(ra1); IVDEP(ra0 != ra1, for (; n-- > 0; i0 += inc0, i1 += inc1) v0[i0] /= v1[i1]); break; } case tc7_VfloR64: { double *v0 = (double *)VELTS(ra0); double *v1 = (double *)VELTS(ra1); IVDEP(ra0 != ra1, for (; n-- > 0; i0 += inc0, i1 += inc1) v0[i0] /= v1[i1]); break; } case tc7_VfloC32: { register double d, r; float (*v0)[2] = (float (*)[2])VELTS(ra0); float (*v1)[2] = (float (*)[2])VELTS(ra1); IVDEP(ra0 != ra1, for (; n-- > 0; i0 += inc0, i1 += inc1) { d = v1[i1][0]*v1[i1][0] + v1[i1][1]*v1[i1][1]; r = (v0[i0][0]*v1[i1][0] + v0[i0][1]*v1[i1][1])/d; v0[i0][1] = (v0[i0][1]*v1[i1][0] - v0[i0][0]*v1[i1][1])/d; v0[i0][0] = r; }) break; } case tc7_VfloC64: { register double d, r; double (*v0)[2] = (double (*)[2])VELTS(ra0); double (*v1)[2] = (double (*)[2])VELTS(ra1); IVDEP(ra0 != ra1, for (; n-- > 0; i0 += inc0, i1 += inc1) { d = v1[i1][0]*v1[i1][0] + v1[i1][1]*v1[i1][1]; r = (v0[i0][0]*v1[i1][0] + v0[i0][1]*v1[i1][1])/d; v0[i0][1] = (v0[i0][1]*v1[i1][0] - v0[i0][0]*v1[i1][1])/d; v0[i0][0] = r; }) break; } # endif /* FLOATS */ } } return 1; } static int ra_identity(dst, src) SCM src, dst; { return racp(CAR(src), cons(dst, EOL)); } static int ramap(ra0, proc, ras) SCM ra0, proc, ras; { SCM heap_ve, auto_rav[5], auto_argv[5]; SCM *rav = &auto_rav[0], *argv = &auto_argv[0]; long argc = ilength(ras); long i, k, inc, n, base; scm_protect_temp(&heap_ve); if (argc >= 5) { heap_ve = make_vector(MAKINUM(2*argc), BOOL_F); rav = VELTS(heap_ve); argv = &(rav[argc]); } for (k = 0; k < argc; k++) { rav[k] = CAR(ras); ras = CDR(ras); } i = ARRAY_DIMS(ra0)->lbnd; inc = ARRAY_DIMS(ra0)->inc; n = ARRAY_DIMS(ra0)->ubnd; base = ARRAY_BASE(ra0) - i*inc; ra0 = ARRAY_V(ra0); for (; i <= n; i++) { for (k = 0; k < argc; k++) argv[k] = aref(rav[k], MAKINUM(i)); aset(ra0, scm_cvapply(proc, argc, argv), MAKINUM(i*inc + base)); } return 1; } static int ramap_cxr(ra0, proc, ras) SCM ra0, proc, ras; { SCM ra1 = CAR(ras); SCM e1 = UNDEFINED; sizet i0 = ARRAY_BASE(ra0), i1 = ARRAY_BASE(ra1); long inc0 = ARRAY_DIMS(ra0)->inc, inc1 = ARRAY_DIMS(ra1)->inc; long n = ARRAY_DIMS(ra0)->ubnd - ARRAY_DIMS(ra1)->lbnd + 1; ra0 = ARRAY_V(ra0); ra1 = ARRAY_V(ra1); switch TYP7(ra0) { default: gencase: for (; n-- > 0; i0 += inc0, i1 += inc1) { e1 = cvref(ra1, i1, e1); aset(ra0, scm_cvapply(proc, 1L, &e1), MAKINUM(i0)); } break; # ifdef FLOATS case tc7_VfloR32: { float *dst = (float *)VELTS(ra0); switch TYP7(ra1) { default: goto gencase; case tc7_VfloR32: for (; n-- > 0; i0 += inc0, i1 += inc1) dst[i0] = DSUBRF(proc)((double)((float *)VELTS(ra1))[i1]); break; case tc7_VfixN32: case tc7_VfixZ32: for (; n-- > 0; i0 += inc0, i1 += inc1) dst[i0] = DSUBRF(proc)((double)VELTS(ra1)[i1]); break; } break; } case tc7_VfloR64: { double *dst = (double *)VELTS(ra0); switch TYP7(ra1) { default: goto gencase; case tc7_VfloR64: for (; n-- > 0; i0 += inc0, i1 += inc1) dst[i0] = DSUBRF(proc)(((double *)VELTS(ra1))[i1]); break; case tc7_VfixN32: case tc7_VfixZ32: for (; n-- > 0; i0 += inc0, i1 += inc1) dst[i0] = DSUBRF(proc)((double)VELTS(ra1)[i1]); break; } break; } # endif /* FLOATS */ } return 1; } static int ramap_rp(ra0, proc, ras) SCM ra0, proc, ras; { SCM ra1 = CAR(ras), ra2 = CAR(CDR(ras)); SCM e1 = UNDEFINED, e2 = UNDEFINED; long n = ARRAY_DIMS(ra0)->ubnd - ARRAY_DIMS(ra0)->lbnd + 1; sizet i0 = ARRAY_BASE(ra0), i1 = ARRAY_BASE(ra1), i2 = ARRAY_BASE(ra2); long inc0 = ARRAY_DIMS(ra0)->inc; long inc1 = ARRAY_DIMS(ra1)->inc; long inc2 = ARRAY_DIMS(ra2)->inc; ra0 = ARRAY_V(ra0); ra1 = ARRAY_V(ra1); ra2 = ARRAY_V(ra2); for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) if (BVE_REF(ra0, i0)) if (FALSEP(SUBRF(proc)(RVREF(ra1, i1, e1), RVREF(ra2, i2, e2)))) BVE_CLR(ra0, i0); return 1; } static int ramap_1(ra0, proc, ras) SCM ra0, proc, ras; { SCM ra1 = CAR(ras); SCM e1 = UNDEFINED; long n = ARRAY_DIMS(ra0)->ubnd - ARRAY_DIMS(ra0)->lbnd + 1; sizet i0 = ARRAY_BASE(ra0), i1 = ARRAY_BASE(ra1); long inc0 = ARRAY_DIMS(ra0)->inc, inc1 = ARRAY_DIMS(ra1)->inc; ra0 = ARRAY_V(ra0); ra1 = ARRAY_V(ra1); if (tc7_vector==TYP7(ra0)) for (; n-- > 0; i0 += inc0, i1 += inc1) VELTS(ra0)[i0] = SUBRF(proc)(cvref(ra1, i1, UNDEFINED)); else for (; n-- > 0; i0 += inc0, i1 += inc1) aset(ra0, SUBRF(proc)(RVREF(ra1, i1, e1)), MAKINUM(i0)); return 1; } static int ramap_2o(ra0, proc, ras) SCM ra0, proc, ras; { SCM ra1 = CAR(ras); SCM e1 = UNDEFINED; long n = ARRAY_DIMS(ra0)->ubnd - ARRAY_DIMS(ra0)->lbnd + 1; sizet i0 = ARRAY_BASE(ra0), i1 = ARRAY_BASE(ra1); long inc0 = ARRAY_DIMS(ra0)->inc, inc1 = ARRAY_DIMS(ra1)->inc; ra0 = ARRAY_V(ra0); ra1 = ARRAY_V(ra1); ras = CDR(ras); if (NULLP(ras)) { if (tc7_vector==TYP7(ra0)) for (; n-- > 0; i0 += inc0, i1 += inc1) VELTS(ra0)[i0] = SUBRF(proc)(cvref(ra1, i1, UNDEFINED), UNDEFINED); else for (; n-- > 0; i0 += inc0, i1 += inc1) aset(ra0, SUBRF(proc)(RVREF(ra1, i1, e1), UNDEFINED), MAKINUM(i0)); } else { SCM ra2 = CAR(ras); SCM e2 = UNDEFINED; sizet i2 = ARRAY_BASE(ra2); long inc2 = ARRAY_DIMS(ra2)->inc; ra2 = ARRAY_V(ra2); if (tc7_vector==TYP7(ra0)) for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) VELTS(ra0)[i0] = SUBRF(proc)(cvref(ra1, i1, UNDEFINED), cvref(ra2, i2, UNDEFINED)); else for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) aset(ra0, SUBRF(proc)(RVREF(ra1, i1, e1), RVREF(ra2, i2, e2)), MAKINUM(i0)); } return 1; } static int ramap_a(ra0, proc, ras) SCM ra0, proc, ras; { SCM e0 = UNDEFINED, e1 = UNDEFINED; long n = ARRAY_DIMS(ra0)->ubnd - ARRAY_DIMS(ra0)->lbnd + 1; sizet i0 = ARRAY_BASE(ra0); long inc0 = ARRAY_DIMS(ra0)->inc; ra0 = ARRAY_V(ra0); if (NULLP(ras)) for (; n-- > 0; i0 += inc0) aset(ra0, SUBRF(proc)(RVREF(ra0, i0, e0), UNDEFINED), MAKINUM(i0)); else { SCM ra1 = CAR(ras); sizet i1 = ARRAY_BASE(ra1); long inc1 = ARRAY_DIMS(ra1)->inc; ra1 = ARRAY_V(ra1); for (; n-- > 0; i0 += inc0, i1 += inc1) aset(ra0, SUBRF(proc)(RVREF(ra0, i0, e0), RVREF(ra1, i1, e1)), MAKINUM(i0)); } return 1; } /* These tables are a kluge that will not scale well when more vectorized subrs are added. It is tempting to steal some bits from the CAR of all subrs (like those selected by SMOBNUM) to hold an offset into a table of vectorized subrs. */ static ra_iproc ra_rpsubrs[] = { {"=", UNDEFINED, ra_eqp}, {"<", UNDEFINED, ra_lessp}, {"<=", UNDEFINED, ra_leqp}, {">", UNDEFINED, ra_grp}, {">=", UNDEFINED, ra_greqp}, {0, 0, 0}}; static ra_iproc ra_asubrs[] = { {"+", UNDEFINED, ra_sum}, {"-", UNDEFINED, ra_difference}, {"*", UNDEFINED, ra_product}, {"/", UNDEFINED, ra_divide}, {0, 0, 0}}; static char s_sarray_map[] = "serial-array-map!"; # define s_array_map (s_sarray_map + 7) SCM array_map(ra0, proc, lra) SCM ra0, proc, lra; { long narg = ilength(lra); tail: #ifndef RECKLESS scm_arity_check(proc, narg, s_array_map); #endif switch TYP7(proc) { default: gencase: ramapc(ramap, proc, ra0, lra, s_array_map); return UNSPECIFIED; case tc7_subr_1: ramapc(ramap_1, proc, ra0, lra, s_array_map); return UNSPECIFIED; case tc7_subr_2: case tc7_subr_2o: ramapc(ramap_2o, proc, ra0, lra, s_array_map); return UNSPECIFIED; case tc7_cxr: if (! SUBRF(proc)) goto gencase; ramapc(ramap_cxr, proc, ra0, lra, s_array_map); return UNSPECIFIED; case tc7_rpsubr: { ra_iproc *p; if (FALSEP(arrayp(ra0, BOOL_T))) goto gencase; array_fill(ra0, BOOL_T); for (p = ra_rpsubrs; p->name; p++) if (proc==p->sproc) { while (NNULLP(lra) && NNULLP(CDR(lra))) { ramapc(p->vproc, UNDEFINED, ra0, lra, s_array_map); lra = CDR(lra); } return UNSPECIFIED; } while (NNULLP(lra) && NNULLP(CDR(lra))) { ramapc(ramap_rp, proc, ra0, lra, s_array_map); lra = CDR(lra); } return UNSPECIFIED; } case tc7_asubr: if (NULLP(lra)) { SCM prot, fill = SUBRF(proc)(UNDEFINED, UNDEFINED); if (INUMP(fill)) { prot = array_prot(ra0); # ifdef FLOATS if (NIMP(prot) && INEXP(prot)) fill = makdbl((double)INUM(fill), 0.0); # endif } array_fill(ra0, fill); } else { SCM tail, ra1 = CAR(lra); SCM v0 = (NIMP(ra0) && ARRAYP(ra0) ? ARRAY_V(ra0) : ra0); ra_iproc *p; /* Check to see if order might matter. This might be an argument for a separate SERIAL-ARRAY-MAP! */ if (v0==ra1 || (NIMP(ra1) && ARRAYP(ra1) && v0==ARRAY_V(ra1))) if (ra0 != ra1 || (ARRAYP(ra0) && !ARRAY_CONTP(ra0))) goto gencase; for (tail = CDR(lra); NNULLP(tail); tail = CDR(tail)) { ra1 = CAR(tail); if (v0==ra1 || (NIMP(ra1) && ARRAYP(ra1) && v0==ARRAY_V(ra1))) goto gencase; } for (p = ra_asubrs; p->name; p++) if (proc==p->sproc) { if (ra0 != CAR(lra)) ramapc(ra_identity, UNDEFINED, ra0, cons(CAR(lra), EOL), s_array_map); lra = CDR(lra); while (1) { ramapc(p->vproc, UNDEFINED, ra0, lra, s_array_map); if (IMP(lra) || IMP(CDR(lra))) return UNSPECIFIED; lra = CDR(lra); } } ramapc(ramap_2o, proc, ra0, lra, s_array_map); lra = CDR(lra); if (NIMP(lra)) for (lra = CDR(lra); NIMP(lra); lra = CDR(lra)) ramapc(ramap_a, proc, ra0, lra, s_array_map); } return UNSPECIFIED; #if 1 /* def CCLO */ case tc7_specfun: if (tc16_cclo==TYP16(proc)) { lra = cons(sc2array(proc, ra0, EOL), lra); proc = CCLO_SUBR(proc); narg++; goto tail; } goto gencase; #endif } } static int rafe(ra0, proc, ras) SCM ra0, proc, ras; { SCM heap_ve, auto_rav[5], auto_argv[5]; SCM *rav = &auto_rav[0], *argv = &auto_argv[0]; long argc = ilength(ras) + 1; long i, k, n; scm_protect_temp(&heap_ve); if (argc >= 5) { heap_ve = make_vector(MAKINUM(2*argc), BOOL_F); rav = VELTS(heap_ve); argv = &(rav[argc]); } rav[0] = ra0; for (k = 1; k < argc; k++) { rav[k] = CAR(ras); ras = CDR(ras); } i = ARRAY_DIMS(ra0)->lbnd; n = ARRAY_DIMS(ra0)->ubnd; for (; i <= n; i++) { for (k = 0; k < argc; k++) argv[k] = aref(rav[k], MAKINUM(i)); scm_cvapply(proc, argc, argv); } return 1; } static char s_array_for_each[] = "array-for-each"; SCM array_for_each(proc, ra0, lra) SCM proc, ra0, lra; { long narg = ilength(lra) + 1; tail: #ifndef RECKLESS scm_arity_check(proc, narg, s_array_for_each); #endif switch TYP7(proc) { default: gencase: ramapc(rafe, proc, ra0, lra, s_array_for_each); return UNSPECIFIED; #if 1 /* def CCLO */ case tc7_specfun: if (tc16_cclo==TYP16(proc)) { lra = cons(ra0, lra); ra0 = sc2array(proc, ra0, EOL); proc = CCLO_SUBR(proc); narg++; goto tail; } goto gencase; #endif } } static char s_array_index_for_each[] = "array-index-for-each"; SCM scm_array_index_for_each(ra, proc) SCM ra, proc; { SCM hp_av, hp_indv, auto_av[5]; SCM *av = &auto_av[0]; long auto_indv[5]; long *indv = &auto_indv[0]; sizet i; ASRTER(NIMP(ra), ra, ARG1, s_array_index_for_each); i = INUM(array_rank(ra)); #ifndef RECKLESS scm_arity_check(proc, i+0L, s_array_index_for_each); #endif if (i >= 5) { scm_protect_temp(&hp_av); scm_protect_temp(&hp_indv); hp_av = make_vector(MAKINUM(i), BOOL_F); av = VELTS(hp_av); hp_indv = make_uve(i+0L, MAKINUM(-32L)); indv = (long *)VELTS(hp_indv); } switch TYP7(ra) { default: badarg: wta(ra, (char *)ARG1, s_array_index_for_each); case tc7_vector: { for (i = 0; i < LENGTH(ra); i++) { av[0] = MAKINUM(i); scm_cvapply(proc, 1L, av); } return UNSPECIFIED; } case tcs_uves: for (i = 0; i < LENGTH(ra); i++) { av[0] = MAKINUM(i); scm_cvapply(proc, 1L, auto_av); } return UNSPECIFIED; case tc7_smob: ASRTGO(ARRAYP(ra), badarg); { int j, k, kmax = ARRAY_NDIM(ra) - 1; if (kmax < 0) return apply(proc, EOL, EOL); for (k = 0; k <= kmax; k++) indv[k] = ARRAY_DIMS(ra)[k].lbnd; k = kmax; do { if (k==kmax) { indv[k] = ARRAY_DIMS(ra)[k].lbnd; i = cind(ra, indv); for (; indv[k] <= ARRAY_DIMS(ra)[k].ubnd; indv[k]++) { for (j = kmax+1; j--;) av[j] = MAKINUM(indv[j]); scm_cvapply(proc, kmax+1L, av); i += ARRAY_DIMS(ra)[k].inc; } k--; continue; } if (indv[k] < ARRAY_DIMS(ra)[k].ubnd) { indv[k]++; k++; continue; } indv[k] = ARRAY_DIMS(ra)[k].lbnd - 1; k--; } while (k >= 0); return UNSPECIFIED; } } } static char s_array_imap[] = "array-index-map!"; SCM array_imap(ra, proc) SCM ra, proc; { SCM hp_av, hp_indv, auto_av[5]; SCM *av = &auto_av[0]; long auto_indv[5]; long *indv = &auto_indv[0]; sizet i; ASRTER(NIMP(ra), ra, ARG1, s_array_imap); i = INUM(array_rank(ra)); #ifndef RECKLESS scm_arity_check(proc, i+0L, s_array_imap); #endif if (i >= 5) { scm_protect_temp(&hp_av); scm_protect_temp(&hp_indv); hp_av = make_vector(MAKINUM(i), BOOL_F); av = VELTS(hp_av); hp_indv = make_uve(i+0L, MAKINUM(-32L)); indv = (long *)VELTS(hp_indv); } switch TYP7(ra) { default: badarg: wta(ra, (char *)ARG1, s_array_imap); case tc7_vector: { SCM *ve = VELTS(ra); for (i = 0; i < LENGTH(ra); i++) { av[0] = MAKINUM(i); ve[i] = scm_cvapply(proc, 1L, av); } return UNSPECIFIED; } case tcs_uves: for (i = 0; i < LENGTH(ra); i++) { av[0] = MAKINUM(i); aset(ra, scm_cvapply(proc, 1L, auto_av), MAKINUM(i)); } return UNSPECIFIED; case tc7_smob: ASRTGO(ARRAYP(ra), badarg); { int j, k, kmax = ARRAY_NDIM(ra) - 1; if (kmax < 0) return aset(ra, apply(proc, EOL, EOL), EOL); for (k = 0; k <= kmax; k++) indv[k] = ARRAY_DIMS(ra)[k].lbnd; k = kmax; do { if (k==kmax) { indv[k] = ARRAY_DIMS(ra)[k].lbnd; i = cind(ra, indv); for (; indv[k] <= ARRAY_DIMS(ra)[k].ubnd; indv[k]++) { for (j = kmax+1; j--;) av[j] = MAKINUM(indv[j]); aset(ARRAY_V(ra), scm_cvapply(proc, kmax+1L, av), MAKINUM(i)); i += ARRAY_DIMS(ra)[k].inc; } k--; continue; } if (indv[k] < ARRAY_DIMS(ra)[k].ubnd) { indv[k]++; k++; continue; } indv[k] = ARRAY_DIMS(ra)[k].lbnd - 1; k--; } while (k >= 0); return UNSPECIFIED; } } } SCM array_equal P((SCM ra0, SCM ra1)); static int raeql_1(ra0, as_equal, ra1) SCM ra0, as_equal, ra1; { SCM e0 = UNDEFINED, e1 = UNDEFINED; sizet i0 = 0, i1 = 0; long inc0 = 1, inc1 = 1; sizet n = LENGTH(ra0); ra1 = CAR(ra1); if (ARRAYP(ra0)) { n = ARRAY_DIMS(ra0)->ubnd - ARRAY_DIMS(ra0)->lbnd + 1; i0 = ARRAY_BASE(ra0); inc0 = ARRAY_DIMS(ra0)->inc; ra0 = ARRAY_V(ra0); } if (ARRAYP(ra1)) { i1 = ARRAY_BASE(ra1); inc1 = ARRAY_DIMS(ra1)->inc; ra1 = ARRAY_V(ra1); } switch TYP7(ra0) { case tc7_vector: default: for (; n--; i0+=inc0, i1+=inc1) { if (FALSEP(as_equal)) { if (FALSEP(array_equal(RVREF(ra0, i0, e0), RVREF(ra1, i1, e1)))) return 0; } else if (FALSEP(equal(RVREF(ra0, i0, e0), RVREF(ra1, i1, e1)))) return 0; } return 1; case tc7_string: { char *v0 = CHARS(ra0) + i0; char *v1 = CHARS(ra1) + i1; for (; n--; v0 += inc0, v1 += inc1) if (*v0 != *v1) return 0; return 1; } case tc7_Vbool: for (; n--; i0 += inc0, i1 += inc1) if (BVE_REF(ra0, i0) != BVE_REF(ra1, i1)) return 0; return 1; case tc7_VfixN32: case tc7_VfixZ32: { long *v0 = (long *)VELTS(ra0) + i0; long *v1 = (long *)VELTS(ra1) + i1; for (; n--; v0 += inc0, v1 += inc1) if (*v0 != *v1) return 0; return 1; } # ifdef FLOATS case tc7_VfloR32: { float *v0 = (float *)VELTS(ra0) + i0; float *v1 = (float *)VELTS(ra1) + i1; for (; n--; v0 += inc0, v1 += inc1) if (*v0 != *v1) return 0; return 1; } case tc7_VfloR64: { double *v0 = (double *)VELTS(ra0) + i0; double *v1 = (double *)VELTS(ra1) + i1; for (; n--; v0 += inc0, v1 += inc1) if (*v0 != *v1) return 0; return 1; } case tc7_VfloC32: { float (*v0)[2]= (float (*)[2])VELTS(ra0) + i0; float (*v1)[2] = (float (*)[2])VELTS(ra1) + i1; for (; n--; v0 += inc0, v1 += inc1) { if ((*v0)[0] != (*v1)[0]) return 0; if ((*v0)[1] != (*v1)[1]) return 0; } return 1; } case tc7_VfloC64: { double (*v0)[2]= (double (*)[2])VELTS(ra0) + i0; double (*v1)[2] = (double (*)[2])VELTS(ra1) + i1; for (; n--; v0 += inc0, v1 += inc1) { if ((*v0)[0] != (*v1)[0]) return 0; if ((*v0)[1] != (*v1)[1]) return 0; } return 1; } # endif /* FLOATS */ } } static int raeql(ra0, as_equal, ra1) SCM ra0, as_equal, ra1; { SCM v0 = ra0, v1 = ra1; array_dim dim0, dim1; array_dim *s0 = &dim0, *s1 = &dim1; sizet bas0 = 0, bas1 = 0; int k, unroll = 1, ndim = 1; if (ARRAYP(ra0)) { ndim = ARRAY_NDIM(ra0); s0 = ARRAY_DIMS(ra0); bas0 = ARRAY_BASE(ra0); v0 = ARRAY_V(ra0); } else { s0->inc = 1; s0->lbnd = 0; s0->ubnd = LENGTH(v0) - 1; } if (ARRAYP(ra1)) { if (ndim != ARRAY_NDIM(ra1)) return 0; s1 = ARRAY_DIMS(ra1); bas1 = ARRAY_BASE(ra1); v1 = ARRAY_V(ra1); } else { if (1 != ndim) return BOOL_F; s1->inc = 1; s1->lbnd = 0; s1->ubnd = LENGTH(v1) - 1; } if (TYP7(v0) != TYP7(v1)) return 0; unroll = (bas0==bas1); for (k = ndim; k--;) { if (s0[k].lbnd != s1[k].lbnd || s0[k].ubnd != s1[k].ubnd) return 0; if (unroll) unroll = (s0[k].inc==s1[k].inc); } if (unroll && v0==v1) return BOOL_T; return ramapc(raeql_1, as_equal, ra0, cons(ra1, EOL), ""); } SCM raequal(ra0, ra1) SCM ra0, ra1; { return (raeql(ra0, BOOL_T, ra1) ? BOOL_T : BOOL_F); } static char s_array_equalp[] = "array-equal?"; SCM array_equal(ra0, ra1) SCM ra0, ra1; { if (IMP(ra0) || IMP(ra1)) callequal: return equal(ra0, ra1); switch TYP7(ra0) { default: goto callequal; case tc7_vector: case tcs_uves: break; case tc7_smob: if (!ARRAYP(ra0)) goto callequal; } switch TYP7(ra1) { default: goto callequal; case tc7_vector: case tcs_uves: break; case tc7_smob: if (!ARRAYP(ra1)) goto callequal; } return (raeql(ra0, BOOL_F, ra1) ? BOOL_T : BOOL_F); } static iproc subr2os[] = { {s_ura_rd, ura_read}, {s_ura_wr, ura_write}, {0, 0}}; /* MinGW complains during a dll build that the string members are not constants, since they are defined in another dll. These functions individually initialized below. static iproc subr2s[] = { {s_array_fill, array_fill}, {s_array_copy, array_copy}, {s_sarray_copy, array_copy}, {0, 0}}; */ static iproc lsubr2s[] = { {s_sc2array, sc2array}, {s_array_map, array_map}, {s_sarray_map, array_map}, {s_array_for_each, array_for_each}, {s_array_imap, array_imap}, {s_array_index_for_each, scm_array_index_for_each}, {0, 0}}; static void init_raprocs(subra) ra_iproc *subra; { for (; subra->name; subra++) subra->sproc = CDR(sysintern(subra->name, UNDEFINED)); } SCM_DLL_EXPORT void init_ramap P((void)); void init_ramap() { init_raprocs(ra_rpsubrs); init_raprocs(ra_asubrs); init_iprocs(subr2os, tc7_subr_2o); /* init_iprocs(subr2s, tc7_subr_2); */ init_iprocs(lsubr2s, tc7_lsubr_2); make_subr(s_array_fill, tc7_subr_2, array_fill); make_subr(s_array_copy, tc7_subr_2, array_copy); make_subr(s_sarray_copy, tc7_subr_2, array_copy); make_subr(s_array_equalp, tc7_rpsubr, array_equal); smobs[0x0ff & (tc16_array>>8)].equalp = raequal; add_feature(s_array_for_each); scm_ldstr("\n\ (define (array-indexes ra)\n\ (let ((ra0 (apply make-array '#() (array-shape ra))))\n\ (array-index-map! ra0 list)\n\ ra0))\n\ (define (array-map prototype proc ra1 . ras)\n\ (define nra (apply make-array prototype (array-shape ra1)))\n\ (apply array-map! nra proc ra1 ras)\n\ nra)\n\ "); } scm-5e5/rgx.c0000644001705200017500000004257410750240521011006 0ustar tbtb/* "rgx.c" regular expression matching using C regex library. * Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see * . */ /* Author: Aubrey Jaffer */ #include "scm.h" #ifdef __FreeBSD__ # include "gnuregex.h" #else # include "regex.h" #endif #include /* added by Denys Duchier: for bcopy */ #ifdef sun #include #endif static char rcsid[] = "$Id: rgx.c,v 1.19 2008/01/31 03:32:33 jaffer Exp $"; #ifdef HAVE_ALLOCA # include # define ALLOCA_PROTECT typedef int foobazzz # define ALLOCA alloca #else # define ALLOCA_PROTECT SCM alloca_protect=EOL # define ALLOCA(size) \ (alloca_protect=cons(makstr((long)(size)), alloca_protect), \ (void *)CDR(CAR(alloca_protect))) #endif #ifdef _GNU_SOURCE /* following two lines stolen from GNU regex.c */ # define CHAR_SET_SIZE 256 # define ISUPPER(c) (isascii (c) && isupper (c)) #endif /* forward function defs */ SCM lregsearch(); SCM lregsearchv(); /* Posix regexp bindings. */ static char s_regex[] = "regex"; static char s_regcomp[] = "regcomp", s_regerror[] = "regerror"; static char s_regexec[] = "regexec", s_regmatp[] = "regmatch?"; static char s_regsearch[] = "regsearch", s_regmatch[] = "regmatch"; static char s_regsearchv[] = "regsearchv", s_regmatchv[] = "regmatchv"; static char s_stringsplit[] = "string-split"; static char s_stringsplitv[] = "string-splitv"; static char s_stringedit[] = "string-edit"; #define s_error &s_regerror[3] #define RGX_INFO(obj) ((regex_info*)CDR(obj)) #define RGX_PATTERN(obj) (((regex_info*)CDR(obj))->pattern) #define RGX(obj) (&((regex_info*)CDR(obj))->rgx) #ifndef _GNU_SOURCE # define RGX2(obj) (&((regex_info*)CDR(obj))->rgx_anchored) #endif #define FIXUP_REGEXP(prog) \ { \ if (STRINGP(prog)) \ prog = lregcomp(prog, UNDEFINED); \ if (NIMP(prog) && CONSP(prog) && STRINGP(CAR(prog)) && \ NIMP(CDR(prog)) && CONSP(CDR(prog)) && STRINGP(CAR(CDR(prog)))) \ prog = lregcomp(CAR(prog), CAR(CDR(prog))); \ } typedef struct regex_info { SCM pattern; /* string we compiled to create our reg exp */ regex_t rgx; #ifndef _GNU_SOURCE int options; /* for anchored pattern when matching */ regex_t rgx_anchored; #endif } regex_info; sizet fregex(ptr) CELLPTR ptr; { regfree(RGX((SCM)ptr)); #ifndef _GNU_SOURCE /* options are null => we compiled the anchored pattern */ if (RGX_INFO((SCM)ptr)->options==0) regfree(RGX2((SCM)ptr)); #endif must_free(CHARS((SCM)ptr), (sizet)LENGTH((SCM)ptr)); return 0; } int prinregex(exp, port, writing) SCM exp; SCM port; int writing; { lputs("#', port); return 1; } SCM markregex(ptr) SCM ptr; { SETGC8MARK(RGX_PATTERN(ptr)); return BOOL_F; } int tc16_rgx; static smobfuns rgxsmob = {markregex, fregex, prinregex}; SCM lregerror(scode) SCM scode; { int code; /* added by Denys Duchier: conditional declaration */ #ifdef __REGEXP_LIBRARY_H__ int len; #endif SCM str; ASRTER(INUMP(scode), scode, ARG1, s_regerror); code = INUM(scode); if (code < 0) return makfromstr("Invalid code", sizeof("Invalid code")-1); /* XXX - is regerror posix or not? */ #ifdef __REGEXP_LIBRARY_H__ /* XXX - gnu regexp doesn't use the re parameter, so we will ignore it in a very untidy way. */ len = regerror(code, 0L, 0L, 0); str = makstr(len-1); regerror(code, 0L, CHARS(str), len); #else str = makfromstr(s_error, (sizet)5); #endif return str; } SCM lregcomp(pattern, flags) SCM pattern, flags; { SCM z; int i, options; regex_t *prog; regex_info *info; char *flagchars; #ifdef _GNU_SOURCE int fastmap = 0; int ignore_case = 0; char *err_msg; #endif ASRTER(NIMP(pattern) && STRINGP(pattern), pattern, ARG1, s_regcomp); ASRTER(UNBNDP(flags) || (NIMP(flags) && STRINGP(flags)), flags, ARG2, s_regcomp); DEFER_INTS; z = must_malloc_cell((long)sizeof(regex_info), (SCM)tc16_rgx, s_regex); scm_protect_temp(&z); info=(regex_info*)CHARS(z); prog = &(info->rgx); #ifdef __REGEXP_LIBRARY_H__ for (i=sizeof(regex_t);i--;((char *)prog)[i] = 0); # ifndef _GNU_SOURCE { regex_t *prog2; prog2 = &(info->rgx_anchored); for (i=sizeof(regex_t);i--;((char *)prog2)[i] = 0); } # endif #endif ALLOW_INTS; info->pattern = pattern; #ifdef _GNU_SOURCE options = RE_SYNTAX_POSIX_EXTENDED; #else options = REG_EXTENDED; #endif if (!UNBNDP(flags)) { flagchars = CHARS(flags); for (i=0; ifastmap = must_malloc(CHAR_SET_SIZE, s_regex); else prog->fastmap = 0; if (ignore_case) { prog->translate = must_malloc(CHAR_SET_SIZE, s_regex); for (i = 0; i < CHAR_SET_SIZE; i++) prog->translate[i] = ISUPPER (i) ? tolower (i) : i; } else prog->translate = 0; prog->buffer = 0; prog->allocated = 0; re_set_syntax(options); err_msg = (char *)re_compile_pattern(CHARS(pattern), LENGTH(pattern), prog); ALLOW_INTS; prog->regs_allocated = REGS_FIXED; /* if error, compile using regcomp to get the error number */ if (err_msg) { int i; char *tmppat; SCM protect; /* Fixup in case pattern has null characters */ tmppat = CHARS(protect=makstr(LENGTH(pattern))); bcopy(CHARS(pattern), tmppat, LENGTH(pattern)); for (i=0; ioptions = options; i = regcomp(prog, CHARS(pattern), options); if (i) z = MAKINUM(i); #endif return z; } SCM lregexec(prog, str) SCM prog, str; { ALLOCA_PROTECT; FIXUP_REGEXP(prog); ASRTER(NIMP(prog) && tc16_rgx==CAR(prog), prog, ARG1, s_regexec); ASRTER(NIMP(str) && STRINGP(str), str, ARG2, s_regexec); #ifdef _GNU_SOURCE return lregsearchv(prog, str, EOL); #else /* not _GNU_SOURCE */ { size_t nsub; SCM ans; regmatch_t *pm; int flags = 0; /* XXX - optional arg? */ nsub = RGX(prog)->re_nsub + 1; /* XXX - is this posix? */ pm = ALLOCA(nsub * sizeof(regmatch_t)); if (regexec(RGX(prog), CHARS(str), nsub, pm, flags) != 0) ans = BOOL_F; else { ans = make_vector(MAKINUM(2L * nsub), MAKINUM(-1L)); while (nsub--) { VELTS(ans)[2*nsub+0] = MAKINUM(pm[nsub].rm_so); VELTS(ans)[2*nsub+1] = MAKINUM(pm[nsub].rm_eo); } } return ans; } #endif /* _GNU_SOURCE */ } SCM lregmatp(prog, str) SCM prog, str; { FIXUP_REGEXP(prog); ASRTER(NIMP(prog) && tc16_rgx==CAR(prog), prog, ARG1, s_regmatp); ASRTER(NIMP(str) && STRINGP(str), str, ARG2, s_regmatp); #ifdef _GNU_SOURCE return (lregsearch(prog, str, EOL)==BOOL_F)?BOOL_F:BOOL_T; #else /* not _GNU_SOURCE */ { int flags = 0; /* XXX - optional arg? */ flags = regexec(RGX(prog), CHARS(str), 0, 0, flags); if (!flags) return BOOL_T; if (REG_NOMATCH!=flags) wta(MAKINUM(flags), s_error, s_regmatp); return BOOL_F; } #endif } #define SCALAR 0 #define VECTOR 1 #define MATCH 0 #define SEARCH 1 SCM lregsearchmatch(prog, str, args, search, vector) SCM prog, str, args; int vector, search; { int len = ilength(args); int start, size, nsub; SCM matches; ALLOCA_PROTECT; FIXUP_REGEXP(prog); ASRTER(NIMP(prog) && tc16_rgx==CAR(prog), prog, ARG1, s_regsearch); ASRTER(NIMP(str) && STRINGP(str), str, ARG2, s_regsearch); ASRTER(len<=2, args, WNA, s_regsearch); ASRTER((len<1)||(INUMP(CAR(args))), CAR(args), ARG3, s_regsearch); ASRTER((len<2)||(INUMP(CAR(CDR(args)))), CAR(CDR(args)), ARG4, s_regsearch); start = (len>=1)?(INUM(CAR(args))):0; size = (len>=2)?(INUM(CAR(CDR(args)))):LENGTH(str); #ifdef _GNU_SOURCE { int ret, dir=1; struct re_registers regs, *pregs=0; if (search && start<0) start *= -1, dir = -1; if (vector) { pregs = ®s; nsub = RGX(prog)->re_nsub + 1; regs.num_regs = nsub; regs.start = ALLOCA(nsub * sizeof(regoff_t)); regs.end = ALLOCA(nsub * sizeof(regoff_t)); } if (search) ret = re_search(RGX(prog), CHARS(str), size, start, dir*size, pregs); else ret = re_match(RGX(prog), CHARS(str), size, start, pregs); if (ret < 0) return BOOL_F; if (!vector) return MAKINUM(ret); matches = make_vector(MAKINUM(2L * nsub), MAKINUM(-1L)); while (nsub--) { VELTS(matches)[2*nsub+0] = MAKINUM(regs.start[nsub]); VELTS(matches)[2*nsub+1] = MAKINUM(regs.end[nsub]); } return matches; } #else /* not _GNU_SOURCE */ { regex_t *regexp; regmatch_t *pm; char *search_string; if (size > LENGTH(str)) size = LENGTH(str); if (start<0 || start >= size) return BOOL_F; if (size < LENGTH(str)) { search_string = ALLOCA(size-start+1); bcopy(CHARS(str)+start, search_string, size-start); search_string[size-start] = 0; } else search_string = CHARS(str)+start; nsub = RGX(prog)->re_nsub + 1; pm = ALLOCA(nsub * sizeof(regmatch_t)); if (search) regexp = RGX(prog); else { /* doing a match */ if (RGX_INFO(prog)->options) { /* strlen & strcpy OK, posix patterns are null terminated */ char *pattern; pattern = ALLOCA(strlen(CHARS(RGX_PATTERN(prog)))+2); pattern[0] = '^'; strcpy(pattern+1, CHARS(RGX_PATTERN(prog))); regcomp(RGX2(prog), pattern, RGX_INFO(prog)->options); RGX_INFO(prog)->options = 0; } regexp = RGX2(prog); } if (regexec(regexp, search_string, nsub, pm, 0) != 0) return BOOL_F; if (vector) { matches = make_vector(MAKINUM(2L * nsub), MAKINUM(-1L)); while (nsub--) { VELTS(matches)[2*nsub+0] = MAKINUM(pm[nsub].rm_so + start); VELTS(matches)[2*nsub+1] = MAKINUM(pm[nsub].rm_eo + start); } return matches; } if (search) return MAKINUM(pm[0].rm_so + start); else return MAKINUM(pm[0].rm_eo - pm[0].rm_so); } #endif /* _GNU_SOURCE */ } SCM lregsearch(prog, str, args) SCM prog, str, args; { return lregsearchmatch(prog, str, args, SEARCH, SCALAR); } SCM lregsearchv(prog, str, args) SCM prog, str, args; { return lregsearchmatch(prog, str, args, SEARCH, VECTOR); } SCM lregmatch(prog, str, args) SCM prog, str, args; { return lregsearchmatch(prog, str, args, MATCH, SCALAR); } SCM lregmatchv(prog, str, args) SCM prog, str, args; { return lregsearchmatch(prog, str, args, MATCH, VECTOR); } SCM stringsplitutil(prog, str, vector) SCM prog, str; int vector; { int anchor, match_start, match_end, num_substrings, num_elements; int search_base; SCM next_break, substrings, ret; SCM st_start, st_end; FIXUP_REGEXP(prog); ASRTER(NIMP(prog) && tc16_rgx==CAR(prog), prog, ARG1, s_stringsplit); ASRTER(NIMP(str) && STRINGP(str), str, ARG2, s_stringsplit); substrings = EOL; anchor = 0; search_base = 0; num_substrings = 0; next_break = lregsearchv(prog, str, cons(MAKINUM(search_base), EOL)); while (next_break != BOOL_F) { match_start = INUM(VELTS(next_break)[0]); match_end = INUM(VELTS(next_break)[1]); if (match_start < match_end) { substrings=cons2(MAKINUM(anchor), MAKINUM(match_start), substrings); anchor = match_end; num_substrings++; } search_base = ((match_end>search_base)?match_end:(search_base+1)); next_break = lregsearchv(prog, str, cons(MAKINUM(search_base), EOL)); } /* get that tail bit */ if (anchor < LENGTH(str)) { substrings = cons2(MAKINUM(anchor), MAKINUM(LENGTH(str)), substrings); num_substrings++; } num_elements = vector?(2*num_substrings):num_substrings; ret = make_vector(MAKINUM(num_elements), EOL); while (num_substrings--) { st_start = CAR(substrings); st_end = CAR(CDR(substrings)); if (vector) { VELTS(ret)[num_substrings*2+0] = st_start; VELTS(ret)[num_substrings*2+1] = st_end; } else VELTS(ret)[num_substrings] = substring(str, st_start, st_end); substrings = CDR(CDR(substrings)); } return ret; } SCM lstringsplit(prog, str) SCM prog, str; { return stringsplitutil(prog, str, SCALAR); } SCM lstringsplitv(prog, str) SCM prog, str; { return stringsplitutil(prog, str, VECTOR); } typedef struct _item { struct _item *next; char *string; int start; int end; } *editItem; #define PUSH(list, string_parm, start_parm, end_parm) \ { \ editItem item; \ \ item = ALLOCA(sizeof(*item)); \ item->next = list; \ list = item; \ item->string = string_parm; \ item->start = start_parm; \ item->end = end_parm; \ } /* (string-edit []) */ SCM lstringedit(prog, editspec, args) SCM prog, editspec, args; { int match_start, match_end, search_base, editcount; int total_len; int i, args_len, anchor, maxsubnum; int backslash; char *ptr; editItem editlist, substrings, edit; SCM str, count, next_edit; SCM result; ALLOCA_PROTECT; args_len = ilength(args); FIXUP_REGEXP(prog); ASRTER(NIMP(prog) && tc16_rgx==CAR(prog), prog, ARG1, s_stringedit); ASRTER(NIMP(editspec) && STRINGP(editspec), editspec, ARG2, s_stringedit); ASRTER((args_len==1)||(args_len==2), args, WNA, s_stringedit); str = CAR(args); ASRTER(NIMP(str)&&STRINGP(str), str, ARG3, s_stringedit); if (args_len==2) { count = CAR(CDR(args)); ASRTER(INUMP(count)||(count==BOOL_T), count, ARG4, s_stringedit); } else count = MAKINUM(1); /* process the editspec - break it into a list of dotted pairs * of integers for substrings to be inserted and * integers representing matched subexpressions that * should be inserted. */ maxsubnum = RGX(prog)->re_nsub; anchor = 0; backslash = 0; editlist = 0; ptr = CHARS(editspec); for (i=0; i='0') && (ptr[i] <='9') && ((ptr[i]-'0')<=maxsubnum)) { if ((i-1)>anchor) PUSH(editlist, CHARS(editspec), anchor, i-1); PUSH(editlist, CHARS(editspec), ptr[i]-'0', -1); anchor = i+1; } backslash = (ptr[i] == '\\')?1:0; } if (anchor < LENGTH(editspec)) PUSH(editlist, CHARS(editspec), anchor, LENGTH(editspec)); /* now, reverse the list of edit items */ { editItem prev, cur, next; for (prev=0, cur=editlist; cur; prev=cur, cur=next) { next = cur->next; cur->next = prev; } editlist = prev; } anchor = 0; search_base = 0; editcount = 0; substrings = 0; next_edit = lregsearchv(prog, str, cons(MAKINUM(search_base), EOL)); while (next_edit != BOOL_F) { if (INUMP(count) && (editcount==INUM(count))) break; match_start = INUM(VELTS(next_edit)[0]); match_end = INUM(VELTS(next_edit)[1]); if (match_start < match_end) { PUSH(substrings, CHARS(str), anchor, match_start); anchor = match_end; } for (edit=editlist; edit; edit=edit->next) { if (edit->end == -1) { /* A backslash number in the original editspec */ PUSH(substrings, CHARS(str), INUM(VELTS(next_edit)[edit->start*2+0]), INUM(VELTS(next_edit)[edit->start*2+1])); } else /* normal string in the editspec */ PUSH(substrings, edit->string, edit->start, edit->end); } editcount++; search_base = ((match_end>search_base)?match_end:(search_base+1)); next_edit = lregsearchv(prog, str, cons(MAKINUM(search_base), EOL)); } /* get that tail bit */ if (anchor < LENGTH(str)) PUSH(substrings, CHARS(str), anchor, LENGTH(str)); /* assemble the result string */ for (edit=substrings, total_len=0; edit; edit=edit->next) total_len += (edit->end - edit->start); result = makstr(total_len); ptr = CHARS(result) + total_len; /* point at the null at the end */ for (edit=substrings; edit; edit=edit->next) { ptr -= (edit->end - edit->start); bcopy(edit->string + edit->start, ptr, edit->end - edit->start); } return result; } #undef PUSH void init_rgx() { tc16_rgx = newsmob(&rgxsmob); make_subr(s_regcomp, tc7_subr_2o, lregcomp); make_subr(s_regexec, tc7_subr_2, lregexec); make_subr(s_regmatp, tc7_subr_2, lregmatp); make_subr(s_regerror, tc7_subr_1, lregerror); make_subr(s_regsearch, tc7_lsubr_2, lregsearch); make_subr(s_regsearchv, tc7_lsubr_2, lregsearchv); make_subr(s_regmatch, tc7_lsubr_2, lregmatch); make_subr(s_regmatchv, tc7_lsubr_2, lregmatchv); make_subr(s_stringsplit, tc7_subr_2, lstringsplit); make_subr(s_stringsplitv, tc7_subr_2, lstringsplitv); make_subr(s_stringedit, tc7_lsubr_2, lstringedit); add_feature(s_regex); } scm-5e5/sys.c0000644001705200017500000023431710750224475011034 0ustar tbtb/* "sys.c" opening and closing files, storage, and GC. * Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2002, 2006 Free Software Foundation, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see * . */ #include #include "scm.h" #include "setjump.h" #ifdef POCKETCONSOLE # include #endif void igc P((const char *what, SCM basecont)); SCM *loc_open_file; /* for open-file callback */ SCM *loc_try_create_file; /* ttyname() etc. should be defined in . But unistd.h is missing on many systems. */ #ifndef STDC_HEADERS char *ttyname P((int fd)); char *tmpnam P((char *s)); # ifdef sun # ifndef __SVR4 int fputs P((char *s, FILE* stream)); int fputc P((char c, FILE* stream)); int fflush P((FILE* stream)); # endif # else sizet fwrite (); # endif int fgetc P((FILE* stream)); int fclose P((FILE* stream)); int pclose P((FILE* stream)); int unlink P((const char *pathname)); char *mktemp P((char *template)); #else # ifdef linux # include # endif # ifdef __NetBSD__ # include # endif # ifdef __OpenBSD__ # include # endif #endif static void gc_sweep P((int contin_bad)); char s_nogrow[] = "could not grow", s_heap[] = "heap", s_hplims[] = "hplims", s_try_create_file[] = "try-create-file"; static char s_segs[] = "segments", s_numheaps[] = "number of heaps"; static char s_input_portp[] = "input-port?", s_output_portp[] = "output-port?"; static char s_port_closedp[] = "port-closed?"; static char s_try_open_file[] = "try-open-file"; #define s_open_file (&s_try_open_file[4]) char s_close_port[] = "close-port"; #ifdef __IBMC__ # include # include # define ttyname(x) "CON:" #else # ifndef MSDOS # ifndef ultrix # ifndef vms # ifdef _DCC # include # define setbuf(stream, buf) setvbuf(stream, buf, _IONBF, 0) # else # ifdef MWC # include # else # ifndef macintosh # ifndef ARM_ULIB # ifndef PLAN9 # include # endif # endif # endif # endif # endif # endif # endif # endif #endif /* __IBMC__ */ SCM i_setbuf0(port) /* should be called with DEFER_INTS active */ SCM port; { VERIFY_INTS("i_setbuf0", 0L); #ifndef NOSETBUF # ifndef MSDOS # ifdef FIONREAD # ifndef ultrix SYSCALL(setbuf(STREAM(port), 0L);); # endif # endif # endif #endif return UNSPECIFIED; } /* The CRDY bit is overloaded to indicate that additional processing is needed when reading or writing, such as updating line and column numbers. Returns 0 if cmodes is non-null and modes string is not valid. */ /* If nonnull, the CMODES argument receives a copy of all chars in MODES which are allowed by ANSI C. */ long mode_bits(modes, cmodes) char *modes, *cmodes; { int iout = 0; long bits = OPN; for (; *modes; modes++) switch (*modes) { case 'r': bits |= RDNG; goto outc; case 'w': case 'a': bits |= WRTNG; goto outc; case '+': bits |= (RDNG | WRTNG); goto outc; case 'b': bits |= BINARY; goto outc; case '0': bits |= BUF0; break; case '?': bits |= (TRACKED | CRDY); break; case 'x': bits |= EXCLUSIVE; break; outc: if (cmodes && (iout < 3)) cmodes[iout++] = *modes; break; } if (!cmodes) return bits; cmodes[iout] = 0; switch (cmodes[0]) { default: return 0; case 'r': case 'w': case 'a': return bits; } } SCM try_open_file(filename, modes) SCM filename, modes; { register SCM port; FILE *f; char cmodes[4]; long flags; ASRTER(NIMP(filename) && STRINGP(filename), filename, ARG1, s_open_file); ASRTER(NIMP(modes) && (STRINGP(modes) || SYMBOLP(modes)), modes, ARG2, s_open_file); flags = mode_bits(CHARS(modes), cmodes); ASRTER(flags, modes, ARG2, s_open_file); if ((EXCLUSIVE & flags) && NIMP(*loc_try_create_file)) { port = apply(*loc_try_create_file, filename, cons(modes, listofnull)); if (UNSPECIFIED != port) return port; } DEFER_INTS; SCM_OPENCALL((f = fopen(CHARS(filename), cmodes))); if (!f) { ALLOW_INTS; return BOOL_F; } port = scm_port_entry(f, tc16_fport, flags); if (BUF0 & flags) i_setbuf0(port); ALLOW_INTS; SCM_PORTDATA(port) = filename; return port; } /* Callback to Scheme */ SCM open_file(filename, modes) SCM filename, modes; { return apply(*loc_open_file, filename, cons(modes, listofnull)); } long tc16_clport; SCM close_port(port) SCM port; { sizet i; SCM ret = UNSPECIFIED; ASRTER(NIMP(port) && PORTP(port), port, ARG1, s_close_port); if (CLOSEDP(port)) return UNSPECIFIED; i = PTOBNUM(port); DEFER_INTS; if (ptobs[i].fclose) { int r; SYSCALL(r = (ptobs[i].fclose)(STREAM(port));); if (EOF == r) ret = BOOL_F; else ret = MAKINUM(r); } CAR(port) &= ~OPN; SCM_PORTFLAGS(port) &= ~OPN; /* Bash the old ptobnum with the closed port ptobnum. This allows catching some errors cheaply. */ SCM_SET_PTOBNUM(port, tc16_clport); ALLOW_INTS; return ret; } SCM input_portp(x) SCM x; { if (IMP(x)) return BOOL_F; return INPORTP(x) ? BOOL_T : BOOL_F; } SCM output_portp(x) SCM x; { if (IMP(x)) return BOOL_F; return OUTPORTP(x) ? BOOL_T : BOOL_F; } SCM port_closedp(port) SCM port; { ASRTER(NIMP(port) && PORTP(port), port, ARG1, s_port_closedp); if (CLOSEDP(port)) return BOOL_T; return BOOL_F; } SCM scm_port_type(port) SCM port; { int i; if (NIMP(port) && PORTP(port)) { i = PTOBNUM(port); if (ptobs[i].name) return CAR(sysintern(ptobs[i].name, UNDEFINED)); return BOOL_T; } return BOOL_F; } #if (__TURBOC__==1) # undef L_tmpnam /* Not supported in TURBOC V1.0 */ #endif #ifdef GO32 # undef L_tmpnam /* Would put files in %TMPDIR% = %DJDIR%/tmp */ #endif #ifdef MWC # undef L_tmpnam #endif #ifdef L_tmpnam SCM ltmpnam() { char name[L_tmpnam]; SYSCALL(tmpnam(name);); return makfrom0str(name); } #else /* TEMPTEMPLATE is used only if mktemp() is being used instead of tmpnam(). */ # ifdef AMIGA # define TEMPTEMPLATE "T:SchemeaaaXXXXXX"; # else # ifdef vms # define TEMPTEMPLATE "sys$scratch:aaaXXXXXX"; # else /* vms */ # ifdef __MSDOS__ # ifdef GO32 # define TEMPTEMPLATE "\\tmp\\TMPaaaXXXXXX"; # else # define TEMPTEMPLATE "TMPaaaXXXXXX"; # endif # else /* __MSDOS__ */ # define TEMPTEMPLATE "/tmp/aaaXXXXXX"; # endif /* __MSDOS__ */ # endif /* vms */ # endif /* AMIGA */ char template[] = TEMPTEMPLATE; # define TEMPLEN (sizeof template/sizeof(char) - 1) SCM ltmpnam() { SCM name; int temppos = TEMPLEN-9; name = makfromstr(template, (sizet)TEMPLEN); DEFER_INTS; inclp: template[temppos]++; if (!isalpha(template[temppos])) { template[temppos++] = 'a'; goto inclp; } # ifndef AMIGA # ifndef __MSDOS__ SYSCALL(temppos = !*mktemp(CHARS(name));); if (temppos) name = BOOL_F; # endif # endif ALLOW_INTS; return name; } #endif /* L_tmpnam */ #ifdef M_SYSV # define remove unlink #endif static char s_del_fil[] = "delete-file"; SCM del_fil(str) SCM str; { int ans; ASRTER(NIMP(str) && STRINGP(str), str, ARG1, s_del_fil); #ifdef STDC_HEADERS SYSCALL(ans = remove(CHARS(str));); #else SYSCALL(ans = unlink(CHARS(str));); #endif return ans ? BOOL_F : BOOL_T; } void prinport(exp, port, type) SCM exp; SCM port; char *type; { int filn = fileno(STREAM(exp)); lputs("#<", port); if (CLOSEDP(exp)) lputs("closed-", port); else { if (RDNG & CAR(exp)) lputs("input-", port); if (WRTNG & CAR(exp)) lputs("output-", port); } lputs(type, port); lputc(' ', port); #ifndef MSDOS # ifndef __EMX__ # ifndef _DCC # ifndef AMIGA # ifndef macintosh # ifndef PLAN9 if (OPENP(exp) && tc16_fport==TYP16(exp) && filn >= 0 && isatty(filn)) { char *ttyn = ttyname(filn); if (ttyn) lputs(ttyn, port); else goto punt; } else # endif # endif # endif # endif # endif #endif punt: { SCM s = PORTP(exp) ? SCM_PORTDATA(exp) : UNDEFINED; if (NIMP(s) && STRINGP(s)) scm_iprin1(s, port, 1); else if (OPFPORTP(exp)) scm_intprint((long)filn, 10, port); else scm_intprint(CDR(exp), -16, port); if (TRACKED & SCM_PORTFLAGS(exp)) { lputs(" L", port); scm_intprint(scm_port_table[SCM_PORTNUM(exp)].line, 10, port); lputs(" C", port); scm_intprint(scm_port_table[SCM_PORTNUM(exp)].col+0L, 10, port); } } lputc('>', port); } static int stputc(c, p) int c; SCM p; { sizet ind = INUM(CAR(p)); if (ind >= LENGTH(CDR(p))) resizuve(CDR(p), MAKINUM(ind + (ind>>1))); CHARS(CDR(p))[ind] = c; CAR(p) = MAKINUM(ind + 1); return c; } sizet stwrite(str, siz, num, p) sizet siz, num; char *str; SCM p; { sizet ind = INUM(CAR(p)); sizet len = siz * num; char *dst; if (ind + len >= LENGTH(CDR(p))) resizuve(CDR(p), MAKINUM(ind + len + ((ind + len)>>1))); dst = &(CHARS(CDR(p))[ind]); while (len--) dst[len] = str[len]; CAR(p) = MAKINUM(ind + siz*num); return num; } static int stputs(s, p) char *s; SCM p; { stwrite(s, 1, strlen(s), p); return 0; } static int stgetc(p) SCM p; { sizet ind = INUM(CAR(p)); if (ind >= LENGTH(CDR(p))) return EOF; CAR(p) = MAKINUM(ind + 1); return UCHARS(CDR(p))[ind]; } static int stclose(p) SCM p; { SETCDR(p, nullstr); return 0; } static int stungetc(c, p) int c; SCM p; { sizet ind; p = CDR(p); ind = INUM(CAR(p)); if (ind == 0) return EOF; CAR(p) = MAKINUM(--ind); ASRTER(UCHARS(CDR(p))[ind] == c, MAKICHR(c), "stungetc", ""); return c; } int noop0(stream) FILE *stream; { return 0; } SCM mkstrport(pos, str, modes, caller) SCM pos; SCM str; long modes; char *caller; { SCM z; ASRTER(INUMP(pos) && INUM(pos) >= 0, pos, ARG1, caller); ASRTER(NIMP(str) && (STRINGP(str) || SYMBOLP(str)), str, ARG1, caller); str = cons(pos, str); NEWCELL(z); DEFER_INTS; SETCHARS(z, str); CAR(z) = (modes | tc16_strport); /* port table entry 0 is scratch. */ /* z = scm_port_entry((FILE *)str, tc16_strport, modes); */ ALLOW_INTS; return z; } static char s_cwos[] = "call-with-output-string"; static char s_cwis[] = "call-with-input-string"; SCM cwos(proc) SCM proc; { SCM p = mkstrport(INUM0, make_string(MAKINUM(30), UNDEFINED), OPN | WRTNG, s_cwos); apply(proc, p, listofnull); return resizuve(CDR(CDR(p)), CAR(CDR(p))); } SCM cwis(str, proc) SCM str, proc; { SCM p = mkstrport(INUM0, str, OPN | RDNG, s_cwis); return apply(proc, p, listofnull); } #ifdef vms sizet pwrite(ptr, size, nitems, port) char *ptr; sizet size, nitems; FILE* port; { sizet len = size * nitems; sizet i = 0; for (;i < len;i++) putc(ptr[i], port); return len; } # define ffwrite pwrite #else # define ffwrite fwrite #endif static ptobfuns fptob = { s_port_type, mark0, fclose, 0, 0, fputc, #ifdef __MWERKS__ (int (*)(char *, struct _FILE *))fputs, (unsigned long (*)(char *, unsigned long, unsigned long, struct _FILE *))ffwrite, #else fputs, ffwrite, #endif fflush, fgetc, fclose}; ptobfuns pipob = { 0, mark0, 0, /* replaced by pclose in init_posix() */ 0, 0, fputc, #ifdef __MWERKS__ (int (*)(char *, struct _FILE *))fputs, (unsigned long (*)(char *, unsigned long, unsigned long, struct _FILE *))ffwrite, #else fputs, ffwrite, #endif fflush, fgetc}; static ptobfuns stptob = { s_string, markcdr, noop0, 0, 0, stputc, stputs, stwrite, noop0, stgetc, stclose, stungetc}; /* Soft ports */ /* fputc, fwrite, fputs, and fclose are called within a SYSCALL. So we need to set errno to 0 before returning. fflush may be called within a SYSCALL. So we need to set errno to 0 before returning. */ static int sfputc(c, p) int c; SCM p; { SCM arg = MAKICHR(c); scm_cvapply(VELTS(p)[0], 1L, &arg); errno = 0; return c; } sizet sfwrite(str, siz, num, p) sizet siz, num; char *str; SCM p; { SCM sstr; sstr = makfromstr(str, siz * num); scm_cvapply(VELTS(p)[1], 1L, &sstr); errno = 0; return num; } static int sfputs(s, p) char *s; SCM p; { sfwrite(s, 1, strlen(s), p); return 0; } int sfflush(stream) SCM stream; { SCM f = VELTS(stream)[2]; if (BOOL_F==f) return 0; f = apply(f, EOL, EOL); errno = 0; return BOOL_F==f ? EOF : 0; } static int sfgetc(p) SCM p; { SCM ans; ans = scm_cvapply(VELTS(p)[3], 0L, (SCM *)0); errno = 0; if (FALSEP(ans) || EOF_VAL==ans) return EOF; ASRTER(ICHRP(ans), ans, ARG1, "getc"); return ICHR(ans); } static int sfclose(p) SCM p; { SCM f = VELTS(p)[4]; if (BOOL_F==f) return 0; f = apply(f, EOL, EOL); errno = 0; return BOOL_F==f ? EOF : 0; } static char s_mksfpt[] = "make-soft-port"; SCM mksfpt(pv, modes) SCM pv, modes; { SCM z; long flags; static long arities[] = {1, 1, 0, 0, 0}; #ifndef RECKLESS int i; if (! (NIMP(pv) && VECTORP(pv) && 5==LENGTH(pv))) badarg: wta(pv, (char *)ARG1, s_mksfpt); for (i = 0; i < 5; i++) { ASRTGO(FALSEP(VELTS(pv)[i]) || scm_arity_check(VELTS(pv)[i], arities[i], (char *)0), badarg); } #endif ASRTER(NIMP(modes) && (STRINGP(modes) || SYMBOLP(modes)), modes, ARG2, s_mksfpt); flags = mode_bits(CHARS(modes), (char *)0); ASRTER(flags, modes, ARG2, s_mksfpt); DEFER_INTS; z = scm_port_entry((FILE *)pv, tc16_sfport, flags); ALLOW_INTS; return z; } static ptobfuns sfptob = { "soft", markcdr, noop0, 0, 0, sfputc, sfputs, sfwrite, sfflush, sfgetc, sfclose}; /* Closed ports, just return an error code and let the caller complain. */ static int clputc(c, p) int c; FILE *p; { return EOF; } static sizet clwrite(str, siz, num, p) sizet siz, num; char *str; FILE *p; { return 0; } static int clputs(s, p) char *s; FILE *p; { return EOF; } static int clgetc(p) FILE *p; { return EOF; } static ptobfuns clptob = { s_port_type, mark0, noop0, 0, 0, clputc, clputs, clwrite, clgetc, clgetc, 0}; /* The following ptob is for printing system messages in an interrupt-safe way. Writing to sys_errp while interrupts are disabled will never enable interrupts, do any actual i/o, or any allocation. Messages will be written to cur_errp as soon as interrupts are enabled. There will only ever be one of these. */ int output_deferred = 0; static int tc16_sysport; #define SYS_ERRP_SIZE 480 static char errbuf[SYS_ERRP_SIZE]; static sizet errbuf_end = 0; static sizet syswrite(str, siz, num, p) sizet siz, num; char *str; FILE *p; { sizet src, dst = errbuf_end; sizet n = siz*num; if (ints_disabled) { deferred_proc = process_signals; output_deferred = !0; for (src = 0; src < n; src++, dst++) errbuf[dst % SYS_ERRP_SIZE] = str[src]; errbuf_end = dst; } else { /* if (NIMP(cur_errp) && OPOUTPORTP(cur_errp)) lfflush(cur_errp); */ if (errbuf_end > 0) { if (errbuf_end > SYS_ERRP_SIZE) { scm_warn("output buffer", " overflowed", UNDEFINED); scm_intprint((long)errbuf_end, 10, cur_errp); lputs(" chars needed\n", cur_errp); errbuf_end = errbuf_end % SYS_ERRP_SIZE; lfwrite(&errbuf[errbuf_end], 1, SYS_ERRP_SIZE - errbuf_end, cur_errp); } lfwrite(errbuf, sizeof(char), errbuf_end, cur_errp); errbuf_end = 0; } num = lfwrite(str, siz, num, cur_errp); /* if (NIMP(cur_errp) && OPOUTPORTP(cur_errp)) lfflush(cur_errp); */ } errno = 0; return num; } static int sysputs(s, p) char *s; FILE *p; { syswrite(s, 1, strlen(s), p); return 0; } static int sysputc(c, p) int c; FILE *p; { char cc = c; syswrite(&cc, 1, 1, p); return c; } static ptobfuns sysptob = { 0, mark0, noop0, 0, 0, sysputc, sysputs, syswrite, noop0, noop0, noop0}; /* A `safeport' is used for writing objects as part of an error response. Since these objects may be very large or circular, the safeport will output only a fixed number of characters before exiting via longjmp. A setjmp must be done before each use of the safeport. */ static char s_msp[] = "mksafeport"; int tc16_safeport; SCM mksafeport(maxlen, port) int maxlen; SCM port; { SCM z; if (UNBNDP(port)) port = cur_errp; ASRTER(NIMP(port) && OPPORTP(port), port, ARG2, s_msp); z = must_malloc_cell(sizeof(safeport)+0L, tc16_safeport | OPN | WRTNG, s_msp); ((safeport *)STREAM(z))->ccnt = maxlen; ((safeport *)STREAM(z))->port = port; return z; } int reset_safeport(sfp, maxlen, port) int maxlen; SCM sfp, port; { if (NIMP(sfp) && tc16_safeport==TYP16(sfp)) { ((safeport *)STREAM(sfp))->ccnt = maxlen; if (NIMP(port)) ((safeport *)STREAM(sfp))->port = port; return !0; } return 0; } static sizet safewrite(str, siz, num, p) sizet siz, num; char *str; safeport *p; { int count = p->ccnt; sizet n = siz*num; if (n < count) { p->ccnt = count - n; lfwrite(str, siz, num, p->port); } else if (count) { num = count / siz; p->ccnt = 0; lfwrite(str, siz, num, p->port); lputs(" ...", p->port); longjmp(p->jmpbuf, !0); /* The usual C longjmp, not SCM's longjump */ } return num; } static int safeputs(s, p) char *s; safeport *p; { safewrite(s, 1, strlen(s), p); return 0; } static int safeputc(c, p) int c; safeport *p; { char cc = c; safewrite(&cc, 1, 1, p); return c; } static int safeflush(p) safeport *p; { if (p && NIMP(p->port) && OPOUTPORTP(p->port)) lfflush(p->port); return 0; } static SCM marksafep(ptr) SCM ptr; { return ((safeport *)STREAM(ptr))->port; } static int freesafep(ptr) FILE *ptr; { must_free((char *)ptr, sizeof(safeport)); return 0; } static ptobfuns safeptob = { 0, marksafep, freesafep, 0, 0, safeputc, safeputs, safewrite, safeflush, noop0, noop0}; static int freeprint(exp, port, writing) SCM exp; SCM port; int writing; { if (tc_broken_heart==CAR(exp)) { lputs("#", port); scm_iprin1(CDR(exp), port, writing); } else { if (NIMP(CDR(exp)) && tc7_smob==CAR(CDR(exp))) { lputs("#', port); return !0; } static smobfuns freecell = { mark0, free0, freeprint, 0}; static smobfuns flob = { mark0, /*flofree*/0, floprint, #ifdef FLOATS floequal #else 0 #endif }; static smobfuns bigob = { mark0, /*bigfree*/0, bigprint, #ifdef BIGDIG bigequal #else 0 #endif }; scm_gra finals_gra; static char s_final[] = "final"; /* statically allocated ports for diagnostic messages */ static cell tmp_errpbuf[3]; static SCM tmp_errp; extern sizet num_protects; /* sys_protects now in scl.c */ void init_types() { sizet j = num_protects; while(j) sys_protects[--j] = UNDEFINED; /* We need to set up tmp_errp before any errors may be thrown, the port_table index will be zero, usable by all ports that don't care about their table entries. */ tmp_errp = PTR2SCM(CELL_UP(&tmp_errpbuf[0])); CAR(tmp_errp) = tc16_fport | OPN | WRTNG; /* CAR(tmp_errp) = scm_port_entry(tc16_fport, OPN|WRTNG); */ SETSTREAM(tmp_errp, stderr); cur_errp = def_errp = sys_safep = tmp_errp; /* subrs_gra is trimmed to actual used by scm_init_extensions() */ scm_init_gra(&subrs_gra, sizeof(subr_info), 420 , 0, "subrs"); scm_init_gra(&ptobs_gra, sizeof(ptobfuns), 8, 255, "ptobs"); /* These newptob calls must be done in this order */ /* tc16_fport = */ newptob(&fptob); /* tc16_pipe = */ newptob(&pipob); /* tc16_strport = */ newptob(&stptob); /* tc16_sfport = */ newptob(&sfptob); tc16_clport = newptob(&clptob); tc16_sysport = newptob(&sysptob); tc16_safeport = newptob(&safeptob); scm_init_gra(&smobs_gra, sizeof(smobfuns), 16, 255, "smobs"); /* These newsmob calls must be done in this order */ newsmob(&freecell); newsmob(&flob); newsmob(&bigob); newsmob(&bigob); scm_init_gra(&finals_gra, sizeof(void (*)()), 4, 0, s_final); } #ifdef TEST_FINAL void test_final() { fputs("test_final ok\n", stderr); } #endif void add_final(final) void (* final)(); { scm_grow_gra(&finals_gra, (char *)&final); } static SCM gc_finalizers = EOL, gc_finalizers_pending = EOL; static char s_add_finalizer[] = "add-finalizer"; SCM scm_add_finalizer(value, finalizer) SCM value, finalizer; { SCM z; ASRTER(NIMP(value), value, ARG1, s_add_finalizer); #ifndef RECKLESS scm_arity_check(finalizer, 0L, s_add_finalizer); #endif z = acons(value, finalizer, EOL); DEFER_INTS; CDR(z) = gc_finalizers; gc_finalizers = z; ALLOW_INTS; return UNSPECIFIED; } static char s_estk[] = "environment stack"; static cell ecache_v[ECACHE_SIZE]; SCM scm_egc_roots[ECACHE_SIZE/20]; CELLPTR scm_ecache; VOLATILE long scm_ecache_index, scm_ecache_len, scm_egc_root_index; SCM scm_estk = UNDEFINED, *scm_estk_ptr; static SCM estk_pool = EOL; long scm_estk_size; static SCM make_stk_seg(size, contents) sizet size; SCM contents; { SCM seg = BOOL_F, *src, *dst; sizet i; VERIFY_INTS("make_stk_seg", 0L); while NIMP(estk_pool) { if (size==LENGTH(estk_pool)) { seg = estk_pool; estk_pool = SCM_ESTK_PARENT(seg); break; } estk_pool = SCM_ESTK_PARENT(estk_pool); } if (IMP(seg)) seg = must_malloc_cell((long)size*sizeof(SCM), MAKE_LENGTH(size, tc7_vector), s_estk); dst = VELTS(seg); if (NIMP(contents)) { src = VELTS(contents); for (i = size; i--;) dst[i] = src[i]; } else { for (i = size; i--;) dst[i] = UNSPECIFIED; SCM_ESTK_PARENT(seg) = BOOL_F; SCM_ESTK_PARENT_INDEX(seg) = INUM0; dst[SCM_ESTK_BASE - 1] = UNDEFINED; /* underflow sentinel */ } dst[size - 1] = UNDEFINED; /* overflow sentinel */ return seg; } /* size is a number of SCM elements, or zero for a default size. If nonzero, size must be SCM_ESTK_BASE + N * SCM_ESTK_FRLEN + 1 for some reasonable number of stackframes N */ void scm_estk_reset(size) sizet size; { VERIFY_INTS("scm_estk_reset", 0L); if (!size) size = SCM_ESTK_BASE + 20*SCM_ESTK_FRLEN + 1; scm_estk = make_stk_seg(size, UNDEFINED); scm_estk_ptr = &(VELTS(scm_estk)[SCM_ESTK_BASE]); scm_estk_size = size + 0L; } void scm_estk_grow() { /* 40 and 10 below are adjustable parameters: the number of frames in a stack segment, and the number of frames to overlap between stack segments. */ sizet size = 40 * SCM_ESTK_FRLEN + SCM_ESTK_BASE + 1; sizet overlap = 10*SCM_ESTK_FRLEN; SCM estk = make_stk_seg(size, UNDEFINED); SCM *newv, *oldv; sizet i, j; newv = VELTS(estk); oldv = VELTS(scm_estk); j = scm_estk_ptr - oldv + SCM_ESTK_FRLEN - overlap; SCM_ESTK_PARENT(estk) = scm_estk; SCM_ESTK_PARENT_WRITABLEP(estk) = BOOL_T; SCM_ESTK_PARENT_INDEX(estk) = MAKINUM(j - SCM_ESTK_FRLEN); for (i = SCM_ESTK_BASE; i < SCM_ESTK_BASE + overlap; i++, j++) { newv[i] = oldv[j]; oldv[j] = BOOL_F; } scm_estk = estk; scm_estk_ptr = &(newv[SCM_ESTK_BASE + overlap]); scm_estk_size += size + 0L; /* growth_mon(s_estk, scm_estk_size, "locations", !0); */ } void scm_estk_shrink() { SCM parent; sizet i; parent = SCM_ESTK_PARENT(scm_estk); i = INUM(SCM_ESTK_PARENT_INDEX(scm_estk)); if (IMP(parent)) wta(UNDEFINED, "underflow", s_estk); if (BOOL_F==SCM_ESTK_PARENT_WRITABLEP(scm_estk)) { parent = make_stk_seg((sizet)LENGTH(parent), parent); SCM_ESTK_PARENT_WRITABLEP(parent) = BOOL_F; } SCM_ESTK_PARENT(scm_estk) = estk_pool; estk_pool = scm_estk; scm_estk_size -= LENGTH(scm_estk); scm_estk = parent; scm_estk_ptr = &(VELTS(parent)[i]); /* growth_mon(s_estk, scm_estk_size, "locations", 0); */ } void scm_env_cons(x, y) SCM x, y; { register SCM z; register int i; DEFER_INTS_EGC; i = scm_ecache_index; if (1>i) { scm_egc(); i = scm_ecache_index; } z = PTR2SCM(&(scm_ecache[--i])); CAR(z) = x; CDR(z) = y; scm_env_tmp = z; scm_ecache_index = i; } void scm_env_cons2(w, x, y) SCM w, x, y; { SCM z1, z2; register int i; DEFER_INTS_EGC; i = scm_ecache_index; if (2>i) { scm_egc(); i = scm_ecache_index; } z1 = PTR2SCM(&(scm_ecache[--i])); CAR(z1) = x; CDR(z1) = y; z2 = PTR2SCM(&(scm_ecache[--i])); CAR(z2) = w; CDR(z2) = z1; scm_env_tmp = z2; scm_ecache_index = i; } void scm_env_cons3(v, w, x, y) SCM v, w, x, y; { SCM z1, z2; register int i; DEFER_INTS_EGC; i = scm_ecache_index; if (3>i) { scm_egc(); i = scm_ecache_index; } z1 = PTR2SCM(&(scm_ecache[--i])); CAR(z1) = x; CDR(z1) = y; z2 = PTR2SCM(&(scm_ecache[--i])); CAR(z2) = w; CDR(z2) = z1; z1 = PTR2SCM(&(scm_ecache[--i])); CAR(z1) = v; CDR(z1) = z2; scm_env_tmp = z1; scm_ecache_index = i; } void scm_env_v2lst(argc, argv) long argc; SCM *argv; { SCM z1, z2; register int i; DEFER_INTS_EGC; i = scm_ecache_index; if (argc>i) { scm_egc(); i = scm_ecache_index; } z1 = z2 = scm_env_tmp; /* set z1 just in case argc is zero */ while (argc--) { z1 = PTR2SCM(&(scm_ecache[--i])); CAR(z1) = argv[argc]; CDR(z1) = z2; z2 = z1; } scm_env_tmp = z1; scm_ecache_index = i; } /* scm_env = acons(names, scm_env_tmp, scm_env) */ void scm_extend_env() { SCM z; register int i; DEFER_INTS_EGC; i = scm_ecache_index; if (1>i) { scm_egc(); i = scm_ecache_index; } z = PTR2SCM(&(scm_ecache[--i])); CAR(z) = scm_env_tmp; CDR(z) = scm_env; scm_env = z; scm_ecache_index = i; } void old_scm_extend_env(names) SCM names; { SCM z1, z2; register int i; DEFER_INTS_EGC; i = scm_ecache_index; if (2>i) { scm_egc(); i = scm_ecache_index; } z1 = PTR2SCM(&(scm_ecache[--i])); CAR(z1) = names; CDR(z1) = scm_env_tmp; z2 = PTR2SCM(&(scm_ecache[--i])); CAR(z2) = z1; CDR(z2) = scm_env; scm_env = z2; scm_ecache_index = i; } char s_obunhash[] = "object-unhash", s_cache_gc[] = "cache_gc"; char s_recursive[] = "recursive"; #define s_gc (s_cache_gc+6) static iproc subr0s[] = { {"tmpnam", ltmpnam}, {"open-ports", scm_open_ports}, {0, 0}}; static iproc subr1s[] = { {s_input_portp, input_portp}, {s_output_portp, output_portp}, {s_port_closedp, port_closedp}, {s_close_port, close_port}, {"eof-object?", eof_objectp}, {"port-type", scm_port_type}, {s_cwos, cwos}, {"object-hash", obhash}, {s_obunhash, obunhash}, {s_del_fil, del_fil}, {0, 0}}; static iproc subr2s[] = { {s_try_open_file, try_open_file}, {s_cwis, cwis}, {s_mksfpt, mksfpt}, {s_add_finalizer, scm_add_finalizer}, {0, 0}}; SCM dynwind P((SCM thunk1, SCM thunk2, SCM thunk3)); void init_io() { make_subr("dynamic-wind", tc7_subr_3, dynwind); make_subr(s_gc, tc7_subr_1o, gc); init_iprocs(subr0s, tc7_subr_0); init_iprocs(subr1s, tc7_subr_1); init_iprocs(subr2s, tc7_subr_2); loc_open_file = &CDR(sysintern(s_open_file, CDR(sysintern(s_try_open_file, UNDEFINED)))); loc_try_create_file = &CDR(sysintern(s_try_create_file, UNDEFINED)); #ifndef CHEAP_CONTINUATIONS add_feature("full-continuation"); #endif #ifdef TEST_FINAL add_final(test_final); #endif } void grew_lim(nm) long nm; { growth_mon(s_limit, nm, "bytes", !0); } int expmem = 0; sizet hplim_ind = 0; long heap_cells = 0; CELLPTR *hplims, heap_org; VOLATILE SCM freelist = EOL; long mltrigger, mtrigger = INIT_MALLOC_LIMIT; int gc_hook_pending = 0, gc_hook_active = 0; /* Ints should be deferred when calling igc_for_alloc. */ static char *igc_for_alloc(where, olen, size, what) char *where; long olen; sizet size; const char *what; { char *ptr; long nm; /* Check to see that heap is initialized */ ASRTER(heap_cells > 0, MAKINUM(size), NALLOC, what); /* printf("igc_for_alloc(%lx, %lu, %u, %s)\n", where, olen, size, what); fflush(stdout); */ igc(what, rootcont); nm = mallocated + size - olen; if (nm > mltrigger) { if (nm > mtrigger) grew_lim(nm + nm/2); else grew_lim(mtrigger + mtrigger/2); } if (where) SYSCALL(ptr = (char *)realloc(where, size);); else SYSCALL(ptr = (char *)malloc(size);); ASRTER(ptr, MAKINUM(size), NALLOC, what); if (nm > mltrigger) { if (nm > mtrigger) mtrigger = nm + nm/2; else mtrigger += mtrigger/2; mltrigger = mtrigger - MIN_MALLOC_YIELD; } mallocated = nm; return ptr; } char *must_malloc(len, what) long len; const char *what; { char *ptr; sizet size = len; long nm = mallocated + size; VERIFY_INTS("must_malloc", what); #ifdef SHORT_SIZET ASRTER(len==size, MAKINUM(len), NALLOC, what); #endif if (nm <= mtrigger) SYSCALL(ptr = (char *)malloc(size);); else ptr = 0; if (!ptr) ptr = igc_for_alloc(0L, 0L, size, what); else mallocated = nm; /* printf("must_malloc(%lu, %s) => %lx\n", len, what, ptr); fflush(stdout); */ return ptr; } SCM must_malloc_cell(len, c, what) long len; SCM c; const char *what; { SCM z; char *ptr; sizet size = len; long nm = mallocated + size; VERIFY_INTS("must_malloc_cell", what); #ifdef SHORT_SIZET ASRTER(len==size, MAKINUM(len), NALLOC, what); #endif NEWCELL(z); if (nm <= mtrigger) SYSCALL(ptr = (char *)malloc(size);); else ptr = 0; if (!ptr) ptr = igc_for_alloc(0L, 0L, size, what); else mallocated = nm; /* printf("must_malloc_cell(%lu, %lx, %s) => %lx\n", len, c, what, ptr); fflush(stdout); */ SETCHARS(z, ptr); CAR(z) = c; return z; } char *must_realloc(where, olen, len, what) char *where; long olen, len; const char *what; { char *ptr; sizet size = len; long nm = mallocated + size - olen; VERIFY_INTS("must_realloc", what); #ifdef SHORT_SIZET ASRTER(len==size, MAKINUM(len), NALLOC, what); #endif ASRTER(!errjmp_bad, MAKINUM(len), NALLOC, what); /* printf("must_realloc(%lx, %lu, %lu, %s)\n", where, olen, len, what); fflush(stdout); printf("nm = %ld <= mtrigger = %ld: %d; size = %u\n", nm, mtrigger, (nm <= mtrigger), size); fflush(stdout); */ if (nm <= mtrigger) SYSCALL(ptr = (char *)realloc(where, size);); else ptr = 0; if (!ptr) ptr = igc_for_alloc(where, olen, size, what); else mallocated = nm; return ptr; } void must_realloc_cell(z, olen, len, what) SCM z; long olen, len; const char *what; { char *ptr, *where = CHARS(z); sizet size = len; long nm = mallocated + size - olen; VERIFY_INTS("must_realloc_cell", what); #ifdef SHORT_SIZET ASRTER(len==size, MAKINUM(len), NALLOC, what); #endif ASRTER(!errjmp_bad, MAKINUM(len), NALLOC, what); /* printf("must_realloc_cell(%lx, %lu, %lu, %s)\n", z, olen, len, what); fflush(stdout); */ if (nm <= mtrigger) SYSCALL(ptr = (char *)realloc(where, size);); else ptr = 0; if (!ptr) ptr = igc_for_alloc(where, olen, size, what); else mallocated = nm; SETCHARS(z, ptr); } void must_free(obj, len) char *obj; sizet len; { if (obj) { #ifdef CAREFUL_INTS while (len--) obj[len] = '#'; #endif /* printf("free(%lx)\n", obj); fflush(stdout); */ free(obj); mallocated = mallocated - len; } else wta(INUM0, "already free", ""); } SCM symhash; /* This used to be a sys_protect, but Radey Shouman added GC for unused, UNDEFINED symbols.*/ int symhash_dim = NUM_HASH_BUCKETS; /* sym2vcell looks up the symbol in the symhash table. */ SCM sym2vcell(sym) SCM sym; { SCM lsym, z; sizet hash = strhash(UCHARS(sym), (sizet)LENGTH(sym), (unsigned long)symhash_dim); for (lsym = VELTS(symhash)[hash];NIMP(lsym);lsym = CDR(lsym)) { z = CAR(lsym); if (CAR(z)==sym) return z; } wta(sym, "uninterned symbol? ", ""); } /* intern() and sysintern() return a pair; CAR is the symbol, CDR is the value. */ SCM intern(name, len) char *name; sizet len; { SCM lsym, z; register sizet i = len; register unsigned char *tmp = (unsigned char *)name; sizet hash = strhash(tmp, i, (unsigned long)symhash_dim); /* printf("intern %s len=%d\n",name,len); fflush(stdout); */ DEFER_INTS; for (lsym = VELTS(symhash)[hash];NIMP(lsym);lsym = CDR(lsym)) { z = CAR(lsym); z = CAR(z); tmp = UCHARS(z); if (LENGTH(z) != len) goto trynext; for (i = len;i--;) if (((unsigned char *)name)[i] != tmp[i]) goto trynext; ALLOW_INTS; return CAR(lsym); trynext: ; } /* lsym = makfromstr(name, len); */ lsym = must_malloc_cell(len+1L, MAKE_LENGTH(len, tc7_msymbol), s_string); i = len; CHARS(lsym)[len] = 0; while (i--) CHARS(lsym)[i] = name[i]; z = acons(lsym, UNDEFINED, UNDEFINED); CDR(z) = VELTS(symhash)[hash]; VELTS(symhash)[hash] = z; z = CAR(z); ALLOW_INTS; return z; } SCM sysintern(name, val) const char *name; SCM val; { SCM lsym, z; sizet len = strlen(name); register sizet i = len; register unsigned char *tmp = (unsigned char *)name; sizet hash = strhash(tmp, i, (unsigned long)symhash_dim); for (lsym = VELTS(symhash)[hash];NIMP(lsym);lsym = CDR(lsym)) { z = CAR(lsym); z = CAR(z); tmp = UCHARS(z); if (LENGTH(z) != len) goto trynext; for (i = len;i--;) if (((unsigned char *)name)[i] != tmp[i]) goto trynext; lsym = CAR(lsym); if (!UNBNDP(val)) CDR(lsym) = val; else if (UNBNDP(CDR(lsym)) && tc7_msymbol==TYP7(CAR(lsym))) scm_gc_protect(lsym); return lsym; trynext: ; } NEWCELL(lsym); SETLENGTH(lsym, len, tc7_ssymbol); SETCHARS(lsym, name); lsym = cons(lsym, val); z = cons(lsym, UNDEFINED); CDR(z) = VELTS(symhash)[hash]; VELTS(symhash)[hash] = z; return lsym; } SCM cons(x, y) SCM x, y; { register SCM z; NEWCELL(z); CAR(z) = x; CDR(z) = y; return z; } SCM cons2(w, x, y) SCM w, x, y; { register SCM z; NEWCELL(z); CAR(z) = x; CDR(z) = y; x = z; NEWCELL(z); CAR(z) = w; CDR(z) = x; return z; } SCM acons(w, x, y) SCM w, x, y; { register SCM z; NEWCELL(z); CAR(z) = w; CDR(z) = x; x = z; NEWCELL(z); CAR(z) = x; CDR(z) = y; return z; } SCM makstr(len) long len; { SCM s; #ifndef SHORT_SIZET ASRTER(!(len & ~LENGTH_MAX), MAKINUM(len), NALLOC, s_string); #endif DEFER_INTS; s = must_malloc_cell(len+1L, MAKE_LENGTH(len, tc7_string), s_string); CHARS(s)[len] = 0; ALLOW_INTS; return s; } char s_redefining[] = "redefining "; scm_gra subrs_gra; SCM scm_maksubr(name, type, fcn) const char *name; int type; SCM (*fcn)(); { subr_info info; int isubr; register SCM z; info.name = name; for (isubr = subrs_gra.len; 0 < isubr--;) { if (0==strcmp(((char **)subrs_gra.elts)[isubr], name)) { scm_warn(s_redefining, (char *)name, UNDEFINED); goto foundit; } } isubr = scm_grow_gra(&subrs_gra, (char *)&info); foundit: NEWCELL(z); if (!fcn && tc7_cxr==type) { const char *p = name; int code = 0; while (*++p != 'r') switch (*p) { default: wta(UNDEFINED, "bad cxr name", (char *)name); case 'a': code = (code<<2) + 1; continue; case 'd': code = (code<<2) + 2; continue; } type += (code << 8); } CAR(z) = (isubr<<16) + type; SUBRF(z) = fcn; return z; } SCM make_subr(name, type, fcn) const char *name; int type; SCM (*fcn)(); { return CDR(sysintern(name, scm_maksubr(name, type, fcn))); } #ifdef CCLO char s_comp_clo[] = "compiled-closure"; SCM makcclo(proc, len) SCM proc; long len; { SCM s; # ifndef SHORT_SIZET ASRTER(len < (((unsigned long)-1L)>>16), UNDEFINED, NALLOC, s_comp_clo); # endif DEFER_INTS; s = must_malloc_cell(len*sizeof(SCM), MAKE_NUMDIGS(len, tc16_cclo), s_comp_clo); while (--len) VELTS(s)[len] = UNSPECIFIED; CCLO_SUBR(s) = proc; ALLOW_INTS; return s; } #endif void stack_check() { STACKITEM *start = CONT(rootcont)->stkbse; STACKITEM stack; #ifdef STACK_GROWS_UP if (&stack - start > STACK_LIMIT/sizeof(STACKITEM)) #else if (start - &stack > STACK_LIMIT/sizeof(STACKITEM)) #endif /* def STACK_GROWS_UP */ { stack_report(); wta(UNDEFINED, (char *)SEGV_SIGNAL, "stack"); } } void stack_report() { STACKITEM stack; lputs(";; stack: 0x", cur_errp); scm_intprint((long)CONT(rootcont)->stkbse, -16, cur_errp); lputs(" - 0x", cur_errp); scm_intprint((long)&stack, -16, cur_errp); lputs("; ", cur_errp); scm_intprint(stack_size(CONT(rootcont)->stkbse)*sizeof(STACKITEM), 10, cur_errp); lputs(" bytes\n", cur_errp); } SCM dynwind(thunk1, thunk2, thunk3) SCM thunk1, thunk2, thunk3; { SCM ans; apply(thunk1, EOL, EOL); dynwinds = acons(thunk1, thunk3, dynwinds); ans = apply(thunk2, EOL, EOL); dynwinds = CDR(dynwinds); apply(thunk3, EOL, EOL); return ans; } void downd(to, delta) SCM to; long delta; { tail: if (dynwinds==to); else if (0 > delta) { downd(CDR(to), 1+delta); apply(CAR(CAR(to)), EOL, EOL); dynwinds = to; } else { SCM from = CDR(CAR(dynwinds)); dynwinds = CDR(dynwinds); apply(from, EOL, EOL); delta--; goto tail; /* downd(to, delta-1); */ } } void dowinds(to) SCM to; { downd(to, ilength(dynwinds) - ilength(to)); } /* Remember that setjump needs to be called after scm_make_cont */ SCM scm_make_cont() { SCM cont, estk, *from; CONTINUATION *ncont; sizet n; VERIFY_INTS("scm_make_cont", 0L); NEWCELL(cont); from = VELTS(scm_estk); n = scm_estk_ptr - from + SCM_ESTK_FRLEN; #ifdef CHEAP_CONTINUATIONS estk = scm_estk; #else from[1] = BOOL_F; /* Can't write to parent stack */ estk = must_malloc_cell((long)n*sizeof(SCM), MAKE_LENGTH(n, tc7_vector), s_cont); { SCM *to = VELTS(estk); while(n--) to[n] = from[n]; } #endif ncont = make_continuation(CONT(rootcont)); if (!ncont) wta(MAKINUM(-1), (char *)NALLOC, s_cont); ncont->other.parent = rootcont; SETCONT(cont, ncont); SETLENGTH(cont, ncont->length, tc7_contin); ncont->other.dynenv = dynwinds; ncont->other.stkframe[0] = scm_env; ncont->other.stkframe[1] = scm_env_tmp; ncont->other.estk = estk; #ifdef CHEAP_CONTINUATIONS ncont->other.estk_ptr = scm_estk_ptr; #else ncont->other.estk_ptr = (SCM *)0; #endif #ifndef RECKLESS ncont->other.stkframe[2] = scm_trace_env; ncont->other.stkframe[3] = scm_trace; #endif return cont; } static char s_sstale[] = "strangely stale"; void scm_dynthrow(tocont, arg1, arg2, rest) SCM tocont; SCM arg1, arg2, rest; { CONTINUATION *cont = CONT(tocont); if (cont->stkbse != CONT(rootcont)->stkbse) wta(tocont, &s_sstale[10], s_cont); dowinds(cont->other.dynenv); { DEFER_INTS; #ifdef CHEAP_CONTINUATIONS scm_estk = cont->other.estk; scm_estk_ptr = cont->other.estk_ptr; #else { SCM *to, *from = VELTS(cont->other.estk); sizet n = LENGTH(cont->other.estk); if (LENGTH(scm_estk) < n) scm_estk_reset(n); to = VELTS(scm_estk); scm_estk_ptr = &(to[n - SCM_ESTK_FRLEN]); while(n--) to[n] = from[n]; } #endif scm_env = cont->other.stkframe[0]; scm_env_tmp = cont->other.stkframe[1]; #ifndef RECKLESS scm_trace_env = cont->other.stkframe[2]; scm_trace = cont->other.stkframe[3]; #endif if (!UNBNDP(arg2) && IM_VALUES_TOKEN == scm_env_tmp) { scm_env_cons(arg2, rest); arg2 = UNDEFINED; } ALLOW_INTS; } if (!UNBNDP(arg2)) return; /* eval will signal wrong number of args */ throw_to_continuation(cont, arg1, CONT(rootcont)); wta(tocont, s_sstale, s_cont); } SCM obhash(obj) SCM obj; { #ifdef BIGDIG long n = SRS(obj, 1); if (!FIXABLE(n)) return long2big(n); #endif return (obj<<1)+2L; } SCM obunhash(obj) SCM obj; { #ifdef BIGDIG if (NIMP(obj) && BIGP(obj)) { sizet i = NUMDIGS(obj); BIGDIG *ds = BDIGITS(obj); if (TYP16(obj)==tc16_bigpos) { obj = 0; while (i--) obj = BIGUP(obj) + ds[i]; } else { obj = 0; while (i--) obj = BIGUP(obj) - ds[i]; } obj <<= 1; goto comm; } #endif ASRTER(INUMP(obj), obj, ARG1, s_obunhash); obj = SRS(obj, 1) & ~1L; comm: if (IMP(obj)) return obj; if (NCELLP(obj)) return BOOL_F; { /* This code is adapted from mark_locations() in "sys.c" and scm_cell_p() in "rope.c", which means that changes to these routines must be coordinated. */ register CELLPTR ptr = (CELLPTR)SCM2PTR(obj); register sizet i = 0, j = hplim_ind; do { if (PTR_GT(hplims[i++], ptr)) break; if (PTR_LE(hplims[--j], ptr)) break; if ((i != j) && PTR_LE(hplims[i++], ptr) && PTR_GT(hplims[--j], ptr)) continue; if (NFREEP(obj)) return obj; break; } while(i5) { sizet i = 5; unsigned long h = 264 % n; while (i--) h = ((h<<8) + ((unsigned)(downcase[str[h % len]]))) % n; return h; } else { sizet i = len; unsigned long h = 0; while (i) h = ((h<<8) + ((unsigned)(downcase[str[--i]]))) % n; return h; } } static void fixconfig(s1, s2, s) char *s1, *s2; int s; { fputs(s1, stderr); fputs(s2, stderr); fputs("\nin ", stderr); fputs(s ? "setjump" : "scmfig", stderr); fputs(".h and recompile scm\n", stderr); quit(MAKINUM(1L)); } void heap_report() { sizet i = 0; if (hplim_ind) lputs("; heap segments:", sys_errp); while(i < hplim_ind) { { long seg_cells = CELL_DN(hplims[i+1]) - CELL_UP(hplims[i]); lputs("\n; 0x", sys_errp); scm_intprint((long)hplims[i++], -16, sys_errp); lputs(" - 0x", sys_errp); scm_intprint((long)hplims[i++], -16, sys_errp); lputs("; ", sys_errp); scm_intprint(seg_cells, 10, sys_errp); lputs(" cells; ", sys_errp); scm_intprint(seg_cells / (1024 / sizeof(CELLPTR)), 10, sys_errp); lputs(".kiB", sys_errp); }} } sizet init_heap_seg(seg_org, size) CELLPTR seg_org; sizet size; { register CELLPTR ptr = seg_org; #ifdef POINTERS_MUNGED register SCM scmptr; #else # define scmptr ptr #endif CELLPTR seg_end = CELL_DN((char *)ptr + size); sizet i = hplim_ind, ni = 0; if (ptr==NULL) return 0; while((ni < hplim_ind) && PTR_LE(hplims[ni], seg_org)) ni++; while(i-- > ni) hplims[i+2] = hplims[i]; hplim_ind += 2; hplims[ni++] = ptr; /* same as seg_org here */ hplims[ni++] = seg_end; ptr = CELL_UP(ptr); ni = seg_end - ptr; /* printf("ni = %u; hplim_ind = %u\n", ni, hplim_ind); */ /* printf("ptr = %lx\n", ptr); */ for (i = ni;i--;ptr++) { #ifdef POINTERS_MUNGED scmptr = PTR2SCM(ptr); #endif CAR(scmptr) = (SCM)tc_free_cell; CDR(scmptr) = PTR2SCM(ptr+1); } /* CDR(scmptr) = freelist; */ CDR(PTR2SCM(--ptr)) = freelist; freelist = PTR2SCM(CELL_UP(seg_org)); heap_cells += ni; return size; #ifdef scmptr # undef scmptr #endif } static void alloc_some_heap() { CELLPTR ptr, *tmplims; sizet len = (2+hplim_ind)*sizeof(CELLPTR); ASRTGO(len==(2+hplim_ind)*sizeof(CELLPTR), badhplims); if (errjmp_bad) wta(UNDEFINED, "need larger initial", s_heap); tmplims = (CELLPTR *)must_realloc((char *)hplims, len-2L*sizeof(CELLPTR), (long)len, s_heap); /* SYSCALL(tmplims = (CELLPTR *)realloc((char *)hplims, len);); */ if (!tmplims) badhplims: wta(UNDEFINED, s_nogrow, s_hplims); else hplims = tmplims; /* hplim_ind gets incremented in init_heap_seg() */ if (expmem) { len = (sizet)(EXPHEAP(heap_cells)*sizeof(cell)); if ((sizet)(EXPHEAP(heap_cells)*sizeof(cell)) != len) len = 0; } else len = HEAP_SEG_SIZE; while (len >= MIN_HEAP_SEG_SIZE) { SYSCALL(ptr = (CELLPTR) malloc(len);); if (ptr) { init_heap_seg(ptr, len); return; } len /= 2; } wta(UNDEFINED, s_nogrow, s_heap); } /* Initialize a Growable arRAy, of initial size LEN, growing to at most MAXLEN elements of size ELTSIZE */ void scm_init_gra(gra, eltsize, len, maxlen, what) scm_gra *gra; sizet eltsize, len, maxlen; const char *what; { char *nelts; /* DEFER_INTS; */ /* Can't call must_malloc, because heap may not be initialized yet. */ /* SYSCALL(nelts = malloc(len*eltsize);); if (!nelts) wta(MAKINUM(len*eltsize), (char *)NALLOC, what); mallocated += len*eltsize; */ nelts = must_malloc((long)len*eltsize, what); gra->eltsize = eltsize; gra->len = 0; gra->elts = nelts; gra->alloclen = len; gra->maxlen = maxlen; gra->what = what; /* ALLOW_INTS; */ } /* Returns the index into the elt array */ int scm_grow_gra(gra, elt) scm_gra *gra; char *elt; { int i; char *tmp; if (gra->alloclen <= gra->len) { sizet inc = gra->len / 5 + 1; sizet nlen = gra->len + inc; if (gra->maxlen && nlen > gra->maxlen) /* growerr: */ wta(MAKINUM(nlen), (char *)NALLOC, gra->what); /* SYSCALL(tmp = realloc(gra->elts, nlen*gra->eltsize);); if (!tmp) goto growerr; mallocated += (nlen - gra->alloclen)*gra->eltsize; */ tmp = must_realloc(gra->elts, (long)gra->alloclen*gra->eltsize, (long)nlen*gra->eltsize, gra->what); gra->elts = tmp; gra->alloclen = nlen; } tmp = &gra->elts[gra->len*gra->eltsize]; gra->len += 1; for (i = 0; i < gra->eltsize; i++) tmp[i] = elt[i]; return gra->len - 1; } void scm_trim_gra(gra) scm_gra *gra; { char *tmp; long curlen = gra->len; if (0L==curlen) curlen = 1L; if (curlen==(long)gra->alloclen) return; tmp = must_realloc(gra->elts, (long)gra->alloclen * gra->eltsize, curlen * gra->eltsize, gra->what); gra->elts = tmp; gra->alloclen = curlen; } void scm_free_gra(gra) scm_gra *gra; { free(gra->elts); gra->elts = 0; mallocated -= gra->maxlen*gra->eltsize; } void gra_report1(gra) scm_gra *gra; { scm_intprint((long)gra->len, -10, cur_errp); lputs(" (of ", cur_errp); scm_intprint((long)gra->alloclen, -10, cur_errp); lputs(") ", cur_errp); lputs(gra->what, cur_errp); lputs("; ", cur_errp); } void gra_report() { lputs(";; gra: ", cur_errp); gra_report1(&ptobs_gra); gra_report1(&smobs_gra); gra_report1(&finals_gra); gra_report1(&subrs_gra); lputs("\n", cur_errp); } scm_gra smobs_gra; long newsmob(smob) smobfuns *smob; { return tc7_smob + 256*scm_grow_gra(&smobs_gra, (char *)smob); } scm_gra ptobs_gra; long newptob(ptob) ptobfuns *ptob; { return tc7_port + 256*scm_grow_gra(&ptobs_gra, (char *)ptob); } port_info *scm_port_table = 0; static sizet scm_port_table_len = 0; static char s_port_table[] = "port table"; SCM scm_port_entry(stream, ptype, flags) FILE *stream; long ptype, flags; { SCM z; sizet nlen; int i, j; VERIFY_INTS("scm_port_entry", 0L); flags = flags | (ptype & ~0xffffL); ASRTER(flags, INUM0, ARG1, "scm_port_entry"); for (i = 1; i < scm_port_table_len; i++) if (0L==scm_port_table[i].flags) goto ret; if (scm_port_table_len <= SCM_PORTNUM_MAX) { nlen = scm_port_table_len + (scm_port_table_len / 2); if (nlen >= SCM_PORTNUM_MAX) nlen = (sizet)SCM_PORTNUM_MAX + 1; scm_port_table = (port_info *) must_realloc((char *)scm_port_table, (long)scm_port_table_len * sizeof(port_info), (long)nlen * sizeof(port_info), s_port_table); scm_port_table_len = nlen; growth_mon(s_port_table, nlen + 0L, "entries", !0); for (j = i; j < scm_port_table_len; j++) { scm_port_table[j].flags = 0L; scm_port_table[j].data = UNDEFINED; scm_port_table[j].port = UNDEFINED; } } else { igc(s_port_table, rootcont); for (i = 0; i < scm_port_table_len; i++) if (0L==scm_port_table[i].flags) goto ret; wta(UNDEFINED, s_nogrow, s_port_table); } ret: NEWCELL(z); SETSTREAM(z, stream); CAR(z) = (((long)i)<<20) | (flags & 0x0f0000) | ptype; scm_port_table[i].unread = EOF; scm_port_table[i].flags = flags; scm_port_table[i].line = 1L; /* should both be one-based? */ scm_port_table[i].col = 1; scm_port_table[i].data = UNSPECIFIED; scm_port_table[i].port = z; return z; } SCM scm_open_ports() { SCM p, res = EOL; int k; for (k = scm_port_table_len - 1; k > 0; k--) { p = scm_port_table[k].port; if (NIMP(p) && OPPORTP(p)) res = cons(p, res); } return res; } SCM markcdr(ptr) SCM ptr; { return CDR(ptr); } sizet free0(ptr) CELLPTR ptr; { return 0; } SCM equal0(ptr1, ptr2) SCM ptr1, ptr2; { return (CDR(ptr1)==CDR(ptr2)) ? BOOL_T : BOOL_F; } static char remsg[] = "remove\n#define ", addmsg[] = "add\n#define ", rdmsg[] = "reduce"; void init_storage(stack_start_ptr, init_heap_size) STACKITEM *stack_start_ptr; long init_heap_size; { sizet j; /* Because not all protects may get initialized */ freelist = EOL; expmem = 0; estk_pool = EOL; scm_estk = BOOL_F; scm_port_table = 0; scm_port_table_len = 0; #ifdef SHORT_SIZET if (sizeof(sizet) >= sizeof(long)) fixconfig(remsg, "SHORT_SIZET", 0); #else if (sizeof(sizet) < sizeof(long)) fixconfig(addmsg, "SHORT_SIZET", 0); #endif #ifdef SHORT_INT if (sizeof(int) >= sizeof(long)) fixconfig(remsg, "SHORT_INT", 0); #else if (sizeof(int) < sizeof(long)) fixconfig(addmsg, "SHORT_INT", 0); #endif #ifdef CDR_DOUBLES if (sizeof(double) != sizeof(long)) fixconfig(remsg, "CDR_DOUBLES", 0); #else # ifdef SINGLES if (sizeof(float) != sizeof(long)) { if (sizeof(double) == sizeof(long)) fixconfig(addmsg, "CDR_DOUBLES", 0); else fixconfig(remsg, "SINGLES", 0); } # endif #endif #ifdef BIGDIG if (2*BITSPERDIG/CHAR_BIT > sizeof(long)) fixconfig(remsg, "BIGDIG", 0); # ifndef DIGSTOOBIG if (DIGSPERLONG*sizeof(BIGDIG) > sizeof(long)) fixconfig(addmsg, "DIGSTOOBIG", 0); # endif if (NUMDIGS_MAX > (((unsigned long)-1L)>>16)) fixconfig(rdmsg, "NUMDIGS_MAX", 0); #endif #ifdef STACK_GROWS_UP if (((STACKITEM *)&j - stack_start_ptr) < 0) fixconfig(remsg, "STACK_GROWS_UP", 1); #else if ((stack_start_ptr - (STACKITEM *)&j) < 0) fixconfig(addmsg, "STACK_GROWS_UP", 1); #endif j = HEAP_SEG_SIZE; if (HEAP_SEG_SIZE != j) fixconfig(rdmsg, "size of HEAP_SEG_SIZE", 0); mtrigger = INIT_MALLOC_LIMIT; mltrigger = mtrigger - MIN_MALLOC_YIELD; hplims = (CELLPTR *) must_malloc(2L*sizeof(CELLPTR), s_hplims); if (0L==init_heap_size) init_heap_size = INIT_HEAP_SIZE; j = init_heap_size; /* printf("j = %u; init_heap_size = %lu\n", j, init_heap_size); */ if ((init_heap_size != j) || !init_heap_seg((CELLPTR) malloc(j), j)) { j = HEAP_SEG_SIZE; /* printf("j = %u; HEAP_SEG_SIZE = %lu\n", j, HEAP_SEG_SIZE); */ if (!init_heap_seg((CELLPTR) malloc(j), j)) wta(MAKINUM(j), (char *)NALLOC, s_heap); } else expmem = 1; heap_org = CELL_UP(hplims[0]); /* hplims[0] can change. do not remove heap_org */ scm_port_table_len = 16; scm_port_table = (port_info *) must_malloc((long)scm_port_table_len * sizeof(port_info), s_port_table); for (j = 0; j < scm_port_table_len; j++) { scm_port_table[j].flags = 0L; scm_port_table[j].data = UNDEFINED; scm_port_table[j].port = UNDEFINED; } nullstr = must_malloc_cell(1L, MAKE_LENGTH(0, tc7_string), s_string); CHARS(nullstr)[0] = 0; nullvect = must_malloc_cell(1L, MAKE_LENGTH(0, tc7_vector), s_vector); { long i = symhash_dim; SCM *velts; symhash = must_malloc_cell(i * sizeof(SCM), MAKE_LENGTH(i, tc7_vector), s_vector); velts = VELTS(symhash); while(--i >= 0) (velts)[i] = EOL; } /* Now that symhash is setup, we can sysintern() */ sysintern("most-positive-fixnum", (SCM)MAKINUM(MOST_POSITIVE_FIXNUM)); sysintern("most-negative-fixnum", (SCM)MAKINUM(MOST_NEGATIVE_FIXNUM)); #ifdef BIGDIG sysintern("bignum-radix", MAKINUM(BIGRAD)); #endif def_inp = scm_port_entry(stdin, tc16_fport, OPN|RDNG); SCM_PORTDATA(def_inp) = CAR(sysintern("stdin", UNDEFINED)); def_outp = scm_port_entry(stdout, tc16_fport, OPN|WRTNG|TRACKED); SCM_PORTDATA(def_outp) = CAR(sysintern("stdout", UNDEFINED)); NEWCELL(def_errp); CAR(def_errp) = (tc16_fport|OPN|WRTNG); SETSTREAM(def_errp, stderr); cur_inp = def_inp; cur_outp = def_outp; cur_errp = def_errp; NEWCELL(sys_errp); CAR(sys_errp) = (tc16_sysport|OPN|WRTNG); SETSTREAM(sys_errp, 0); sys_safep = mksafeport(0, def_errp); dynwinds = EOL; NEWCELL(rootcont); SETCONT(rootcont, make_root_continuation(stack_start_ptr)); CAR(rootcont) = tc7_contin; CONT(rootcont)->other.dynenv = EOL; CONT(rootcont)->other.parent = BOOL_F; listofnull = cons(EOL, EOL); undefineds = cons(UNDEFINED, EOL); CDR(undefineds) = undefineds; /* flo0 is now setup in scl.c */ /* Set up environment cache */ scm_ecache_len = sizeof(ecache_v)/sizeof(cell); scm_ecache = CELL_UP(ecache_v); scm_ecache_len = CELL_DN(ecache_v + scm_ecache_len - 1) - scm_ecache + 1; scm_ecache_index = scm_ecache_len; scm_egc_root_index = sizeof(scm_egc_roots)/sizeof(SCM); scm_estk = BOOL_F; scm_estk_reset(0); } /* The way of garbage collecting which allows use of the cstack is due to */ /* Scheme In One Defun, but in C this time. * COPYRIGHT (c) 1989 BY * * PARADIGM ASSOCIATES INCORPORATED, CAMBRIDGE, MASSACHUSETTS. * * ALL RIGHTS RESERVED * Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Paradigm Associates Inc not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. PARADIGM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL PARADIGM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. gjc@paradigm.com Paradigm Associates Inc Phone: 617-492-6079 29 Putnam Ave, Suite 6 Cambridge, MA 02138 */ char s_cells[] = "cells"; SCM gc_for_newcell() { SCM fl; int oints = ints_disabled; /* Temporary expedient */ if (!oints) ints_disabled = 1; igc(s_cells, rootcont); if ((gc_cells_collected < MIN_GC_YIELD) || IMP(freelist)) { alloc_some_heap(); growth_mon(s_numheaps, (long)(hplim_ind/2), s_segs, !0); growth_mon(s_heap, heap_cells, s_cells, !0); } ++cells_allocated; fl = freelist; freelist = CDR(fl); ints_disabled = oints; return fl; } void gc_for_open_files() { igc("open files", rootcont); } void scm_fill_freelist() { while IMP(freelist) { igc(s_cells, rootcont); if ((gc_cells_collected < MIN_GC_YIELD) || IMP(freelist)) { alloc_some_heap(); growth_mon(s_numheaps, (long)(hplim_ind/2), s_segs, !0); growth_mon(s_heap, heap_cells, s_cells, !0); } } } static char s_bad_type[] = "unknown type in "; void mark_locations P((STACKITEM x[], sizet n)); static void mark_syms P((SCM v)); static void mark_sym_values P((SCM v)); static void mark_subrs P((void)); static void sweep_symhash P((SCM v)); static void mark_finalizers P((SCM *live, SCM *dead)); static void mark_port_table P((SCM port)); static void sweep_port_table P((void)); static void egc_mark P((void)); static void egc_sweep P((void)); SCM gc(arg) SCM arg; { DEFER_INTS; if (UNBNDP(arg)) igc("call", rootcont); else scm_egc(); ALLOW_INTS; return UNSPECIFIED; } void scm_run_finalizers(exiting) int exiting; { SCM f; if (exiting) { /* run all finalizers, we're going home. */ DEFER_INTS; while NIMP(gc_finalizers) { f = CAR(gc_finalizers); CAR(f) = CDR(f); CDR(f) = gc_finalizers_pending; gc_finalizers_pending = f; gc_finalizers = CDR(gc_finalizers); } ALLOW_INTS; } while (!0) { DEFER_INTS; if (NIMP(gc_finalizers_pending)) { f = CAR(gc_finalizers_pending); gc_finalizers_pending = CDR(gc_finalizers_pending); } else f = BOOL_F; ALLOW_INTS; if (IMP(f)) break; apply(f, EOL, EOL); } } static SCM *loc_gc_hook = 0; void scm_gc_hook () { if (gc_hook_active) { scm_warn("gc-hook thrashing?\n", "", UNDEFINED); return; } gc_hook_active = !0; if (! loc_gc_hook) loc_gc_hook = &CDR(sysintern("gc-hook", UNDEFINED)); if (NIMP(*loc_gc_hook)) apply(*loc_gc_hook, EOL, EOL); scm_run_finalizers(0); gc_hook_active = 0; } void igc(what, basecont) const char *what; SCM basecont; { int j = num_protects; long oheap_cells = heap_cells; STACKITEM * stackbase = IMP(basecont) ? 0 : CONT(basecont)->stkbse; #ifdef DEBUG_GMALLOC int err = check_frag_blocks(); if (err) wta(MAKINUM(err), "malloc corrupted", what); #endif gc_start(what); if (errjmp_bad) wta(UNDEFINED, s_recursive, s_gc); errjmp_bad = s_gc; #ifdef NO_SYM_GC gc_mark(symhash); #else /* By marking symhash first, we provide the best immunity from accidental references. In order to accidentally protect a symbol, a pointer will have to point directly at the symbol (as opposed to the vector or bucket lists). */ mark_syms(symhash); /* mark_sym_values() can be called anytime after mark_syms. */ mark_sym_values(symhash); #endif mark_subrs(); egc_mark(); if (stackbase) { #ifdef __ia64__ mark_regs_ia64(CONT(basecont)); #else jump_buf save_regs_gc_mark; FLUSH_REGISTER_WINDOWS; /* This assumes that all registers are saved into the jump_buf */ setjump(save_regs_gc_mark); mark_locations((STACKITEM *) save_regs_gc_mark, (sizet) (sizeof(STACKITEM) - 1 + sizeof save_regs_gc_mark) / sizeof(STACKITEM)); { /* stack_len is long rather than sizet in order to guarantee that &stack_len is long aligned */ # ifdef STACK_GROWS_UP # ifdef nosve long stack_len = (STACKITEM *)(&stack_len) - stackbase; # else long stack_len = stack_size(stackbase); # endif mark_locations(stackbase, (sizet)stack_len); # else # ifdef nosve long stack_len = stackbase - (STACKITEM *)(&stack_len); # else long stack_len = stack_size(stackbase); # endif mark_locations((stackbase - stack_len), (sizet)stack_len); # endif } #endif } while(j--) gc_mark(sys_protects[j]); mark_finalizers(&gc_finalizers, &gc_finalizers_pending); #ifndef NO_SYM_GC sweep_symhash(symhash); #endif gc_sweep(!stackbase); sweep_port_table(); egc_sweep(); estk_pool = EOL; errjmp_bad = (char *)0; gc_end(); if (oheap_cells != heap_cells) { int grewp = heap_cells > oheap_cells; growth_mon(s_numheaps, (long)(hplim_ind/2), s_segs, grewp); growth_mon(s_heap, heap_cells, s_cells, grewp); } gc_hook_pending = !0; deferred_proc = process_signals; } static char s_not_free[] = "not freed"; void free_storage() { DEFER_INTS; loc_gc_hook = (SCM *)0; gc_start("free"); errjmp_bad = "free_storage"; cur_inp = BOOL_F; cur_outp = BOOL_F; cur_errp = tmp_errp; sys_errp = tmp_errp; gc_mark(def_inp); /* don't want to close stdin */ gc_mark(def_outp); /* don't want to close stdout */ gc_mark(def_errp); /* don't want to close stderr */ gc_sweep(0); rootcont = BOOL_F; while (hplim_ind) { /* free heap segments */ hplim_ind -= 2; { CELLPTR ptr = CELL_UP(hplims[hplim_ind]); sizet seg_cells = CELL_DN(hplims[hplim_ind+1]) - ptr; heap_cells -= seg_cells; free((char *)hplims[hplim_ind]); hplims[hplim_ind] = 0; growth_mon(s_heap, heap_cells, s_cells, 0); fflush(stderr); }} if (heap_cells) wta(MAKINUM(heap_cells), s_not_free, s_heap); if (hplim_ind) wta((SCM)MAKINUM(hplim_ind), s_not_free, s_hplims); /* Not all cells get freed (see gc_mark() calls above). */ /* if (cells_allocated) wta(MAKINUM(cells_allocated), s_not_free, "cells"); */ /* either there is a small memory leak or I am counting wrong. */ must_free((char *)hplims, 0); /* if (mallocated) wta(MAKINUM(mallocated), s_not_free, "malloc"); */ hplims = 0; scm_free_gra(&finals_gra); scm_free_gra(&smobs_gra); scm_free_gra(&subrs_gra); gc_end(); ALLOW_INTS; /* A really bad idea, but printing does it anyway. */ exit_report(); lfflush(sys_errp); scm_free_gra(&ptobs_gra); lmallocated = mallocated = 0; /* Can't do gc_end() here because it uses ptobs which have been freed */ fflush(stdout); /* in lieu of close */ fflush(stderr); /* in lieu of close */ } #define HUGE_LENGTH(x) (LENGTH_MAX==LENGTH(x) ? *((long *)VELTS(x)) : LENGTH(x)) /* This is used to force allocation of SCM temporaries on the stack, it should be called with any SCM variables used for malloc headers and entirely local to a C procedure. */ void scm_protect_temp(ptr) SCM *ptr; { return; } static char s_gc_sym[] = "mark_syms", s_wrong_length[] = "wrong length"; void gc_mark(p) SCM p; { register long i; register SCM ptr = p; CHECK_STACK; gc_mark_loop: if (IMP(ptr)) return; gc_mark_nimp: if (NCELLP(ptr) /* #ifndef RECKLESS */ /* || PTR_GT(hplims[0], (CELLPTR)ptr) */ /* || PTR_GE((CELLPTR)ptr, hplims[hplim_ind-1]) */ /* #endif */ ) wta(ptr, "rogue pointer in ", s_heap); switch TYP7(ptr) { case tcs_cons_nimcar: if (GCMARKP(ptr)) break; SETGCMARK(ptr); if (IMP(CDR(ptr))) { /* IMP works even with a GC mark */ ptr = CAR(ptr); goto gc_mark_nimp; } gc_mark(CAR(ptr)); ptr = GCCDR(ptr); goto gc_mark_nimp; case tcs_cons_imcar: case tcs_cons_gloc: if (GCMARKP(ptr)) break; SETGCMARK(ptr); ptr = GCCDR(ptr); goto gc_mark_loop; case tcs_closures: if (GCMARKP(ptr)) break; SETGCMARK(ptr); if (IMP(GCENV(ptr))) { ptr = CODE(ptr); goto gc_mark_nimp; } gc_mark(CODE(ptr)); ptr = GCENV(ptr); goto gc_mark_nimp; case tc7_specfun: if (GC8MARKP(ptr)) break; SETGC8MARK(ptr); #ifdef CCLO if (tc16_cclo==GCTYP16(ptr)) { i = CCLO_LENGTH(ptr); if (i==0) break; while(--i>0) if (NIMP(VELTS(ptr)[i])) gc_mark(VELTS(ptr)[i]); ptr = VELTS(ptr)[0]; } else #endif ptr = CDR(ptr); goto gc_mark_loop; case tc7_vector: if (GC8MARKP(ptr)) break; SETGC8MARK(ptr); i = LENGTH(ptr); if (i==0) break; while(--i>0) if (NIMP(VELTS(ptr)[i])) gc_mark(VELTS(ptr)[i]); ptr = VELTS(ptr)[0]; goto gc_mark_loop; case tc7_contin: if (GC8MARKP(ptr)) break; SETGC8MARK(ptr); mark_locations((STACKITEM *)VELTS(ptr), (sizet)(LENGTH(ptr) + (sizeof(STACKITEM) - 1 + sizeof(CONTINUATION)) / sizeof(STACKITEM))); break; case tc7_string: case tc7_msymbol: if (GC8MARKP(ptr)) break; ASRTER(!(CHARS(ptr)[HUGE_LENGTH(ptr)]), MAKINUM(HUGE_LENGTH(ptr)), s_wrong_length, s_gc); case tc7_ssymbol: case tc7_Vbool: case tc7_VfixZ32: case tc7_VfixN32: case tc7_VfixZ16: case tc7_VfixN16: case tc7_VfixN8: case tc7_VfixZ8: case tc7_VfloR32: case tc7_VfloC32: case tc7_VfloR64: case tc7_VfloC64: SETGC8MARK(ptr); case tcs_subrs: break; case tc7_port: if (GC8MARKP(ptr)) break; SETGC8MARK(ptr); i = PTOBNUM(ptr); if (!(i < numptob)) goto def; mark_port_table(ptr); if (!ptobs[i].mark) break; ptr = (ptobs[i].mark)(ptr); goto gc_mark_loop; case tc7_smob: if (GC8MARKP(ptr)) break; SETGC8MARK(ptr); switch TYP16(ptr) { /* should be faster than going through smobs */ case tc_free_cell: /* printf("found free_cell %X ", ptr); fflush(stdout); */ ASRTER(tc_broken_heart!=CAR(ptr), ptr, "found ecache forward", s_gc); /* CDR(ptr) = UNDEFINED */; break; #ifdef BIGDIG case tcs_bignums: break; #endif #ifdef FLOATS case tc16_flo: break; #endif default: i = SMOBNUM(ptr); if (!(i < numsmob)) goto def; SETGC8MARK(ptr); if (!smobs[i].mark) break; ptr = (smobs[i].mark)(ptr); goto gc_mark_loop; } break; default: def: wta(ptr, s_bad_type, "gc_mark"); } } /* mark_locations() marks a location pointed to by x[0:n] only if `x[m]' is cell-aligned and points into a valid heap segment. This code is duplicated by obunhash() in "sys.c" and scm_cell_p() in "rope.c", which means that changes to these routines must be coordinated. */ void mark_locations(x, n) STACKITEM x[]; sizet n; { register long m = n; register int i, j; register CELLPTR ptr; while(0 <= --m) if (CELLP(*(SCM **)&x[m])) { ptr = (CELLPTR)SCM2PTR((SCM)(*(SCM **)&x[m])); i = 0; j = hplim_ind; do { if (PTR_GT(hplims[i++], ptr)) break; if (PTR_LE(hplims[--j], ptr)) break; if ((i != j) && PTR_LE(hplims[i++], ptr) && PTR_GT(hplims[--j], ptr)) continue; /* if (NFREEP(*(SCM **)&x[m])) */ gc_mark(*(SCM *)&x[m]); break; } while(ilength) scm_warn("uncollected ", "", scmptr); goto c8mrkcontinue; } minc = LENGTH(scmptr)*sizeof(STACKITEM) + sizeof(CONTINUATION); mallocated = mallocated - minc; free_continuation(CONT(scmptr)); break; /* goto freechars; */ case tc7_ssymbol: if (GC8MARKP(scmptr)) goto c8mrkcontinue; /* Do not free storage because tc7_ssymbol means scmptr's storage was not created by a call to malloc(). */ break; case tcs_subrs: continue; case tc7_port: if (GC8MARKP(scmptr)) goto c8mrkcontinue; if (OPENP(scmptr)) { int k = PTOBNUM(scmptr); if (!(k < numptob)) goto sweeperr; /* Yes, I really do mean ptobs[k].free */ /* rather than ptobs[k].close. .close */ /* is for explicit CLOSE-PORT by user */ (ptobs[k].free)(STREAM(scmptr)); gc_ports_collected++; SETSTREAM(scmptr, 0); CAR(scmptr) &= ~OPN; } break; case tc7_smob: switch GCTYP16(scmptr) { case tc_free_cell: if (GC8MARKP(scmptr)) goto c8mrkcontinue; break; #ifdef BIGDIG case tcs_bignums: if (GC8MARKP(scmptr)) goto c8mrkcontinue; minc = (NUMDIGS(scmptr)*sizeof(BIGDIG)); goto freechars; #endif /* def BIGDIG */ #ifdef FLOATS case tc16_flo: if (GC8MARKP(scmptr)) goto c8mrkcontinue; switch ((int)(CAR(scmptr)>>16)) { case (IMAG_PART | REAL_PART)>>16: minc = 2*sizeof(double); goto freechars; case REAL_PART>>16: case IMAG_PART>>16: minc = sizeof(double); goto freechars; case 0: break; default: goto sweeperr; } break; #endif /* def FLOATS */ default: if (GC8MARKP(scmptr)) goto c8mrkcontinue; { int k = SMOBNUM(scmptr); if (!(k < numsmob)) goto sweeperr; minc = (smobs[k].free)((CELLPTR)scmptr); } } break; default: sweeperr: wta(scmptr, s_bad_type, "gc_sweep"); } ++n; CAR(scmptr) = (SCM)tc_free_cell; CDR(scmptr) = nfreelist; nfreelist = scmptr; continue; c8mrkcontinue: CLRGC8MARK(scmptr); continue; cmrkcontinue: CLRGCMARK(scmptr); } #ifdef GC_FREE_SEGMENTS if (n==seg_cells) { heap_cells -= seg_cells; n = 0; free((char *)hplims[i-2]); /* must_free((char *)hplims[i-2], sizeof(cell) * (hplims[i-1] - hplims[i-2])); */ hplims[i-2] = 0; for (j = i;j < hplim_ind;j++) hplims[j-2] = hplims[j]; hplim_ind -= 2; i -= 2; /* need to scan segment just moved. */ nfreelist = freelist; } else #endif /* ifdef GC_FREE_SEGMENTS */ freelist = nfreelist; gc_cells_collected += n; n = 0; } lcells_allocated += (heap_cells - gc_cells_collected - cells_allocated); cells_allocated = (heap_cells - gc_cells_collected); gc_malloc_collected = (pre_m - mallocated); lmallocated = lmallocated - gc_malloc_collected; } #ifndef NO_SYM_GC /* mark_syms marks those symbols of hash table V which have non-UNDEFINED values. */ static void mark_syms(v) SCM v; { SCM x, al; int k = LENGTH(v); while (k--) for (al = VELTS(v)[k]; NIMP(al); al = GCCDR(al)) { /* If this bucket has already been marked, then something is wrong. */ ASRTER(!GCMARKP(al), al, s_bad_type, s_gc_sym); x = CAR(al); SETGCMARK(al); /* Do mark bucket list */ # ifdef CAREFUL_INTS ASRTER(NIMP(x) && NIMP(CAR(x)) && !GCMARKP(x), x, s_bad_type, s_gc_sym); ASRTER(!GC8MARKP(CAR(x)) && !(CHARS(CAR(x))[LENGTH(CAR(x))]), CAR(x), s_wrong_length, s_gc_sym); ASRTER(strhash(UCHARS(CAR(x)), (sizet)LENGTH(CAR(x)), (unsigned long)symhash_dim)==k, CAR(x), "bad hash", s_gc_sym); # endif if (UNDEFINED==CDR(x) && tc7_msymbol==TYP7(CAR(x))) goto used; /* Don't mark symbol. */ SETGC8MARK(CAR(x)); used: /* SETGCMARK(x) */; /* Don't mark value cell. */ /* We used to mark the value cell, but value cells get returned by calls to intern(). This caused a rare GC leak which only showed up in large programs. */ } SETGC8MARK(v); /* Mark bucket vector. */ } /* mark_symhash marks the values of hash table V. */ static void mark_sym_values(v) SCM v; { SCM x, al; int k = LENGTH(v); /* SETGC8MARK(v); */ /* already set by mark_syms */ while (k--) for (al = VELTS(v)[k]; NIMP(al); al = GCCDR(al)) { x = GCCDR(CAR(al)); if (IMP(x)) continue; gc_mark(x); } } /* Splice any unused valueless symbols out of the hash buckets. */ static void sweep_symhash(v) SCM v; { SCM al, x, *lloc; int k = LENGTH(v); while (k--) { lloc = &(VELTS(v)[k]); while NIMP(al = (*lloc & ~1L)) { x = CAR(al); if (GC8MARKP(CAR(x))) { lloc = &(CDR(al)); SETGCMARK(x); } else { *lloc = CDR(al); CLRGCMARK(al); /* bucket pair to be collected by gc_sweep */ CLRGCMARK(x); /* value cell to be collected by gc_sweep */ gc_syms_collected++; } } VELTS(v)[k] &= ~1L; /* We may have deleted the first cell */ } } #endif /* This function should be called after all other marking is done. */ static void mark_finalizers(finalizers, pending) SCM *finalizers, *pending; { SCM lst, elt, v; SCM live = EOL, undead = *finalizers; int more_to_do = !0; gc_mark(*pending); while NIMP(*pending) pending = &CDR(*pending); while (more_to_do) { more_to_do = 0; lst = undead; undead = EOL; while (NIMP(lst)) { elt = CAR(lst); v = CAR(elt); switch (TYP3(v)) { default: if (GCMARKP(v)) goto marked; goto unmarked; case tc3_tc7_types: if (GC8MARKP(v)) { marked: gc_mark(CDR(elt)); more_to_do = !0; v = lst; lst = CDR(lst); CDR(v) = live; live = v; } else { unmarked: v = lst; lst = CDR(lst); CDR(v) = undead; undead = v; } break; } } } gc_mark(live); for (lst = undead; NIMP(lst); lst = CDR(lst)) CAR(lst) = CDR(CAR(lst)); gc_mark(undead); *finalizers = live; *pending = undead; } static void mark_subrs() { /* subr_info *table = subrs; */ /* int k = subrs_gra.len; */ /* while (k--) { } */ } static void mark_port_table(port) SCM port; { int i = SCM_PORTNUM(port); ASRTER(i>=0 && i 0; k--) { if (scm_port_table[k].flags & 1) scm_port_table[k].flags &= (~1L); else { scm_port_table[k].flags = 0L; scm_port_table[k].data = UNDEFINED; scm_port_table[k].port = UNDEFINED; } } } /* Environment cache GC routines */ /* This is called during a non-cache gc. We only mark those stack frames that are in use. */ static void egc_mark() { SCM *v; int i; gc_mark(scm_env); gc_mark(scm_env_tmp); if (IMP(scm_estk)) return; /* Can happen when moving estk. */ if (GC8MARKP(scm_estk)) return; v = VELTS(scm_estk); SETGC8MARK(scm_estk); i = scm_estk_ptr - v + SCM_ESTK_FRLEN; while(--i >= 0) if (NIMP(v[i])) gc_mark(v[i]); } static void egc_sweep() { SCM z; int i; for (i = scm_ecache_index; i < scm_ecache_len; i++) { z = PTR2SCM(&(scm_ecache[i])); if (CONSP(z)) { CLRGCMARK(z); } else { CLRGC8MARK(z); } } /* Under some circumstances I don't fully understand, continuations may point to dead ecache cells. This prevents gc marked cells from causing errors during ecache gc. */ for (i = scm_ecache_index; i--;) { scm_ecache[i].car = UNSPECIFIED; scm_ecache[i].cdr = UNSPECIFIED; } } #define ECACHEP(x) (PTR_LE((CELLPTR)(ecache_v), (CELLPTR)SCM2PTR(x)) && \ PTR_GT((CELLPTR)(ecache_v) + ECACHE_SIZE, (CELLPTR)SCM2PTR(x))) static void egc_copy(px) SCM *px; { SCM z, x = *px; do { if (tc_broken_heart==CAR(x)) { *px = CDR(x); return; } if (IMP(freelist)) wta(freelist, "empty freelist", "ecache gc"); z = freelist; freelist = CDR(freelist); ++cells_allocated; CAR(z) = CAR(x); CDR(z) = CDR(x); CAR(x) = (SCM)tc_broken_heart; CDR(x) = z; *px = z; x = CAR(z); if (NIMP(x) && ECACHEP(x)) egc_copy(&(CAR(z))); px = &(CDR(z)); x = *px; } while (NIMP(x) && ECACHEP(x)); } static void egc_copy_locations(ve, len) SCM *ve; sizet len; { SCM x; while (len--) { x = ve[len]; if (NIMP(x) && ECACHEP(x)) { if (tc_broken_heart==CAR(x)) ve[len] = CDR(x); else egc_copy(&(ve[len])); } } } static void egc_copy_stack(stk, len) SCM stk; sizet len; { while (!0) { egc_copy_locations(VELTS(stk), len); len = INUM(SCM_ESTK_PARENT_INDEX(stk)) + SCM_ESTK_FRLEN; stk =SCM_ESTK_PARENT(stk); if (IMP(stk)) return; /* len = LENGTH(stk); */ } } extern long tc16_env, tc16_promise; static void egc_copy_roots() { SCM *roots = &(scm_egc_roots[scm_egc_root_index]); SCM e, x; int len = sizeof(scm_egc_roots)/sizeof(SCM) - scm_egc_root_index ; if (!(len>=0 && len <= sizeof(scm_egc_roots)/sizeof(SCM))) wta(MAKINUM(scm_egc_root_index), "egc-root-index", "corrupted"); while (len--) { x = roots[len]; if (IMP(x)) continue; switch TYP3(x) { clo: case tc3_closure: e = ENV(x); if (NIMP(e) && ECACHEP(e)) { egc_copy(&e); CDR(x) = (6L & CDR(x)) | e; } break; case tc3_cons_imcar: case tc3_cons_nimcar: /* These are environment frames that have been destructively altered by DEFINE or LETREC. This is only a problem if a non-cache cell was made to point into the cache. */ if (ECACHEP(x)) break; e = CAR(x); if (NIMP(e) && ECACHEP(e)) egc_copy(&(CAR(x))); break; default: if (tc7_contin==TYP7(x)) { egc_copy_locations(CONT(x)->other.stkframe, 2); #ifndef CHEAP_CONTINUATIONS x = CONT(x)->other.estk; egc_copy_stack(x, LENGTH(x)); #endif break; } if (tc16_env==CAR(x)) { e = CDR(x); if (NIMP(e) && ECACHEP(e)) egc_copy(&(CDR(x))); break; } if (tc16_promise==CAR(x)) { x = CDR(x); goto clo; } } } scm_egc_root_index = sizeof(scm_egc_roots)/sizeof(SCM); } extern long scm_stk_moved, scm_clo_moved, scm_env_work; static int egc_need_gc() { SCM fl = freelist; int n; if (heap_cells - cells_allocated <= scm_ecache_len) return 1; /* Interrupting a NEWCELL could leave cells_allocated inconsistent with freelist, see handle_it() in repl.c */ for (n = 4; n; n--) { if (IMP(fl)) return 1; fl = CDR(fl); } return 0; } void scm_egc() { VERIFY_INTS("scm_egc", 0L); /* We need to make sure there are enough cells available to migrate the entire environment cache, gc does not work properly during ecache gc */ while (egc_need_gc()) { igc("ecache", rootcont); if ((gc_cells_collected < MIN_GC_YIELD) || (heap_cells - cells_allocated <= scm_ecache_len) || IMP(freelist)) { alloc_some_heap(); growth_mon("number of heaps", (long)(hplim_ind/2), "segments", !0); growth_mon(s_heap, heap_cells, s_cells, !0); } } if (errjmp_bad) wta(UNDEFINED, s_recursive, s_cache_gc); { SCM stkframe[2]; long lcells = cells_allocated; sizet nstk = (scm_estk_ptr - VELTS(scm_estk) + SCM_ESTK_FRLEN); ASRTER(nstk<=LENGTH(scm_estk), UNDEFINED, "estk corrupted", s_cache_gc); scm_egc_start(); stkframe[0] = scm_env; stkframe[1] = scm_env_tmp; egc_copy_roots(); scm_clo_moved += cells_allocated - lcells; lcells = cells_allocated; egc_copy_locations(stkframe, sizeof(stkframe)/sizeof(SCM)); egc_copy_stack(scm_estk, nstk); scm_env = stkframe[0]; scm_env_tmp = stkframe[1]; scm_stk_moved += cells_allocated - lcells; scm_ecache_index = scm_ecache_len; scm_env_work += scm_ecache_len; scm_egc_end(); } errjmp_bad = (char *)0; } scm-5e5/dynl.c0000644001705200017500000004271110750224323011147 0ustar tbtb/* "dynl.c" dynamically link&load object files. * Copyright (C) 1990-1999 Free Software Foundation, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see * . */ /* Author: Aubrey Jaffer */ #include "scm.h" #ifndef STDC_HEADERS int free (); /* P((char *ptr)) */ #endif /* linkpath holds the filename which just got linked. Scheme *loadpath* will get set to linkpath and then restored around the initialization call */ /* static SCM linkpath; */ #ifdef DLD # include "dld.h" void listundefs() { int i; char **undefs = dld_list_undefined_sym(); puts(" undefs:"); for (i = dld_undefined_sym_count;i--;) { putc('"', stdout); fputs(undefs[i], stdout); puts("\""); } free(undefs); } static char s_link[] = "dyn:link", s_call[] = "dyn:call"; SCM l_dyn_link(fname) SCM fname; { int status; ASRTER(NIMP(fname) && STRINGP(fname), fname, ARG1, s_link); DEFER_INTS; status = dld_link(CHARS(fname)); ALLOW_INTS; if (!status) {/* linkpath = fname; */ return fname;} if (DLD_ENOFILE==status) return BOOL_F; if (DLD_EBADOBJECT==status) return BOOL_F; dld_perror("DLD"); return BOOL_F; } SCM l_dyn_call(symb, shl) SCM symb, shl; { int i; void (*func)() = 0; /* SCM oloadpath = *loc_loadpath; */ ASRTER(NIMP(symb) && STRINGP(symb), symb, ARG1, s_call); DEFER_INTS; if ((i = dld_function_executable_p(CHARS(symb)))) func = (void (*) ()) dld_get_func(CHARS(symb)); else dld_perror("DLDP"); ALLOW_INTS; if (!i) listundefs(); if (!func) { dld_perror("DLD"); return BOOL_F; } /* *loc_loadpath = linkpath; */ (*func) (); /* *loc_loadpath = oloadpath; */ return BOOL_T; } static char s_main_call[] = "dyn:main-call"; SCM l_dyn_main_call(symb, shl, args) SCM symb, shl, args; { int i; int (*func)(int argc, const char **argv) = 0; const char **argv; /* SCM oloadpath = *loc_loadpath; */ ASRTER(NIMP(symb) && STRINGP(symb), symb, ARG1, s_main_call); DEFER_INTS; argv = makargvfrmstrs(args, s_main_call); if ((i = dld_function_executable_p(CHARS(symb)))) func = (int (*) (int argc, const char **argv)) dld_get_func(CHARS(symb)); else dld_perror("DLDP"); if (!i) listundefs(); if (!func) { must_free_argv(argv); ALLOW_INTS; dld_perror("DLD"); return BOOL_F; } ALLOW_INTS; /* *loc_loadpath = linkpath; */ i = (*func) ((int)ilength(args), argv); /* *loc_loadpath = oloadpath; */ DEFER_INTS; must_free_argv(argv); ALLOW_INTS; return MAKINUM(0L+i); } static char s_unlink[] = "dyn:unlink"; SCM l_dyn_unlink(fname) SCM fname; { int status; ASRTER(NIMP(fname) && STRINGP(fname), fname, ARG1, s_unlink); DEFER_INTS; status = dld_unlink_by_file(CHARS(fname), 1); ALLOW_INTS; if (!status) return BOOL_T; dld_perror("DLD"); return BOOL_F; } static iproc subr1s[] = { {s_link, l_dyn_link}, {s_unlink, l_dyn_unlink}, {0, 0}}; void init_dynl() { /* if (!execpath) execpath = scm_find_execpath(); */ if ((!execpath) || dld_init(execpath)) { dld_perror("DLD:"); return; } if (!dumped) { init_iprocs(subr1s, tc7_subr_1); make_subr(s_call, tc7_subr_2, l_dyn_call); make_subr(s_main_call, tc7_lsubr_2, l_dyn_main_call); add_feature("dld"); # ifdef DLD_DYNCM add_feature("dld:dyncm"); # endif } } #else # ifdef hpux # include "dl.h" # define P_SHL(obj) ((shl_t*)(&CDR(obj))) # define SHL(obj) (*P_SHL(obj)) int prinshl(exp, port, writing) SCM exp; SCM port; int writing; { lputs("#', port); return 1; } int tc16_shl; static smobfuns shlsmob = {mark0, free0, prinshl}; static char s_link[] = "dyn:link", s_call[] = "dyn:call"; SCM l_dyn_link(fname) SCM fname; { SCM z; shl_t shl; ASRTER(NIMP(fname) && STRINGP(fname), fname, ARG1, s_link); NEWCELL(z); DEFER_INTS; shl = shl_load(CHARS(fname), BIND_DEFERRED , 0L); if (NULL==shl) { ALLOW_INTS; return BOOL_F; } SETCHARS(z, shl); CAR(z) = tc16_shl; ALLOW_INTS; /* linkpath = fname; */ return z; } SCM l_dyn_call(symb, shl) SCM symb, shl; { void (*func)() = 0; int i; /* SCM oloadpath = *loc_loadpath; */ ASRTER(NIMP(symb) && STRINGP(symb), symb, ARG1, s_call); ASRTER(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG2, s_call); DEFER_INTS; if ((i = shl_findsym(P_SHL(shl), CHARS(symb), TYPE_PROCEDURE, &func)) != 0) { puts(" undef:"); puts(CHARS(symb)); } ALLOW_INTS; if (i != 0) return BOOL_F; /* *loc_loadpath = linkpath; */ (*func) (); /* *loc_loadpath = oloadpath; */ return BOOL_T; } static char s_main_call[] = "dyn:main-call"; SCM l_dyn_main_call(symb, shl, args) SCM symb, shl, args; { int i; int (*func)P((int argc, const char **argv)) = 0; const char **argv; /* SCM oloadpath = *loc_loadpath; */ ASRTER(NIMP(symb) && STRINGP(symb), symb, ARG1, s_main_call); ASRTER(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG2, s_main_call); DEFER_INTS; if ((i = shl_findsym(P_SHL(shl), CHARS(symb), TYPE_PROCEDURE, &func)) != 0) { puts(" undef:"); puts(CHARS(symb)); } argv = makargvfrmstrs(args, s_main_call); ALLOW_INTS; if (i != 0) return BOOL_F; /* *loc_loadpath = linkpath; */ i = (*func) ((int)ilength(args), argv); /* *loc_loadpath = oloadpath; */ DEFER_INTS; must_free_argv(argv); ALLOW_INTS; return MAKINUM(0L+i); } static char s_unlink[] = "dyn:unlink"; SCM l_dyn_unlink(shl) SCM shl; { int status; ASRTER(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG1, s_unlink); DEFER_INTS; status = shl_unload(SHL(shl)); ALLOW_INTS; if (!status) return BOOL_T; return BOOL_F; } static iproc subr1s[] = { {s_link, l_dyn_link}, {s_unlink, l_dyn_unlink}, {0, 0}}; void init_dynl() { if (!dumped) { tc16_shl = newsmob(&shlsmob); init_iprocs(subr1s, tc7_subr_1); make_subr(s_call, tc7_subr_2, l_dyn_call); make_subr(s_main_call, tc7_lsubr_2, l_dyn_main_call); add_feature("shl"); } } # endif #endif #ifdef vms /* This permits dynamic linking. For example, the procedure of 0 arguments from a file could be the initialization procedure. (vms:dynamic-link-call "MYDISK:[MYDIR].EXE" "foo" "INIT_FOO") The first argument specifies the directory where the file specified by the second argument resides. The current directory would be "SYS$DISK:[].EXE". The second argument cannot contain any punctuation. The third argument probably needs to be uppercased to mimic the VMS linker. */ # include # include # include struct dsc$descriptor *descriptorize(x, buff) struct dsc$descriptor *x; SCM buff; {(*x).dsc$w_length = LENGTH(buff); (*x).dsc$a_pointer = CHARS(buff); (*x).dsc$b_class = DSC$K_CLASS_S; (*x).dsc$b_dtype = DSC$K_DTYPE_T; return(x);} static char s_dynl[] = "vms:dynamic-link-call"; SCM dynl(dir, symbol, fname) SCM dir, symbol, fname; { struct dsc$descriptor fnamed, symbold, dird; void (*fcn)(); long retval; ASRTER(IMP(dir) || STRINGP(dir), dir, ARG1, s_dynl); ASRTER(NIMP(fname) && STRINGP(fname), fname, ARG2, s_dynl); ASRTER(NIMP(symbol) && STRINGP(symbol), symbol, ARG3, s_dynl); descriptorize(&fnamed, fname); descriptorize(&symbold, symbol); DEFER_INTS; retval = lib$find_image_symbol(&fnamed, &symbold, &fcn, IMP(dir) ? 0 : descriptorize(&dird, dir)); if (SS$_NORMAL != retval) { /* wta(MAKINUM(retval), "vms error", s_dynl); */ ALLOW_INTS; return BOOL_F; } ALLOW_INTS; /* *loc_loadpath = dir; */ (*fcn)(); /* *loc_loadpath = oloadpath; */ return BOOL_T; } void init_dynl() { if (!dumped) { make_subr(s_dynl, tc7_subr_3, dynl); } } #endif #ifdef SUN_DL # include # define SHL(obj) ((void*)CDR(obj)) # ifdef RTLD_GLOBAL # define DLOPEN_MODE (RTLD_NOW | RTLD_GLOBAL) # else # ifdef RTLD_LAZY /* This is here out of conservatism, not because it's known to be right. */ # define DLOPEN_MODE RTLD_LAZY # else # define DLOPEN_MODE 1 /* Thats what it says in the man page. */ # endif # endif sizet frshl(ptr) CELLPTR ptr; { # if 0 /* Should freeing a shl close and possibly unmap the object file it */ /* refers to? */ if (SHL(ptr)) dlclose(SHL(ptr)); # endif return 0; } int prinshl(exp, port, writing) SCM exp; SCM port; int writing; { lputs("#', port); return 1; } int tc16_shl; static smobfuns shlsmob = {mark0, frshl, prinshl}; static char s_link[] = "dyn:link", s_call[] = "dyn:call"; SCM l_dyn_link(fname) SCM fname; { SCM z; void *handle; if (FALSEP(fname)) return fname; ASRTER(NIMP(fname) && STRINGP(fname), fname, ARG1, s_link); NEWCELL(z); DEFER_INTS; handle = dlopen(CHARS(fname), DLOPEN_MODE); if (NULL==handle) { if (verbose > 1) { char *dlr = dlerror(); ALLOW_INTS; if (dlr) { lputs(s_link, cur_errp); lputs(": ", cur_errp); lputs(dlr, cur_errp); scm_newline(cur_errp); }} return BOOL_F; } SETCHARS(z, handle); CAR(z) = tc16_shl; ALLOW_INTS; /* linkpath = fname; */ return z; } SCM l_dyn_call(symb, shl) SCM symb, shl; { void (*func)() = 0; /* SCM oloadpath = *loc_loadpath; */ ASRTER(NIMP(symb) && STRINGP(symb), symb, ARG1, s_call); ASRTER(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG2, s_call); DEFER_INTS; func = dlsym(SHL(shl), CHARS(symb)); if (!func) { char *dlr = dlerror(); ALLOW_INTS; if (dlr) { lputs(s_call, cur_errp); lputs(": ", cur_errp); lputs(dlr, cur_errp); scm_newline(cur_errp); } return BOOL_F; } ALLOW_INTS; /* *loc_loadpath = linkpath; */ (*func) (); /* *loc_loadpath = oloadpath; */ return BOOL_T; } static char s_main_call[] = "dyn:main-call"; SCM l_dyn_main_call(symb, shl, args) SCM symb, shl, args; { int i; int (*func)P((int argc, const char **argv)) = 0; char **argv; /* SCM oloadpath = *loc_loadpath; */ ASRTER(NIMP(symb) && STRINGP(symb), symb, ARG1, s_main_call); ASRTER(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG2, s_main_call); DEFER_INTS; func = dlsym(SHL(shl), CHARS(symb)); if (!func) { char *dlr = dlerror(); ALLOW_INTS; if (dlr) { lputs(s_main_call, cur_errp); lputs(": ", cur_errp); lputs(dlr, cur_errp); scm_newline(cur_errp); } return BOOL_F; } argv = makargvfrmstrs(args, s_main_call); ALLOW_INTS; /* *loc_loadpath = linkpath; */ i = (*func) ((int)ilength(args), argv); /* *loc_loadpath = oloadpath; */ DEFER_INTS; must_free_argv(argv); ALLOW_INTS; return MAKINUM(0L+i); } static char s_unlink[] = "dyn:unlink"; SCM l_dyn_unlink(shl) SCM shl; { int status; ASRTER(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG1, s_unlink); DEFER_INTS; status = dlclose(SHL(shl)); SETCHARS(shl, NULL); ALLOW_INTS; if (!status) return BOOL_T; return BOOL_F; } static iproc subr1s[] = { {s_link, l_dyn_link}, {s_unlink, l_dyn_unlink}, {0, 0}}; void init_dynl() { if (!dumped) { tc16_shl = newsmob(&shlsmob); init_iprocs(subr1s, tc7_subr_1); make_subr(s_call, tc7_subr_2, l_dyn_call); make_subr(s_main_call, tc7_lsubr_2, l_dyn_main_call); add_feature("sun-dl"); } } #endif /* SUN_DL */ #ifdef macintosh # include # include # define SHL(obj) ((void*)CDR(obj)) sizet frshl(ptr) CELLPTR ptr; { # if 0 /* Should freeing a shl close and possibly unmap the object file it */ /* refers to? */ if (SHL(ptr)) dlclose(SHL(ptr)); # endif return 0; } int prinshl(exp, port, writing) SCM exp; SCM port; int writing; { lputs("#', port); return 1; } int tc16_shl; static smobfuns shlsmob = {mark0, frshl, prinshl}; static char s_link[] = "dyn:link", s_call[] = "dyn:call"; SCM l_dyn_link(fname) SCM fname; { OSErr err; SCM z; void *handle; Str63 libName; CFragConnectionID connID; Ptr mainAddr; Str255 errMessage; if (FALSEP(fname)) return fname; ASRTER(NIMP(fname) && STRINGP(fname), fname, ARG1, s_link); NEWCELL(z); DEFER_INTS; strcpy((char *)libName, CHARS(fname)); c2pstr((char *)libName); err = GetSharedLibrary (libName, kCompiledCFragArch, kReferenceCFrag, &connID, &mainAddr, errMessage); if (err!=noErr) { ALLOW_INTS; return BOOL_F; } SETCHARS(z, (void *)connID); CAR(z) = tc16_shl; ALLOW_INTS; /* linkpath = fname; */ return z; } SCM l_dyn_call(symb, shl) SCM symb, shl; { void (*func)() = 0; OSErr err; CFragSymbolClass symClass; Str255 symName; /* SCM oloadpath = *loc_loadpath; */ ASRTER(NIMP(symb) && STRINGP(symb), symb, ARG1, s_call); ASRTER(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG2, s_call); DEFER_INTS; strcpy((char *)symName, CHARS(symb)); c2pstr((char *)symName); err = FindSymbol((CFragConnectionID)SHL(shl), symName, (Ptr *)&func, &symClass); if (err!=noErr /* || symClass != kCodeCFragSymbol */) { ALLOW_INTS; if (err == cfragConnectionIDErr) puts("Invalid library connection."); if (err == cfragNoSymbolErr) puts("Symbol not found."); return BOOL_F; } ALLOW_INTS; /* *loc_loadpath = linkpath; */ (*func) (); /* *loc_loadpath = oloadpath; */ return BOOL_T; } static char s_main_call[] = "dyn:main-call"; SCM l_dyn_main_call(symb, shl, args) SCM symb, shl, args; { int i; int (*func)P((int argc, const char **argv)) = 0; const char **argv; OSErr err; CFragSymbolClass symClass; Str255 symName; /* SCM oloadpath = *loc_loadpath; */ ASRTER(NIMP(symb) && STRINGP(symb), symb, ARG1, s_main_call); ASRTER(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG2, s_main_call); DEFER_INTS; strcpy((char *)symName, CHARS(symb)); c2pstr((char *)symName); err = FindSymbol((CFragConnectionID)SHL(shl), symName, (Ptr *)&func, &symClass); if (err!=noErr || symClass != kCodeCFragSymbol) { ALLOW_INTS; if (err == cfragConnectionIDErr) puts("Invalid library connection."); if (err == cfragNoSymbolErr) puts("Symbol not found."); return BOOL_F; } argv = makargvfrmstrs(args, s_main_call); ALLOW_INTS; /* *loc_loadpath = linkpath; */ i = (*func) ((int)ilength(args), argv); /* *loc_loadpath = oloadpath; */ DEFER_INTS; must_free_argv(argv); ALLOW_INTS; return MAKINUM(0L+i); } static char s_unlink[] = "dyn:unlink"; SCM l_dyn_unlink(shl) SCM shl; { OSErr status; CFragConnectionID connID; ASRTER(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG1, s_unlink); DEFER_INTS; connID = (CFragConnectionID)SHL(shl); status = CloseConnection(&connID); SETCHARS(shl, NULL); ALLOW_INTS; if (status!=noErr) return BOOL_T; return BOOL_F; } static iproc subr1s[] = { {s_link, l_dyn_link}, {s_unlink, l_dyn_unlink}, {0, 0}}; void init_dynl() { if (!dumped) { tc16_shl = newsmob(&shlsmob); init_iprocs(subr1s, tc7_subr_1); make_subr(s_call, tc7_subr_2, l_dyn_call); make_subr(s_main_call, tc7_lsubr_2, l_dyn_main_call); add_feature("mac-dl"); } } #endif /* MACOS */ #ifdef _WIN32 # include # define SHL(obj) ((HINSTANCE)(CDR(obj))) int prinshl(exp, port, writing) SCM exp; SCM port; int writing; { lputs("#', port); return 1; } int tc16_shl; static smobfuns shlsmob = {mark0, free0, prinshl}; static char s_link[] = "dyn:link"; SCM scm_dyn_link(fname) SCM fname; { SCM z, shl = BOOL_F; HINSTANCE hshl; ASRTER(NIMP(fname) && STRINGP(fname), fname, ARG1, s_link); NEWCELL(z); DEFER_INTS; hshl = LoadLibrary(CHARS(fname)); if (hshl) { SETCHARS(z, hshl); CAR(z) = tc16_shl; shl = z; } ALLOW_INTS; return shl; } static char s_unlink[] = "dyn:unlink"; SCM scm_dyn_unlink(shl) SCM shl; { BOOL status; ASRTER(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG1, s_unlink); DEFER_INTS; status = FreeLibrary(SHL(shl)); ALLOW_INTS; return status ? BOOL_T : BOOL_F; } static char s_call[] = "dyn:call"; SCM scm_dyn_call(symb, shl) SCM symb, shl; { FARPROC func; int i; ASRTER(NIMP(symb) && STRINGP(symb), symb, ARG1, s_call); ASRTER(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG2, s_call); DEFER_INTS; func = GetProcAddress(SHL(shl), CHARS(symb)); ALLOW_INTS; if (!func) return BOOL_F; (*func) (); return BOOL_T; } static char s_main_call[] = "dyn:main-call"; SCM scm_dyn_main_call(symb, shl, args) SCM symb, shl, args; { int i; FARPROC func; const char **argv; ASRTER(NIMP(symb) && STRINGP(symb), symb, ARG1, s_main_call); ASRTER(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG2, s_main_call); DEFER_INTS; func = GetProcAddress(SHL(shl), CHARS(symb)); if (!func) { ALLOW_INTS; return BOOL_F; } argv = makargvfrmstrs(args, s_main_call); ALLOW_INTS; i = (*func) ((int)ilength(args), argv); DEFER_INTS; must_free_argv(argv); ALLOW_INTS; return MAKINUM(0L+i); } static iproc subr1s[] = { {s_link, scm_dyn_link}, {s_unlink, scm_dyn_unlink}, {0, 0}}; void init_dynl() { if (!dumped) { tc16_shl = newsmob(&shlsmob); init_iprocs(subr1s, tc7_subr_1); make_subr(s_call, tc7_subr_2, scm_dyn_call); make_subr(s_main_call, tc7_lsubr_2, scm_dyn_main_call); add_feature("win32-dl"); } } #endif scm-5e5/example.scm0000644001705200017500000000661406467700740012212 0ustar tbtb;From Revised^4 Report on the Algorithmic Language Scheme ;William Clinger and Jonathon Rees (Editors) ; EXAMPLE ;INTEGRATE-SYSTEM integrates the system ; y_k' = f_k(y_1, y_2, ..., y_n), k = 1, ..., n ;of differential equations with the method of Runge-Kutta. ;The parameter SYSTEM-DERIVATIVE is a function that takes a system ;state (a vector of values for the state variables y_1, ..., y_n) and ;produces a system derivative (the values y_1', ..., y_n'). The ;parameter INITIAL-STATE provides an initial system state, and H is an ;initial guess for the length of the integration step. ;The value returned by INTEGRATE-SYSTEM is an infinite stream of ;system states. (define integrate-system (lambda (system-derivative initial-state h) (let ((next (runge-kutta-4 system-derivative h))) (letrec ((states (cons initial-state (delay (map-streams next states))))) states)))) ;RUNGE-KUTTA-4 takes a function, F, that produces a ;system derivative from a system state. RUNGE-KUTTA-4 ;produces a function that takes a system state and ;produces a new system state. (define runge-kutta-4 (lambda (f h) (let ((*h (scale-vector h)) (*2 (scale-vector 2)) (*1/2 (scale-vector (/ 1 2))) (*1/6 (scale-vector (/ 1 6)))) (lambda (y) ;; Y is a system state (let* ((k0 (*h (f y))) (k1 (*h (f (add-vectors y (*1/2 k0))))) (k2 (*h (f (add-vectors y (*1/2 k1))))) (k3 (*h (f (add-vectors y k2))))) (add-vectors y (*1/6 (add-vectors k0 (*2 k1) (*2 k2) k3)))))))) (define elementwise (lambda (f) (lambda vectors (generate-vector (vector-length (car vectors)) (lambda (i) (apply f (map (lambda (v) (vector-ref v i)) vectors))))))) (define generate-vector (lambda (size proc) (let ((ans (make-vector size))) (letrec ((loop (lambda (i) (cond ((= i size) ans) (else (vector-set! ans i (proc i)) (loop (+ i 1))))))) (loop 0))))) (define add-vectors (elementwise +)) (define scale-vector (lambda (s) (elementwise (lambda (x) (* x s))))) ;MAP-STREAMS is analogous to MAP: it applies its first ;argument (a procedure) to all the elements of its second argument (a ;stream). (define map-streams (lambda (f s) (cons (f (head s)) (delay (map-streams f (tail s)))))) ;Infinite streams are implemented as pairs whose car holds the first ;element of the stream and whose cdr holds a promise to deliver the rest ;of the stream. (define head car) (define tail (lambda (stream) (force (cdr stream)))) ;The following illustrates the use of INTEGRATE-SYSTEM in ;integrating the system ; ; dvC vC ; C --- = -i - -- ; dt L R ; ; diL ; L --- = v ; dt C ; ;which models a damped oscillator. (define damped-oscillator (lambda (R L C) (lambda (state) (let ((Vc (vector-ref state 0)) (Il (vector-ref state 1))) (vector (- 0 (+ (/ Vc (* R C)) (/ Il C))) (/ Vc L)))))) (define the-states (integrate-system (damped-oscillator 10000 1000 .001) '#(1 0) .01)) (do ((i 10 (- i 1)) (s the-states (tail s))) ((zero? i) (newline)) (newline) (write (head s))) ; #(1 0) ; #(0.99895054 9.994835e-6) ; #(0.99780226 1.9978681e-5) ; #(0.9965554 2.9950552e-5) ; #(0.9952102 3.990946e-5) ; #(0.99376684 4.985443e-5) ; #(0.99222565 5.9784474e-5) ; #(0.9905868 6.969862e-5) ; #(0.9888506 7.9595884e-5) ; #(0.9870173 8.94753e-5) scm-5e5/xevent.scm0000644001705200017500000000171110752242351012050 0ustar tbtb;; xgen.scm extracted typedef structs from /usr/include/X11/Xlib.h (define X-event:type #x10) (define X-event:serial #x11) (define X-event:send-event #x12) (define X-event:time #x13) (define X-event:x #x14) (define X-event:y #x15) (define X-event:x-root #x16) (define X-event:y-root #x17) (define X-event:state #x18) (define X-event:keycode #x19) (define X-event:same-screen #x1a) (define X-event:button #x1b) (define X-event:is-hint #x1c) (define X-event:mode #x1d) (define X-event:detail #x1e) (define X-event:focus #x1f) (define X-event:width #x20) (define X-event:height #x21) (define X-event:count #x22) (define X-event:major-code #x23) (define X-event:minor-code #x24) (define X-event:border-width #x25) (define X-event:override-redirect #x26) (define X-event:from-configure #x27) (define X-event:value-mask #x28) (define X-event:place #x29) (define X-event:new #x2a) (define X-event:format #x2b) (define X-event:request #x2c) (define X-event:first-keycode #x2d) scm-5e5/x11.scm0000644001705200017500000004176610750407300011161 0ustar tbtb;;inc2scm extracted #define values from /usr/include/X11/X.h (define X:PROTOCOL 11) (define X:PROTOCOL-REVISION 0) (define x:None 0) (define x:Parent-Relative 1) (define x:Copy-From-Parent 0) (define x:Pointer-Window 0) (define x:Input-Focus 1) (define x:Pointer-Root 1) (define x:Any-Property-Type 0) (define x:Any-Key 0) (define x:Any-Button 0) (define x:All-Temporary 0) (define x:Current-Time 0) (define x:No-Symbol 0) (define x:No-Event-Mask 0) (define x:Key-Press-Mask 1) (define x:Key-Release-Mask 2) (define x:Button-Press-Mask 4) (define x:Button-Release-Mask 8) (define x:Enter-Window-Mask 16) (define x:Leave-Window-Mask 32) (define x:Pointer-Motion-Mask 64) (define x:Pointer-Motion-Hint-Mask 128) (define x:Button1-Motion-Mask 256) (define x:Button2-Motion-Mask 512) (define x:Button3-Motion-Mask 1024) (define x:Button4-Motion-Mask 2048) (define x:Button5-Motion-Mask 4096) (define x:Button-Motion-Mask 8192) (define x:Keymap-State-Mask 16384) (define x:Exposure-Mask 32768) (define x:Visibility-Change-Mask 65536) (define x:Structure-Notify-Mask 131072) (define x:Resize-Redirect-Mask 262144) (define x:Substructure-Notify-Mask 524288) (define x:Substructure-Redirect-Mask 1048576) (define x:Focus-Change-Mask 2097152) (define x:Property-Change-Mask 4194304) (define x:Colormap-Change-Mask 8388608) (define x:Owner-Grab-Button-Mask 16777216) (define x:Key-Press 2) (define x:Key-Release 3) (define x:Button-Press 4) (define x:Button-Release 5) (define x:Motion-Notify 6) (define x:Enter-Notify 7) (define x:Leave-Notify 8) (define x:Focus-In 9) (define x:Focus-Out 10) (define x:Keymap-Notify 11) (define x:Expose 12) (define x:Graphics-Expose 13) (define x:No-Expose 14) (define x:Visibility-Notify 15) (define x:Create-Notify 16) (define x:Destroy-Notify 17) (define x:Unmap-Notify 18) (define x:Map-Notify 19) (define x:Map-Request 20) (define x:Reparent-Notify 21) (define x:Configure-Notify 22) (define x:Configure-Request 23) (define x:Gravity-Notify 24) (define x:Resize-Request 25) (define x:Circulate-Notify 26) (define x:Circulate-Request 27) (define x:Property-Notify 28) (define x:Selection-Clear 29) (define x:Selection-Request 30) (define x:Selection-Notify 31) (define x:Colormap-Notify 32) (define x:Client-Message 33) (define x:Mapping-Notify 34) (define x:LAST-Event 35) (define x:Shift-Mask 1) (define x:Lock-Mask 2) (define x:Control-Mask 4) (define x:Mod1-Mask 8) (define x:Mod2-Mask 16) (define x:Mod3-Mask 32) (define x:Mod4-Mask 64) (define x:Mod5-Mask 128) (define x:Shift-Map-Index 0) (define x:Lock-Map-Index 1) (define x:Control-Map-Index 2) (define x:Mod1-Map-Index 3) (define x:Mod2-Map-Index 4) (define x:Mod3-Map-Index 5) (define x:Mod4-Map-Index 6) (define x:Mod5-Map-Index 7) (define x:Button1-Mask 256) (define x:Button2-Mask 512) (define x:Button3-Mask 1024) (define x:Button4-Mask 2048) (define x:Button5-Mask 4096) (define x:Any-Modifier 32768) (define x:Button1 1) (define x:Button2 2) (define x:Button3 3) (define x:Button4 4) (define x:Button5 5) (define x:Notify-Normal 0) (define x:Notify-Grab 1) (define x:Notify-Ungrab 2) (define x:Notify-While-Grabbed 3) (define x:Notify-Hint 1) (define x:Notify-Ancestor 0) (define x:Notify-Virtual 1) (define x:Notify-Inferior 2) (define x:Notify-Nonlinear 3) (define x:Notify-Nonlinear-Virtual 4) (define x:Notify-Pointer 5) (define x:Notify-Pointer-Root 6) (define x:Notify-Detail-None 7) (define x:Visibility-Unobscured 0) (define x:Visibility-Partially-Obscured 1) (define x:Visibility-Fully-Obscured 2) (define x:Place-On-Top 0) (define x:Place-On-Bottom 1) (define x:Family-Internet 0) (define x:Family-DE-Cnet 1) (define x:Family-Chaos 2) (define x:Family-Internet6 6) (define x:Family-Server-Interpreted 5) (define x:Property-New-Value 0) (define x:Property-Delete 1) (define x:Colormap-Uninstalled 0) (define x:Colormap-Installed 1) (define x:Grab-Mode-Sync 0) (define x:Grab-Mode-Async 1) (define x:Grab-Success 0) (define x:Already-Grabbed 1) (define x:Grab-Invalid-Time 2) (define x:Grab-Not-Viewable 3) (define x:Grab-Frozen 4) (define x:Async-Pointer 0) (define x:Sync-Pointer 1) (define x:Replay-Pointer 2) (define x:Async-Keyboard 3) (define x:Sync-Keyboard 4) (define x:Replay-Keyboard 5) (define x:Async-Both 6) (define x:Sync-Both 7) (define x:Revert-To-None 0) (define x:Revert-To-Pointer-Root 1) (define x:Revert-To-Parent 2) (define x:Success 0) (define x:Bad-Request 1) (define x:Bad-Value 2) (define x:Bad-Window 3) (define x:Bad-Pixmap 4) (define x:Bad-Atom 5) (define x:Bad-Cursor 6) (define x:Bad-Font 7) (define x:Bad-Match 8) (define x:Bad-Drawable 9) (define x:Bad-Access 10) (define x:Bad-Alloc 11) (define x:Bad-Color 12) (define x:Bad-GC 13) (define x:Bad-ID-Choice 14) (define x:Bad-Name 15) (define x:Bad-Length 16) (define x:Bad-Implementation 17) (define x:First-Extension-Error 128) (define x:Last-Extension-Error 255) (define x:Input-Output 1) (define x:Input-Only 2) (define x:CW-Back-Pixmap 1) (define x:CW-Back-Pixel 2) (define x:CW-Border-Pixmap 4) (define x:CW-Border-Pixel 8) (define x:CW-Bit-Gravity 16) (define x:CW-Win-Gravity 32) (define x:CW-Backing-Store 64) (define x:CW-Backing-Planes 128) (define x:CW-Backing-Pixel 256) (define x:CW-Override-Redirect 512) (define x:CW-Save-Under 1024) (define x:CW-Event-Mask 2048) (define x:CW-Dont-Propagate 4096) (define x:CW-Colormap 8192) (define x:CW-Cursor 16384) (define x:CWX 1) (define x:CWY 2) (define x:CW-Width 4) (define x:CW-Height 8) (define x:CW-Border-Width 16) (define x:CW-Sibling 32) (define x:CW-Stack-Mode 64) (define x:Forget-Gravity 0) (define x:North-West-Gravity 1) (define x:North-Gravity 2) (define x:North-East-Gravity 3) (define x:West-Gravity 4) (define x:Center-Gravity 5) (define x:East-Gravity 6) (define x:South-West-Gravity 7) (define x:South-Gravity 8) (define x:South-East-Gravity 9) (define x:Static-Gravity 10) (define x:Unmap-Gravity 0) (define x:Not-Useful 0) (define x:When-Mapped 1) (define x:Always 2) (define x:Is-Unmapped 0) (define x:Is-Unviewable 1) (define x:Is-Viewable 2) (define x:Set-Mode-Insert 0) (define x:Set-Mode-Delete 1) (define x:Destroy-All 0) (define x:Retain-Permanent 1) (define x:Retain-Temporary 2) (define x:Above 0) (define x:Below 1) (define x:Top-If 2) (define x:Bottom-If 3) (define x:Opposite 4) (define x:Raise-Lowest 0) (define x:Lower-Highest 1) (define x:Prop-Mode-Replace 0) (define x:Prop-Mode-Prepend 1) (define x:Prop-Mode-Append 2) (define x:G-Xclear 0) (define x:G-Xand 1) (define x:G-Xand-Reverse 2) (define x:G-Xcopy 3) (define x:G-Xand-Inverted 4) (define x:G-Xnoop 5) (define x:G-Xxor 6) (define x:G-Xor 7) (define x:G-Xnor 8) (define x:G-Xequiv 9) (define x:G-Xinvert 10) (define x:G-Xor-Reverse 11) (define x:G-Xcopy-Inverted 12) (define x:G-Xor-Inverted 13) (define x:G-Xnand 14) (define x:G-Xset 15) (define x:Line-Solid 0) (define x:Line-On-Off-Dash 1) (define x:Line-Double-Dash 2) (define x:Cap-Not-Last 0) (define x:Cap-Butt 1) (define x:Cap-Round 2) (define x:Cap-Projecting 3) (define x:Join-Miter 0) (define x:Join-Round 1) (define x:Join-Bevel 2) (define x:Fill-Solid 0) (define x:Fill-Tiled 1) (define x:Fill-Stippled 2) (define x:Fill-Opaque-Stippled 3) (define x:Even-Odd-Rule 0) (define x:Winding-Rule 1) (define x:Clip-By-Children 0) (define x:Include-Inferiors 1) (define x:Unsorted 0) (define x:Y-Sorted 1) (define x:YX-Sorted 2) (define x:YX-Banded 3) (define x:Coord-Mode-Origin 0) (define x:Coord-Mode-Previous 1) (define x:Complex 0) (define x:Nonconvex 1) (define x:Convex 2) (define x:Arc-Chord 0) (define x:Arc-Pie-Slice 1) (define x:GC-Function 1) (define x:GC-Plane-Mask 2) (define x:GC-Foreground 4) (define x:GC-Background 8) (define x:GC-Line-Width 16) (define x:GC-Line-Style 32) (define x:GC-Cap-Style 64) (define x:GC-Join-Style 128) (define x:GC-Fill-Style 256) (define x:GC-Fill-Rule 512) (define x:GC-Tile 1024) (define x:GC-Stipple 2048) (define x:GC-Tile-Stip-X-Origin 4096) (define x:GC-Tile-Stip-Y-Origin 8192) (define x:GC-Font 16384) (define x:GC-Subwindow-Mode 32768) (define x:GC-Graphics-Exposures 65536) (define x:GC-Clip-X-Origin 131072) (define x:GC-Clip-Y-Origin 262144) (define x:GC-Clip-Mask 524288) (define x:GC-Dash-Offset 1048576) (define x:GC-Dash-List 2097152) (define x:GC-Arc-Mode 4194304) (define x:GC-Last-Bit 22) (define x:Font-Left-To-Right 0) (define x:Font-Right-To-Left 1) (define x:Font-Change 255) (define x:XY-Bitmap 0) (define x:XY-Pixmap 1) (define x:Z-Pixmap 2) (define x:Alloc-None 0) (define x:Alloc-All 1) (define x:Do-Red 1) (define x:Do-Green 2) (define x:Do-Blue 4) (define x:Cursor-Shape 0) (define x:Tile-Shape 1) (define x:Stipple-Shape 2) (define x:Auto-Repeat-Mode-Off 0) (define x:Auto-Repeat-Mode-On 1) (define x:Auto-Repeat-Mode-Default 2) (define x:Led-Mode-Off 0) (define x:Led-Mode-On 1) (define x:KB-Key-Click-Percent 1) (define x:KB-Bell-Percent 2) (define x:KB-Bell-Pitch 4) (define x:KB-Bell-Duration 8) (define x:KB-Led 16) (define x:KB-Led-Mode 32) (define x:KB-Key 64) (define x:KB-Auto-Repeat-Mode 128) (define x:Mapping-Success 0) (define x:Mapping-Busy 1) (define x:Mapping-Failed 2) (define x:Mapping-Modifier 0) (define x:Mapping-Keyboard 1) (define x:Mapping-Pointer 2) (define x:Dont-Prefer-Blanking 0) (define x:Prefer-Blanking 1) (define x:Default-Blanking 2) (define x:Disable-Screen-Saver 0) (define x:Disable-Screen-Interval 0) (define x:Dont-Allow-Exposures 0) (define x:Allow-Exposures 1) (define x:Default-Exposures 2) (define x:Screen-Saver-Reset 0) (define x:Screen-Saver-Active 1) (define x:Host-Insert 0) (define x:Host-Delete 1) (define x:Enable-Access 1) (define x:Disable-Access 0) (define x:Static-Gray 0) (define x:Gray-Scale 1) (define x:Static-Color 2) (define x:Pseudo-Color 3) (define x:True-Color 4) (define x:Direct-Color 5) (define x:LSB-First 0) (define x:MSB-First 1) ;;inc2scm extracted #define values from /usr/include/X11/cursorfont.h (define XC:num-glyphs 154) (define XC:X-cursor 0) (define XC:arrow 2) (define XC:based-arrow-down 4) (define XC:based-arrow-up 6) (define XC:boat 8) (define XC:bogosity 10) (define XC:bottom-left-corner 12) (define XC:bottom-right-corner 14) (define XC:bottom-side 16) (define XC:bottom-tee 18) (define XC:box-spiral 20) (define XC:center-ptr 22) (define XC:circle 24) (define XC:clock 26) (define XC:coffee-mug 28) (define XC:cross 30) (define XC:cross-reverse 32) (define XC:crosshair 34) (define XC:diamond-cross 36) (define XC:dot 38) (define XC:dotbox 40) (define XC:double-arrow 42) (define XC:draft-large 44) (define XC:draft-small 46) (define XC:draped-box 48) (define XC:exchange 50) (define XC:fleur 52) (define XC:gobbler 54) (define XC:gumby 56) (define XC:hand1 58) (define XC:hand2 60) (define XC:heart 62) (define XC:icon 64) (define XC:iron-cross 66) (define XC:left-ptr 68) (define XC:left-side 70) (define XC:left-tee 72) (define XC:leftbutton 74) (define XC:ll-angle 76) (define XC:lr-angle 78) (define XC:man 80) (define XC:middlebutton 82) (define XC:mouse 84) (define XC:pencil 86) (define XC:pirate 88) (define XC:plus 90) (define XC:question-arrow 92) (define XC:right-ptr 94) (define XC:right-side 96) (define XC:right-tee 98) (define XC:rightbutton 100) (define XC:rtl-logo 102) (define XC:sailboat 104) (define XC:sb-down-arrow 106) (define XC:sb-h-double-arrow 108) (define XC:sb-left-arrow 110) (define XC:sb-right-arrow 112) (define XC:sb-up-arrow 114) (define XC:sb-v-double-arrow 116) (define XC:shuttle 118) (define XC:sizing 120) (define XC:spider 122) (define XC:spraycan 124) (define XC:star 126) (define XC:target 128) (define XC:tcross 130) (define XC:top-left-arrow 132) (define XC:top-left-corner 134) (define XC:top-right-corner 136) (define XC:top-side 138) (define XC:top-tee 140) (define XC:trek 142) (define XC:ul-angle 144) (define XC:umbrella 146) (define XC:ur-angle 148) (define XC:watch 150) (define XC:xterm 152) ;;inc2scm extracted #define values from /usr/include/X11/Xlib.h (define x:Xlib-Specification-Release 6) (define X:HAVE-UTF8-STRING 1) (define x:True 1) (define x:False 0) (define x:Queued-Already 0) (define x:Queued-After-Reading 1) (define x:Queued-After-Flush 2) (define x:All-Planes -1) (define x:XN-Required-Char-Set 134532633) (define x:XN-Query-Orientation 134532672) (define x:XN-Base-Font-Name 134532712) (define x:XNOM-Automatic 134532745) (define x:XN-Missing-Char-Set 134532774) (define x:XN-Default-String 134532811) (define x:XN-Orientation 134532845) (define x:XN-Directional-Dependent-Drawing 134532874) (define x:XN-Contextual-Drawing 134532939) (define x:XN-Font-Info 134532981) (define x:XIM-Preedit-Area 1) (define x:XIM-Preedit-Callbacks 2) (define x:XIM-Preedit-Position 4) (define x:XIM-Preedit-Nothing 8) (define x:XIM-Preedit-None 16) (define x:XIM-Status-Area 256) (define x:XIM-Status-Callbacks 512) (define x:XIM-Status-Nothing 1024) (define x:XIM-Status-None 2048) (define x:XN-Va-Nested-List 134533192) (define x:XN-Query-Input-Style 134533227) (define x:XN-Client-Window 134533266) (define x:XN-Input-Style 134533298) (define x:XN-Focus-Window 134533326) (define x:XN-Resource-Name 134533356) (define x:XN-Resource-Class 134533388) (define x:XN-Geometry-Callback 134533422) (define x:XN-Destroy-Callback 134533462) (define x:XN-Filter-Events 134533500) (define x:XN-Preedit-Start-Callback 134533532) (define x:XN-Preedit-Done-Callback 134533581) (define x:XN-Preedit-Draw-Callback 134533628) (define x:XN-Preedit-Caret-Callback 134533675) (define x:XN-Preedit-State-Notify-Callback 134533724) (define x:XN-Preedit-Attributes 134533787) (define x:XN-Status-Start-Callback 134533829) (define x:XN-Status-Done-Callback 134533876) (define x:XN-Status-Draw-Callback 134533921) (define x:XN-Status-Attributes 134533966) (define x:XN-Area 134534006) (define x:XN-Area-Needed 134534021) (define x:XN-Spot-Location 134534049) (define x:XN-Colormap 134534081) (define x:XN-Std-Colormap 134534104) (define x:XN-Foreground 134534134) (define x:XN-Background 134534161) (define x:XN-Background-Pixmap 134534188) (define x:XN-Font-Set 134534228) (define x:XN-Line-Space 134534250) (define x:XN-Cursor 134534276) (define x:XN-Query-IM-Values-List 134534295) (define x:XN-Query-IC-Values-List 134534339) (define x:XN-Visible-Position 134534383) (define x:XNR6-Preedit-Callback 134534421) (define x:XN-String-Conversion-Callback 134534463) (define x:XN-String-Conversion 134534520) (define x:XN-Reset-State 134534560) (define x:XN-Hot-Key 134534588) (define x:XN-Hot-Key-State 134534608) (define x:XN-Preedit-State 134534639) (define x:XN-Separatorof-Nested-List 134534671) (define x:X-Buffer-Overflow -1) (define x:X-Lookup-None 1) (define x:X-Lookup-Chars 2) (define x:X-Lookup-Key-Sym 3) (define x:X-Lookup-Both 4) (define x:XIM-Reverse 1) (define x:XIM-Underline 2) (define x:XIM-Highlight 4) (define x:XIM-Primary 32) (define x:XIM-Secondary 64) (define x:XIM-Tertiary 128) (define x:XIM-Visible-To-Forward 256) (define x:XIM-Visible-To-Backword 512) (define x:XIM-Visible-To-Center 1024) (define x:XIM-Preedit-Un-Known 0) (define x:XIM-Preedit-Enable 1) (define x:XIM-Preedit-Disable 2) (define x:XIM-Initial-State 1) (define x:XIM-Preserve-State 2) (define x:XIM-String-Conversion-Left-Edge 1) (define x:XIM-String-Conversion-Right-Edge 2) (define x:XIM-String-Conversion-Top-Edge 4) (define x:XIM-String-Conversion-Bottom-Edge 8) (define x:XIM-String-Conversion-Concealed 16) (define x:XIM-String-Conversion-Wrapped 32) (define x:XIM-String-Conversion-Buffer 1) (define x:XIM-String-Conversion-Line 2) (define x:XIM-String-Conversion-Word 3) (define x:XIM-String-Conversion-Char 4) (define x:XIM-String-Conversion-Substitution 1) (define x:XIM-String-Conversion-Retrieval 2) (define x:XIM-Hot-Key-State-ON 1) (define x:XIM-Hot-Key-State-OFF 2) ;;inc2scm extracted #define values from /usr/include/X11/Xutil.h (define x:No-Value 0) (define x:X-Value 1) (define x:Y-Value 2) (define x:Width-Value 4) (define x:Height-Value 8) (define x:All-Values 15) (define x:X-Negative 16) (define x:Y-Negative 32) (define x:US-Position 1) (define x:US-Size 2) (define x:P-Position 4) (define x:P-Size 8) (define x:P-Min-Size 16) (define x:P-Max-Size 32) (define x:P-Resize-Inc 64) (define x:P-Aspect 128) (define x:P-Base-Size 256) (define x:P-Win-Gravity 512) (define x:P-All-Hints 252) (define x:Input-Hint 1) (define x:State-Hint 2) (define x:Icon-Pixmap-Hint 4) (define x:Icon-Window-Hint 8) (define x:Icon-Position-Hint 16) (define x:Icon-Mask-Hint 32) (define x:Window-Group-Hint 64) (define x:All-Hints 127) (define x:X-Urgency-Hint 256) (define x:Withdrawn-State 0) (define x:Normal-State 1) (define x:Iconic-State 3) (define x:Dont-Care-State 0) (define x:Zoom-State 2) (define x:Inactive-State 4) (define x:X-No-Memory -1) (define x:X-Locale-Not-Supported -2) (define x:X-Converter-Not-Found -3) (define x:Rectangle-Out 0) (define x:Rectangle-In 1) (define x:Rectangle-Part 2) (define x:Visual-No-Mask 0) (define x:Visual-ID-Mask 1) (define x:Visual-Screen-Mask 2) (define x:Visual-Depth-Mask 4) (define x:Visual-Class-Mask 8) (define x:Visual-Red-Mask-Mask 16) (define x:Visual-Green-Mask-Mask 32) (define x:Visual-Blue-Mask-Mask 64) (define x:Visual-Colormap-Size-Mask 128) (define x:Visual-Bits-Per-RGB-Mask 256) (define x:Visual-All-Mask 511) (define x:Release-By-Freeing-Colormap 1) (define x:Bitmap-Success 0) (define x:Bitmap-Open-Failed 1) (define x:Bitmap-File-Invalid 2) (define x:Bitmap-No-Memory 3) (define x:XCSUCCESS 0) (define x:XCNOMEM 1) (define x:XCNOENT 2) scm-5e5/unexelf.c0000644001705200017500000012733610750241221011652 0ustar tbtb/* Copyright (C) 1985, 1986, 1987, 1988, 1990, 1992, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This file is part of GNU Emacs. GNU Emacs 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 3 of the License, or (at your option) any later version. GNU Emacs 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 GNU Emacs. If not, see . */ /* * unexec.c - Convert a running program into an a.out file. * * Author: Spencer W. Thomas * Computer Science Dept. * University of Utah * Date: Tue Mar 2 1982 * Modified heavily since then. * * Synopsis: * unexec (new_name, old_name, data_start, bss_start, entry_address) * char *new_name, *old_name; * unsigned data_start, bss_start, entry_address; * * Takes a snapshot of the program and makes an a.out format file in the * file named by the string argument new_name. * If old_name is non-NULL, the symbol table will be taken from the given file. * On some machines, an existing old_name file is required. * * The boundaries within the a.out file may be adjusted with the data_start * and bss_start arguments. Either or both may be given as 0 for defaults. * * Data_start gives the boundary between the text segment and the data * segment of the program. The text segment can contain shared, read-only * program code and literal data, while the data segment is always unshared * and unprotected. Data_start gives the lowest unprotected address. * The value you specify may be rounded down to a suitable boundary * as required by the machine you are using. * * Bss_start indicates how much of the data segment is to be saved in the * a.out file and restored when the program is executed. It gives the lowest * unsaved address, and is rounded up to a page boundary. The default when 0 * is given assumes that the entire data segment is to be stored, including * the previous data and bss as well as any additional storage allocated with * break (2). * * The new file is set up to start at entry_address. * */ /* Even more heavily modified by james@bigtex.cactus.org of Dell Computer Co. * ELF support added. * * Basic theory: the data space of the running process needs to be * dumped to the output file. Normally we would just enlarge the size * of .data, scooting everything down. But we can't do that in ELF, * because there is often something between the .data space and the * .bss space. * * In the temacs dump below, notice that the Global Offset Table * (.got) and the Dynamic link data (.dynamic) come between .data1 and * .bss. It does not work to overlap .data with these fields. * * The solution is to create a new .data segment. This segment is * filled with data from the current process. Since the contents of * various sections refer to sections by index, the new .data segment * is made the last in the table to avoid changing any existing index. * This is an example of how the section headers are changed. "Addr" * is a process virtual address. "Offset" is a file offset. raid:/nfs/raid/src/dist-18.56/src> dump -h temacs temacs: **** SECTION HEADER TABLE **** [No] Type Flags Addr Offset Size Name Link Info Adralgn Entsize [1] 1 2 0x80480d4 0xd4 0x13 .interp 0 0 0x1 0 [2] 5 2 0x80480e8 0xe8 0x388 .hash 3 0 0x4 0x4 [3] 11 2 0x8048470 0x470 0x7f0 .dynsym 4 1 0x4 0x10 [4] 3 2 0x8048c60 0xc60 0x3ad .dynstr 0 0 0x1 0 [5] 9 2 0x8049010 0x1010 0x338 .rel.plt 3 7 0x4 0x8 [6] 1 6 0x8049348 0x1348 0x3 .init 0 0 0x4 0 [7] 1 6 0x804934c 0x134c 0x680 .plt 0 0 0x4 0x4 [8] 1 6 0x80499cc 0x19cc 0x3c56f .text 0 0 0x4 0 [9] 1 6 0x8085f3c 0x3df3c 0x3 .fini 0 0 0x4 0 [10] 1 2 0x8085f40 0x3df40 0x69c .rodata 0 0 0x4 0 [11] 1 2 0x80865dc 0x3e5dc 0xd51 .rodata1 0 0 0x4 0 [12] 1 3 0x8088330 0x3f330 0x20afc .data 0 0 0x4 0 [13] 1 3 0x80a8e2c 0x5fe2c 0x89d .data1 0 0 0x4 0 [14] 1 3 0x80a96cc 0x606cc 0x1a8 .got 0 0 0x4 0x4 [15] 6 3 0x80a9874 0x60874 0x80 .dynamic 4 0 0x4 0x8 [16] 8 3 0x80a98f4 0x608f4 0x449c .bss 0 0 0x4 0 [17] 2 0 0 0x608f4 0x9b90 .symtab 18 371 0x4 0x10 [18] 3 0 0 0x6a484 0x8526 .strtab 0 0 0x1 0 [19] 3 0 0 0x729aa 0x93 .shstrtab 0 0 0x1 0 [20] 1 0 0 0x72a3d 0x68b7 .comment 0 0 0x1 0 raid:/nfs/raid/src/dist-18.56/src> dump -h xemacs xemacs: **** SECTION HEADER TABLE **** [No] Type Flags Addr Offset Size Name Link Info Adralgn Entsize [1] 1 2 0x80480d4 0xd4 0x13 .interp 0 0 0x1 0 [2] 5 2 0x80480e8 0xe8 0x388 .hash 3 0 0x4 0x4 [3] 11 2 0x8048470 0x470 0x7f0 .dynsym 4 1 0x4 0x10 [4] 3 2 0x8048c60 0xc60 0x3ad .dynstr 0 0 0x1 0 [5] 9 2 0x8049010 0x1010 0x338 .rel.plt 3 7 0x4 0x8 [6] 1 6 0x8049348 0x1348 0x3 .init 0 0 0x4 0 [7] 1 6 0x804934c 0x134c 0x680 .plt 0 0 0x4 0x4 [8] 1 6 0x80499cc 0x19cc 0x3c56f .text 0 0 0x4 0 [9] 1 6 0x8085f3c 0x3df3c 0x3 .fini 0 0 0x4 0 [10] 1 2 0x8085f40 0x3df40 0x69c .rodata 0 0 0x4 0 [11] 1 2 0x80865dc 0x3e5dc 0xd51 .rodata1 0 0 0x4 0 [12] 1 3 0x8088330 0x3f330 0x20afc .data 0 0 0x4 0 [13] 1 3 0x80a8e2c 0x5fe2c 0x89d .data1 0 0 0x4 0 [14] 1 3 0x80a96cc 0x606cc 0x1a8 .got 0 0 0x4 0x4 [15] 6 3 0x80a9874 0x60874 0x80 .dynamic 4 0 0x4 0x8 [16] 8 3 0x80c6800 0x7d800 0 .bss 0 0 0x4 0 [17] 2 0 0 0x7d800 0x9b90 .symtab 18 371 0x4 0x10 [18] 3 0 0 0x87390 0x8526 .strtab 0 0 0x1 0 [19] 3 0 0 0x8f8b6 0x93 .shstrtab 0 0 0x1 0 [20] 1 0 0 0x8f949 0x68b7 .comment 0 0 0x1 0 [21] 1 3 0x80a98f4 0x608f4 0x1cf0c .data 0 0 0x4 0 * This is an example of how the file header is changed. "Shoff" is * the section header offset within the file. Since that table is * after the new .data section, it is moved. "Shnum" is the number of * sections, which we increment. * * "Phoff" is the file offset to the program header. "Phentsize" and * "Shentsz" are the program and section header entries sizes respectively. * These can be larger than the apparent struct sizes. raid:/nfs/raid/src/dist-18.56/src> dump -f temacs temacs: **** ELF HEADER **** Class Data Type Machine Version Entry Phoff Shoff Flags Ehsize Phentsize Phnum Shentsz Shnum Shstrndx 1 1 2 3 1 0x80499cc 0x34 0x792f4 0 0x34 0x20 5 0x28 21 19 raid:/nfs/raid/src/dist-18.56/src> dump -f xemacs xemacs: **** ELF HEADER **** Class Data Type Machine Version Entry Phoff Shoff Flags Ehsize Phentsize Phnum Shentsz Shnum Shstrndx 1 1 2 3 1 0x80499cc 0x34 0x96200 0 0x34 0x20 5 0x28 22 19 * These are the program headers. "Offset" is the file offset to the * segment. "Vaddr" is the memory load address. "Filesz" is the * segment size as it appears in the file, and "Memsz" is the size in * memory. Below, the third segment is the code and the fourth is the * data: the difference between Filesz and Memsz is .bss raid:/nfs/raid/src/dist-18.56/src> dump -o temacs temacs: ***** PROGRAM EXECUTION HEADER ***** Type Offset Vaddr Paddr Filesz Memsz Flags Align 6 0x34 0x8048034 0 0xa0 0xa0 5 0 3 0xd4 0 0 0x13 0 4 0 1 0x34 0x8048034 0 0x3f2f9 0x3f2f9 5 0x1000 1 0x3f330 0x8088330 0 0x215c4 0x25a60 7 0x1000 2 0x60874 0x80a9874 0 0x80 0 7 0 raid:/nfs/raid/src/dist-18.56/src> dump -o xemacs xemacs: ***** PROGRAM EXECUTION HEADER ***** Type Offset Vaddr Paddr Filesz Memsz Flags Align 6 0x34 0x8048034 0 0xa0 0xa0 5 0 3 0xd4 0 0 0x13 0 4 0 1 0x34 0x8048034 0 0x3f2f9 0x3f2f9 5 0x1000 1 0x3f330 0x8088330 0 0x3e4d0 0x3e4d0 7 0x1000 2 0x60874 0x80a9874 0 0x80 0 7 0 */ /* Modified by wtien@urbana.mcd.mot.com of Motorola Inc. * * The above mechanism does not work if the unexeced ELF file is being * re-layout by other applications (such as `strip'). All the applications * that re-layout the internal of ELF will layout all sections in ascending * order of their file offsets. After the re-layout, the data2 section will * still be the LAST section in the section header vector, but its file offset * is now being pushed far away down, and causes part of it not to be mapped * in (ie. not covered by the load segment entry in PHDR vector), therefore * causes the new binary to fail. * * The solution is to modify the unexec algorithm to insert the new data2 * section header right before the new bss section header, so their file * offsets will be in the ascending order. Since some of the section's (all * sections AFTER the bss section) indexes are now changed, we also need to * modify some fields to make them point to the right sections. This is done * by macro PATCH_INDEX. All the fields that need to be patched are: * * 1. ELF header e_shstrndx field. * 2. section header sh_link and sh_info field. * 3. symbol table entry st_shndx field. * * The above example now should look like: **** SECTION HEADER TABLE **** [No] Type Flags Addr Offset Size Name Link Info Adralgn Entsize [1] 1 2 0x80480d4 0xd4 0x13 .interp 0 0 0x1 0 [2] 5 2 0x80480e8 0xe8 0x388 .hash 3 0 0x4 0x4 [3] 11 2 0x8048470 0x470 0x7f0 .dynsym 4 1 0x4 0x10 [4] 3 2 0x8048c60 0xc60 0x3ad .dynstr 0 0 0x1 0 [5] 9 2 0x8049010 0x1010 0x338 .rel.plt 3 7 0x4 0x8 [6] 1 6 0x8049348 0x1348 0x3 .init 0 0 0x4 0 [7] 1 6 0x804934c 0x134c 0x680 .plt 0 0 0x4 0x4 [8] 1 6 0x80499cc 0x19cc 0x3c56f .text 0 0 0x4 0 [9] 1 6 0x8085f3c 0x3df3c 0x3 .fini 0 0 0x4 0 [10] 1 2 0x8085f40 0x3df40 0x69c .rodata 0 0 0x4 0 [11] 1 2 0x80865dc 0x3e5dc 0xd51 .rodata1 0 0 0x4 0 [12] 1 3 0x8088330 0x3f330 0x20afc .data 0 0 0x4 0 [13] 1 3 0x80a8e2c 0x5fe2c 0x89d .data1 0 0 0x4 0 [14] 1 3 0x80a96cc 0x606cc 0x1a8 .got 0 0 0x4 0x4 [15] 6 3 0x80a9874 0x60874 0x80 .dynamic 4 0 0x4 0x8 [16] 1 3 0x80a98f4 0x608f4 0x1cf0c .data 0 0 0x4 0 [17] 8 3 0x80c6800 0x7d800 0 .bss 0 0 0x4 0 [18] 2 0 0 0x7d800 0x9b90 .symtab 19 371 0x4 0x10 [19] 3 0 0 0x87390 0x8526 .strtab 0 0 0x1 0 [20] 3 0 0 0x8f8b6 0x93 .shstrtab 0 0 0x1 0 [21] 1 0 0 0x8f949 0x68b7 .comment 0 0 0x1 0 */ /* We do not use mmap because that fails with NFS. Instead we read the whole file, modify it, and write it out. */ #ifndef emacs #define fatal(a, b, c) fprintf (stderr, a, b, c), exit (1) #include #else #include extern void fatal (const char *msgid, ...); #endif #include #include #include #include #include #include #include #if !defined (__NetBSD__) && !defined (__OpenBSD__) #include #endif #include #if defined (__sony_news) && defined (_SYSTYPE_SYSV) #include #include #endif /* __sony_news && _SYSTYPE_SYSV */ #if __sgi #include /* for HDRR declaration */ #endif /* __sgi */ #ifndef MAP_ANON #ifdef MAP_ANONYMOUS #define MAP_ANON MAP_ANONYMOUS #else #define MAP_ANON 0 #endif #endif #ifndef MAP_FAILED #define MAP_FAILED ((void *) -1) #endif #if defined (__alpha__) && !defined (__NetBSD__) && !defined (__OpenBSD__) /* Declare COFF debugging symbol table. This used to be in /usr/include/sym.h, but this file is no longer included in Red Hat 5.0 and presumably in any other glibc 2.x based distribution. */ typedef struct { short magic; short vstamp; int ilineMax; int idnMax; int ipdMax; int isymMax; int ioptMax; int iauxMax; int issMax; int issExtMax; int ifdMax; int crfd; int iextMax; long cbLine; long cbLineOffset; long cbDnOffset; long cbPdOffset; long cbSymOffset; long cbOptOffset; long cbAuxOffset; long cbSsOffset; long cbSsExtOffset; long cbFdOffset; long cbRfdOffset; long cbExtOffset; } HDRR, *pHDRR; #define cbHDRR sizeof(HDRR) #define hdrNil ((pHDRR)0) #endif #ifdef __NetBSD__ /* * NetBSD does not have normal-looking user-land ELF support. */ # if defined __alpha__ || defined __sparc_v9__ # define ELFSIZE 64 # else # define ELFSIZE 32 # endif # include # ifndef PT_LOAD # define PT_LOAD Elf_pt_load # if 0 /* was in pkgsrc patches for 20.7 */ # define SHT_PROGBITS Elf_sht_progbits # endif # define SHT_SYMTAB Elf_sht_symtab # define SHT_DYNSYM Elf_sht_dynsym # define SHT_NULL Elf_sht_null # define SHT_NOBITS Elf_sht_nobits # define SHT_REL Elf_sht_rel # define SHT_RELA Elf_sht_rela # define SHN_UNDEF Elf_eshn_undefined # define SHN_ABS Elf_eshn_absolute # define SHN_COMMON Elf_eshn_common # endif /* !PT_LOAD */ # ifdef __alpha__ # include # define HDRR struct ecoff_symhdr # define pHDRR HDRR * # endif /* __alpha__ */ #ifdef __mips__ /* was in pkgsrc patches for 20.7 */ # define SHT_MIPS_DEBUG DT_MIPS_FLAGS # define HDRR struct Elf_Shdr #endif /* __mips__ */ #endif /* __NetBSD__ */ #ifdef __OpenBSD__ # include #endif #if __GNU_LIBRARY__ - 0 >= 6 # include /* get ElfW etc */ #endif #ifndef ElfW # ifdef __STDC__ # define ElfBitsW(bits, type) Elf##bits##_##type # else # define ElfBitsW(bits, type) Elf/**/bits/**/_/**/type # endif # ifdef _LP64 # define ELFSIZE 64 # else # define ELFSIZE 32 # endif /* This macro expands `bits' before invoking ElfBitsW. */ # define ElfExpandBitsW(bits, type) ElfBitsW (bits, type) # define ElfW(type) ElfExpandBitsW (ELFSIZE, type) #endif #ifndef ELF_BSS_SECTION_NAME #define ELF_BSS_SECTION_NAME ".bss" #endif /* Get the address of a particular section or program header entry, * accounting for the size of the entries. */ /* On PPC Reference Platform running Solaris 2.5.1 the plt section is also of type NOBI like the bss section. (not really stored) and therefore sections after the bss section start at the plt offset. The plt section is always the one just before the bss section. Thus, we modify the test from if (NEW_SECTION_H (nn).sh_offset >= new_data2_offset) to if (NEW_SECTION_H (nn).sh_offset >= OLD_SECTION_H (old_bss_index-1).sh_offset) This is just a hack. We should put the new data section before the .plt section. And we should not have this routine at all but use the libelf library to read the old file and create the new file. The changed code is minimal and depends on prep set in m/prep.h Erik Deumens Quantum Theory Project University of Florida deumens@qtp.ufl.edu Apr 23, 1996 */ #define OLD_SECTION_H(n) \ (*(ElfW(Shdr) *) ((byte *) old_section_h + old_file_h->e_shentsize * (n))) #define NEW_SECTION_H(n) \ (*(ElfW(Shdr) *) ((byte *) new_section_h + new_file_h->e_shentsize * (n))) #define OLD_PROGRAM_H(n) \ (*(ElfW(Phdr) *) ((byte *) old_program_h + old_file_h->e_phentsize * (n))) #define NEW_PROGRAM_H(n) \ (*(ElfW(Phdr) *) ((byte *) new_program_h + new_file_h->e_phentsize * (n))) #define PATCH_INDEX(n) \ do { \ if ((int) (n) >= old_bss_index) \ (n)++; } while (0) typedef unsigned char byte; /* Round X up to a multiple of Y. */ static ElfW(Addr) round_up (x, y) ElfW(Addr) x, y; { int rem = x % y; if (rem == 0) return x; return x - rem + y; } /* Return the index of the section named NAME. SECTION_NAMES, FILE_NAME and FILE_H give information about the file we are looking in. If we don't find the section NAME, that is a fatal error if NOERROR is 0; we return -1 if NOERROR is nonzero. */ static int find_section (name, section_names, file_name, old_file_h, old_section_h, noerror) char *name; char *section_names; char *file_name; ElfW(Ehdr) *old_file_h; ElfW(Shdr) *old_section_h; int noerror; { int idx; for (idx = 1; idx < old_file_h->e_shnum; idx++) { #ifdef DEBUG fprintf (stderr, "Looking for %s - found %s\n", name, section_names + OLD_SECTION_H (idx).sh_name); #endif if (!strcmp (section_names + OLD_SECTION_H (idx).sh_name, name)) break; } if (idx == old_file_h->e_shnum) { if (noerror) return -1; else fatal ("Can't find %s in %s.\n", name, file_name); } return idx; } /* **************************************************************** * unexec * * driving logic. * * In ELF, this works by replacing the old .bss section with a new * .data section, and inserting an empty .bss immediately afterwards. * */ void unexec (new_name, old_name, data_start, bss_start, entry_address) char *new_name, *old_name; unsigned data_start, bss_start, entry_address; { int new_file, old_file, new_file_size; /* Pointers to the base of the image of the two files. */ caddr_t old_base, new_base; #if MAP_ANON == 0 int mmap_fd; #else # define mmap_fd -1 #endif /* Pointers to the file, program and section headers for the old and new files. */ ElfW(Ehdr) *old_file_h, *new_file_h; ElfW(Phdr) *old_program_h, *new_program_h; ElfW(Shdr) *old_section_h, *new_section_h; /* Point to the section name table in the old file. */ char *old_section_names; ElfW(Addr) old_bss_addr, new_bss_addr; ElfW(Word) old_bss_size, new_data2_size; ElfW(Off) new_data2_offset; ElfW(Addr) new_data2_addr; int n, nn; int old_bss_index, old_sbss_index; int old_data_index, new_data2_index; int old_mdebug_index; struct stat stat_buf; int old_file_size; /* Open the old file, allocate a buffer of the right size, and read in the file contents. */ old_file = open (old_name, O_RDONLY); if (old_file < 0) fatal ("Can't open %s for reading: errno %d\n", old_name, errno); if (fstat (old_file, &stat_buf) == -1) fatal ("Can't fstat (%s): errno %d\n", old_name, errno); #if MAP_ANON == 0 mmap_fd = open ("/dev/zero", O_RDONLY); if (mmap_fd < 0) fatal ("Can't open /dev/zero for reading: errno %d\n", errno, 0); #endif /* We cannot use malloc here because that may use sbrk. If it does, we'd dump our temporary buffers with Emacs, and we'd have to be extra careful to use the correct value of sbrk(0) after allocating all buffers in the code below, which we aren't. */ old_file_size = stat_buf.st_size; old_base = mmap (NULL, old_file_size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, mmap_fd, 0); if (old_base == MAP_FAILED) fatal ("Can't allocate buffer for %s\n", old_name, 0); if (read (old_file, old_base, stat_buf.st_size) != stat_buf.st_size) fatal ("Didn't read all of %s: errno %d\n", old_name, errno); /* Get pointers to headers & section names */ old_file_h = (ElfW(Ehdr) *) old_base; old_program_h = (ElfW(Phdr) *) ((byte *) old_base + old_file_h->e_phoff); old_section_h = (ElfW(Shdr) *) ((byte *) old_base + old_file_h->e_shoff); old_section_names = (char *) old_base + OLD_SECTION_H (old_file_h->e_shstrndx).sh_offset; /* Find the mdebug section, if any. */ old_mdebug_index = find_section (".mdebug", old_section_names, old_name, old_file_h, old_section_h, 1); /* Find the old .bss section. Figure out parameters of the new data2 and bss sections. */ old_bss_index = find_section (".bss", old_section_names, old_name, old_file_h, old_section_h, 0); old_sbss_index = find_section (".sbss", old_section_names, old_name, old_file_h, old_section_h, 1); if (old_sbss_index != -1) if (OLD_SECTION_H (old_sbss_index).sh_type == SHT_PROGBITS) old_sbss_index = -1; if (old_sbss_index == -1) { old_bss_addr = OLD_SECTION_H (old_bss_index).sh_addr; old_bss_size = OLD_SECTION_H (old_bss_index).sh_size; new_data2_index = old_bss_index; } else { old_bss_addr = OLD_SECTION_H (old_sbss_index).sh_addr; old_bss_size = OLD_SECTION_H (old_bss_index).sh_size + OLD_SECTION_H (old_sbss_index).sh_size; new_data2_index = old_sbss_index; } /* Find the old .data section. Figure out parameters of the new data2 and bss sections. */ old_data_index = find_section (".data", old_section_names, old_name, old_file_h, old_section_h, 0); #if defined (emacs) || !defined (DEBUG) new_bss_addr = (ElfW(Addr)) sbrk (0); #else new_bss_addr = old_bss_addr + old_bss_size + 0x1234; #endif new_data2_addr = old_bss_addr; new_data2_size = new_bss_addr - old_bss_addr; new_data2_offset = OLD_SECTION_H (old_data_index).sh_offset + (new_data2_addr - OLD_SECTION_H (old_data_index).sh_addr); #ifdef DEBUG fprintf (stderr, "old_bss_index %d\n", old_bss_index); fprintf (stderr, "old_bss_addr %x\n", old_bss_addr); fprintf (stderr, "old_bss_size %x\n", old_bss_size); fprintf (stderr, "new_bss_addr %x\n", new_bss_addr); fprintf (stderr, "new_data2_addr %x\n", new_data2_addr); fprintf (stderr, "new_data2_size %x\n", new_data2_size); fprintf (stderr, "new_data2_offset %x\n", new_data2_offset); #endif if ((unsigned) new_bss_addr < (unsigned) old_bss_addr + old_bss_size) fatal (".bss shrank when undumping???\n", 0, 0); /* Set the output file to the right size. Allocate a buffer to hold the image of the new file. Set pointers to various interesting objects. stat_buf still has old_file data. */ new_file = open (new_name, O_RDWR | O_CREAT, 0666); if (new_file < 0) fatal ("Can't creat (%s): errno %d\n", new_name, errno); new_file_size = stat_buf.st_size + old_file_h->e_shentsize + new_data2_size; if (ftruncate (new_file, new_file_size)) fatal ("Can't ftruncate (%s): errno %d\n", new_name, errno); new_base = mmap (NULL, new_file_size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, mmap_fd, 0); if (new_base == MAP_FAILED) fatal ("Can't allocate buffer for %s\n", old_name, 0); new_file_h = (ElfW(Ehdr) *) new_base; new_program_h = (ElfW(Phdr) *) ((byte *) new_base + old_file_h->e_phoff); new_section_h = (ElfW(Shdr) *) ((byte *) new_base + old_file_h->e_shoff + new_data2_size); /* Make our new file, program and section headers as copies of the originals. */ memcpy (new_file_h, old_file_h, old_file_h->e_ehsize); memcpy (new_program_h, old_program_h, old_file_h->e_phnum * old_file_h->e_phentsize); /* Modify the e_shstrndx if necessary. */ PATCH_INDEX (new_file_h->e_shstrndx); /* Fix up file header. We'll add one section. Section header is further away now. */ new_file_h->e_shoff += new_data2_size; new_file_h->e_shnum += 1; #ifdef DEBUG fprintf (stderr, "Old section offset %x\n", old_file_h->e_shoff); fprintf (stderr, "Old section count %d\n", old_file_h->e_shnum); fprintf (stderr, "New section offset %x\n", new_file_h->e_shoff); fprintf (stderr, "New section count %d\n", new_file_h->e_shnum); #endif /* Fix up a new program header. Extend the writable data segment so that the bss area is covered too. Find that segment by looking for a segment that ends just before the .bss area. Make sure that no segments are above the new .data2. Put a loop at the end to adjust the offset and address of any segment that is above data2, just in case we decide to allow this later. */ for (n = new_file_h->e_phnum - 1; n >= 0; n--) { /* Compute maximum of all requirements for alignment of section. */ ElfW(Word) alignment = (NEW_PROGRAM_H (n)).p_align; if ((OLD_SECTION_H (old_bss_index)).sh_addralign > alignment) alignment = OLD_SECTION_H (old_bss_index).sh_addralign; #ifdef __sgi /* According to r02kar@x4u2.desy.de (Karsten Kuenne) and oliva@gnu.org (Alexandre Oliva), on IRIX 5.2, we always get "Program segment above .bss" when dumping when the executable doesn't have an sbss section. */ if (old_sbss_index != -1) #endif /* __sgi */ if (NEW_PROGRAM_H (n).p_vaddr + NEW_PROGRAM_H (n).p_filesz > (old_sbss_index == -1 ? old_bss_addr : round_up (old_bss_addr, alignment))) fatal ("Program segment above .bss in %s\n", old_name, 0); if (NEW_PROGRAM_H (n).p_type == PT_LOAD && (round_up ((NEW_PROGRAM_H (n)).p_vaddr + (NEW_PROGRAM_H (n)).p_filesz, alignment) == round_up (old_bss_addr, alignment))) break; } if (n < 0) fatal ("Couldn't find segment next to .bss in %s\n", old_name, 0); /* Make sure that the size includes any padding before the old .bss section. */ NEW_PROGRAM_H (n).p_filesz = new_bss_addr - NEW_PROGRAM_H (n).p_vaddr; NEW_PROGRAM_H (n).p_memsz = NEW_PROGRAM_H (n).p_filesz; #if 0 /* Maybe allow section after data2 - does this ever happen? */ for (n = new_file_h->e_phnum - 1; n >= 0; n--) { if (NEW_PROGRAM_H (n).p_vaddr && NEW_PROGRAM_H (n).p_vaddr >= new_data2_addr) NEW_PROGRAM_H (n).p_vaddr += new_data2_size - old_bss_size; if (NEW_PROGRAM_H (n).p_offset >= new_data2_offset) NEW_PROGRAM_H (n).p_offset += new_data2_size; } #endif /* Fix up section headers based on new .data2 section. Any section whose offset or virtual address is after the new .data2 section gets its value adjusted. .bss size becomes zero and new address is set. data2 section header gets added by copying the existing .data header and modifying the offset, address and size. */ for (old_data_index = 1; old_data_index < (int) old_file_h->e_shnum; old_data_index++) if (!strcmp (old_section_names + OLD_SECTION_H (old_data_index).sh_name, ".data")) break; if (old_data_index == old_file_h->e_shnum) fatal ("Can't find .data in %s.\n", old_name, 0); /* Walk through all section headers, insert the new data2 section right before the new bss section. */ for (n = 1, nn = 1; n < (int) old_file_h->e_shnum; n++, nn++) { caddr_t src; /* If it is (s)bss section, insert the new data2 section before it. */ /* new_data2_index is the index of either old_sbss or old_bss, that was chosen as a section for new_data2. */ if (n == new_data2_index) { /* Steal the data section header for this data2 section. */ memcpy (&NEW_SECTION_H (nn), &OLD_SECTION_H (old_data_index), new_file_h->e_shentsize); NEW_SECTION_H (nn).sh_addr = new_data2_addr; NEW_SECTION_H (nn).sh_offset = new_data2_offset; NEW_SECTION_H (nn).sh_size = new_data2_size; /* Use the bss section's alignment. This will assure that the new data2 section always be placed in the same spot as the old bss section by any other application. */ NEW_SECTION_H (nn).sh_addralign = OLD_SECTION_H (n).sh_addralign; /* Now copy over what we have in the memory now. */ memcpy (NEW_SECTION_H (nn).sh_offset + new_base, (caddr_t) OLD_SECTION_H (n).sh_addr, new_data2_size); nn++; } memcpy (&NEW_SECTION_H (nn), &OLD_SECTION_H (n), old_file_h->e_shentsize); if (n == old_bss_index /* The new bss and sbss section's size is zero, and its file offset and virtual address should be off by NEW_DATA2_SIZE. */ || n == old_sbss_index ) { /* NN should be `old_s?bss_index + 1' at this point. */ NEW_SECTION_H (nn).sh_offset = NEW_SECTION_H (new_data2_index).sh_offset + new_data2_size; NEW_SECTION_H (nn).sh_addr = NEW_SECTION_H (new_data2_index).sh_addr + new_data2_size; /* Let the new bss section address alignment be the same as the section address alignment followed the old bss section, so this section will be placed in exactly the same place. */ NEW_SECTION_H (nn).sh_addralign = OLD_SECTION_H (nn).sh_addralign; NEW_SECTION_H (nn).sh_size = 0; } else { /* Any section that was originally placed after the .bss section should now be off by NEW_DATA2_SIZE. If a section overlaps the .bss section, consider it to be placed after the .bss section. Overlap can occur if the section just before .bss has less-strict alignment; this was observed between .symtab and .bss on Solaris 2.5.1 (sparc) with GCC snapshot 960602. */ #ifdef SOLARIS_POWERPC /* On PPC Reference Platform running Solaris 2.5.1 the plt section is also of type NOBI like the bss section. (not really stored) and therefore sections after the bss section start at the plt offset. The plt section is always the one just before the bss section. It would be better to put the new data section before the .plt section, or use libelf instead. Erik Deumens, deumens@qtp.ufl.edu. */ if (NEW_SECTION_H (nn).sh_offset >= OLD_SECTION_H (old_bss_index-1).sh_offset) NEW_SECTION_H (nn).sh_offset += new_data2_size; #else if (NEW_SECTION_H (nn).sh_offset + NEW_SECTION_H (nn).sh_size > new_data2_offset) NEW_SECTION_H (nn).sh_offset += new_data2_size; #endif /* Any section that was originally placed after the section header table should now be off by the size of one section header table entry. */ if (NEW_SECTION_H (nn).sh_offset > new_file_h->e_shoff) NEW_SECTION_H (nn).sh_offset += new_file_h->e_shentsize; } /* If any section hdr refers to the section after the new .data section, make it refer to next one because we have inserted a new section in between. */ PATCH_INDEX (NEW_SECTION_H (nn).sh_link); /* For symbol tables, info is a symbol table index, so don't change it. */ if (NEW_SECTION_H (nn).sh_type != SHT_SYMTAB && NEW_SECTION_H (nn).sh_type != SHT_DYNSYM) PATCH_INDEX (NEW_SECTION_H (nn).sh_info); if (old_sbss_index != -1) if (!strcmp (old_section_names + NEW_SECTION_H (nn).sh_name, ".sbss")) { NEW_SECTION_H (nn).sh_offset = round_up (NEW_SECTION_H (nn).sh_offset, NEW_SECTION_H (nn).sh_addralign); NEW_SECTION_H (nn).sh_type = SHT_PROGBITS; } /* Now, start to copy the content of sections. */ if (NEW_SECTION_H (nn).sh_type == SHT_NULL || NEW_SECTION_H (nn).sh_type == SHT_NOBITS) continue; /* Write out the sections. .data and .data1 (and data2, called ".data" in the strings table) get copied from the current process instead of the old file. */ if (!strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".data") || !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name), ".sdata") || !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name), ".lit4") || !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name), ".lit8") /* The conditional bit below was in Oliva's original code (1999-08-25) and seems to have been dropped by mistake subsequently. It prevents a crash at startup under X in `IRIX64 6.5 6.5.17m', whether compiled on that relase or an earlier one. It causes no trouble on the other ELF platforms I could test (Irix 6.5.15m, Solaris 8, Debian Potato x86, Debian Woody SPARC); however, it's reported to cause crashes under some version of GNU/Linux. It's not yet clear what's changed in that Irix version to cause the problem, or why the fix sometimes fails under GNU/Linux. There's probably no good reason to have something Irix-specific here, but this will have to do for now. IRIX6_5 is the most specific macro we have to test. -- fx 2002-10-01 The issue _looks_ as though it's gone away on 6.5.18m, but maybe it's still lurking, to be triggered by some change in the binary. It appears to concern the dynamic loader, but I never got anywhere with an SGI support call seeking clues. -- fx 2002-11-29. */ #ifdef IRIX6_5 || !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name), ".got") #endif || !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name), ".sdata1") || !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name), ".data1") || !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name), ".sbss")) src = (caddr_t) OLD_SECTION_H (n).sh_addr; else src = old_base + OLD_SECTION_H (n).sh_offset; memcpy (NEW_SECTION_H (nn).sh_offset + new_base, src, NEW_SECTION_H (nn).sh_size); #ifdef __alpha__ /* Update Alpha COFF symbol table: */ if (strcmp (old_section_names + OLD_SECTION_H (n).sh_name, ".mdebug") == 0) { pHDRR symhdr = (pHDRR) (NEW_SECTION_H (nn).sh_offset + new_base); symhdr->cbLineOffset += new_data2_size; symhdr->cbDnOffset += new_data2_size; symhdr->cbPdOffset += new_data2_size; symhdr->cbSymOffset += new_data2_size; symhdr->cbOptOffset += new_data2_size; symhdr->cbAuxOffset += new_data2_size; symhdr->cbSsOffset += new_data2_size; symhdr->cbSsExtOffset += new_data2_size; symhdr->cbFdOffset += new_data2_size; symhdr->cbRfdOffset += new_data2_size; symhdr->cbExtOffset += new_data2_size; } #endif /* __alpha__ */ #if defined (__sony_news) && defined (_SYSTYPE_SYSV) if (NEW_SECTION_H (nn).sh_type == SHT_MIPS_DEBUG && old_mdebug_index != -1) { int diff = NEW_SECTION_H(nn).sh_offset - OLD_SECTION_H(old_mdebug_index).sh_offset; HDRR *phdr = (HDRR *)(NEW_SECTION_H (nn).sh_offset + new_base); if (diff) { phdr->cbLineOffset += diff; phdr->cbDnOffset += diff; phdr->cbPdOffset += diff; phdr->cbSymOffset += diff; phdr->cbOptOffset += diff; phdr->cbAuxOffset += diff; phdr->cbSsOffset += diff; phdr->cbSsExtOffset += diff; phdr->cbFdOffset += diff; phdr->cbRfdOffset += diff; phdr->cbExtOffset += diff; } } #endif /* __sony_news && _SYSTYPE_SYSV */ #if __sgi /* Adjust the HDRR offsets in .mdebug and copy the line data if it's in its usual 'hole' in the object. Makes the new file debuggable with dbx. patches up two problems: the absolute file offsets in the HDRR record of .mdebug (see /usr/include/syms.h), and the ld bug that gets the line table in a hole in the elf file rather than in the .mdebug section proper. David Anderson. davea@sgi.com Jan 16,1994. */ if (n == old_mdebug_index) { #define MDEBUGADJUST(__ct,__fileaddr) \ if (n_phdrr->__ct > 0) \ { \ n_phdrr->__fileaddr += movement; \ } HDRR * o_phdrr = (HDRR *)((byte *)old_base + OLD_SECTION_H (n).sh_offset); HDRR * n_phdrr = (HDRR *)((byte *)new_base + NEW_SECTION_H (nn).sh_offset); unsigned movement = new_data2_size; MDEBUGADJUST (idnMax, cbDnOffset); MDEBUGADJUST (ipdMax, cbPdOffset); MDEBUGADJUST (isymMax, cbSymOffset); MDEBUGADJUST (ioptMax, cbOptOffset); MDEBUGADJUST (iauxMax, cbAuxOffset); MDEBUGADJUST (issMax, cbSsOffset); MDEBUGADJUST (issExtMax, cbSsExtOffset); MDEBUGADJUST (ifdMax, cbFdOffset); MDEBUGADJUST (crfd, cbRfdOffset); MDEBUGADJUST (iextMax, cbExtOffset); /* The Line Section, being possible off in a hole of the object, requires special handling. */ if (n_phdrr->cbLine > 0) { if (o_phdrr->cbLineOffset > (OLD_SECTION_H (n).sh_offset + OLD_SECTION_H (n).sh_size)) { /* line data is in a hole in elf. do special copy and adjust for this ld mistake. */ n_phdrr->cbLineOffset += movement; memcpy (n_phdrr->cbLineOffset + new_base, o_phdrr->cbLineOffset + old_base, n_phdrr->cbLine); } else { /* somehow line data is in .mdebug as it is supposed to be. */ MDEBUGADJUST (cbLine, cbLineOffset); } } } #endif /* __sgi */ /* If it is the symbol table, its st_shndx field needs to be patched. */ if (NEW_SECTION_H (nn).sh_type == SHT_SYMTAB || NEW_SECTION_H (nn).sh_type == SHT_DYNSYM) { ElfW(Shdr) *spt = &NEW_SECTION_H (nn); unsigned int num = spt->sh_size / spt->sh_entsize; ElfW(Sym) * sym = (ElfW(Sym) *) (NEW_SECTION_H (nn).sh_offset + new_base); for (; num--; sym++) { if ((sym->st_shndx == SHN_UNDEF) || (sym->st_shndx == SHN_ABS) || (sym->st_shndx == SHN_COMMON)) continue; PATCH_INDEX (sym->st_shndx); } } } /* Update the symbol values of _edata and _end. */ for (n = new_file_h->e_shnum - 1; n; n--) { byte *symnames; ElfW(Sym) *symp, *symendp; if (NEW_SECTION_H (n).sh_type != SHT_DYNSYM && NEW_SECTION_H (n).sh_type != SHT_SYMTAB) continue; symnames = ((byte *) new_base + NEW_SECTION_H (NEW_SECTION_H (n).sh_link).sh_offset); symp = (ElfW(Sym) *) (NEW_SECTION_H (n).sh_offset + new_base); symendp = (ElfW(Sym) *) ((byte *)symp + NEW_SECTION_H (n).sh_size); for (; symp < symendp; symp ++) if (strcmp ((char *) (symnames + symp->st_name), "_end") == 0 || strcmp ((char *) (symnames + symp->st_name), "end") == 0 || strcmp ((char *) (symnames + symp->st_name), "_edata") == 0 || strcmp ((char *) (symnames + symp->st_name), "edata") == 0) memcpy (&symp->st_value, &new_bss_addr, sizeof (new_bss_addr)); } /* This loop seeks out relocation sections for the data section, so that it can undo relocations performed by the runtime linker. */ for (n = new_file_h->e_shnum - 1; n; n--) { ElfW(Shdr) section = NEW_SECTION_H (n); /* Cause a compilation error if anyone uses n instead of nn below. */ struct {int a;} n; (void)n.a; /* Prevent `unused variable' warnings. */ switch (section.sh_type) { default: break; case SHT_REL: case SHT_RELA: /* This code handles two different size structs, but there should be no harm in that provided that r_offset is always the first member. */ nn = section.sh_info; if (!strcmp (old_section_names + NEW_SECTION_H (nn).sh_name, ".data") || !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name), ".sdata") || !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name), ".lit4") || !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name), ".lit8") #ifdef IRIX6_5 /* see above */ || !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name), ".got") #endif || !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name), ".sdata1") || !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name), ".data1")) { ElfW(Addr) offset = (NEW_SECTION_H (nn).sh_addr - NEW_SECTION_H (nn).sh_offset); caddr_t reloc = old_base + section.sh_offset, end; for (end = reloc + section.sh_size; reloc < end; reloc += section.sh_entsize) { ElfW(Addr) addr = ((ElfW(Rel) *) reloc)->r_offset - offset; #ifdef __alpha__ /* The Alpha ELF binutils currently have a bug that sometimes results in relocs that contain all zeroes. Work around this for now... */ if (((ElfW(Rel) *) reloc)->r_offset == 0) continue; #endif memcpy (new_base + addr, old_base + addr, sizeof(ElfW(Addr))); } } break; } } /* Write out new_file, and free the buffers. */ if (write (new_file, new_base, new_file_size) != new_file_size) #ifndef emacs fatal ("Didn't write %d bytes: errno %d\n", new_file_size, errno); #else fatal ("Didn't write %d bytes to %s: errno %d\n", new_file_size, new_base, errno); #endif munmap (old_base, old_file_size); munmap (new_base, new_file_size); /* Close the files and make the new file executable. */ #if MAP_ANON == 0 close (mmap_fd); #endif if (close (old_file)) fatal ("Can't close (%s): errno %d\n", old_name, errno); if (close (new_file)) fatal ("Can't close (%s): errno %d\n", new_name, errno); if (stat (new_name, &stat_buf) == -1) fatal ("Can't stat (%s): errno %d\n", new_name, errno); n = umask (777); umask (n); stat_buf.st_mode |= 0111 & ~n; if (chmod (new_name, stat_buf.st_mode) == -1) fatal ("Can't chmod (%s): errno %d\n", new_name, errno); } /* arch-tag: e02e1512-95e2-4ef0-bba7-b6bce658f1e3 (do not change this comment) */ scm-5e5/pi.scm0000644001705200017500000001200010750212465011141 0ustar tbtb;;;; "pi.scm" Programs for computing digits of PI and e. ;; Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc. ;; ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU Lesser General Public License as ;; published by the Free Software Foundation, either version 3 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 ;; Lesser General Public License for more details. ;; ;; You should have received a copy of the GNU Lesser General Public ;; License along with this program. If not, see ;; . ;;; Authors: Aubrey Jaffer & Jerry D. Hedden ;;; (pi ) prints out digits of pi in groups of digits. ;;; 'Spigot' algorithm origionally due to Stanly Rabinowitz. ;;; This algorithm takes time proportional to the square of /. ;;; This fact can make comparisons of computational speed between systems ;;; of vastly differring performances quicker and more accurate. ;;; Try (pi 100 5) ;;; The digit size will have to be reduced for larger or an ;;; overflow error will occur (on systems lacking bignums). ;;; It your Scheme has bignums try (pi 1000). (define (pi n . args) (if (null? args) (bigpi n) (let* ((d (car args)) (r (do ((s 1 (* 10 s)) (i d (- i 1))) ((zero? i) s))) (n (+ (quotient n d) 1)) (m (quotient (* n d 3322) 1000)) (a (make-vector (+ 1 m) 2))) (vector-set! a m 4) (do ((j 1 (+ 1 j)) (q 0 0) (b 2 (remainder q r))) ((> j n)) (do ((k m (- k 1))) ((zero? k)) (set! q (+ q (* (vector-ref a k) r))) (let ((t (+ 1 (* 2 k)))) (vector-set! a k (remainder q t)) (set! q (* k (quotient q t))))) (let ((s (number->string (+ b (quotient q r))))) (do ((l (string-length s) (+ 1 l))) ((>= l d) (display s)) (display #\0))) (if (zero? (modulo j 10)) (newline) (display #\ ))) (newline)))) ;;; (pi ) prints out digits of pi. ;;; 'Spigot' algorithm originally due to Stanly Rabinowitz: ;;; ;;; PI = 2+(1/3)*(2+(2/5)*(2+(3/7)*(2+ ... *(2+(k/(2k+1))*(4)) ... ))) ;;; ;;; where 'k' is approximately equal to the desired precision of 'n' ;;; places times 'log2(10)'. ;;; ;;; This version takes advantage of "bignums" in SCM to compute all ;;; of the requested digits in one pass! Basically, it calculates ;;; the truncated portion of (PI * 10^n), and then displays it in a ;;; nice format. (define (bigpi digits) (let* ((n (* 10 (quotient (+ digits 9) 10))) ; digits in multiples of 10 (z (inexact->exact (truncate ; z = number of terms (/ (* n (log 10)) (log 2))))) (q (do ((x 2 (* 10000000000 x)) ; q = 2 * 10^n (i (/ n 10) (- i 1))) ((zero? i) x))) (_pi (number->string ; _pi = PI * 10^n ;; do the calculations in one pass!!! (let pi_calc ((j z) (k (+ z z 1)) (p (+ q q))) (if (zero? j) p (pi_calc (- j 1) (- k 2) (+ q (quotient (* p j) k)))))))) ;; print out the result ("3." followed by 5 groups of 10 digits per line) (display (substring _pi 0 1)) (display #\.) (newline) (do ((i 0 (+ i 10))) ((>= i n)) (display (substring _pi (+ i 1) (+ i 11))) (display (if (zero? (modulo (+ i 10) 50)) #\newline #\ ))) (if (not (zero? (modulo n 50))) (newline)))) ;;; (e ) prints out digits of 'e'. ;;; Uses the formula: ;;; ;;; 1 1 1 1 1 ;;; e = 1 + -- + -- + -- + -- + ... + -- ;;; 1! 2! 3! 4! k! ;;; ;;; where 'k' is determined using the desired precision 'n' in: ;;; ;;; n < ((k * (ln(k) - 1)) / ln(10)) ;;; ;;; which uses Stirling's formula for approximating ln(k!) ;;; ;;; This program takes advantage of "bignums" in SCM to compute all ;;; the requested digits at once! Basically, it calculates the ;;; fractional part of 'e' (i.e., e-2) as a fraction of two bignums ;;; 'e_n' and 'e_d', determines the integer part of (e_n * 10^n)/e_d, ;;; and then displays it in a nice format. (define (e digits) (let* ((n (* 10 (quotient (+ digits 9) 10))) ; digits in multiples of 10 (k (do ((i 15 (+ i 1))) ; k = number of terms ((< n (/ (* i (- (log i) 1)) (log 10))) i))) (q (do ((x 1 (* 10000000000 x)) ; q = 10^n (i (/ n 10) (- i 1))) ((zero? i) x))) (_e (let ((ee ; do calculations (let e_calc ((i k) (e_d 1) (e_n 0)) (if (= i 1) (cons (* q e_n) e_d) (e_calc (- i 1) (* e_d i) (+ e_n e_d)))))) (number->string (+ (quotient (car ee) (cdr ee)) ; rounding (if (< (remainder (car ee) (cdr ee)) (quotient (cdr ee) 2)) 0 1)))))) ;; print out the result ("2." followed by 5 groups of 10 digits per line) (display "2.") (newline) (do ((i 0 (+ i 10))) ((>= i n)) (display (substring _e i (+ i 10))) (display (if (zero? (modulo (+ i 10) 50)) #\newline #\ ))) (if (not (zero? (modulo n 50))) (newline)))) scm-5e5/turtle0000644001705200017500000000246305267114342011305 0ustar tbtb#define turtle_width 40 #define turtle_height 40 static char turtle_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0xe0, 0x84, 0x07, 0x00, 0x00, 0x10, 0x0c, 0x78, 0x00, 0x00, 0x0c, 0x08, 0xc0, 0x00, 0x00, 0x02, 0x18, 0x40, 0x03, 0x00, 0x01, 0x28, 0x40, 0x02, 0x80, 0x0f, 0xcc, 0x7f, 0x02, 0xc0, 0xf8, 0x07, 0x10, 0x06, 0x40, 0x00, 0x04, 0x30, 0x0c, 0x60, 0x00, 0x04, 0x7c, 0x08, 0xf8, 0x00, 0x04, 0xc2, 0x0f, 0x8c, 0x01, 0x0f, 0x01, 0x0b, 0x26, 0x01, 0xf1, 0x01, 0x11, 0x03, 0x81, 0x01, 0x81, 0x20, 0x07, 0x83, 0x80, 0x80, 0x40, 0x9a, 0x83, 0x00, 0x8f, 0xf8, 0x42, 0xc6, 0xff, 0xe3, 0x0f, 0x7e, 0x63, 0x18, 0x22, 0x00, 0xc0, 0x31, 0xf0, 0x13, 0x00, 0x00, 0x11, 0x00, 0x11, 0x00, 0x00, 0x0f, 0x00, 0x1b, 0x00, 0x00, 0x06, 0x00, 0x0e, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x09, 0x00, 0x00, 0x00, 0xc0, 0x88, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x05, 0x38, 0x08, 0x00, 0x80, 0x08, 0x44, 0x08, 0x00, 0x40, 0x04, 0x44, 0x08, 0x00, 0x20, 0x02, 0x48, 0x04, 0x00, 0x10, 0x01, 0x70, 0x06, 0x00, 0x88, 0x00, 0xc0, 0x01, 0x00, 0x44, 0x00, 0x40, 0x00, 0x00, 0x22, 0x0e, 0x40, 0x00, 0x00, 0x11, 0x0a, 0x40, 0x00, 0x00, 0x09, 0x0c, 0x40, 0x00, 0x80, 0x06, 0x3e, 0x20, 0x00, 0x80, 0xf1, 0xc1, 0x1f, 0x00}; scm-5e5/compile.scm0000755001705200017500000000623010750210226012165 0ustar tbtb#! /bin/sh :;exec scm -e"(set! *script* \"$0\")" -f$0 "$@" ;;;; "compile.scm", Compile C ==> Scheme ==> object-file. ;; Copyright (C) 1992-2002 Free Software Foundation, Inc. ;; ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU Lesser General Public License as ;; published by the Free Software Foundation, either version 3 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 ;; Lesser General Public License for more details. ;; ;; You should have received a copy of the GNU Lesser General Public ;; License along with this program. If not, see ;; . ;;; Author: Aubrey Jaffer. (require-if 'compiling 'hobbit) (require-if 'compiling 'filename) (require-if 'compiling 'build) (define (compile.scm args) (cond ((and (<= 1 (length args)) (not (eqv? #\- (string-ref (car args) 0)))) (apply compile-file args)) (else (compile.usage)))) (define (compile.usage) (display "\ \ Usage: compile.scm FILE1.scm FILE2.scm ... \ Compiles Scheme FILE1.scm FILE2.scm ... to an object file named FILE1, where is the object file suffix for your computer (for instance, `.o'). FILE1.scm must be in the current directory; FILE2.scm ... can be in other directories. http://swiss.csail.mit.edu/~jaffer/SCM " (current-error-port)) #f) ;;; This unusual autoload loads either the ;;; source or compiled version if present. (if (not (defined? hobbit)) ;Autoload for hobbit (define (hobbit . args) (require 'hobbit) (apply hobbit args))) (define (find-option-file file) (let ((opt file)) (if (file-exists? opt) (list "-f" opt) '()))) ;@ (define (compile-file file . args) (define sfs (scheme-file-suffix)) (require 'filename) (apply hobbit file args) (let ((command (apply list "build" "-hsystem" "-tdll" (string-append "--compiler-options=-I" (implementation-vicinity)) "-c" (replace-suffix file sfs ".c") (find-option-file (replace-suffix file sfs ".opt"))))) (require 'build) (cond ((>= (verbose) 3) (write command) (newline))) (build-from-whole-argv command))) ;@ (define (compile->executable exename . files) (define sfs (scheme-file-suffix)) (require 'filename) (for-each hobbit files) (let ((inits (map (lambda (file) (string-append "-iinit_" (replace-suffix file sfs ""))) files)) (files (map (lambda (file) (string-append "-c" (replace-suffix file sfs ".c"))) files))) (define command (append (list "build" "-hsystem" "--type=exe" "-o" exename "-F" "compiled-closure" "inexact" (string-append "--linker-options=-L" (implementation-vicinity))) (find-option-file (string-append exename ".opt")) files inits)) (require 'build) (cond ((>= (verbose) 3) (write command) (newline))) (build-from-whole-argv command))) ;;; Local Variables: ;;; mode:scheme ;;; End: (and *script* (exit (compile.scm (list-tail *argv* *optind*)))) scm-5e5/scm.nsi0000644001705200017500000003250210751113535011332 0ustar tbtb; Install SCM on Windows for current user ; Basic script generated by the HM NIS Edit Script Wizard. ; Augmented by Jerry van Dijk, february 2007 ; placed in the public domain ; *** version numbers *** !define PRODUCT_VERSION "5e5-1" !define REQ_SLIB_VERSION "3b1-1" ; ----------------[ NO CHANGES BELOW ]---------------- ; *** unless files are added or removed *** ; *** remember to edit both 'file' and 'delete' sections! ; *** registry settings *** !define KEY_VERSION "version" !define SCM_KEY "Software\Voluntocracy\scm" !define SLIB_KEY "Software\Voluntocracy\slib" ; HM NIS Edit Wizard helper defines !define PRODUCT_NAME "SCM" !define PRODUCT_COMPANY "Voluntocracy" !define PRODUCT_PUBLISHER "Aubrey Jaffer" !define PRODUCT_WEB_SITE "http://swissnet.ai.mit.edu/~jaffer/SCM.html" !define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\scm-${PRODUCT_VERSION}.exe" !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" !define PRODUCT_UNINST_ROOT_KEY "HKLM" !define PRODUCT_STARTMENU_REGVAL "NSIS:StartMenuDir" ; MUI 1.67 compatible ------ !include "MUI.nsh" ; MUI Settings !define MUI_ABORTWARNING !define MUI_ICON "SCM.ico" !define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico" ; Welcome page !insertmacro MUI_PAGE_WELCOME ; License page !insertmacro MUI_PAGE_LICENSE "COPYING" ; Directory page !insertmacro MUI_PAGE_DIRECTORY ; Start menu page var ICONS_GROUP !define MUI_STARTMENUPAGE_NODISABLE !define MUI_STARTMENUPAGE_DEFAULTFOLDER "scm" !define MUI_STARTMENUPAGE_REGISTRY_ROOT "${PRODUCT_UNINST_ROOT_KEY}" !define MUI_STARTMENUPAGE_REGISTRY_KEY "${PRODUCT_UNINST_KEY}" !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "${PRODUCT_STARTMENU_REGVAL}" !insertmacro MUI_PAGE_STARTMENU Application $ICONS_GROUP ; Instfiles page !insertmacro MUI_PAGE_INSTFILES ; Finish page !insertmacro MUI_PAGE_FINISH ; Uninstaller pages !insertmacro MUI_UNPAGE_INSTFILES ; Language files !insertmacro MUI_LANGUAGE "English" ; MUI end ------ Name "${PRODUCT_NAME} ${PRODUCT_VERSION}" OutFile "scm-${PRODUCT_VERSION}.exe" InstallDir "$PROGRAMFILES\scm" InstallDirRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_DIR_REGKEY}" "" ShowInstDetails show ShowUnInstDetails show ; Check that the correct slib is installed, and no other scm version is present Function .onInit ; Check that slib is installed ClearErrors ReadRegStr $0 ${PRODUCT_UNINST_ROOT_KEY} "${SLIB_KEY}" "${KEY_VERSION}" IfErrors 0 +3 MessageBox MB_OK|MB_ICONSTOP "No SLIB found. Please install SLIB before installing SCM." Abort ; Check that the correct slib is installed StrCmp $0 ${REQ_SLIB_VERSION} +3 0 MessageBox MB_OK|MB_ICONSTOP "Found SLIB version $0. SCM ${PRODUCT_VERSION} requires SLIB ${REQ_SLIB_VERSION}. Please install this SLIB version first." Abort ; Check for older scm installed ReadRegStr $0 ${PRODUCT_UNINST_ROOT_KEY} "${SCM_KEY}" "${KEY_VERSION}" StrCmp $0 '' +4 0 StrCmp $0 ${PRODUCT_VERSION} +3 0 MessageBox MB_OK|MB_ICONSTOP "You already have SCM version $0 installed. Please uninstall this SCM first." Abort FunctionEnd Section "MainSection" SEC01 SetOutPath "$INSTDIR" SetOverwrite try File "scm.exe" File "scm.html" File "SCM.ico" File "Init5e5.scm" File "Transcen.scm" File "mkimpcat.scm" File "hobbit.scm" File "scmhob.scm" File "hobbit.html" File "wbtab.scm" File "rwb-isam.scm" File "r4rstest.scm" File "pi.scm" ; Shortcuts !insertmacro MUI_STARTMENU_WRITE_BEGIN Application CreateShortCut "$DESKTOP\SCM.lnk" "$INSTDIR\scm.exe" "" "$INSTDIR\SCM.ico" CreateDirectory "$SMPROGRAMS\$ICONS_GROUP" CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\SCM Manual.lnk" "$INSTDIR\scm.html" CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\SCM.lnk" "$INSTDIR\scm.exe" "" "$INSTDIR\SCM.ico" CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\Hobbit Manual.lnk" "$INSTDIR\hobbit.html" !insertmacro MUI_STARTMENU_WRITE_END ; Jaffer scm registry settings WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${SCM_KEY}" "${KEY_VERSION}" "${PRODUCT_VERSION}" ; Jaffer scm path settings Push "$INSTDIR\" Call AddToPath SectionEnd Section -AdditionalIcons !insertmacro MUI_STARTMENU_WRITE_BEGIN Application WriteIniStr "$INSTDIR\${PRODUCT_NAME}.url" "InternetShortcut" "URL" "${PRODUCT_WEB_SITE}" CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\Website.lnk" "$INSTDIR\${PRODUCT_NAME}.url" CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\Uninstall.lnk" "$INSTDIR\uninst.exe" !insertmacro MUI_STARTMENU_WRITE_END SectionEnd Section -Post WriteUninstaller "$INSTDIR\uninst.exe" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\scm-${PRODUCT_VERSION}.exe" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\scm-${PRODUCT_VERSION}.exe" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}" SectionEnd Function .onInstSuccess IfRebootFlag 0 noreboot MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON1 "A reboot is required to finish the installation. Do you wish to reboot now?" IDNO noreboot Reboot noreboot: FunctionEnd Function un.onUninstSuccess HideWindow MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) was successfully removed from your computer." FunctionEnd Function un.onInit MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "Are you sure you want to completely remove $(^Name) and all of its components?" IDYES +2 Abort FunctionEnd Section Uninstall !insertmacro MUI_STARTMENU_GETFOLDER "Application" $ICONS_GROUP Delete "$INSTDIR\${PRODUCT_NAME}.url" Delete "$INSTDIR\uninst.exe" Delete "$INSTDIR\pi.scm" Delete "$INSTDIR\r4rstest.scm" Delete "$INSTDIR\rwb-isam.scm" Delete "$INSTDIR\wbtab.scm" Delete "$INSTDIR\hobbit.html" Delete "$INSTDIR\scmhob.scm" Delete "$INSTDIR\hobbit.scm" Delete "$INSTDIR\mkimpcat.scm" Delete "$INSTDIR\Transcen.scm" Delete "$INSTDIR\Init5e5.scm" Delete "$INSTDIR\SCM.ico" Delete "$INSTDIR\scm.html" Delete "$INSTDIR\scm.exe" Delete "$INSTDIR\scmlit.exe" Delete "$INSTDIR\implcat" Delete "$INSTDIR\slibcat" Delete "$INSTDIR\tmp1" Delete "$INSTDIR\tmp2" Delete "$INSTDIR\tmp3" Delete "$SMPROGRAMS\$ICONS_GROUP\Uninstall.lnk" Delete "$SMPROGRAMS\$ICONS_GROUP\Website.lnk" Delete "$SMPROGRAMS\$ICONS_GROUP\SCM.lnk" Delete "$SMPROGRAMS\$ICONS_GROUP\SCM Manual.lnk" Delete "$SMPROGRAMS\$ICONS_GROUP\Hobbit Manual.lnk" Delete "$DESKTOP\SCM.lnk" RMDir "$SMPROGRAMS\$ICONS_GROUP" RMDir "$INSTDIR" # remove from the path Push "$INSTDIR\" Call un.RemoveFromPath ; remove Jaffer registry entries DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${SCM_KEY}" DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_DIR_REGKEY}" SetAutoClose true SectionEnd ; ----------------[ ENVIRONMENT MANIPULATION ]---------------- !ifndef WriteEnvStr_RegKey !ifdef ALL_USERS !define WriteEnvStr_RegKey \ 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' !else !define WriteEnvStr_RegKey 'HKCU "Environment"' !endif !endif ; ----------------[ EXECUTABLE PATH MANIPULATION ]---------------- ; AddToPath - Adds the given dir to the search path. ; Input - head of the stack ; Note - Win9x systems requires reboot Function AddToPath Exch $0 Push $1 Push $2 Push $3 # don't add if the path doesn't exist IfFileExists "$0\*.*" "" AddToPath_done ReadEnvStr $1 PATH Push "$1;" Push "$0;" Call StrStr Pop $2 StrCmp $2 "" "" AddToPath_done Push "$1;" Push "$0\;" Call StrStr Pop $2 StrCmp $2 "" "" AddToPath_done GetFullPathName /SHORT $3 $0 Push "$1;" Push "$3;" Call StrStr Pop $2 StrCmp $2 "" "" AddToPath_done Push "$1;" Push "$3\;" Call StrStr Pop $2 StrCmp $2 "" "" AddToPath_done Call IsNT Pop $1 StrCmp $1 1 AddToPath_NT ; Not on NT StrCpy $1 $WINDIR 2 FileOpen $1 "$1\autoexec.bat" a FileSeek $1 -1 END FileReadByte $1 $2 IntCmp $2 26 0 +2 +2 # DOS EOF FileSeek $1 -1 END # write over EOF FileWrite $1 "$\r$\nSET PATH=%PATH%;$3$\r$\n" FileClose $1 SetRebootFlag true Goto AddToPath_done AddToPath_NT: ReadRegStr $1 ${WriteEnvStr_RegKey} "PATH" StrCmp $1 "" AddToPath_NTdoIt Push $1 Call Trim Pop $1 StrCpy $0 "$1;$0" AddToPath_NTdoIt: WriteRegExpandStr ${WriteEnvStr_RegKey} "PATH" $0 SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 AddToPath_done: Pop $3 Pop $2 Pop $1 Pop $0 FunctionEnd ; RemoveFromPath - Remove a given dir from the path ; Input: head of the stack Function un.RemoveFromPath Exch $0 Push $1 Push $2 Push $3 Push $4 Push $5 Push $6 IntFmt $6 "%c" 26 # DOS EOF Call un.IsNT Pop $1 StrCmp $1 1 unRemoveFromPath_NT ; Not on NT StrCpy $1 $WINDIR 2 FileOpen $1 "$1\autoexec.bat" r GetTempFileName $4 FileOpen $2 $4 w GetFullPathName /SHORT $0 $0 StrCpy $0 "SET PATH=%PATH%;$0" Goto unRemoveFromPath_dosLoop unRemoveFromPath_dosLoop: FileRead $1 $3 StrCpy $5 $3 1 -1 # read last char StrCmp $5 $6 0 +2 # if DOS EOF StrCpy $3 $3 -1 # remove DOS EOF so we can compare StrCmp $3 "$0$\r$\n" unRemoveFromPath_dosLoopRemoveLine StrCmp $3 "$0$\n" unRemoveFromPath_dosLoopRemoveLine StrCmp $3 "$0" unRemoveFromPath_dosLoopRemoveLine StrCmp $3 "" unRemoveFromPath_dosLoopEnd FileWrite $2 $3 Goto unRemoveFromPath_dosLoop unRemoveFromPath_dosLoopRemoveLine: SetRebootFlag true Goto unRemoveFromPath_dosLoop unRemoveFromPath_dosLoopEnd: FileClose $2 FileClose $1 StrCpy $1 $WINDIR 2 Delete "$1\autoexec.bat" CopyFiles /SILENT $4 "$1\autoexec.bat" Delete $4 Goto unRemoveFromPath_done unRemoveFromPath_NT: ReadRegStr $1 ${WriteEnvStr_RegKey} "PATH" StrCpy $5 $1 1 -1 # copy last char StrCmp $5 ";" +2 # if last char != ; StrCpy $1 "$1;" # append ; Push $1 Push "$0;" Call un.StrStr ; Find `$0;` in $1 Pop $2 ; pos of our dir StrCmp $2 "" unRemoveFromPath_done ; else, it is in path # $0 - path to add # $1 - path var StrLen $3 "$0;" StrLen $4 $2 StrCpy $5 $1 -$4 # $5 is now the part before the path to remove StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove StrCpy $3 $5$6 StrCpy $5 $3 1 -1 # copy last char StrCmp $5 ";" 0 +2 # if last char == ; StrCpy $3 $3 -1 # remove last char WriteRegExpandStr ${WriteEnvStr_RegKey} "PATH" $3 SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 unRemoveFromPath_done: Pop $6 Pop $5 Pop $4 Pop $3 Pop $2 Pop $1 Pop $0 FunctionEnd ; ----------------[ OS TYPE DETERMINATION ]---------------- # # [un.]IsNT - Pushes 1 if running on NT, 0 if not # # Example: # Call IsNT # Pop $0 # StrCmp $0 1 +3 # MessageBox MB_OK "Not running on NT!" # Goto +2 # MessageBox MB_OK "Running on NT!" # !macro IsNT UN Function ${UN}IsNT Push $0 ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion StrCmp $0 "" 0 IsNT_yes ; we are not NT. Pop $0 Push 0 Return IsNT_yes: ; NT!!! Pop $0 Push 1 FunctionEnd !macroend !insertmacro IsNT "" !insertmacro IsNT "un." ; ----------------[ STRING MANIPULATION ]---------------- ; StrStr ; input, top of stack = string to search for ; top of stack-1 = string to search in ; output, top of stack (replaces with the portion of the string remaining) ; modifies no other variables. ; ; Usage: ; Push "this is a long ass string" ; Push "ass" ; Call StrStr ; Pop $R0 ; ($R0 at this point is "ass string") !macro StrStr un Function ${un}StrStr Exch $R1 ; st=haystack,old$R1, $R1=needle Exch ; st=old$R1,haystack Exch $R2 ; st=old$R1,old$R2, $R2=haystack Push $R3 Push $R4 Push $R5 StrLen $R3 $R1 StrCpy $R4 0 ; $R1=needle ; $R2=haystack ; $R3=len(needle) ; $R4=cnt ; $R5=tmp loop: StrCpy $R5 $R2 $R3 $R4 StrCmp $R5 $R1 done StrCmp $R5 "" done IntOp $R4 $R4 + 1 Goto loop done: StrCpy $R1 $R2 "" $R4 Pop $R5 Pop $R4 Pop $R3 Pop $R2 Exch $R1 FunctionEnd !macroend !insertmacro StrStr "" !insertmacro StrStr "un." Function Trim ; Added by Pelaca Exch $R1 Push $R2 Loop: StrCpy $R2 "$R1" 1 -1 StrCmp "$R2" " " RTrim StrCmp "$R2" "$\n" RTrim StrCmp "$R2" "$\r" RTrim StrCmp "$R2" ";" RTrim GoTo Done RTrim: StrCpy $R1 "$R1" -1 Goto Loop Done: Pop $R2 Exch $R1 FunctionEnd scm-5e5/grtest.scm0000644001705200017500000000343005702353536012056 0ustar tbtb ; This is a quick hack to test the graphics primitives. ; The SLIB scheme library is needed for random. ; IMHO, the syntax of `do' in scheme is horrible! ; - sjm (define (grtest) (require 'random) ; needs SLIB (graphics-mode!) (display "testing draw-to") (newline) (clear-graphics!) (goto-center!) (do ((x 0 (+ x 3))) ((> x (max-x)) 0) (set-color! (remainder (/ x 3) (max-color))) (draw-to x 0) (draw-to x (max-y)) ) (do ((y 0 (+ y 3))) ((> y (max-y)) 0) (set-color! (remainder (/ y 3) (max-color))) (goto-center!) (draw-to! 0 y) (goto-center!) (draw-to! (max-x) y) ) (goto-nw!) (do ((x 0 (+ x 2))) ((> x (max-x)) 0) (set-color! (remainder (/ x 2) (max-color))) (draw-to x (max-y)) ) (do ((y (+ (max-y) 1) (- y 2))) ((< y 0) 0) (set-color! (remainder (/ y 2) (max-color))) (draw-to (max-x) y) ) (display "testing set-dot!") (newline) (clear-graphics!) (do ((x 0 (+ x 1))) ((= x 100) 0) (set-dot! (+ (random (max-x)) 1) (+ (random (max-y)) 1) (+ (random (max-color)) 1)) ) (display "testing draw with turn-to!") (newline) (clear-graphics!) (goto-center!) (do ((x 0 (+ x 1))) ((= x 100) 0) (set-color! (+ (random (max-color)) 1)) (turn-to! (random 360)) (draw (random 50)) ) (display "testing draw with turn-right") (newline) (clear-graphics!) (goto-center!) (do ((x 0 (+ x 1))) ((= x 100) 0) (set-color! (+ (random (max-color)) 1)) (turn-right (random 90)) (draw (random 50)) ) (display "testing draw with turn-left") (newline) (clear-graphics!) (goto-center!) (do ((x 0 (+ x 1))) ((= x 100) 0) (set-color! (+ (random (max-color)) 1)) (turn-left (random 90)) (draw (random 50)) ) (text-mode!) ) scm-5e5/QUICKREF0000644001705200017500000001472206467700737011214 0ustar tbtb;; FILE "Scheme Sigs" ;; IMPLEMENTS R^4RS Function Signature Synopsis ;; AUTHOR Kenneth A Dickey ;; DATE 1992 October 2 ;; LAST UPDATED 1992 October 3 ;; NOTES: Extracted from Amiga Gambit QuickTour file === FUNCTION SYNOPSIS === Notation: any Scheme data object. * zero or more objects + one or more objects [] optional object ( )... Zero or more occurances of ( ) ; SYNTAX (LAMBDA + ) (LAMBDA (* ) + ) (AND *) (OR *) (IF [] ) (COND ( * )... [(ELSE +)] ) (CASE ((+ ) * )... [(ELSE +)] ) (DEFINE ( * ) + ) (DEFINE ) (LET [] ( ( )... ) + ) (LET* ( ( )... ) + ) (LETREC ( ( )... ) + ) (BEGIN + ) (DO ( ( )... ) ( * ) * ) ;; Note also R^4RS syntax, below ; IEEE Scheme (NOT ) (BOOLEAN? ) (EQ? ) (EQV? ) (EQUAL? ) (PAIR? ) (CONS ) (CAR ) (CDR ) (SET-CAR! ) (SET-CDR! ) (CAAR ) (CADR ) (CDAR ) (CDDR ) (CAAAR ) (CAADR ) (CADAR ) (CADDR ) (CDAAR ) (CDADR ) (CDDAR ) (CDDDR ) (CAAAAR ) (CAAADR ) (CAADAR ) (CAADDR ) (CADAAR ) (CADADR ) (CADDAR ) (CADDDR ) (CDAAAR ) (CDAADR ) (CDADAR ) (CDADDR ) (CDDAAR ) (CDDADR ) (CDDDAR ) (CDDDDR ) (NULL? ) (LIST? ) (LIST * ) (LENGTH ) (APPEND + ) (REVERSE ) (LIST-REF ) (MEMQ ) (MEMV ) (MEMBER ) (ASSQ ) (ASSV ) (ASSOC ) (SYMBOL? ) (SYMBOL->STRING ) (STRING->SYMBOL ) (NUMBER? ) (COMPLEX? ) (REAL? ) (RATIONAL? ) (INTEGER? ) (EXACT? ) (INEXACT? ) (= + ) (< + ) (> + ) (<= + ) (>= + ) (ZERO? ) (POSITIVE? ) (NEGATIVE? ) (ODD? ) (EVEN? ) (MAX + ) (MIN + ) (+ + ) (* + ) (- + ) (/ + ) (ABS ) (QUOTIENT ) (REMAINDER ) (MODULO ) (GCD * ) (LCM * ) (NUMERATOR ) (DENOMINATOR ) (FLOOR ) (CEILING ) (TRUNCATE ) (ROUND ) (RATIONALIZE ) (EXP ) (LOG ) (SIN ) (COS ) (TAN ) (ASIN ) (ACOS ) (ATAN []) (SQRT ) (EXPT ) (MAKE-RECTANGULAR ) (MAKE-POLAR ) (REAL-PART ) (IMAG-PART ) (MAGNITUDE ) (ANGLE ) (EXACT->INEXACT ) (INEXACT->EXACT ) (NUMBER->STRING ) (STRING->NUMBER ) (CHAR? ) (CHAR=? ) (CHAR-CI=? ) (CHAR ) (CHAR-CI ) (CHAR>? ) (CHAR-CI>? ) (CHAR<=? ) (CHAR-CI<=? ) (CHAR>=? ) (CHAR-CI>=? ) (CHAR-ALPHABETIC? ) (CHAR-NUMERIC? ) (CHAR-WHITESPACE? ) (CHAR-UPPER-CASE? ) (CHAR-LOWER-CASE? ) (CHAR->INTEGER ) (INTEGER->CHAR ) (CHAR-UPCASE ) (CHAR-DOWNCASE ) (STRING? ) (MAKE-STRING [] ) (STRING + ) (STRING-LENGTH ) (STRING-REF ) (STRING-SET! ) (STRING=? ) (STRING-CI=? ) (STRING ) (STRING-CI ) (STRING>? ) (STRING-CI>? ) (STRING<=? ) (STRING-CI<=? ) (STRING>=? ) (STRING-CI>=? ) (SUBSTRING ) (STRING-APPEND + ) (VECTOR? ) (MAKE-VECTOR [] ) (VECTOR * ) (VECTOR-LENGTH ) (VECTOR-REF ) (VECTOR-SET! ) (PROCEDURE? ) (APPLY * ) (MAP + ) (FOR-EACH + ) (CALL-WITH-CURRENT-CONTINUATION ) (CALL-WITH-INPUT-FILE ) (CALL-WITH-OUTPUT-FILE ) (INPUT-PORT? ) (OUTPUT-PORT? ) (CURRENT-INPUT-PORT) (CURRENT-OUTPUT-PORT) (OPEN-INPUT-FILE ) (OPEN-OUTPUT-FILE ) (CLOSE-INPUT-PORT ) (CLOSE-OUTPUT-PORT ) (EOF-OBJECT? ) (READ [] ) (READ-CHAR [] ) (PEEK-CHAR [] ) (WRITE [] ) (DISPLAY [] ) (NEWLINE [] ) (WRITE-CHAR [] ) ; R4RS Scheme (LIST-TAIL ) (STRING->LIST ) (LIST->STRING ) (STRING-COPY ) (STRING-FILL! ) (VECTOR->LIST ) (LIST->VECTOR ) (VECTOR-FILL! ) (DELAY ) (FORCE ) (WITH-INPUT-FROM-FILE ) (WITH-OUTPUT-TO-FILE ) (CHAR-READY? [] ) (LOAD ) (TRANSCRIPT-ON ) (TRANSCRIPT-OFF) (DEFINE-SYNTAX ) -- High-Level macros (only) (LET-SYNTAX ( * ) + ) (LETREC-SYNTAX ( * ) + ) === STANDARDS REFERENCES === IEEE Standard 1178-1990. "IEEE Standard for the Scheme Programming Language", IEEE, New York, 1991, ISBN 1-55937-125-0 [1-800-678-IEEE: order # SH14209]. -- now also an ANSI standard. W. Clinger and J. Rees, eds., "Revised^4 Report on the Algorithmic Language Scheme", ACM LISP Pointers IV, 3 (July-September 1991). scm-5e5/README0000644001705200017500000004165510751235423010727 0ustar tbtbThis directory contains the distribution of scm5e5. SCM conforms to Revised^5 Report on the Algorithmic Language Scheme and the IEEE P1178 specification. SCM runs under Amiga, Atari-ST, MacOS, MS-DOS, OS/2, NOS/VE, Unicos, VMS, Unix and similar systems. SCM supports the SLIB Scheme library; both SCM and SLIB are GNU packages. `http://swiss.csail.mit.edu/~jaffer/SCM' 0.1 Manifest ============ `.gdbinit' provides commands for debugging SCM with GDB `COPYING' GNU GENERAL PUBLIC LICENSE `COPYING.LESSER' GNU LESSER GENERAL PUBLIC LICENSE `ChangeLog' changes to SCM. `Idiffer.scm' Linear-space O(PN) sequence comparison. `Iedline.scm' Gnu readline input editing. `Init.scm' Scheme initialization. `Link.scm' Dynamic link/loading. `Macro.scm' Supports Syntax-Rules Macros. `Makefile' builds SCMLIT using the `make' program. `QUICKREF' Quick Reference card for R4RS and IEEE Scheme. `README' contains a MANIFEST, INSTALLATION INSTRUCTIONS, hints for EDITING SCHEME CODE, and a TROUBLE SHOOTING GUIDE. `Transcen.scm' inexact builtin procedures. `bench.scm' computes and records performance statistics of pi.scm. `build.bat' invokes build.scm for MS-DOS `build.scm' database for compiling and linking new SCM programs. `byte.c' strings as bytes. `bytenumb.c' Byte-number conversions. `compile.scm' Hobbit compilation to C. `continue-ia64.S'replaces make_root_continuation(), make_continuation(), and dynthrow() in continue.c `continue.c' continuations. `continue.h' continuations. `crs.c' interactive terminal control. `debug.c' debugging, printing code. `differ.c' Linear-space O(PN) sequence comparison. `dynl.c' dynamically load object files. `ecrt0.c' discover the start of initialized data space dynamically at runtime. `edline.c' Gnu readline input editing (get ftp.sys.toronto.edu:/pub/rc/editline.shar). `eval.c' evaluator, apply, map, and foreach. `example.scm' example from R4RS which uses inexact numbers. `fdl.texi' GNU Free Documentation License. `findexec.c' find the executable file function. `get-contoffset-ia64.c'makes contoffset-ia64.S for inclusion by continue-ia64.S `gmalloc.c' Gnu malloc(); used for unexec. `gsubr.c' make_gsubr for arbitrary (< 11) arguments to C functions. `ioext.c' system calls in common between PC compilers and unix. `lastfile.c' find the point in data space between data and libraries. `macos-config.h' Included by unexmacosx.c and lastfile.c. `mkimpcat.scm' build SCM-specific catalog for SLIB. `patchlvl.h' patchlevel of this release. `pi.c' computes digits of pi [cc -o pi pi.c;time pi 100 5]. `pi.scm' computes digits of pi [type (pi 100 5)]. Test performance against pi.c. `posix.c' posix library interface. `pre-crt0.c' loaded before crt0.o on machines which do not remap part of the data space into text space in unexec. `r4rstest.scm' tests conformance with Scheme specifications. `ramap.c' array mapping `record.c' proposed `Record' user definable datatypes. `repl.c' error, read-eval-print loop, read, write and load. `rgx.c' string regular expression match. `rope.c' C interface functions. `sc2.c' procedures from R2RS and R3RS not in R4RS. `scl.c' inexact arithmetic `scm.1' unix style man page. `scm.c' initialization, interrupts, and non-IEEE utility functions. `scm.doc' man page generated from scm.1. `scm.h' data type and external definitions of SCM. `scm.texi' SCM installation and use. `scmfig.h' contains system dependent definitions. `scmmain.c' initialization, interrupts, and non-IEEE utility functions. `script.c' utilities for running as `#!' script. `setjump.h' continuations, stacks, and memory allocation. `setjump.mar' provides setjump and longjump which do not use $unwind utility on VMS. `setjump.s' provides setjump and longjump for the Cray YMP. `socket.c' BSD socket interface. `split.scm' example use of crs.c. Input, output, and diagnostic output directed to separate windows. `subr.c' the rest of IEEE functions. `sys.c' call-with-current-continuation, opening and closing files, storage allocation and garbage collection. `time.c' functions dealing with time. `ugsetjump.s' provides setjump and longjump which work on Ultrix VAX. `unexalpha.c' Convert a running program into an Alpha executable file. `unexec.c' Convert a running program into an executable file. `unexelf.c' Convert a running ELF program into an executable file. `unexhp9k800.c' Convert a running HP-UX program into an executable file. `unexmacosx.c' Convert a running program into an executable file under MacOS X. `unexsgi.c' Convert a running program into an IRIX executable file. `unexsunos4.c' Convert a running program into an executable file. `unif.c' uniform vectors. `unix.c' non-posix system calls on unix systems. File: scm.info, Node: SLIB, Next: Building SCM, Prev: Making SCM, Up: Installing SCM 2.2 SLIB ======== [SLIB] is a portable Scheme library meant to provide compatibility and utility functions for all standard Scheme implementations. Although SLIB is not _neccessary_ to run SCM, I strongly suggest you obtain and install it. Bug reports about running SCM without SLIB have very low priority. SLIB is available from the same sites as SCM: * swiss.csail.mit.edu:/pub/scm/slib-3b1.tar.gz * ftp.gnu.org:/pub/gnu/jacal/slib-3b1.tar.gz Unpack SLIB (`tar xzf slib-3b1.tar.gz' or `unzip -ao slib-3b1.zip') in an appropriate directory for your system; both `tar' and `unzip' will create the directory `slib'. Then create a file `require.scm' in the SCM "implementation-vicinity" (this is the same directory as where the file `Init5e5.scm' is installed). `require.scm' should have the contents: (define (library-vicinity) "/usr/local/lib/slib/") where the pathname string `/usr/local/lib/slib/' is to be replaced by the pathname into which you installed SLIB. Absolute pathnames are recommended here; if you use a relative pathname, SLIB can get confused when the working directory is changed (*note chmod: I/O-Extensions.). The way to specify a relative pathname is to append it to the implementation-vicinity, which is absolute: (define library-vicinity (let ((lv (string-append (implementation-vicinity) "../slib/"))) (lambda () lv))) Alternatively, you can set the (shell) environment variable `SCHEME_LIBRARY_PATH' to the pathname of the SLIB directory (*note SCHEME_LIBRARY_PATH: SCM Variables.). If set, the environment variable overrides `require.scm'. Again, absolute pathnames are recommended. File: scm.info, Node: Making SCM, Next: SLIB, Prev: Installing SCM, Up: Installing SCM 2.1 Making SCM ============== The SCM distribution has "Makefile" which contains rules for making "scmlit", a "bare-bones" version of SCM sufficient for running `build'. `build' is used to compile (or create scripts to compile) full featured versions (*note Building SCM::). Makefiles are not portable to the majority of platforms. If `Makefile' works for you, good; If not, I don't want to hear about it. If you need to compile SCM without build, there are several ways to proceed: * Use the build (http://swiss.csail.mit.edu/~jaffer/buildscm.html) web page to create custom batch scripts for compiling SCM. * Use SCM on a different platform to run `build' to create a script to build SCM; * Use another implementation of Scheme to run `build' to create a script to build SCM; * Create your own script or `Makefile'. File: scm.info, Node: Editing Scheme Code, Next: Debugging Scheme Code, Prev: SCM Session, Up: Operational Features 3.7 Editing Scheme Code ======================= -- Function: ed arg1 ... The value of the environment variable `EDITOR' (or just `ed' if it isn't defined) is invoked as a command with arguments ARG1 .... -- Function: ed filename If SCM is compiled under VMS `ed' will invoke the editor with a single the single argument FILENAME. Gnu Emacs: Editing of Scheme code is supported by emacs. Buffers holding files ending in .scm are automatically put into scheme-mode. If your Emacs can run a process in a buffer you can use the Emacs command `M-x run-scheme' with SCM. Otherwise, use the emacs command `M-x suspend-emacs'; or see "other systems" below. Epsilon (MS-DOS): There is lisp (and scheme) mode available by use of the package `LISP.E'. It offers several different indentation formats. With this package, buffers holding files ending in `.L', `.LSP', `.S', and `.SCM' (my modification) are automatically put into lisp-mode. It is possible to run a process in a buffer under Epsilon. With Epsilon 5.0 the command line options `-e512 -m0' are neccessary to manage RAM properly. It has been reported that when compiling SCM with Turbo C, you need to `#define NOSETBUF' for proper operation in a process buffer with Epsilon 5.0. One can also call out to an editor from SCM if RAM is at a premium; See "under other systems" below. other systems: Define the environment variable `EDITOR' to be the name of the editing program you use. The SCM procedure `(ed arg1 ...)' will invoke your editor and return to SCM when you exit the editor. The following definition is convenient: (define (e) (ed "work.scm") (load "work.scm")) Typing `(e)' will invoke the editor with the file of interest. After editing, the modified file will be loaded. File: scm.info, Node: Problems Compiling, Next: Problems Linking, Prev: Automatic C Preprocessor Definitions, Up: Installing SCM 2.8 Problems Compiling ====================== FILE PROBLEM / MESSAGE HOW TO FIX *.c include file not found. Correct the status of STDC_HEADERS in scmfig.h. fix #include statement or add #define for system type to scmfig.h. *.c Function should return a value. Ignore. Parameter is never used. Condition is always false. Unreachable code in function. scm.c assignment between incompatible Change SIGRETTYPE in scm.c. types. time.c CLK_TCK redefined. incompatablility between and . Remove STDC_HEADERS in scmfig.h. Edit to remove incompatability. subr.c Possibly incorrect assignment Ignore. in function lgcd. sys.c statement not reached. Ignore. constant in conditional expression. sys.c undeclared, outside of #undef STDC_HEADERS in scmfig.h. functions. scl.c syntax error. #define SYSTNAME to your system type in scl.c (softtype). File: scm.info, Node: Problems Linking, Next: Problems Running, Prev: Problems Compiling, Up: Installing SCM 2.9 Problems Linking ==================== PROBLEM HOW TO FIX _sin etc. missing. Uncomment LIBS in makefile. File: scm.info, Node: Problems Running, Next: Testing, Prev: Problems Linking, Up: Installing SCM 2.10 Problems Running ===================== PROBLEM HOW TO FIX Opening message and then machine Change memory model option to C crashes. compiler (or makefile). Make sure sizet definition is correct in scmfig.h. Reduce the size of HEAP_SEG_SIZE in setjump.h. Input hangs. #define NOSETBUF ERROR: heap: need larger initial. Increase initial heap allocation using -a or INIT_HEAP_SIZE. ERROR: Could not allocate. Check sizet definition. Use 32 bit compiler mode. Don't try to run as subproccess. remove in scmfig.h and Do so and recompile files. recompile scm. add in scmfig.h and recompile scm. ERROR: Init5e5.scm not found. Assign correct IMPLINIT in makefile or scmfig.h. Define environment variable SCM_INIT_PATH to be the full pathname of Init5e5.scm. WARNING: require.scm not found. Define environment variable SCHEME_LIBRARY_PATH to be the full pathname of the scheme library [SLIB]. Change library-vicinity in Init5e5.scm to point to library or remove. Make sure the value of (library-vicinity) has a trailing file separator (like / or \). File: scm.info, Node: Testing, Next: Reporting Problems, Prev: Problems Running, Up: Installing SCM 2.11 Testing ============ Loading `r4rstest.scm' in the distribution will run an [R4RS] conformance test on `scm'. > (load "r4rstest.scm") -| ;loading "r4rstest.scm" SECTION(2 1) SECTION(3 4) # # # # ... Loading `pi.scm' in the distribution will enable you to compute digits of pi. > (load "pi") ;loading "pi" ;done loading "pi.scm" ;Evaluation took 20 ms (0 in gc) 767 cells work, 233.B other # > (pi 100 5) 00003 14159 26535 89793 23846 26433 83279 50288 41971 69399 37510 58209 74944 59230 78164 06286 20899 86280 34825 34211 70679 ;Evaluation took 550 ms (60 in gc) 36976 cells work, 1548.B other # Loading `bench.scm' will compute and display performance statistics of SCM running `pi.scm'. `make bench' or `make benchlit' appends the performance report to the file `BenchLog', facilitating tracking effects of changes to SCM on performance. PROBLEM HOW TO FIX Runs some and then machine crashes. See above under machine crashes. Runs some and then ERROR: ... Remove optimization option to C (after a GC has happened). compiler and recompile. #define SHORT_ALIGN in `scmfig.h'. Some symbol names print incorrectly. Change memory model option to C compiler (or makefile). Check that HEAP_SEG_SIZE fits within sizet. Increase size of HEAP_SEG_SIZE (or INIT_HEAP_SIZE if it is smaller than HEAP_SEG_SIZE). ERROR: Rogue pointer in Heap. See above under machine crashes. Newlines don't appear correctly in Check file mode (define OPEN_... in output files. `Init5e5.scm'). Spaces or control characters appear Check character defines in in symbol names. `scmfig.h'. Negative numbers turn positive. Check SRS in `scmfig.h'. ;ERROR: bignum: numerical overflow Increase NUMDIGS_MAX in `scmfig.h' and recompile. VMS: Couldn't unwind stack. #define CHEAP_CONTINUATIONS in `scmfig.h'. VAX: botched longjmp. Sparc(SUN-4) heap is growing out of control You are experiencing a GC problem peculiar to the Sparc. The problem is that SCM doesn't know how to clear register windows. Every location which is not reused still gets marked at GC time. This causes lots of stuff which should be collected to not be. This will be a problem with any _conservative_ GC until we find what instruction will clear the register windows. This problem is exacerbated by using lots of call-with-current-continuations. A possible fix for dynthrow() is commented out in `continue.c'. scm-5e5/build.scm0000644001705200017500000021756310750211103011641 0ustar tbtb;; "build.scm" Build database and program -*-scheme-*- ;; Copyright (C) 1994-2006 Free Software Foundation, Inc. ;; ;; 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 3 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, see ;; . (require 'parameters) (require 'databases) (require 'database-commands) (require 'alist) (require 'common-list-functions) (require 'object->string) (require 'filename) (require 'batch) (require-if 'compiling 'posix-time) ;@ (set! OPEN_WRITE "w") ; Because MS-DOS scripts need ^M ;@ (define build (add-command-tables (create-database #f 'alist-table))) (batch:initialize! build) (((open-table! build 'batch-dialect) 'row:insert) '(default-for-platform 0)) ;;;; This first part is about SCM files and features. (define-tables build '(file-formats ((format symbol)) () ((plaintext) (c-source) (c-header) (scheme) (vax-asm) (gnu-as) (gdb-init) (cray-asm) (makefile) (MS-DOS-batch) (nroff) (texinfo))) '(file-categories ((category symbol)) ((documentation string)) ((documentation "documentation") (platform-specific "required for certain platforms") (core "core for building executable SCM") (optional "required for some feature") (linkable "can be statically or dynamically linked for some feature") (test "test SCM") (none "no files"))) '(manifest ((file string) (format file-formats) (category file-categories)) ((documentation string)) (("README" plaintext documentation "contains a MANIFEST, INSTALLATION INSTRUCTIONS, hints for EDITING SCHEME CODE, and a TROUBLE SHOOTING GUIDE.") ("COPYING" plaintext documentation "GNU GENERAL PUBLIC LICENSE") ("COPYING.LESSER" plaintext documentation "GNU LESSER GENERAL PUBLIC LICENSE") ("scm.1" nroff documentation "unix style man page.") ("scm.doc" plaintext documentation "man page generated from scm.1.") ("QUICKREF" plaintext documentation "Quick Reference card for R4RS and IEEE Scheme.") ("scm.texi" Texinfo documentation "SCM installation and use.") ("fdl.texi" Texinfo documentation "GNU Free Documentation License.") ("ChangeLog" plaintext documentation "changes to SCM.") ("r4rstest.scm" Scheme test "tests conformance with Scheme specifications.") ("example.scm" Scheme test "example from R4RS which uses inexact numbers.") ("pi.scm" Scheme test "computes digits of pi [type (pi 100 5)]. Test performance against pi.c.") ("pi.c" c-source test "computes digits of pi [cc -o pi pi.c;time pi 100 5].") ("bench.scm" Scheme test "computes and records performance statistics of pi.scm.") ("Makefile" Makefile core "builds SCMLIT using the `make' program.") ("build.scm" Scheme core "database for compiling and linking new SCM programs.") ("build.bat" MS-DOS-batch platform-specific "invokes build.scm for MS-DOS") ("mkimpcat.scm" Scheme core "build SCM-specific catalog for SLIB.") (".gdbinit" gdb-init optional "provides commands for debugging SCM with GDB") ("setjump.mar" Vax-asm platform-specific "provides setjump and longjump which do not use $unwind utility on VMS.") ("ugsetjump.s" gnu-as platform-specific "provides setjump and longjump which work on Ultrix VAX.") ("setjump.s" Cray-asm platform-specific "provides setjump and longjump for the Cray YMP.") ("continue-ia64.S" gnu-as platform-specific "replaces make_root_continuation(), make_continuation(), and dynthrow() in continue.c") ("get-contoffset-ia64.c" c-source platform-specific "makes contoffset-ia64.S for inclusion by continue-ia64.S") ("Init.scm" Scheme core "Scheme initialization.") ("Transcen.scm" Scheme core "inexact builtin procedures.") ("Link.scm" Scheme core "Dynamic link/loading.") ("compile.scm" Scheme core "Hobbit compilation to C.") ("Macro.scm" Scheme core "Supports Syntax-Rules Macros.") ("scmfig.h" c-header core "contains system dependent definitions.") ("patchlvl.h" c-header core "patchlevel of this release.") ("setjump.h" c-header core "continuations, stacks, and memory allocation.") ("continue.h" c-header core "continuations.") ("continue.c" c-source core "continuations.") ("scm.h" c-header core "data type and external definitions of SCM.") ("scm.c" c-source core "initialization, interrupts, and non-IEEE utility functions.") ("scmmain.c" c-source core "initialization, interrupts, and non-IEEE utility functions.") ("findexec.c" c-source core "find the executable file function.") ("script.c" c-source core "utilities for running as `#!' script.") ("time.c" c-source core "functions dealing with time.") ("repl.c" c-source core "error, read-eval-print loop, read, write and load.") ("scl.c" c-source core "inexact arithmetic") ("eval.c" c-source core "evaluator, apply, map, and foreach.") ("sys.c" c-source core "call-with-current-continuation, opening and closing files, storage allocation and garbage collection.") ("subr.c" c-source core "the rest of IEEE functions.") ("debug.c" c-source core "debugging, printing code.") ("unif.c" c-source core "uniform vectors.") ("rope.c" c-source core "C interface functions.") ("ramap.c" c-source optional "array mapping") ("dynl.c" c-source optional "dynamically load object files.") ("sc2.c" c-source linkable "procedures from R2RS and R3RS not in R4RS.") ("byte.c" c-source linkable "strings as bytes.") ("rgx.c" c-source linkable "string regular expression match.") ("crs.c" c-source linkable "interactive terminal control.") ("split.scm" Scheme test "example use of crs.c. Input, output, and diagnostic output directed to separate windows.") ("edline.c" c-source linkable "Gnu readline input editing (get ftp.sys.toronto.edu:/pub/rc/editline.shar).") ("Iedline.scm" Scheme optional "Gnu readline input editing.") ("bytenumb.c" c-source linkable "Byte-number conversions.") ("differ.c" c-source linkable "Linear-space O(PN) sequence comparison.") ("Idiffer.scm" Scheme optional "Linear-space O(PN) sequence comparison.") ("record.c" c-source linkable "proposed `Record' user definable datatypes.") ("gsubr.c" c-source linkable "make_gsubr for arbitrary (< 11) arguments to C functions.") ("ioext.c" c-source linkable "system calls in common between PC compilers and unix.") ("posix.c" c-source linkable "posix library interface.") ("unix.c" c-source linkable "non-posix system calls on unix systems.") ("socket.c" c-source linkable "BSD socket interface.") ("pre-crt0.c" c-source platform-specific "loaded before crt0.o on machines which do not remap part of the data space into text space in unexec.") ("ecrt0.c" c-source platform-specific "discover the start of initialized data space dynamically at runtime.") ("gmalloc.c" c-source platform-specific "Gnu malloc(); used for unexec.") ("unexec.c" c-source platform-specific "Convert a running program into an executable file.") ("unexhp9k800.c" c-source platform-specific "Convert a running HP-UX program into an executable file.") ("unexelf.c" c-source platform-specific "Convert a running ELF program into an executable file.") ("unexalpha.c" c-source platform-specific "Convert a running program into an Alpha executable file.") ("unexsgi.c" c-source platform-specific "Convert a running program into an IRIX executable file.") ("unexsunos4.c" c-source platform-specific "Convert a running program into an executable file.") ("macos-config.h" c-header platform-specific "Included by unexmacosx.c and lastfile.c.") ("unexmacosx.c" c-source platform-specific "Convert a running program into an executable file under MacOS X.") ("lastfile.c" c-source platform-specific "find the point in data space between data and libraries.") )) '(build-whats ((name symbol)) ((class file-categories) (c-proc symbol) (o-proc symbol) (spec expression) (documentation string)) ((exe core compile-c-files link-c-program #f "executable program") (lib core compile-c-files make-archive ((c-lib lib)) "library module") (dlls linkable compile-dll-c-files make-dll-archive ((define "DLL")) "archived dynamically linked library object files") (dll none compile-dll-c-files update-catalog ((define "DLL")) "dynamically linked library object file"))) '(features ((name symbol)) ((spec expression) (documentation string)) ((none () "No features")))) (define-domains build '(optstring #f (lambda (x) (or (not x) (string? x))) string #f) '(filename #f #f string #f) '(features features #f symbol #f) '(build-whats build-whats #f symbol #f)) (define define-build-feature (let ((defeature ((open-table! build 'features) 'row:insert))) (lambda args (defeature (append args (list (comment))))))) #;Lightweight -- no features (define-build-feature 'lit '()) #;Normally, the number of arguments arguments to interpreted closures #;(from LAMBDA) are checked if the function part of a form is not a #;symbol or only the first time the form is executed if the function #;part is a symbol. defining @samp{reckless} disables any checking. #;If you want to have SCM always check the number of arguments to #;interpreted closures define feature @samp{cautious}. (define-build-feature 'cautious '((define "CAUTIOUS"))) #;Define this for extra checking of interrupt masking and some simple #;checks for proper use of malloc and free. This is for debugging C #;code in @file{sys.c}, @file{eval.c}, @file{repl.c} and makes the #;interpreter several times slower than usual. (define-build-feature 'careful-interrupt-masking '((define "CAREFUL_INTS"))) #;Turns on the features @samp{cautious} and #;@samp{careful-interrupt-masking}; uses #;@code{-g} flags for debugging SCM source code. (define-build-feature 'debug '((c-lib debug) (features cautious careful-interrupt-masking))) #;If your scheme code runs without any errors you can disable almost #;all error checking by compiling all files with @samp{reckless}. (define-build-feature 'reckless '((define "RECKLESS"))) #;C level support for hygienic and referentially transparent macros #;(syntax-rules macros). (define-build-feature 'macro '((define "MACRO") (features rev2-procedures record))) #;Large precision integers. (define-build-feature 'bignums '((define "BIGNUMS"))) #;Use if you want arrays, uniform-arrays and uniform-vectors. (define-build-feature 'arrays '((define "ARRAYS"))) #;Alias for ARRAYS (define-build-feature 'array '((features arrays))) #;array-map! and array-for-each (arrays must also be featured). (define-build-feature 'array-for-each '((c-file "ramap.c") (compiled-init "init_ramap"))) #;Use if you want floating point numbers. (define-build-feature 'inexact '((define "FLOATS") (c-lib m))) #;Use if you want floats to display in engineering notation (exponents #;always multiples of 3) instead of scientific notation. (define-build-feature 'engineering-notation '((define "ENGNOT"))) #;Use if you want all inexact real numbers to be single precision. This #;only has an effect if SINGLES is also defined (which is the default). #;This does not affect complex numbers. (define-build-feature 'single-precision-only '((define "SINGLESONLY"))) #;Use if you want to run code from: #; #;@cindex SICP #;Harold Abelson and Gerald Jay Sussman with Julie Sussman. #;@cite{Structure and Interpretation of Computer Programs.} #;The MIT Press, Cambridge, Massachusetts, USA, 1985. #; #;Differences from R5RS are: #;@itemize @bullet #;@item #;(eq? '() '#f) #;@item #;(define a 25) returns the symbol a. #;@item #;(set! a 36) returns 36. #;@end itemize (define-build-feature 'sicp '((define "SICP"))) #;These procedures were specified in the @cite{Revised^2 Report on Scheme} #;but not in @cite{R4RS}. (define-build-feature 'rev2-procedures '((c-file "sc2.c") (init "init_sc2"))) #;Treating strings as byte-vectors. (define-build-feature 'byte '((c-file "byte.c") (init "init_byte"))) #;The Record package provides a facility for user to define their own #;record data types. See SLIB for documentation. (define-build-feature 'record '((define "CCLO") (c-file "record.c") (compiled-init "init_record"))) #;Use if you want to use compiled closures. (define-build-feature 'compiled-closure '((define "CCLO"))) #;@code{make_gsubr} for arbitrary (< 11) arguments to C functions. (define-build-feature 'generalized-c-arguments '((c-file "gsubr.c") (compiled-init "init_gsubr"))) #;Use if you want the ticks and ticks-interrupt functions. (define-build-feature 'tick-interrupts '((define "TICKS"))) #;Commonly available I/O extensions: @dfn{exec}, line I/O, file #;positioning, file delete and rename, and directory functions. (define-build-feature 'i/o-extensions '((c-file "ioext.c") (init "init_ioext"))) #;@dfn{Turtle} graphics calls for both Borland-C and X11 from #;sjm@@ee.tut.fi. (define-build-feature 'turtlegr '((c-file "turtlegr.c") (c-lib graphics) (features inexact) (compiled-init "init_turtlegr"))) #;Interface to Xlib graphics routines. (define-build-feature 'Xlib '((c-file "x.c") (c-lib graphics) (compiled-init "init_x") (features arrays))) #;Alias for Xlib feature. (define-build-feature 'X '((features Xlib))) #;For the @dfn{curses} screen management package. (define-build-feature 'curses '((c-file "crs.c") (c-lib curses) (compiled-init "init_crs"))) #;interface to the editline or GNU readline library. (define-build-feature 'edit-line '((c-file "edline.c") (c-lib termcap editline) (compiled-init "init_edline"))) #;Client connections to the mysql databases. (define-build-feature 'mysql '((c-file "database.c") (c-lib mysql) (compiled-init "init_database"))) #;String regular expression matching. (define-build-feature 'regex '((c-file "rgx.c") (c-lib regex) (compiled-init "init_rgx"))) #;BSD @dfn{socket} interface. Socket addr functions require #;inexacts or bignums for 32-bit precision. (define-build-feature 'socket '((c-lib socket) (c-file "socket.c") (compiled-init "init_socket"))) #;Posix functions available on all @dfn{Unix-like} systems. fork and #;process functions, user and group IDs, file permissions, and #;@dfn{link}. (define-build-feature 'posix '((c-file "posix.c") (compiled-init "init_posix"))) #;Those unix features which have not made it into the Posix specs: #;nice, acct, lstat, readlink, symlink, mknod and sync. (define-build-feature 'unix '((c-file "unix.c") (compiled-init "init_unix"))) #;Sequence comparison (define-build-feature 'differ '((c-file "differ.c") (compiled-init "init_differ"))) #;Byte/number conversions (define-build-feature 'byte-number '((c-file "bytenumb.c") (compiled-init "init_bytenumb"))) #;Microsoft Windows executable. (define-build-feature 'windows '((c-lib windows))) ; (define "NON_PREEMPTIVE") #;Be able to load compiled files while running. (define-build-feature 'dynamic-linking '((c-file "dynl.c") (c-lib dlll))) #;Convert a running scheme program into an executable file. (define-build-feature 'dump '((define "CAN_DUMP") (c-lib dump) (c-lib nostart))) ;;; Descriptions of these parameters is in "setjump.h". ;; (initial-heap-size ((define "INIT_HEAP_SIZE" (* 25000 sizeof-cell)))) ;; (heap-segment-size ((define "HEAP_SEG_SIZE" (* 8100 sizeof-cell)))) ;; (short-aligned-stack ((define "SHORT_ALIGN"))) ;; (initial-malloc-limit ((define "INIT_MALLOC_LIMIT" 100000))) ;; (number-of-hash-buckets ((define "NUM_HASH_BUCKETS" 137))) ;; (minimum-gc-yield ((define "MIN_GC_YIELD" "(heap_cells/4)"))) #;Use if you want segments of unused heap to not be freed up after #;garbage collection. This may increase time in GC for *very* large #;working sets. (define-build-feature 'no-heap-shrink '((define "DONT_GC_FREE_SEGMENTS"))) #;SCM normally converts references to local variables to ILOCs, which #;make programs run faster. If SCM is badly broken, try using this #;option to disable the MEMOIZE_LOCALS feature. (define-build-feature 'dont-memoize-locals '((define "DONT_MEMOIZE_LOCALS"))) #;If you only need straight stack continuations, executables compile with #;this feature will run faster and use less storage than not having it. #;Machines with unusual stacks @emph{need} this. Also, if you incorporate #;new C code into scm which uses VMS system services or library routines #;(which need to unwind the stack in an ordrly manner) you may need to #;use this feature. (define-build-feature 'cheap-continuations '((define "CHEAP_CONTINUATIONS"))) #;WB database with relational wrapper. (define-build-feature 'wb '((c-file "../wb/blink.c" "../wb/blkio.c" "../wb/del.c" "../wb/ents.c" "../wb/handle.c" "../wb/prev.c" "../wb/scan.c" "../wb/segs.c" "../wb/stats.c" "../wb/wbsys.c" "../wb/db.c") (scm-srcdir "../scm") (compiled-init "init_db"))) ;;;; The rest is about building on specific platforms. (define-tables build '(processor-family ((family symbol)) ((also-runs processor-family)) ((*unknown* #f) (i8086 #f) (ia64 #f) (acorn #f) (alpha #f) (cray #f) (hp-risc #f) (i386 i8086) (m68000 #f) (m68030 m68000) (mips #f) (nos/ve #f) (pdp-10 #f) (pdp-11 #f) (pdp-8 #f) (powerpc #f) (pyramid #f) (sequent #f) (sparc #f) (tahoe #f) (vax pdp-11) )) '(platform ((name symbol)) ((processor processor-family) (operating-system operating-system) (compiler symbol) ;;(linker symbol) ) ((*unknown* *unknown* unix cc ) ;ld (acorn-unixlib acorn *unknown* cc ) ;link (aix powerpc aix cc ) ;cc (osf1 alpha unix cc ) ;cc (alpha-elf alpha unix cc ) ;cc (alpha-linux alpha linux gcc ) ;gcc (amiga-aztec m68000 amiga cc ) ;cc (amiga-dice-c m68000 amiga dcc ) ;dcc (amiga-gcc m68000 amiga gcc ) ;gcc (amiga-sas m68000 amiga lc ) ;link (atari-st-gcc m68000 atari-st gcc ) ;gcc (atari-st-turbo-c m68000 atari-st tcc ) ;tlink (borland-c i8086 ms-dos bcc ) ;bcc (gnu-win32 i386 unix gcc ) ;gcc (djgpp i386 ms-dos gcc ) ;gcc (freebsd *unknown* unix cc ) ;cc (gcc *unknown* unix gcc ) ;gcc (highc i386 ms-dos hc386 ) ;bind386 (hp-ux hp-risc hp-ux cc ) ;cc (irix mips irix gcc ) ;gcc (linux *unknown* linux gcc ) ;gcc (linux-aout i386 linux gcc ) ;gcc (linux-ia64 ia64 linux gcc ) ;gcc (darwin powerpc unix cc ) ;gcc (microsoft-c i8086 ms-dos cl ) ;link (microsoft-c-nt i386 ms-dos cl ) ;link (microsoft-quick-c i8086 ms-dos qcl ) ;qlink (ms-dos i8086 ms-dos cc ) ;link (netbsd *unknown* unix gcc ) ;gcc (openbsd *unknown* unix gcc ) ;gcc (os/2-cset i386 os/2 icc ) ;link386 (os/2-emx i386 os/2 gcc ) ;gcc (plan9-8 i386 plan9 8c ) ;8l (svr4-gcc-sun-ld sparc sunos gcc ) ;ld (sunos sparc sunos cc ) ;ld (svr4 *unknown* unix cc ) ;ld (turbo-c i8086 ms-dos tcc ) ;tcc (unicos cray unicos cc ) ;cc (unix *unknown* unix cc ) ;cc (vms vax vms cc ) ;link (vms-gcc vax vms gcc ) ;link (watcom-9.0 i386 ms-dos wcc386p ) ;wlinkp )) '(C-libraries ((library symbol) (platform platform)) ((compiler-flags string) (link-lib-flag string) (lib-path optstring) (lib-support expression) (suppress-files expression)) ((m *unknown* "" "-lm" "/usr/lib/libm.a" () ()) (c *unknown* "" "-lc" "/usr/lib/libc.a" () ()) (regex *unknown* "" "-lregex" "/usr/lib/libregex.a" () ()) (curses *unknown* "" "-lcurses" "/usr/lib/libcurses.a" () ()) (graphics *unknown* "-I/usr/X11/include -DX11" "-lX11" "/usr/X11/lib/libX11.sa" () ()) (editline *unknown* "" "-lreadline" "/usr/lib/libreadline.a" () ()) (termcap *unknown* "" "-ltermcap" "/usr/lib/libtermcap.a" () ()) (debug *unknown* "-g" "-g" #f () ()) (socket *unknown* "" "" #f () ()) (lib *unknown* "" "" #f () ("scmmain.c")) (mysql *unknown* "-I/usr/include/mysql" "-L/usr/lib/mysql -lmysqlclient" "/usr/lib/mysql/libmysqlclient.a" () ()) (m gnu-win32 "" "" #f () ()) (c gnu-win32 "" "" #f () ()) (dlll gnu-win32 "-DSCM_WIN_DLL" "" #f () ("posix.c" "unix.c" "socket.c")) (m linux-aout "" "-lm" "/usr/lib/libm.sa" () ()) (c linux-aout "" "-lc" "/usr/lib/libc.sa" () ()) (dlll linux-aout "-DDLD -DDLD_DYNCM" "-ldld" #f () ("findexec.c")) (curses linux-aout "-I/usr/include/ncurses" "-lncurses" "/usr/lib/libncurses.a" () ()) (nostart linux-aout "" "-nostartfiles" #f ("pre-crt0.c") ()) (dump linux-aout "" "/usr/lib/crt0.o" #f ("unexec.c" "gmalloc.c") ()) (m linux "" "-lm" "/lib/libm.so" () ()) (c linux "" "-lc" "/lib/libc.so" () ()) (dlll linux "-DSUN_DL" "-ldl" #f () ()) (regex linux "" "" #f () ()) (graphics linux "-I/usr/include/X11 -DX11" "-L/usr/X11R6/lib -lX11" "/usr/X11R6/lib/libX11.so" () ()) (curses linux "" "-lcurses" "/lib/libncurses.so" () ()) (nostart linux "" "" #f () ()) (dump linux "" "" #f ("unexelf.c" "gmalloc.c") ()) (dump irix "" "-G 0" #f () ()) (m acorn-unixlib "" "" #f () ()) (nostart osf1 "" "" #f ("pre-crt0.c") ()) (dlll osf1 "-DSUN_DL" "" #f () ()) (dump osf1 "" "" #f ("unexalpha.c" "gmalloc.c") ()) (regex osf1 "" "" #f () ()) (graphics osf1 "-I/usr/include/X11 -DX11" "-lX11" #f () ()) (m amiga-dice-c "" "-lm" #f () ()) (m amiga-sas "" "lcmieee.lib" #f () ()) (c amiga-sas "" "lc.lib" #f () ()) (m vms-gcc "" "" #f () ()) (m vms "" "" #f () ()) (m atari-st-gcc "" "-lpml" #f () ()) (m atari-st-turbo-c "" "" #f () ()) (c plan9-8 "" "" #f () ()) (m plan9-8 "" "" #f () ()) (m sunos "" "-lm" #f () ()) (dlll sunos "-DSUN_DL" "-ldl" #f () ()) (nostart sunos "" "-e __start -nostartfiles -static" #f ("ecrt0.c") ()) (dump sunos "" "" #f ("unexelf.c" "gmalloc.c") ()) (m svr4-gcc-sun-ld "" "-lm" #f () ()) (dlll svr4-gcc-sun-ld "-DSUN_DL" "-Wl,-ldl -export-dynamic" #f () ()) (nostart svr4-gcc-sun-ld "" "-e __start -nostartfiles" #f ("ecrt0.c") ()) (dump svr4-gcc-sun-ld "" "" #f ("unexelf.c" "gmalloc.c") ()) (socket svr4-gcc-sun-ld "" "-lsocket -lnsl" #f () ()) (regex svr4-gcc-sun-ld "" "" #f () ()) (nostart gcc "" "-e __start -nostartfiles" #f ("ecrt0.c") ()) (dump gcc "" "" #f ("unexelf.c" "gmalloc.c") ()) (m hp-ux "" "-lm" #f () ()) (dlll hp-ux "-DHAVE_DYNL" "-Wl,-E -ldld" #f () ()) (graphics hp-ux "-DX11" "-lX" "/usr/lib/X11R5/libX11.sl" () ()) (nostart hp-ux "" "" #f ("ecrt0.c") ()) (dump hp-ux "" "" #f ("unexhp9k800.c" "gmalloc.c") ()) (c djgpp "" "-lc" #f () ("findexec.c")) (curses djgpp "-I/djgpp/contrib/pdcurses/include/" "-L/djgpp/contrib/pdcurses/lib/ -lcurses" "\\djgpp\\contrib\\pdcurses\\lib\\libcurse.a" () ()) (nostart djgpp "" "-nostartfiles" #f ("pre-crt0.c") ()) (dump djgpp "" "c:/djgpp/lib/crt0.o" #f ("unexec.c" "gmalloc.c") ()) ;;; (nostart djgpp "" "" #f ("ecrt0.c") ()) ;;; (dump djgpp "" "" #f ("unexelf.c" "gmalloc.c") ()) ;;; (nostart djgpp "" "-e __start -nostartfiles -static" #f ("ecrt0.c") ()) ;;; (dump djgpp "" "" #f ("unexelf.c" "gmalloc.c") ()) (c microsoft-c "" "" #f () ("findexec.c")) (m microsoft-c "" "" #f () ()) (c microsoft-c-nt "" "" #f () ("findexec.c")) (m microsoft-c-nt "" "" #f () ()) (dlll microsoft-c-nt "-DSCM_WIN_DLL -MD" "" #f () ("posix.c" "unix.c" "socket.c")) (debug microsoft-c-nt "-Zi" "/debug" #f () ()) (c microsoft-quick-c "" "" #f () ("findexec.c")) (m microsoft-quick-c "" "" #f () ()) (c turbo-c "" "" #f () ("findexec.c")) (m turbo-c "" "" #f () ()) (graphics turbo-c "" "graphics.lib" #f () ()) (c borland-c "" "" #f () ("findexec.c")) (m borland-c "" "" #f () ()) (graphics borland-c "" "graphics.lib" #f () ()) (windows borland-c "-N -W" "-W" #f () ()) (c highc "" "" #f () ("findexec.c")) (m highc "" "" #f () ()) (windows highc "-Hwin" "-Hwin" #f () ()) (m darwin "" "" #f () ()) (c darwin "" "" #f () ()) (curses darwin "" "" #f () ()) (regex darwin "" "" #f () ()) (dump darwin "" "" #f ("unexmacosx.c" "lastfile.c") ()) (dlll darwin "-DSUN_DL" "-ldl" "" () ()) (c freebsd "" "-export-dynamic" #f () ()) (m freebsd "" "-lm" #f () ()) (curses freebsd "" "-lncurses" "/usr/lib/libncurses.a" () ()) (regex freebsd "-I/usr/include/gnu" "-lgnuregex" "" () ()) (editline freebsd "" "-lreadline" "" () ()) (dlll freebsd "-DSUN_DL" "-export-dynamic" "" () ()) (nostart freebsd "" "-e start -dc -dp -Bstatic -lgnumalloc" #f ("pre-crt0.c") ()) (dump freebsd "" "/usr/lib/crt0.o" "" ("unexsunos4.c") ()) (curses netbsd "-I/usr/pkg/include" "-lncurses" "-Wl,-rpath -Wl,/usr/pkg/lib -L/usr/pkg/lib" () ()) (editline netbsd "-I/usr/pkg/include" "-lreadline" "-Wl,-rpath -Wl,/usr/pkg/lib -L/usr/pkg/lib" () ()) (graphics netbsd "-I/usr/X11R6/include -DX11" "-lX11" "-Wl,-rpath -Wl,/usr/X11R6/lib -L/usr/X11R6/lib" () ()) (m netbsd "" "-lm" #f () ()) (m openbsd "" "-lm" #f () ()) (dlll openbsd "-DSUN_DL" "" "" () ()) (curses openbsd "" "-lcurses" "/usr/lib/libcurses.a" () ()) (regex openbsd "" "" #f () ()) )) '(compile-commands ((name symbol) (platform platform)) ((procedure expression)) ((update-catalog *unknown* (lambda (oname objects libs parms) (batch:rebuild-catalog parms) (if (= 1 (length objects)) (car objects) objects)))))) (define define-compile-commands (let ((defcomms ((open-table! build 'compile-commands) 'row:insert))) (lambda args (defcomms args)))) ;(append args (list (comment))) (defmacro defcommand (name platform procedure) `(define-compile-commands ',name ',platform ',procedure)) (defcommand compile-c-files borland-c (lambda (files parms) (define rsp-name "temp.rsp") (apply batch:lines->file parms rsp-name files) (and (batch:try-command parms "bcc" "-d" "-Z" "-G" "-w-pro" "-ml" "-c" (if (member '(define "FLOATS" #t) (c-defines parms)) "" "-f-") (include-spec "-I" parms) (c-includes parms) (c-flags parms) (string-append "@" rsp-name)) (truncate-up-to (map c->obj files) #\\)))) (defcommand link-c-program borland-c (lambda (oname objects libs parms) (define lnk-name (string-append oname ".lnk")) (apply batch:lines->file parms lnk-name (append libs objects)) (and (batch:try-command parms "bcc" (string-append "-e" oname) "-ml" (string-append "@" lnk-name)) (string-append oname ".exe")))) (defcommand compile-c-files turbo-c (lambda (files parms) (and (batch:try-chopped-command parms "tcc" "-c" "-d" "-Z" "-G" "-ml" "-c" "-Ic:\\turboc\\include" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->obj files) #\\)))) (defcommand link-c-program turbo-c (lambda (oname objects libs parms) (let ((exe (truncate-up-to (obj->exe (car objects)) #\\)) (oexe (string-append oname ".exe"))) (and (or (string-ci=? exe oexe) (batch:delete-file parms oexe)) (batch:try-command parms "tcc" "-Lc:\\turboc\\lib" libs objects) (or (string-ci=? exe oexe) (batch:rename-file parms exe oexe)) oexe)))) (defcommand compile-c-files microsoft-c (lambda (files parms) (and (batch:try-chopped-command parms "cl" "-c" "Oxp" "-AH" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->obj files) #\\)))) (defcommand link-c-program microsoft-c (lambda (oname objects libs parms) (let ((exe (truncate-up-to (obj->exe (car objects)) #\\)) (oexe (string-append oname ".exe"))) (and (or (string-ci=? exe oexe) (batch:delete-file parms oexe)) (batch:try-command parms "link" "/noe" "/ST:40000" (apply string-join "+" (map obj-> objects)) libs) (or (string-ci=? exe oexe) (batch:rename-file parms exe oexe)) oexe)))) (defcommand compile-c-files microsoft-c-nt (lambda (files parms) (and (batch:try-chopped-command parms "cl" "-c" "-nologo" (if (memq 'stack-limit (parameter-list-ref parms 'features)) "-Oityb1" "-Ox") (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->obj files) #\\)))) (defcommand compile-dll-c-files microsoft-c-nt (lambda (files parms) (define platform (car (parameter-list-ref parms 'platform))) (let ((suppressors (build:c-suppress 'dlll platform))) (define c-files (remove-if (lambda (file) (member file suppressors)) files)) (and (batch:try-chopped-command parms "cl" "-c" "-nologo" (if (memq 'stack-limit (parameter-list-ref parms 'features)) "-Oityb1" "-Ox") (include-spec "-I" parms) (c-includes parms) (c-flags parms) c-files) (let ((fnames (map c-> c-files))) (and (batch:try-command parms "link" "/dll" "/nologo" (string-append "/out:" (car fnames) ".dll") (string-append "/implib:" (car fnames) ".lib") fnames (map (lambda (l) (build:lib-ld-flag l platform)) (parameter-list-ref parms 'c-lib)) "scm.lib") (list (string-append (car fnames) ".dll")))))))) (defcommand make-dll-archive microsoft-c-nt (lambda (oname objects libs parms) objects)) (defcommand make-archive microsoft-c-nt (lambda (oname objects libs parms) (let ((aname (string-append oname ".dll"))) (and (batch:try-command parms "link" "/dll" "/nologo" (string-append "/out:" aname) (string-append "/implib:" oname ".lib") libs (map obj-> objects)) aname)))) (defcommand link-c-program microsoft-c-nt (lambda (oname objects libs parms) (let ((exe (truncate-up-to (obj->exe (car objects)) #\\)) (oexe (string-append oname ".exe"))) (and (batch:try-command parms "link" "/nologo" (string-append "/out:" oexe) (apply string-join " " (map obj-> objects)) libs) oexe)))) (defcommand compile-c-files microsoft-quick-c (lambda (files parms) (and (batch:try-chopped-command parms "qcl" "/AH" "/W1" "/Ze" "/O" "/Ot" "/DNDEBUG" (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->obj files) #\\)))) (defcommand link-c-program microsoft-quick-c (lambda (oname objects libs parms) (define crf-name (string-append oname ".crf")) (apply batch:lines->file parms crf-name `(,@(map (lambda (f) (string-append f " +")) objects) "" ,(string-append oname ".exe") ,(apply string-join " " libs) ";")) (and (batch:try-command parms "qlink" "/CP:0xffff" "/NOI" "/SE:0x80" "/ST:0x9c40" crf-name) (string-append oname ".exe")))) (defcommand compile-c-files watcom-9.0 (lambda (files parms) (and (batch:try-chopped-command parms "wcc386p" "/mf" "/d2" "/ze" "/oxt" "/3s" "/zq" "/w3" (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->obj files) #\\)))) (defcommand link-c-program watcom-9.0 (lambda (oname objects libs parms) (let ((exe (truncate-up-to (obj->exe (car objects)) #\\)) (oexe (string-append oname ".exe"))) (and (or (string-ci=? exe oexe) (batch:delete-file parms oexe)) (batch:try-command parms "wlinkp" "option" "quiet" "option" "stack=40000" "FILE" (apply string-join "," (map obj-> objects)) libs) (if (not (string-ci=? exe oexe)) (batch:rename-file parms exe oexe)) oexe)))) (defcommand compile-c-files highc (lambda (files parms) (define hcc-name "temp.hcc") (apply batch:lines->file parms hcc-name files) (and (batch:try-command parms "d:\\hi_c\\hc386.31\\bin\\hc386" (include-spec "-I" parms) (c-includes parms) (c-flags parms) "-c" (string-append "@" hcc-name)) (truncate-up-to (map c->obj files) #\\)))) (defcommand link-c-program highc (lambda (oname objects libs parms) (let ((oexe (string-append oname ".exe"))) (define lnk-name (string-append oname ".lnk")) (apply batch:lines->file parms lnk-name (append libs objects)) (and (batch:try-command parms "d:\\hi_c\\hc386.31\\bin\\hc386" "-o" oname "-stack 65000" (string-append "@" lnk-name)) (batch:try-command parms "bind386" "d:/hi_c/pharlap.51/run386b.exe" oname "-exe" oexe) oexe)))) (defcommand compile-c-files djgpp (lambda (files parms) (and (batch:try-chopped-command parms "gcc" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->o files) "\\/")))) (defcommand link-c-program djgpp (lambda (oname objects libs parms) (let ((exe (string-append oname ".exe"))) (and (or (batch:try-command parms "gcc" "-o" oname (must-be-first '("-nostartfiles" "pre-crt0.o" "ecrt0.o" "c:/djgpp/lib/crt0.o") (append objects libs))) (let ((arname (string-append oname ".a"))) (batch:delete-file parms arname) (and (batch:try-chopped-command parms "ar" "r" arname objects) (batch:try-command parms "gcc" "-o" oname (must-be-first '("-nostartfiles" "pre-crt0.o" "ecrt0.o" "c:/djgpp/lib/crt0.o") (cons arname libs))) (batch:delete-file parms arname))) ;;(build:error 'build "couldn't build archive") ) (batch:try-command parms "strip" exe) (batch:delete-file parms oname) ;;(batch:delete-file parms exe) ;;(batch:try-command parms "coff2exe" "-s" "c:\\djgpp\\bin\\go32.exe" oname) exe)))) (defcommand compile-c-files os/2-emx (lambda (files parms) (and (batch:try-chopped-command parms "gcc" "-m386" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->o files) #\\)))) (defcommand link-c-program os/2-emx (lambda (oname objects libs parms) (and (batch:try-command parms "gcc" "-o" (string-append oname ".exe") objects libs) (string-append oname ".exe")))) (defcommand compile-c-files os/2-cset (lambda (files parms) (and (batch:try-chopped-command parms "icc" "/Gd-" "/Ge+" "/Gm+" "/Q" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->obj files) #\\)))) (defcommand link-c-program os/2-cset (lambda (oname objects libs parms) (and (batch:try-command parms "link386" objects libs (string-append "," oname ".exe,,,;")) (string-append oname ".exe")))) (defcommand compile-c-files HP-UX (lambda (files parms) (and (batch:try-chopped-command parms "cc" "+O1" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->o files) #\/)))) (defcommand compile-dll-c-files HP-UX (lambda (files parms) (and (batch:try-chopped-command parms "cc" "+O1" "-Wl,-E" "+z" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (let ((fnames (truncate-up-to (map c-> files) #\/))) (define fname.sl (string-append (car fnames) ".sl")) (batch:rename-file parms fname.sl (string-append fname.sl "~")) (and (batch:try-command parms "ld" "-b" "-o" fname.sl (map (lambda (fname) (string-append fname ".o")) fnames)) (list fname.sl)))))) ; (make-dll-archive HP-UX ; (lambda (oname objects libs parms) ; (and (batch:try-command ; parms "ld" "-b" "-o" (string-append oname ".sl") ; objects) ; (batch:rebuild-catalog parms) ; (string-append oname ".sl")))) (defcommand compile-dll-c-files linux-aout (lambda (files parms) (and (batch:try-chopped-command parms "gcc" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->o files) #\/)))) ;;; (make-dll-archive linux-aout ;;; (lambda (oname objects libs parms) #t ;;; (batch:rebuild-catalog parms) ;;; oname)) (defcommand compile-c-files linux (lambda (files parms) (and (batch:try-chopped-command parms "gcc" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->o files) #\/)))) (defcommand compile-dll-c-files linux (lambda (files parms) (and (batch:try-chopped-command parms "gcc" "-fpic" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (let* ((platform (car (parameter-list-ref parms 'platform))) (fnames (truncate-up-to (map c-> files) #\/)) (fname.so (string-append (car fnames) ".so")) (result (and (batch:try-command parms "gcc" "-shared" "-o" fname.so (map (lambda (fname) (string-append fname ".o")) fnames) (map (lambda (l) (build:lib-ld-flag l platform)) (parameter-list-ref parms 'c-lib))) (list fname.so)))) (for-each (lambda (fname) (batch:delete-file parms (string-append fname ".o"))) fnames) result)))) (defcommand make-dll-archive linux (lambda (oname objects libs parms) (let ((platform (car (parameter-list-ref parms 'platform)))) (and (batch:try-command parms "gcc" "-shared" "-o" (string-append (car (parameter-list-ref parms 'implvic)) oname ".so") objects (map (lambda (l) (build:lib-ld-flag l platform)) (parameter-list-ref parms 'c-lib))) (batch:rebuild-catalog parms) (string-append (car (parameter-list-ref parms 'implvic)) oname ".so"))))) (defcommand link-c-program linux (lambda (oname objects libs parms) (and (batch:try-command parms "gcc" "-rdynamic" "-o" oname (must-be-first '("pre-crt0.o" "ecrt0.o" "/usr/lib/crt0.o") (append objects libs))) oname))) (defcommand link-c-program linux-ia64 (lambda (oname objects libs parms) (and (and (batch:try-command parms "gcc -o get-contoffset-ia64 get-contoffset-ia64.c") (batch:try-command parms "./get-contoffset-ia64 contoffset-ia64.S") (batch:try-command parms "gcc -c continue-ia64.S")) (batch:try-command parms "gcc" "-rdynamic" "-o" oname "continue-ia64.o" (must-be-first '("pre-crt0.o" "ecrt0.o" "/usr/lib/crt0.o") (append objects libs))) oname))) (defcommand compile-c-files unicos (lambda (files parms) (and (batch:try-chopped-command parms "cc" "-hvector2" "-hscalar2" "-c" (include-spec "-i" parms) (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->o files) #\/)))) (defcommand link-c-program unicos (lambda (oname objects libs parms) (and (batch:try-command parms "cc" "setjump.o" "-o" oname objects libs) oname))) ;; George Bronnikov describes options for the ;; PLAN9 native C compiler `8c': ;; ;; -F Enable type-checking of calls to print(2) and other ;; formatted print routines. ;; -V By default, the compilers are non-standardly lax about ;; type equality between void* values and other pointers. ;; This flag requires ANSI C conformance. ;; -w Print warning messages about unused variables etc. (It ;; does print a lot of them, indeed.) ;; -p Invoke a standard ANSI C preprocessor before compiling ;; (instead of a rudimentary builtin one used by default). (defcommand compile-c-files plan9-8 (lambda (files parms) (and (batch:try-chopped-command parms "8c" "-Fwp" "-DPLAN9" ;"-V" ;;(include-spec "-i" parms) (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->8 files) #\/)))) (defcommand link-c-program plan9-8 (lambda (oname objects libs parms) (and (batch:try-command parms "8l" "-o" oname objects libs) oname))) (defcommand compile-c-files gcc (lambda (files parms) (and (batch:try-chopped-command parms "gcc" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->o files) #\/)))) (defcommand link-c-program gcc (lambda (oname objects libs parms) (batch:rename-file parms oname (string-append oname "~")) (and (batch:try-command parms "gcc" "-o" oname (must-be-first '("-nostartfiles" "pre-crt0.o" "ecrt0.o" "/usr/lib/crt0.o") (append objects libs))) oname))) (defcommand compile-dll-c-files gcc (lambda (files parms) (and (batch:try-chopped-command parms "gcc" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->o files) "\\/]")))) (defcommand make-dll-archive gcc (lambda (oname objects libs parms) (and (batch:try-command parms "ld" "-assert" "pure-text" "-o" (string-append (car (parameter-list-ref parms 'implvic)) oname ".so.1.0") objects) (batch:rebuild-catalog parms) (string-append (car (parameter-list-ref parms 'implvic)) oname ".so.1.0")))) (defcommand compile-dll-c-files gnu-win32 (lambda (files parms) (define platform (car (parameter-list-ref parms 'platform))) (let ((suppressors (build:c-suppress 'dlll platform))) (define c-files (remove-if (lambda (file) (member file suppressors)) files)) (and (batch:try-chopped-command parms "gcc" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) c-files) (let ((fnames (map c-> c-files))) (and (batch:try-command parms "dllwrap" "--output-lib" (string-append (car fnames) ".lib") "-dllname" (string-append (car fnames) ".dll") "--output-def" (string-append (car fnames) ".def") (map (lambda (fname) (string-append fname ".o")) fnames) (map (lambda (l) (build:lib-ld-flag l platform)) (parameter-list-ref parms 'c-lib)) "scm.lib") (list (string-append (car fnames) ".dll")))))))) (defcommand make-dll-archive gnu-win32 (lambda (oname objects libs parms) objects)) (defcommand make-archive gnu-win32 (lambda (oname objects libs parms) (let ((aname (string-append oname ".dll"))) (and (batch:try-command parms "dllwrap" "--output-lib" (string-append oname ".lib") "-dllname" aname "--output-def" (string-append oname ".def") libs objects) aname)))) (defcommand compile-c-files gnu-win32 (lambda (files parms) (and (batch:try-chopped-command parms "gcc" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->o files) #\/)))) (defcommand link-c-program gnu-win32 (lambda (oname objects libs parms) (batch:rename-file parms (string-append oname ".exe") (string-append oname "~")) (and (batch:try-command parms "gcc" "-o" oname (must-be-first '("-nostartfiles" "pre-crt0.o" "ecrt0.o" "/usr/lib/crt0.o") (append objects libs))) oname))) (defcommand compile-c-files osf1 (lambda (files parms) (and (batch:try-chopped-command parms "cc" "-std1" ;;(if (member "-g" (c-includes parms)) "" "-O") "-c" (c-includes parms) (include-spec "-I" parms) (c-flags parms) files) (truncate-up-to (map c->o files) #\/)))) (defcommand compile-dll-c-files osf1 (lambda (files parms) (and (batch:try-chopped-command parms "cc" "-std1" "-c" (c-includes parms) (include-spec "-I" parms) (c-flags parms) files) (let* ((platform (car (parameter-list-ref parms 'platform))) (fnames (truncate-up-to (map c-> files) #\/))) (and (batch:try-command parms "cc" "-shared" "-o" (string-append (car fnames) ".so") (map (lambda (fname) (string-append fname ".o")) fnames) (map (lambda (l) (build:lib-ld-flag l platform)) (parameter-list-ref parms 'c-lib))) (for-each (lambda (fname) (batch:delete-file parms (string-append fname ".o"))) fnames) (list (string-append (car fnames) ".so"))))))) (defcommand make-dll-archive osf1 (lambda (oname objects libs parms) (let ((platform (car (parameter-list-ref parms 'platform)))) (and (batch:try-command parms "cc" "-shared" "-o" (string-append (car (parameter-list-ref parms 'implvic)) oname ".so") objects (map (lambda (l) (build:lib-ld-flag l platform)) (parameter-list-ref parms 'c-lib))) (batch:rebuild-catalog parms) (string-append (car (parameter-list-ref parms 'implvic)) oname ".so"))))) (defcommand compile-c-files svr4-gcc-sun-ld (lambda (files parms) (and (batch:try-chopped-command parms "gcc" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->o files) #\/)))) (defcommand link-c-program svr4-gcc-sun-ld (lambda (oname objects libs parms) (batch:rename-file parms oname (string-append oname "~")) (and (batch:try-command parms "gcc" "-o" oname (must-be-first '("-nostartfiles" "pre-crt0.o" "ecrt0.o" "/usr/lib/crt0.o") (append objects libs))) oname))) (defcommand compile-dll-c-files svr4-gcc-sun-ld (lambda (files parms) (and (batch:try-chopped-command parms "gcc" "-fpic" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (let* ((platform (car (parameter-list-ref parms 'platform))) (fnames (truncate-up-to (map c-> files) #\/))) (and (batch:try-command parms "ld" "-G" "-o" (string-append (car fnames) ".so") (map (lambda (fname) (string-append fname ".o")) fnames) (map (lambda (l) (build:lib-ld-flag l platform)) (parameter-list-ref parms 'c-lib))) (for-each (lambda (fname) (batch:delete-file parms (string-append fname ".o"))) fnames) (list (string-append (car fnames) ".so"))))))) (defcommand compile-c-files svr4 (lambda (files parms) (and (batch:try-chopped-command parms "cc" "-DSVR4" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->o files) #\/)))) (defcommand compile-c-files aix (lambda (files parms) (and (batch:try-chopped-command parms "cc" "-Dunix" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->o files) #\/)))) (defcommand link-c-program aix (lambda (oname objects libs parms) (and (batch:try-command parms "cc" "-lansi" "-o" oname objects libs) oname))) (defcommand compile-c-files amiga-aztec (lambda (files parms) (and (batch:try-chopped-command parms "cc" "-dAMIGA" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->o files) #\/)))) (defcommand link-c-program amiga-aztec (lambda (oname objects libs parms) (and (batch:try-command parms "cc" "-o" oname objects libs "-lma") oname))) (defcommand compile-c-files amiga-sas (lambda (files parms) (and (batch:try-chopped-command parms "lc" "-d3" "-M" "-fi" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (batch:try-command parms "blink with link.amiga NODEBUG") (truncate-up-to (map c->o files) #\/)))) (defcommand link-c-program amiga-sas (lambda (oname objects libs parms) (define lnk-name "link.amiga") (apply batch:lines->file parms lnk-name (apply string-join "+" ">FROM LIB:c.o" (map object->string objects)) (string-append "TO " (object->string (string-append "/" oname))) (append (cond ((pair? libs) (cons (string-append "LIB LIB:" (car libs)) (map (lambda (s) (string-append " LIB:" s)) (cdr libs)))) (else '())) '("VERBOSE" "SC" "SD"))) oname)) (defcommand compile-c-files amiga-dice-c (lambda (files parms) (and (batch:try-command parms "dcc" "-r" "-gs" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files "-o" (truncate-up-to (map c->o files) #\/)) (truncate-up-to (map c->o files) #\/)))) (defcommand link-c-program amiga-dice-c (lambda (oname objects libs parms) (and (batch:try-command parms "dcc" "-r" "-gs" "-o" oname objects libs) oname))) (defcommand compile-c-files amiga-gcc (lambda (files parms) (and (batch:try-chopped-command parms "gcc" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->o files) #\/)))) (defcommand link-c-program amiga-gcc (lambda (oname objects libs parms) (batch:rename-file parms oname (string-append oname "~")) (and (batch:try-command parms "gcc" "-o" oname (must-be-first '("-nostartfiles" "pre-crt0.o" "ecrt0.o" "/usr/lib/crt0.o") (append objects libs))) oname))) (defcommand compile-c-files atari-st-gcc (lambda (files parms) (and (batch:try-chopped-command parms "gcc" "-v" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->o files) #\/)))) (defcommand link-c-program atari-st-gcc (lambda (oname objects libs parms) (and (batch:try-command parms "gcc" "-v" "-o" (string-append oname ".ttp") objects libs) (string-append oname ".ttp")))) (defcommand compile-c-files atari-st-turbo-c (lambda (files parms) (and (batch:try-chopped-command parms "tcc" "-P" "-W-" "-Datarist" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->o files) #\/)))) (defcommand link-c-program atari-st-turbo-c (lambda (oname objects libs parms) (and (batch:try-command parms "tlink" "-o" (string-append oname ".ttp") objects libs "mintlib.lib" "osbind.lib" "pcstdlib.lib" "pcfltlib.lib") (string-append oname ".ttp")))) (defcommand compile-c-files acorn-unixlib (lambda (files parms) (and (batch:try-chopped-command parms "cc" "-c" "-depend" "!Depend" "-IUnixLib:" "-pcc" "-Dunix" "-DSVR3" "-DARM_ULIB" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->o files) #\/)))) (defcommand link-c-program acorn-unixlib (lambda (oname objects libs parms) (and (batch:try-command parms "link" "-o" oname objects libs ":5.$.dev.gcc.unixlib36d.clib.o.unixlib") (batch:try-command parms "squeeze" oname) oname))) (defcommand compile-c-files vms (lambda (files parms) (and (batch:try-chopped-command parms "cc" (c-includes parms) (c-flags parms) (map c-> files)) (truncate-up-to (map c->obj files) "/]")))) (defcommand link-c-program vms (lambda (oname objects libs parms) (let ((exe (truncate-up-to (obj->exe (car objects)) "/]")) (oexe (string-append oname ".exe"))) (and (batch:try-command parms "macro" "setjump") (batch:try-command parms "link" (apply string-join "," (append (map obj-> objects) '("setjump" "sys$input/opt\n "))) (apply string-join "," (append (remove "" libs) '("sys$share:vaxcrtl/share")))) (or (string-ci=? exe oexe) (batch:rename-file parms exe oexe)) oexe)))) (defcommand compile-c-files vms-gcc (lambda (files parms) (and (batch:try-chopped-command parms "gcc" (include-spec "-I" parms) (c-includes parms) (c-flags parms) (map c-> files)) (truncate-up-to (map c->obj files) "/]")))) (defcommand link-c-program vms-gcc (lambda (oname objects libs parms) (let ((exe (truncate-up-to (obj->exe (car objects)) "/]")) (oexe (string-append oname ".exe"))) (and (batch:try-command parms "macro" "setjump") (batch:try-command parms "link" (apply string-join "," (append objects '("setjump.obj" "sys$input/opt\n "))) (apply string-join "," (append (remove "" libs) '("gnu_cc:[000000]gcclib/lib" "sys$share:vaxcrtl/share")))) (or (string-ci=? exe oexe) (batch:rename-file parms exe oexe)) oexe)))) (defcommand compile-c-files *unknown* (lambda (files parms) (batch:try-chopped-command parms "cc" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->o files) "\\/]"))) (defcommand link-c-program *unknown* (lambda (oname objects libs parms) (batch:rename-file parms oname (string-append oname "~")) (and (batch:try-command parms "cc" "-o" oname (must-be-first '("-nostartfiles" "pre-crt0.o" "ecrt0.o" "/usr/lib/crt0.o") (append objects libs))) oname))) (defcommand make-archive *unknown* (lambda (oname objects libs parms) (let ((aname (string-append "lib" oname ".a"))) (and (batch:try-command parms "ar rc" aname objects) (batch:try-command parms "ranlib" aname) aname)))) (defcommand compile-dll-c-files *unknown* (lambda (files parms) (and (batch:try-chopped-command parms "cc" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (truncate-up-to (map c->o files) "\\/]")))) (defcommand make-dll-archive *unknown* (lambda (oname objects libs parms) (let ((aname (string-append (car (parameter-list-ref parms 'implvic)) oname ".a"))) (and (batch:try-command parms "ar rc" aname objects) (batch:try-command parms "ranlib" aname) (batch:rebuild-catalog parms) aname)))) (defcommand compile-c-files freebsd (lambda (files parms) (and (batch:try-chopped-command parms ;;; gcc 3.4.2 for FreeBSD does not allow options other than default i.e. -O0 if NO -DGCC_SPARC_BUG - dai 2004-10-30 ;;"cc" "-O3 -pipe -DGCC_SPARC_BUG " "-c" "cc" "-O3 -pipe " "-c" (c-includes parms) (c-flags parms) files) (map c->o files)))) (defcommand link-c-program freebsd (lambda (oname objects libs parms) (batch:rename-file parms oname (string-append oname "~")) (and (batch:try-command parms "cc" "-o" oname (must-be-first '("-nostartfiles" "pre-crt0.o" "crt0.o" "/usr/lib/crt0.o") (append objects libs))) oname))) (defcommand compile-dll-c-files freebsd (lambda (files parms) (and (batch:try-chopped-command parms "cc" "-O3 -pipe " "-fPIC" "-c" (c-includes parms) (c-flags parms) files) (let ((fnames (truncate-up-to (map c-> files) #\/))) (and (batch:try-command parms "cc" "-shared" (cond ((equal? (car fnames) "edline") "-lreadline") ((equal? (car fnames) "x") "-L/usr/X11R6/lib -lSM -lICE -lXext -lX11 -lxpg4") (else "")) "-o" (string-append (car fnames) ".so") (map (lambda (fname) (string-append fname ".o")) fnames)) (for-each (lambda (fname) (batch:delete-file parms (string-append fname ".o"))) fnames) (list (string-append (car fnames) ".so"))))))) (defcommand make-dll-archive freebsd (lambda (oname objects libs parms) (and (batch:try-command parms "cc" "-shared" "-o" (string-append (car (parameter-list-ref parms 'implvic)) oname ".so") objects) (batch:rebuild-catalog parms) (string-append (car (parameter-list-ref parms 'implvic)) oname ".so")))) (defcommand compile-c-files darwin (lambda (files parms) (and (batch:try-chopped-command parms "cc" "-O3" "-c" (c-includes parms) (c-flags parms) files) (map c->o files)))) (defcommand link-c-program darwin (lambda (oname objects libs parms) (batch:rename-file parms oname (string-append oname "~")) (and (batch:try-command parms "cc" "-o" oname (append objects libs)) oname))) (defcommand compile-dll-c-files darwin (lambda (files parms) (and (batch:try-chopped-command parms "gcc" "-c" (c-includes parms) (c-flags parms) files) (let ((fnames (truncate-up-to (map c-> files) #\/))) (and (batch:try-command parms "gcc" "-dynamiclib" "-single_module" "-L." "-undefined" "dynamic_lookup" "-o" (string-append (car fnames) ".so") (map (lambda (fname) (string-append fname ".o")) fnames)) (for-each (lambda (fname) (batch:delete-file parms (string-append fname ".o"))) fnames) (list (string-append (car fnames) ".so"))))))) (defcommand make-dll-archive darwin (lambda (oname objects libs parms) (let ((platform (car (parameter-list-ref parms 'platform)))) (and (batch:try-command parms "gcc" "-dynamiclib" "-L." "-undefined" "dynamic_lookup" "-o" (string-append (car (parameter-list-ref parms 'implvic)) oname ".so") objects (map (lambda (l) (build:lib-ld-flag l platform)) (parameter-list-ref parms 'c-lib))) (batch:rebuild-catalog parms) (string-append (car (parameter-list-ref parms 'implvic)) oname ".so"))))) (defcommand compile-c-files netbsd (lambda (files parms) (and (batch:try-chopped-command parms "cc" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (map c->o files)))) (defcommand link-c-program netbsd (lambda (oname objects libs parms) (batch:rename-file parms oname (string-append oname "~")) (and (batch:try-command parms "cc" "-o" oname (must-be-first '("-nostartfiles" "pre-crt0.o" "crt0.o" "/usr/lib/crt0.o") (append libs objects))) oname))) (defcommand compile-dll-c-files netbsd (lambda (files parms) (and (batch:try-chopped-command parms "cc" "-fPIC" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (let ((objs (map c->o files))) (and (batch:try-command parms "gcc" "-shared" "-fPIC" objs) (batch:try-command parms "mv" "a.out" (car objs)) (list (car objs))))))) (defcommand make-dll-archive netbsd (lambda (oname objects libs parms) (and (batch:try-command parms "gcc" "-shared" "-fPIC" "-o" (string-append (car (parameter-list-ref parms 'implvic)) oname ".so") objects) (batch:rebuild-catalog parms) (string-append (car (parameter-list-ref parms 'implvic)) oname ".so")))) (defcommand compile-c-files openbsd (lambda (files parms) (and (batch:try-chopped-command parms "cc" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (map c->o files)))) (defcommand link-c-program openbsd (lambda (oname objects libs parms) (batch:rename-file parms oname (string-append oname "~")) (and (batch:try-command parms "cc" "-o" oname (must-be-first '("-nostartfiles" "pre-crt0.o" "crt0.o" "/usr/lib/crt0.o") (append objects libs))) oname))) (defcommand compile-dll-c-files openbsd (lambda (files parms) (and (batch:try-chopped-command parms "cc" "-fPIC" "-c" (include-spec "-I" parms) (c-includes parms) (c-flags parms) files) (let ((objs (map c->o files))) (and (batch:try-command parms "gcc" "-shared" "-fPIC" objs) (batch:try-command parms "mv" "a.out" (car objs)) (list (car objs))))))) (defcommand make-dll-archive openbsd (lambda (oname objects libs parms) (and (batch:try-command parms "gcc" "-shared" "-fPIC" "-o" (string-append (car (parameter-list-ref parms 'implvic)) oname ".so") objects) (batch:rebuild-catalog parms) (string-append (car (parameter-list-ref parms 'implvic)) oname ".so")))) (define-domains build '(C-libraries C-libraries #f symbol #f)) (define-tables build '(build-params *parameter-columns* *parameter-columns* ((1 platform single platform (lambda (pl) (list *operating-system*)) #f "what to build it for") (2 target-name single string (lambda (pl) '("scm")) #f "base name of target") (3 c-lib nary C-libraries (lambda (pl) '(c)) #f "C library (and include files)") (4 define nary string #f #f "#define FLAG") (5 implvic single string (lambda (pl) (list "")) #f "implementation vicinity") (6 c-file nary filename #f #f "C source files") (7 o-file nary filename #f #f "other object files") (8 init nary string #f #f "initialization calls") (9 compiled-init nary string #f #f "later initialization calls") (10 features nary features (lambda (pl) '(arrays inexact bignums)) (lambda (rdb) ((open-table rdb 'features) 'get 'spec)) "features to include") (11 what single build-whats (lambda (pl) '(exe)) (lambda (rdb) (let* ((bwt (open-table rdb 'build-whats)) (getclass (bwt 'get 'class)) (getspec (bwt 'get 'spec)) (getfile ((open-table rdb 'manifest) 'get* 'file))) (lambda (what) `((c-file ,@(getfile #f 'c-source (getclass what))) ,@(or (getspec what) '()))))) "what to build") (12 batch-dialect single batch-dialect (lambda (pl) '(default-for-platform)) ;;guess-how #f "scripting language") (13 who optional expression #f #f "name of buildfile") (14 compiler-options nary string #f #f "command-line compiler options") (15 linker-options nary string #f #f "command-line linker options") (16 scm-srcdir single filename (lambda (pl) (list (user-vicinity))) #f "directory path for files in the manifest") (17 c-defines nary expression #f #f "#defines for C") (18 c-includes nary expression #f #f "library induced defines for C") (19 batch-port nary expression #f #f "port batch file will be written to.") ;; The options file is read by a fluid-let getopt-- in "build". ;; This is here so the usage message will include -f . (20 options-file nary filename #f #f "file containing more build options.") )) '(build-pnames ((name string)) ((parameter-index uint)) ;should be build-params ( ("p" 1) ("platform" 1) ("o" 2) ("outname" 2) ("l" 3) ("libraries" 3) ("D" 4) ("defines" 4) ("s" 5) ("scheme initialization file" 5) ("c" 6) ("c source files" 6) ("j" 7) ("object files" 7) ("i" 9) ("initialization calls" 9) ("F" 10) ("features" 10) ("t" 11) ("type" 11) ("h" 12) ("batch dialect" 12) ("w" 13) ("script name" 13) ("compiler options" 14) ("linker options" 15) ("scm srcdir" 16) ("f" 20) )) '(*commands* ((name symbol)) ;or just desc:*commands* ((parameters parameter-list) (parameter-names parameter-name-translation) (procedure expression) (documentation string)) ((build build-params build-pnames build:command "compile and link SCM programs.") (*initialize* no-parameters no-parameters #f "SCM Build Database")))) (define build:error slib:error) (define build:c-libraries #f) (define build:lib-cc-flag #f) (define build:lib-ld-flag #f) (define build:c-lib-support #f) (define build:c-suppress #f) (define plan-command #f) (define platform->os #f) ;;; Look up command on a platform, but default to '*unknown* if not ;;; initially found. (define (make-defaulting-platform-lookup getter) (lambda (thing plat) (define (look platform) (let ((ans (getter thing platform))) (cond (ans ans) (else (let ((os (platform->os platform))) (cond ((eq? os platform) (look '*unknown*)) ((eq? platform '*unknown*) '()) (else (look os)))))))) (look plat))) (define (build:command rdb) (lambda (parms) (let ((expanders (map (lambda (e) (and e (lambda (s) (e s)))) (map (lambda (f) (if f ((slib:eval f) rdb) f)) (((open-table rdb 'build-params) 'get* 'expander)))))) (parameter-list-expand expanders parms) (set! parms (fill-empty-parameters (map slib:eval (((open-table rdb 'build-params) 'get* 'defaulter))) parms)) (parameter-list-expand expanders parms)) (let* ((platform (car (parameter-list-ref parms 'platform))) (init= (apply string-append (map (lambda (c) (string-append c "();")) (parameter-list-ref parms 'init)))) (compiled-init= (apply string-append (map (lambda (c) (string-append c "();")) (parameter-list-ref parms 'compiled-init)))) (implvic (let ((impl (car (parameter-list-ref parms 'implvic)))) (if (equal? "" impl) (car (parameter-list-ref parms 'scm-srcdir)) impl))) (c-defines `((define "IMPLINIT" ,(object->string (string-append implvic "Init" (read-version (in-vicinity (car (parameter-list-ref parms 'scm-srcdir)) "patchlvl.h")) ".scm"))) ;;,@`(if (equal? "" implvic) '() (...)) ,@(if (string=? "" init=) '() `((define "INITS" ,init=))) ,@(if (string=? "" compiled-init=) '() `((define "COMPILED_INITS" ,compiled-init=))) ,@(map (lambda (d) (if (pair? d) `(define ,@d) `(define ,d #t))) (parameter-list-ref parms 'define)))) (c-includes (map (lambda (l) (build:lib-cc-flag l platform)) (parameter-list-ref parms 'c-lib))) (what (car (parameter-list-ref parms 'what))) (c-proc (plan-command (((open-table rdb 'build-whats) 'get 'c-proc) what) platform))) (case (car (parameter-list-ref parms 'batch-dialect)) ((default-for-platform) (let ((os (((open-table build 'platform) 'get 'operating-system) platform))) (if (not os) (build:error "OS corresponding to " platform " unknown")) (adjoin-parameters! parms (cons 'batch-dialect (list (os->batch-dialect os))))))) (adjoin-parameters! parms (cons 'c-defines c-defines) (cons 'c-includes c-includes)) (set! parms (cons (cons 'operating-system (map platform->os (parameter-list-ref parms 'platform))) parms)) (let ((name (parameter-list-ref parms 'who))) (set! name (if (null? name) (current-output-port) (car name))) (batch:call-with-output-script parms name (lambda (batch-port) (define o-files #f) (adjoin-parameters! parms (list 'batch-port batch-port)) (batch:comment parms (string-append "[-p " (symbol->string platform) "]")) (let ((options-file (parameter-list-ref parms 'options-file))) (and (not (null? options-file)) (batch:comment parms (apply string-join " " "used options from:" options-file)))) (batch:comment parms "================ Write file with C defines") (cond ((not (apply batch:lines->file parms "scmflags.h" (defines->c-defines c-defines))) (batch:comment parms "================ Write failed!") #f) (else (batch:comment parms "================ Compile C source files") (set! o-files (let ((suppressors (apply append (map (lambda (l) (build:c-suppress l platform)) (parameter-list-ref parms 'c-lib))))) (c-proc (apply append (remove-if (lambda (file) (member file suppressors)) (parameter-list-ref parms 'c-file)) (map (lambda (l) (build:c-lib-support l platform)) (parameter-list-ref parms 'c-lib))) parms))) (cond ((not o-files) (batch:comment parms "================ Compilation failed!") #f) (else (batch:comment parms "================ Link C object files") (let ((ans ((plan-command (((open-table rdb 'build-whats) 'get 'o-proc) what) platform) (car (parameter-list-ref parms 'target-name)) (append o-files (parameter-list-ref parms 'o-file)) (append (parameter-list-ref parms 'linker-options) (map (lambda (l) (build:lib-ld-flag l platform)) (parameter-list-ref parms 'c-lib))) parms))) (cond ((not ans) (batch:comment parms "================ Link failed!") #f) (else ans))))))))))))) (define (include-spec str parms) (let ((path (car (parameter-list-ref parms 'scm-srcdir)))) (if (eqv? "" path) () (list str path)))) (define (c-defines parms) (parameter-list-ref parms 'c-defines)) (define (c-includes parms) (parameter-list-ref parms 'c-includes)) (define (c-flags parms) (parameter-list-ref parms 'compiler-options)) (define (defines->c-defines defines) (map (lambda (d) (case (caddr d) ((#t) (string-join " " "#define" (cadr d))) ((#f) (string-join " " "#undef" (cadr d))) (else (apply string-join " " "#define" (cdr d))))) defines)) (define (defines->flags defines) (map (lambda (d) (case (caddr d) ((#t) (string-append "-D" (cadr d))) ((#f) (string-append "-U" (cadr d))) (else (string-append "-D" (cadr d) "=" (object->string (caddr d)))))) defines)) (define c-> (filename:substitute?? "*.c" "*")) (define c->o (filename:substitute?? "*.c" "*.o")) (define c->8 (filename:substitute?? "*.c" "*.8")) (define c->obj (filename:substitute?? "*.c" "*.obj")) (define obj-> (filename:substitute?? "*.obj" "*")) (define obj->exe (filename:substitute?? "*.obj" "*.exe")) (define (read-version revfile) (call-with-input-file (if (file-exists? revfile) revfile (in-vicinity (implementation-vicinity) "patchlvl.h")) (lambda (port) (do ((c (read-char port) (read-char port))) ((or (eof-object? c) (eqv? #\= c)) (do ((c (read-char port) (read-char port)) (lst '() (cons c lst))) ((or (eof-object? c) (char-whitespace? c)) (list->string (reverse lst))))))))) (define (batch:rebuild-catalog parms) (batch:delete-file parms (in-vicinity (car (parameter-list-ref parms 'implvic)) "slibcat")) #t) (define (logger . args) (define cep (current-error-port)) (for-each (lambda (x) (display #\space cep) (display x cep)) (cond ((provided? 'bignum) (require 'posix-time) (let ((ct (ctime (current-time)))) (string-set! ct (+ -1 (string-length ct)) #\:) (cons ct args))) (else args))) (newline cep)) (define build:qacs #f) ;@ (define (build:serve request-line query-string header) (define query-alist (and query-string (uri:decode-query query-string))) (if (not build:qacs) (set! build:qacs (make-query-alist-command-server build '*commands* #t))) (call-with-outputs (lambda () (build:qacs query-alist)) (lambda (stdout stderr . status) (cond ((or (substring? ": ERROR: " stderr) (substring? ": WARN: " stderr)) => (lambda (idx) (set! stderr (substring stderr (+ 2 idx) (string-length stderr)))))) (cond ((null? status) (logger "Aborting query") (pretty-print query-alist) (display stderr) (list "buildscm Abort" (html:pre stdout) "" (html:pre stderr) "")) (else (display stderr) ;query is already logged (if (car status) (http:content '(("Content-Type" . "text/plain")) ;application/x-sh stdout) (list "buildscm Error" "" (html:pre stderr) "" "
" (html:pre stdout)))))))) ;;; (print 'request-line '= (cgi:request-line)) (print 'header '=) (for-each print (cgi:query-header)) (define build:initializer (lambda (rdb) (set! build:c-libraries (open-table rdb 'c-libraries)) (set! build:lib-cc-flag (make-defaulting-platform-lookup (build:c-libraries 'get 'compiler-flags))) (set! build:lib-ld-flag (make-defaulting-platform-lookup (build:c-libraries 'get 'link-lib-flag))) (set! build:c-lib-support (make-defaulting-platform-lookup (build:c-libraries 'get 'lib-support))) (set! build:c-suppress (make-defaulting-platform-lookup (build:c-libraries 'get 'suppress-files))) (set! platform->os ((open-table rdb 'platform) 'get 'operating-system)) (set! plan-command (let ((lookup (make-defaulting-platform-lookup ((open-table rdb 'compile-commands) 'get 'procedure)))) (lambda (thing plat) ;;(print 'thing thing 'plat plat) (slib:eval (lookup thing plat))))))) (build:initializer build) scm-5e5/Makefile0000644001705200017500000006102310752242266011502 0ustar tbtb# "Makefile" for scm Scheme Interpreter # Copyright (C) 1990-2008 Free Software Foundation, Inc. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation, either version 3 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program. If not, see # . # Author: Aubrey Jaffer SHELL = /bin/sh #CC = gcc #CFLAGS = -g #LIBS = #LD = $(CC) -g LD = $(CC) SCMLIT = ./scmlit SCMEXE = ./scm #SHOBJS = *.sl SHOBJS = *.so #BUILD = ./build -hsystem -p svr4-gcc-sun-ld BUILD = ./build -hsystem # Workaround for unexec on Fedora Core 1 GNU/Linux i386 #SETARCH = setarch i386 # http://jamesthornton.com/writing/emacs-compile.html # [For FC3] combreloc has become the default for recent GNU ld, which # breaks the unexec/undump on all versions of both Emacs and # XEmacs... # # Add the following to udscm5.opt: #--linker-options="-z nocombreloc" # http://www.opensubscriber.com/message/emacs-devel@gnu.org/1007118.html # Kernels later than 2.6.11 must do (as root) before dumping: #echo 0 > /proc/sys/kernel/randomize_va_space #for RPMs RELEASE = 1 intro: @echo @echo "This is the scm-$(VERSION) distribution. Read \"scm.info\"" @echo "to learn how to build and install SCM. Or browse" @echo " http://swiss.csail.mit.edu/~jaffer/SCM" @echo $(MAKE) scm srcdir.mk: Makefile echo "CPROTO=`type cproto | sed 's%.* %%'`" > srcdir.mk echo "srcdir=`pwd`/" >> srcdir.mk #srcdir=$(HOME)/scm/ #srcdir=/usr/local/src/scm/ include srcdir.mk # directory where COPYING and InitXXX.scm reside. #IMPLPATH = /usr/local/src/scm/ #this one is good for bootstrapping #IMPLPATH = `pwd`/ IMPLPATH=$(srcdir) include patchlvl.h IMPLINIT = $(IMPLPATH)Init$(VERSION).scm # If pathname where InitXXX.scm resides is not known in advance then # SCM_INIT_PATH is the environment variable whose value is the # pathname where InitXXX.scm resides. hfiles = scm.h scmfig.h setjump.h patchlvl.h continue.h cfiles = scmmain.c scm.c time.c repl.c ioext.c scl.c sys.c eval.c \ subr.c sc2.c unif.c rgx.c crs.c dynl.c record.c posix.c socket.c\ unix.c rope.c ramap.c gsubr.c edline.c continue.c \ findexec.c script.c debug.c byte.c bytenumb.c differ.c ufiles = pre-crt0.c ecrt0.c gmalloc.c unexec.c unexelf.c unexhp9k800.c \ unexsunos4.c unexalpha.c unexsgi.c # cxux-crt0.s ecrt0.c gmalloc.c pre-crt0.c unexaix.c unexalpha.c \ # unexapollo.c unexconvex.c unexec.c unexelf.c unexelf1.c \ # unexencap.c unexenix.c unexfx2800.c unexhp9k800.c unexmips.c \ # unexnext.c unexnt.c unexsgi.c unexsni.c unexsunos4.c ofiles = scm.o time.o repl.o scl.o sys.o eval.o subr.o unif.o rope.o \ continue.o findexec.o script.o debug.o # continue-ia64.o ifiles = Init$(VERSION).scm Transcen.scm Link.scm Macro.scm Macexp.scm \ Tscript.scm compile.scm Iedline.scm Idiffer.scm hobfiles = hobbit.scm scmhob.scm scmhob.h turfiles = turtlegr.c turtle grtest.scm xafiles = xatoms.scm x11.scm xevent.scm keysymdef.scm xfiles = x.c x.h xgen.scm xevent.h inc2scm $(xafiles) all: require.scm $(MAKE) mydlls $(MAKE) dscm5 $(MAKE) differ.so $(MAKE) db.so if [ -d /usr/X11R6/lib ]; then $(MAKE) x.so; fi require.scm: cp -p requires.scm require.scm # SCMLIT -- try making this first! scmlit: $(ofiles) scmmain.o require.scm Makefile $(LD) -o scmlit $(ofiles) scmmain.o $(LIBS) $(MAKE) checklit scmflags.h: scmflags scmflags: echo "#ifndef IMPLINIT" > newflags.h echo "#define IMPLINIT \"$(IMPLINIT)\"" >> newflags.h echo "#endif" >> newflags.h echo "#define CHEAP_CONTINUATIONS" >> newflags.h echo "#define CAUTIOUS" >> newflags.h -if (cmp -s newflags.h scmflags.h) then rm newflags.h; \ else mv newflags.h scmflags.h; fi .c.o: $(CC) -c $(CFLAGS) $< -o $@ scm.o: scm.c scm.h scmfig.h scmflags.h patchlvl.h scmmain.o: scmmain.c scm.h scmfig.h scmflags.h patchlvl.h scl.o: scl.c scm.h scmfig.h scmflags.h eval.o: eval.c scm.h scmfig.h scmflags.h setjump.h debug.o: debug.c scm.h scmfig.h scmflags.h setjump.h unif.o: unif.c scm.h scmfig.h scmflags.h #ramap.o: ramap.c scm.h scmfig.h scmflags.h repl.o: repl.c scm.h scmfig.h scmflags.h setjump.h sys.o: sys.c scm.h scmfig.h scmflags.h setjump.h time.o: time.c scm.h scmfig.h scmflags.h subr.o: subr.c scm.h scmfig.h scmflags.h rope.o: rope.c scm.h scmfig.h scmflags.h continue.o: continue.c continue.h setjump.h scm.h scmfig.h scmflags.h continue-ia64.o: continue-ia64.S get-contoffset-ia64.c gcc -o get-contoffset-ia64 get-contoffset-ia64.c ./get-contoffset-ia64 contoffset-ia64.S gcc -c -o continue-ia64.o continue-ia64.S # Simple build with bignums for running JACAL scm: scmlit $(BUILD) -s $(IMPLPATH) -F cautious bignums arrays # i/o-extensions $(MAKE) check # R4RS interpreter (not dumpable) scm4.opt: echo "-F cautious bignums arrays inexact" >> scm4.opt echo "-F engineering-notation dynamic-linking" >> scm4.opt # if type gcc; then echo "--compiler-options=\"-fno-guess-branch-probability\"" >> scm4.opt; fi scm4: $(cfiles) $(hfiles) build.scm build scm4.opt $(BUILD) -f scm4.opt -o scm -s $(IMPLPATH) -rm $(ofiles) scmmain.o -$(MAKE) check # R5RS interpreter (not dumpable) scm5.opt: echo "-F cautious bignums arrays inexact" >> scm5.opt echo "-F engineering-notation dynamic-linking" >> scm5.opt echo "-F macro" >> scm5.opt # if type gcc; then echo "--compiler-options=\"-fno-guess-branch-probability\"" >> scm5.opt; fi scm5: $(cfiles) $(hfiles) build.scm build scm5.opt $(BUILD) -f scm5.opt -o scm -s $(IMPLPATH) -rm $(ofiles) scmmain.o -$(MAKE) check -$(MAKE) checkmacro # dumpable R4RS interpreter udscm4.opt: echo "-F cautious bignums arrays inexact" >> udscm4.opt echo "-F engineering-notation dump dynamic-linking" >> udscm4.opt # if type gcc; then echo "--compiler-options=\"-fno-guess-branch-probability\"" >> udscm4.opt; fi udscm4: $(cfiles) $(hfiles) build.scm build udscm4.opt $(BUILD) -f udscm4.opt -o udscm4 -s $(IMPLPATH) -rm $(ofiles) scmmain.o dscm4: udscm4 $(ifiles) require.scm if [ -f /proc/sys/kernel/randomize_va_space -a\ "`cat /proc/sys/kernel/randomize_va_space`" != "0" ]; then {\ cat /proc/sys/kernel/randomize_va_space > randomize_va_space.tmp;\ echo 0 > /proc/sys/kernel/randomize_va_space;\ } fi -rm -f slibcat implcat scm~ -mv scm scm~ echo "(quit)" | $(SETARCH) ./udscm4 -no-init-file -o scm if [ -f randomize_va_space.tmp ]; then {\ cat randomize_va_space.tmp > /proc/sys/kernel/randomize_va_space;\ rm randomize_va_space.tmp;\ } fi # dumpable R5RS interpreter udscm5.opt: $(MAKE) udscm4.opt cat udscm4.opt >> udscm5.opt echo "-F macro" >> udscm5.opt udscm5: $(cfiles) $(ufiles) $(hfiles) build.scm build udscm5.opt $(BUILD) -f udscm5.opt -o udscm5 -s $(IMPLPATH) -rm $(ofiles) scmmain.o strip udscm5 dscm5: udscm5 $(ifiles) require.scm if [ -f /proc/sys/kernel/randomize_va_space -a\ "`cat /proc/sys/kernel/randomize_va_space`" != "0" ]; then {\ cat /proc/sys/kernel/randomize_va_space > randomize_va_space.tmp;\ echo 0 > /proc/sys/kernel/randomize_va_space;\ } fi -rm -f slibcat implcat scm~ -mv scm scm~ echo "(quit)" | $(SETARCH) ./udscm5 -no-init-file -r5 -o scm if [ -f randomize_va_space.tmp ]; then {\ cat randomize_va_space.tmp > /proc/sys/kernel/randomize_va_space;\ rm randomize_va_space.tmp;\ } fi $(MAKE) check $(MAKE) checkmacro # R5RS interpreter for debugging with GDB. gdb.opt: udscm5.opt cat udscm5.opt > gdb.opt echo "-F debug" >> gdb.opt echo "--compiler-options=-Wall" >> gdb.opt echo "--linker-options=-Wall" >> gdb.opt echo "-D NO_ENV_CACHE" >> gdb.opt # echo "-DTEST_FARLOC -DTEST_SCM2PTR" >> gdb.opt udgdbscm: gdb.opt $(cfiles) $(ufiles) $(hfiles) build.scm build $(BUILD) -f gdb.opt -o udgdbscm -s $(IMPLPATH) gdbscm: udgdbscm $(ifiles) require.scm echo "(quit)" | $(SETARCH) ./udgdbscm -no-init-file -r5 -o gdbscm # R4RS interpreter for profiling pg.opt: udscm4.opt cat udscm4.opt >> pg.opt echo "--compiler-options=-pg" >> pg.opt echo "--linker-options=-pg" >> pg.opt echo "-DLACK_SETITIMER" >> pg.opt udpgscm: pg.opt $(BUILD) -f pg.opt -o udpgscm -s $(IMPLPATH) pgscm: udpgscm echo "(quit)" | $(SETARCH) ./udpgscm -no-init-file -o pgscm # R4RS SCM library libscm.opt: echo "-F cautious bignums arrays inexact" >> libscm.opt echo "-F engineering-notation" >> libscm.opt echo "-F dynamic-linking" >> libscm.opt mylib: libscm.a libscm.a: libscm.opt scm.h scmfig.h $(BUILD) -t lib -f libscm.opt libtest: libscm.a libtest.c $(LD) -o libtest libtest.c libscm.a -ldl -lm -lc ./libtest # DLLs for dynamic linking dlls.opt: echo "--compiler-options=-Wall" >> dlls.opt echo "--linker-options=-Wall" >> dlls.opt mydlls: dlls.opt bytenumb.so $(BUILD) -t dll -f dlls.opt -c ramap.c $(BUILD) -t dll -f dlls.opt -c record.c $(BUILD) -t dll -f dlls.opt -c gsubr.c $(BUILD) -t dll -f dlls.opt -c byte.c $(BUILD) -t dll -f dlls.opt -c sc2.c $(BUILD) -t dll -f dlls.opt -c ioext.c $(BUILD) -t dll -f dlls.opt -c posix.c $(BUILD) -t dll -f dlls.opt -c socket.c $(BUILD) -t dll -f dlls.opt -c unix.c $(BUILD) -t dll -f dlls.opt -F curses $(BUILD) -t dll -f dlls.opt -c rgx.c if [ -f /usr/lib/libreadline.so ]; \ then $(BUILD) -t dll -f dlls.opt -F edit-line; fi rwb-isam.scm wbtab.scm: ../wb/rwb-isam.scm ../wb/wbtab.scm cp ../wb/rwb-isam.scm ../wb/wbtab.scm ./ db.so: dlls.opt rwb-isam.scm wbtab.scm scm.h scmfig.h if [ -f ../wb/blink.c ]; then \ $(BUILD) -t dll -f dlls.opt -F wb; fi bytenumb.so: bytenumb.c scm.h scmfig.h $(BUILD) -t dll -f dlls.opt -F byte-number inexact bignums differ.so: differ.c scm.h scmfig.h $(BUILD) -t dll -f dlls.opt -F differ myturtle: dlls.opt scm.h scmfig.h $(BUILD) -t dll -f dlls.opt -F turtlegr x.so: x.c x.h xevent.h dlls.opt scm.h scmfig.h $(BUILD) -t dll -f dlls.opt -F x # Generate x11 include and Scheme files incdir=/usr/include/ x11.scm: inc2scm rm -f x11.scm $(SCMLIT) -l inc2scm x11.scm x: $(DESTDIR)$(incdir) X11/X.h X11/cursorfont.h X11/Xlib.h \ X11/Xutil.h keysymdef.scm: inc2scm rm -f keysymdef.scm $(SCMLIT) -l inc2scm keysymdef.scm x: $(DESTDIR)$(incdir) X11/keysym.h X11/keysymdef.h xevent.h xevent.scm xatoms.scm: xgen.scm Makefile $(SCMLIT) -l xgen.scm $(DESTDIR)$(incdir)X11/Xlib.h x.h: x.c xevent.h if [ -x "$(CPROTO)" ]; then $(CPROTO) x.c > x.h; fi # Check SCM; SCMLIT function. checklit: $(SCMLIT) -fr4rstest.scm -e'(test-sc4)(test-delay)(gc)' \ -e '(or (null? errs) (quit 1))' Checklit: $(SCMLIT) --no-symbol-case-fold -fr4rstest.scm -e'(test-sc4)(test-delay)(gc)' \ -e '(or (null? errs) (quit 1))' check: r4rstest.scm $(SCMEXE) -fr4rstest.scm -e'(test-sc4)(test-cont)(test-delay)(gc)' \ -e '(or (null? errs) (quit 1))' Check: r4rstest.scm $(SCMEXE) --no-symbol-case-fold -fr4rstest.scm -e'(test-sc4)(test-cont)(test-delay)(gc)' \ -e '(or (null? errs) (quit 1))' checkmacro: syntest1.scm syntest2.scm r4rstest.scm $(SCMEXE) -rmacro -fsyntest1.scm -fsyntest2.scm \ -fr4rstest.scm -e'(test-sc4)(test-cont)(test-delay)' -fsyntest1 \ -e '(or (null? errs) (quit 1))' # Measuare running speed of SCM; SCMLIT. Results are appended to file # "BenchLog" bench: echo `whoami`@`hostname` testing scm \ `$(SCMEXE) -e'(display *scm-version*)'` >> BenchLog echo on `date` >> BenchLog ls -l scm >> BenchLog size scm >> BenchLog uname -a >> BenchLog $(SCMEXE) -lbench.scm -cat prng.log >> BenchLog echo >> BenchLog -cat pi.log >> BenchLog echo >> BenchLog echo tail -20 BenchLog -rm -f pi.log prng.log benchlit: echo `whoami`@`hostname` testing scmlit \ `$(SCMLIT) -e'(display *scm-version*)'` >> BenchLog echo on `date` >> BenchLog ls -l scmlit >> BenchLog size scmlit >> BenchLog uname -a >> BenchLog $(SCMLIT) -lbench.scm -cat prng.log >> BenchLog echo >> BenchLog -cat pi.log >> BenchLog echo >> BenchLog echo tail -20 BenchLog -rm -f pi.log prng.log report: $(SCMLIT) -e"(slib:report #t)" $(SCMEXE) -e"(slib:report #t)" implcat: $(SHOBJS) mkimpcat.scm $(SCMLIT) -lmkimpcat.scm htmldir=../public_html/ dvi: scm.dvi Xlibscm.dvi hobbit.dvi scm.dvi: $(texifiles) Makefile texi2dvi -b -c scm.texi Xlibscm.dvi: version.txi Xlibscm.texi Makefile texi2dvi -b -c Xlibscm.texi hobbit.dvi: version.txi hobbit.texi Makefile texi2dvi -b -c hobbit.texi xdvi: scm.dvi xdvi scm.dvi Xdvi: Xlibscm.dvi xdvi Xlibscm.dvi hobdvi: hobbit.dvi xdvi hobbit.dvi pdf: $(htmldir)scm.pdf $(htmldir)Xlibscm.pdf $(htmldir)hobbit.pdf $(htmldir)scm.pdf: $(texifiles) Makefile texi2pdf -b -c scm.texi mv scm.pdf $(htmldir) $(htmldir)Xlibscm.pdf: version.txi Xlibscm.texi Makefile texi2pdf -b -c Xlibscm.texi mv Xlibscm.pdf $(htmldir) $(htmldir)hobbit.pdf: version.txi hobbit.texi Makefile texi2pdf -b -c hobbit.texi mv hobbit.pdf $(htmldir) xpdf: $(htmldir)scm.pdf xpdf $(htmldir)scm.pdf Xpdf: $(htmldir)Xlibscm.pdf xpdf $(htmldir)Xlibscm.pdf hobpdf: $(htmldir)hobbit.pdf xpdf $(htmldir)hobbit.pdf PREVDOCS = prevdocs/ html: $(htmldir)scm_toc.html $(htmldir)Xlibscm_toc.html $(htmldir)hobbit_toc.html TEXI2HTML = /usr/local/bin/texi2html -split -verbose $(htmldir)scm_toc.html: Makefile $(texifiles) ${TEXI2HTML} scm.texi -rm -f scm_stoc.html if [ -f $(PREVDOCS)scm_toc.html ]; \ then hitch $(PREVDOCS)scm_\*.html scm_\*.html $(htmldir); \ else cp scm_*.html $(htmldir); fi $(htmldir)Xlibscm_toc.html: Makefile version.txi Xlibscm.texi ${TEXI2HTML} Xlibscm.texi -rm -f Xlibscm_stoc.html chpat '' '\ \ ' Xlibscm_*.html cp Xlibscm_*.html $(htmldir) $(htmldir)hobbit_toc.html: Makefile version.txi hobbit.texi ${TEXI2HTML} hobbit.texi -rm -f hobbit_stoc.html chpat '' '\ \ ' hobbit_*.html cp hobbit_*.html $(htmldir) prevdocs: $(PREVDOCS)scm_toc.html $(PREVDOCS)scm.info $(PREVDOCS)scm_toc.html: $(PREVDOCS)scm.info: Makefile cd $(PREVDOCS); unzip -a $(dest)scm*.zip rm $(PREVDOCS)scm/scm.info cd $(PREVDOCS)scm; make scm.info; make scm_toc.html cd $(PREVDOCS); mv -f scm/scm.info scm/*.html ./ rm -rf $(PREVDOCS)scm -rm -f scm-$(VERSION).info ################ INSTALL DEFINITIONS ################ rpm_prefix=$(HOME)/rpmbuild/ prefix = /usr/local/ exec_prefix = $(prefix) # directory where `make install' will put executable. bindir = $(exec_prefix)bin/ libdir = $(exec_prefix)lib/ libscmdir = $(libdir)scm/ # directory where `make install' will put manual page. man1dir = $(prefix)man/man1/ infodir = $(prefix)info/ includedir = $(prefix)include/ README: build build.scm scm.info $(SCMEXE) -l build -e"(make-readme)" platform.txi: build.scm $(SCMLIT) -r database-browse -l build.scm -e "(browse build 'platform)" \ > platform.txi features.txi: build build.scm $(SCMLIT) -l build -e"(make-features-txi)" scm.info: $(texifiles) makeinfo scm.texi --no-split -o scm.info mv scm.info scm-$(VERSION).info if [ -f $(PREVDOCS)scm.info ]; \ then infobar $(PREVDOCS)scm.info scm-$(VERSION).info scm.info; \ else cp scm-$(VERSION).info scm.info; fi $(DESTDIR)$(infodir)scm.info: scm.info mkdir -p $(DESTDIR)$(infodir) cp -p scm.info $(DESTDIR)$(infodir)scm.info -install-info $(DESTDIR)$(infodir)scm.info $(DESTDIR)$(infodir)dir -rm $(DESTDIR)$(infodir)scm.info.gz Xlibscm.info: version.txi Xlibscm.texi makeinfo Xlibscm.texi --no-split -o Xlibscm.info $(DESTDIR)$(infodir)Xlibscm.info: Xlibscm.info mkdir -p $(DESTDIR)$(infodir) cp Xlibscm.info $(DESTDIR)$(infodir)Xlibscm.info -install-info $(DESTDIR)$(infodir)Xlibscm.info $(DESTDIR)$(infodir)dir -rm $(DESTDIR)$(infodir)Xlibscm.info*.gz hobbit.info: version.txi hobbit.texi makeinfo hobbit.texi --no-split -o hobbit.info $(DESTDIR)$(infodir)hobbit.info: hobbit.info mkdir -p $(DESTDIR)$(infodir) cp hobbit.info $(DESTDIR)$(infodir)hobbit.info -install-info $(DESTDIR)$(infodir)hobbit.info $(DESTDIR)$(infodir)dir -rm $(DESTDIR)$(infodir)hobbit.info*.gz info: installinfo installinfo: $(DESTDIR)$(infodir)scm.info $(DESTDIR)$(infodir)Xlibscm.info $(DESTDIR)$(infodir)hobbit.info infoz: installinfoz installinfoz: $(DESTDIR)$(infodir)scm.info.gz $(DESTDIR)$(infodir)Xlibscm.info.gz $(DESTDIR)$(infodir)hobbit.info.gz $(DESTDIR)$(infodir)scm.info.gz: $(DESTDIR)$(infodir)scm.info gzip -f $(DESTDIR)$(infodir)scm.info $(DESTDIR)$(infodir)Xlibscm.info.gz: $(DESTDIR)$(infodir)Xlibscm.info gzip -f $(DESTDIR)$(infodir)Xlibscm.info $(DESTDIR)$(infodir)hobbit.info.gz: $(DESTDIR)$(infodir)hobbit.info gzip -f $(DESTDIR)$(infodir)hobbit.info lsdfiles = $(ifiles) $(hobfiles) COPYING COPYING.LESSER r4rstest.scm \ build build.scm mkimpcat.scm $(SHOBJS) patchlvl.h \ Iedline.scm $(xafiles) db.so wbtab.scm rwb-isam.scm install: scm.1 mkdir -p $(DESTDIR)$(bindir) mkdir -p $(DESTDIR)$(man1dir) -cp scm scmlit $(DESTDIR)$(bindir) -strip $(DESTDIR)$(bindir)scmlit -cp scm.1 $(DESTDIR)$(man1dir) mkdir -p $(DESTDIR)$(libscmdir) test -f $(DESTDIR)$(libscmdir)require.scm || \ cp requires.scm $(DESTDIR)$(libscmdir)require.scm -cp $(lsdfiles) $(DESTDIR)$(libscmdir) installlib: mkdir -p $(DESTDIR)$(includedir) cp scm.h scmfig.h scmflags.h $(DESTDIR)$(includedir) mkdir -p $(DESTDIR)$(libdir) cp libscm.a $(DESTDIR)$(libdir)libscm.a uninstall: -rm $(DESTDIR)$(bindir)scm $(DESTDIR)$(bindir)scmlit -rm $(DESTDIR)$(man1dir)scm.1 -rm $(DESTDIR)$(includedir)scm.h $(DESTDIR)$(includedir)scmfig.h $(DESTDIR)$(includedir)scmflags.h -rm $(DESTDIR)$(libdir)libscm.a -(cd $(DESTDIR)$(libscmdir); rm $(lsdfiles) require.scm) uninstallinfo: -rm $(DESTDIR)$(infodir)scm.info.gz $(DESTDIR)$(infodir)Xlibscm.info.gz\ $(DESTDIR)$(infodir)hobbit.info.gz scm.doc: scm.1 nroff -man $< | ul -tunknown >$@ docs: $(DESTDIR)$(infodir)scm.info.gz $(htmldir)scm_toc.html scm.doc \ scm.dvi Xlibscm.dvi hobbit.dvi \ $(htmldir)scm.pdf $(htmldir)Xlibscm.pdf $(htmldir)hobbit.pdf xdvi -s 4 scm.dvi winscm5.opt: echo "-F arrays array-for-each byte i/o-extensions" >> winscm5.opt echo "-F bignums inexact engineering-notation" >> winscm5.opt echo "-F cautious rev2-procedures macro" >> winscm5.opt echo "-F wb" >> winscm5.opt gw32scmwb.sh: winscm5.opt build.scm Makefile version.txi scmlit ./build -p gnu-win32 -f winscm5.opt -w gw32scmwb.sh scm.exe: gw32scmwb.sh ./gw32scmwb.sh hobbit.html: hobbit.texi makeinfo --html --no-split --no-warn hobbit.texi scm.html: $(texifiles) makeinfo --html --no-split --no-warn --force scm.texi ## to build a windows installer ## make sure makeinfo and NSIS are available on the commandline w32install: scm.exe hobbit.html scm.html makensis scm.nsi #### Stuff for maintaining SCM below #### ver = $(VERSION) version.txi: patchlvl.h echo @set SCMVERSION $(ver) > version.txi echo @set SCMDATE `date +"%B %Y"` >> version.txi RM_R = rm -rf confiles = scmconfig.h.in mkinstalldirs acconfig-1.5.h install-sh \ configure configure.in Makefile.in COPYING COPYING.LESSER \ README.unix tfiles = r4rstest.scm example.scm pi.scm pi.c split.scm bench.scm \ syntest2.scm syntest1.scm texifiles = version.txi scm.texi fdl.texi indexes.texi platform.txi features.txi dfiles = ANNOUNCE README COPYING COPYING.LESSER scm.1 scm.doc QUICKREF \ $(texifiles) scm.info Xlibscm.info Xlibscm.texi \ hobbit.info hobbit.texi ChangeLog mfiles = Makefile build.scm build build.bat requires.scm \ .gdbinit mkimpcat.scm disarm.scm scm.spec scm.nsi sfiles = setjump.mar setjump.s ugsetjump.s continue-ia64.S \ get-contoffset-ia64.c wbfiles = wbtab.scm rwb-isam.scm afiles = $(dfiles) $(cfiles) $(hfiles) $(ifiles) $(tfiles) $(mfiles) \ $(hobfiles) $(sfiles) $(ufiles) $(xfiles) $(turfiles) $(wbfiles) makedev = make -f $(HOME)/makefile.dev CHPAT=$(HOME)/bin/chpat RSYNC=rsync -bav UPLOADEE=swissnet_upload dest = $(HOME)/dist/ DOSCM = /c/Voluntocracy/dist/ temp/scm: $(afiles) -$(RM_R) temp mkdir -p temp/scm ln $(afiles) temp/scm release: dist pdf # rpm cvs tag -F scm-$(VERSION) cp ANNOUNCE $(htmldir)SCM_ANNOUNCE.txt $(RSYNC) $(htmldir)SCM.html $(htmldir)SCM_ANNOUNCE.txt $(UPLOADEE):public_html/ $(RSYNC) $(dest)README $(dest)scm-$(VERSION).zip \ $(dest)scm-$(VERSION)-$(RELEASE).src.rpm $(dest)scm-$(VERSION)-$(RELEASE).i386.rpm \ $(htmldir)hobbit.pdf $(htmldir)Xlibscm.pdf $(UPLOADEE):dist/ # upload $(dest)README $(dest)scm-$(VERSION).zip ftp.gnu.org:gnu/jacal/ upzip: $(HOME)/pub/scm.zip $(RSYNC) $(HOME)/pub/scm.zip $(UPLOADEE):pub/ $(RSYNC) r4rstest.scm $(HOME)/dist/ $(RSYNC) r4rstest.scm $(UPLOADEE):dist/ dist: $(dest)scm-$(VERSION).zip $(dest)scm-$(VERSION).zip: temp/scm $(makedev) DEST=$(dest) PROD=scm ver=-$(VERSION) zip rpm: pubzip # $(dest)scm-$(VERSION)-$(RELEASE).i386.rpm: $(dest)scm-$(VERSION).zip cp -f $(HOME)/pub/scm.zip $(rpm_prefix)SOURCES/scm-$(VERSION).zip rpmbuild -ba scm.spec # --clean rm $(rpm_prefix)SOURCES/scm-$(VERSION).zip mv $(rpm_prefix)RPMS/i386/scm-$(VERSION)-$(RELEASE).i386.rpm \ $(rpm_prefix)SRPMS/scm-$(VERSION)-$(RELEASE).src.rpm $(dest) shar: scm.shar scm.shar: temp/scm $(makedev) PROD=scm shar dclshar: scm.com com: scm.com scm.com: temp/scm $(makedev) PROD=scm com zip: scm.zip scm.zip: temp/scm $(makedev) PROD=scm zip doszip: $(DOSCM)scm-$(VERSION).zip $(DOSCM)scm-$(VERSION).zip: temp/scm turtle turtlegr.c grtest.scm SCM.ico scm.html hobbit.html $(makedev) DEST=$(DOSCM) PROD=scm ver=-$(VERSION) zip -cd ..; zip -9ur $(DOSCM)scm-$(VERSION).zip \ scm/turtle scm/turtlegr.c scm/grtest.scm \ scm/SCM.ico \ scm/scm.html scm/hobbit.html zip -d $(DOSCM)scm-$(VERSION).zip scm/scm.info scm/Xlibscm.info scm/hobbit.info pubzip: $(HOME)/pub/scm.zip $(HOME)/pub/scm.zip: temp/scm $(makedev) DEST=$(HOME)/pub/ PROD=scm zip diffs: pubdiffs pubdiffs: temp/scm $(makedev) DEST=$(HOME)/pub/ PROD=scm pubdiffs distdiffs: temp/scm $(makedev) DEST=$(dest) PROD=scm ver=$(ver) distdiffs CITERS = ANNOUNCE hobbit.texi hobbit.scm \ ../jacal/ANNOUNCE ../jacal/jacal.texi \ ../wb/ANNOUNCE ../wb/README ../wb/wb.texi \ ../synch/ANNOUNCE \ ../dist/README \ $(DOSCM)unzipall.bat $(DOSCM)buildall \ $(htmldir)JACAL.html $(htmldir)README.html \ $(htmldir)SIMSYNCH.html $(htmldir)SLIB.html \ $(htmldir)FreeSnell/ANNOUNCE $(htmldir)FreeSnell/index.html CITES = scm.spec scm.nsi ../wb/wb.spec $(htmldir)SCM.html updates: Init$(ver).scm $(CHPAT) slib-$(VERSION) slib-$(ver) $(CITERS) $(CHPAT) $(VERSION) $(ver) $(CITES) make README Init$(ver).scm: mv -f Init$(VERSION).scm Init$(ver).scm $(CHPAT) $(VERSION) $(ver) patchlvl.h Init$(ver).scm new: updates echo `date -I` \ Aubrey Jaffer \ \<`whoami`@`hostname`\>> change echo>> change echo \ \* patchlvl.h \(SCMVERSION\): Bumped from $(VERSION) to $(ver).>>change echo>> change cat ChangeLog >> change mv -f change ChangeLog cvs remove Init$(VERSION).scm cvs add Init$(ver).scm cvs commit -m 'Init$(VERSION).scm changed to Init$(ver).scm' \ Init$(VERSION).scm Init$(ver).scm cvs commit -m '(SCMVERSION): Bumped from $(VERSION) to $(ver).' cvs tag -F scm-$(ver) configtemp/scm: $(confiles) -$(RM_R) configtemp/scm -mkdir -p configtemp/scm ln $(confiles) configtemp/scm confdist: scmconfig.tar.gz scmconfig.tar.gz: configtemp/scm cd configtemp; tar cohf ../scmconfig.tar scm chmod 664 scmconfig.tar -rm -f scmconfig.tar.*z gzip scmconfig.tar chmod 664 scmconfig.tar.*z lint: lints lints: $(cfiles) $(hfiles) lint $(CPPFLAGS) $(ALL_CFLAGS) $(cfiles) | tee lints # lint $(CPPFLAGS) $(ALL_CFLAGS) $(cfiles) | tee lintes #seds to help find names not unique in first 8 characters (name8s) # for BSD nm format SED_TO_STRIP_NM=sed -e '/.*\.o$$/d' -e 's/.* _//' -e 's/.* T //' #old, bad for T [^_] on suns: SED_TO_STRIP_NM=sed -e '/.*\.o$$/d' -e 's/.* _//' # For a System V nm where plain C identifiers have _ prepended: #SED_TO_STRIP_NM=sed -e '/^_[A-Za-z][A-za-z0-9_]*[ |].*|extern|!d' -e 's/|/ /g' -e 's/^_//' # For a System V nm where plain C identifiers have nothing prepended: #SED_TO_STRIP_NM=sed -e '/^[A-Za-z][A-za-z0-9_]*[ |].*|extern|!d' -e 's/|/ /g' name8: name8s name8s: scmlit nm scmlit |\ $(SED_TO_STRIP_NM) |\ sort -u|\ awk '{ if (substr(l,1,8)==substr($$1,1,8)) {\ if (p) print l;\ print $$1;p=0;stat=1\ }else p=1;\ l=$$1\ }END{exit stat}' - ctagfiles = $(hfiles) $(cfiles) $(xfiles) ctags: $(ctagfiles) etags $(ctagfiles) TAGFILES = $(hfiles) $(cfiles) $(ifiles) $(sfiles) $(xfiles) $(mfiles)\ $(txifiles) Xlibscm.texi hobbit.texi build hobbit.scm # # $(ufiles) ChangeLog TAGS: $(TAGFILES) etags $(TAGFILES) tags: TAGS mostlyclean: clean: -rm -f core a.out ramap.o ramap.obj $(ofiles) scmmain.o lints -$(RM_R) *temp distclean: clean -rm -f $(EXECFILES) *.o *.obj a.out TAGS implcat slibcat gdbscm realclean: distclean -rm -f scm.doc scm.html hobbit.html scm.exe scmlit.exe scm~ SCM-*.exe realempty: temp/scm -rm -f $(afiles) myclean: clean -rm -f *~ *.bak *.orig *.rej tmp* \#* *\# scm-5e5/inc2scm0000755001705200017500000001247210750210226011317 0ustar tbtb#! /usr/local/bin/scm \ %0 %* - !# ;;;; "inc2scm", Convert numeric C #defines to Scheme definitions. ;; Copyright (C) 1991-1999 Free Software Foundation, Inc. ;; ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU Lesser General Public License as ;; published by the Free Software Foundation, either version 3 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 ;; Lesser General Public License for more details. ;; ;; You should have received a copy of the GNU Lesser General Public ;; License along with this program. If not, see ;; . ;;; Author: Aubrey Jaffer. (define (inc2scm.script args) (cond ((< 1 (length args)) (apply scm<-usr/includes args)) (else (inc2scm.usage)))) (define (inc2scm.usage) (display "\ \ Usage: inc2scm defines.scm [pre:] [/usr/include/] file1.h file2.h ... \ Appends to DEFINES.SCM the Scheme translations of the numeric #define statements in /USR/INCLUDE/FILE1.H, /USR/INCLUDE/FILE2.H, ... PRE: is prepended to those scheme names lacking a prefix. /USR/INCLUDE/ defaults to /usr/include/. http://swiss.csail.mit.edu/~jaffer/SCM " (current-error-port)) #f) (require 'string-search) (require 'printf) (require 'scanf) (define (StudlyCaps->dashed-name nstr) (do ((idx (+ -1 (string-length nstr)) (+ -1 idx))) ((> 2 idx)) (cond ((and (char-upper-case? (string-ref nstr (+ -1 idx))) (char-lower-case? (string-ref nstr idx))) (set! nstr (string-append (substring nstr 0 (+ -1 idx)) "-" (substring nstr (+ -1 idx) (string-length nstr))))) ((and (char-lower-case? (string-ref nstr (+ -1 idx))) (char-upper-case? (string-ref nstr idx))) (set! nstr (string-append (substring nstr 0 idx) "-" (substring nstr idx (string-length nstr))))))) nstr) ;; SCHEMEIFY-NAME: ;; * Changes _ to - ;; * Changes the first - to : if it is within the first 3 characters. ;; * inserts dashes between `StudlyCaps' (define (schemeify-name pre name) (define nstr (string-subst name "_" "-")) (let ((sid (string-index nstr #\-))) (cond ((and sid (< sid 3)) (string-set! nstr sid #\:) nstr) (pre (string-append pre (StudlyCaps->dashed-name nstr))) (else (StudlyCaps->dashed-name nstr))))) (define (extract-defineds port) (define sharp (string #\newline #\#)) (define defineds '()) (do ((find? (find-string-from-port? sharp port) (find-string-from-port? sharp port))) ((not find?) (reverse defineds)) (do ((chr (read-char port) (read-char port))) ((or (eof-object? chr) (not (char-whitespace? chr))) (and (eqv? chr #\d) (let ((op #f) (va #f)) (fscanf port "efine%*[ \t]%s%*[ \t]%s" op va) (if (and op va (not (string-index op #\()) (not (eqv? #\_ (string-ref op 0))) (not (equal? "int" va))) (set! defineds (cons op defineds))))))))) (define (scm<-includes scmname pre non-local? . filenames) (define tmpprog "tmpprog") (call-with-output-file (string-append tmpprog ".c") (lambda (cport) (for-each (lambda (filename) (fprintf cport (if non-local? "#include <%s>\\n" "#include \"%s\"\\n") filename)) filenames) (for-each (lambda (args) (apply fprintf cport args)) `(("#include \\n") ("void pSl(sname, value)\\n") (" char sname[];\\n") (" int value;\\n") ("{\\n") ("%s\\n" " printf(\"(define %s %d)\\n\", sname, value);") ("}\\n") ("\\n") ("int main(argc, argv)\\n") (" int argc;\\n") (" char *argv[];\\n") ("{\\n") )) (for-each (lambda (filename) (if non-local? (set! filename (string-append non-local? filename))) (fprintf cport "/* Extract #define values from %s */\\n" filename) (fprintf cport "%s %s%s\\n" " printf(\";;inc2scm extracted #define values from" filename "\\n\");") (for-each (lambda (name) (fprintf cport "#ifdef %s\\n pSl(\"%s\", %s);\\n#endif\\n" name (schemeify-name pre name) name)) (call-with-input-file filename extract-defineds))) filenames) (fprintf cport "}\\n"))) (cond ((not (zero? (system (sprintf #f "cc -o %s %s.c" tmpprog tmpprog))))) ((not (zero? (system (sprintf #f "./%s >> %s" tmpprog scmname))))))) (define (scm<-usr/includes scmname . filenames) (define pre (let ((first (car filenames))) (cond ((substring-ci? ".h" first) #f) (else (set! filenames (cdr filenames)) first)))) (define include-path "/usr/include/") (let* ((first (car filenames))) (cond ((memv (string-ref first (+ -1 (string-length first))) '(#\\ #\/)) (set! include-path first) (set! filenames (cdr filenames))))) (apply scm<-includes scmname pre include-path filenames) (delete-file "tmpprog.c") (delete-file "tmpprog")) (define (scm<-h* scmname . filenames) (define pre (let ((first (car filenames))) (cond ((substring-ci? ".h" first) first) (else (set! filenames (cdr filenames)) #f)))) (apply scm<-includes scmname pre #f filenames) (delete-file "tmpprog.c") (delete-file "tmpprog")) (define h2scm scm<-h*) ;;; Local Variables: ;;; mode:scheme ;;; End: (exit (inc2scm.script (list-tail *argv* *optind*))) scm-5e5/syntest1.scm0000644001705200017500000000771307432111115012333 0ustar tbtb;Most of the tests themselves are taken from William Clinger's reference ;implementation of syntax-rules, `macros.will' in the Scheme repository ;at ftp.cs.indiana.edu ;Copyright 1992 William Clinger ;Permission to copy this software, in whole or in part, to use this ;software for any lawful purpose, and to redistribute this software ;is granted subject to the restriction that all copies made of this ;software must include this copyright notice in full. ;I also request that you send me a copy of any improvements that you ;make to this software so that they may be incorporated within it to ;the benefit of the Scheme community. (require 'macro) (define synerrs '()) (define-syntax test (syntax-rules () ((test ?exp ?ans) (begin (display '?exp) (display " ==> ") (let* ((exp (copy-tree '?exp)) (x ?exp) #+f(x (eval (macro:expand '?exp))) ) (display x) (newline) (or (equal? x ?ans) (begin (set! synerrs (cons (list x ?ans '?exp) synerrs)) (display "ERROR: expected ") (display ?ans) (newline)))))) ((test ?exp0 ?exp1 ?exp2 ...) (begin (display '?exp0) (newline) ?exp0 (test ?exp1 ?exp2 ...))))) (test (let ((x 'outer)) (let-syntax ((m (syntax-rules () ((m) x)))) (let ((x 'inner)) (m)))) 'outer) (test (let-syntax ((when (syntax-rules () ((when ?test ?stmt1 ?stmt2 ...) (if ?test (begin ?stmt1 ?stmt2 ...)))))) (let ((if #t)) (when if (set! if 'now)) if)) 'now) (test (letrec-syntax ((or (syntax-rules () ((or) #f) ((or ?e) ?e) ((or ?e1 ?e2 ...) (let ((temp ?e1)) (if temp temp (or ?e2 ...))))))) (let ((x #f) (y 7) (temp 8) (let odd?) (if even?)) (or x (let temp) (if y) y))) 7) (test (let ((=> #f)) (cond (#t => 'ok))) 'ok) ; This syntax of set*! matches that of an example in the R4RS. ; That example was put forth as an example of a hygienic macro ; that supposedly couldn't be written using syntax-rules. Hah! (test (define-syntax set*! (syntax-rules () ((set*! (?var ?val) ...) (set*!-help (?val ...) () (?var ?val) ...)))) (define-syntax set*!-help (syntax-rules () ((set*!-help () (?temp ...) (?var ?val) ...) (let ((?temp ?val) ...) (set! ?var ?temp) ...)) ((set*!-help (?var1 ?var2 ...) ?temps ?assignments ...) (set*!-help (?var2 ...) (temp . ?temps) ?assignments ...)))) (let ((x 3) (y 4) (z 5)) (set*! (x (+ x y z)) (y (- x y z)) (z (* x y z))) (list x y z)) '(12 -6 60)) (test (let ((else #f)) (cond (#f 3) (else 4) (#t 5))) 5) (test (define-syntax push (syntax-rules () ((push item place) (set! place (cons item place))))) (let* ((cons (lambda (name) (case name ((phil) '("three-card monte")) ((dick) '("secret plan to end the war" "agnew" "not a crook")) ((jimmy) '("why not the best")) ((ron) '("abolish the draft" "balance the budget")) (else '())))) (scams (cons 'phil))) (push (car (cons 'jimmy)) scams) (push (cadr (cons 'ron)) scams) scams) '("balance the budget" "why not the best" "three-card monte")) (test (define-syntax replic (syntax-rules () ((_ (?x ...) (?y ...)) (let ((?x (list ?y ...)) ...) (list ?x ...))))) (replic (x y z) (1 2)) '((1 2) (1 2) (1 2))) ;; The behavior of this one is one is not specified by R5RS, below ;; is what SCM does. ;(test (define-syntax spread ; (syntax-rules () ; ((_ ?x (?y ...)) ; '(((?x ?y) ...))))) ; (spread x (1 2 3)) ; '(((x 1) (x 2) (x 3)))) (cond ((null? synerrs) (newline) (display "Passed all tests\n") (display "Load \"syntest2\" to rewrite derived expressions and test\n")) (else (newline) (display "FAILED, errors were:") (newline) (display "(got expected call)") (newline) (for-each (lambda (l) (write l) (newline)) synerrs) (newline))) scm-5e5/Transcen.scm0000644001705200017500000001240010752350440012310 0ustar tbtb;;;; "Transcen.scm", Complex transcendental functions for SCM. ;; Copyright (C) 1992, 1993, 1995, 1997, 2005, 2006 Free Software Foundation, Inc. ;; ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU Lesser General Public License as ;; published by the Free Software Foundation, either version 3 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 ;; Lesser General Public License for more details. ;; ;; You should have received a copy of the GNU Lesser General Public ;; License along with this program. If not, see ;; . ;;; Author: Jerry D. Hedden. ;;;; 2005-05 SRFI-70 extensions. ;;; Author: Aubrey Jaffer (define compile-allnumbers #t) ;for HOBBIT compiler ;;;; Legacy real function names (cond ((defined? $exp) (define real-sqrt $sqrt) (define real-exp $exp) (define real-expt $expt) (define real-ln $log) (define real-log10 $log10) (define real-sin $sin) (define real-cos $cos) (define real-tan $tan) (define real-asin $asin) (define real-acos $acos) (define real-atan $atan) (define real-sinh $sinh) (define real-cosh $cosh) (define real-tanh $tanh) (define real-asinh $asinh) (define real-acosh $acosh) (define real-atanh $atanh)) (else (define $sqrt real-sqrt) (define $exp real-exp) (define $expt real-expt) (define $log real-ln) (define $log10 real-log10) (define $sin real-sin) (define $cos real-cos) (define $tan real-tan) (define $asin real-asin) (define $acos real-acos) (define $atan real-atan) (define $sinh real-sinh) (define $cosh real-cosh) (define $tanh real-tanh) (define $asinh real-asinh) (define $acosh real-acosh) (define $atanh real-atanh))) (define $pi (* 4 (real-atan 1))) (define pi $pi) (define (pi* z) (* $pi z)) (define (pi/ z) (/ $pi z)) ;;;; Complex functions (define (exp z) (if (real? z) (real-exp z) (make-polar (real-exp (real-part z)) (imag-part z)))) (define (ln z) (if (and (real? z) (>= z 0)) (real-ln z) (make-rectangular (real-ln (magnitude z)) (angle z)))) (define log ln) (define (sqrt z) (if (real? z) (if (negative? z) (make-rectangular 0 (real-sqrt (- z))) (real-sqrt z)) (make-polar (real-sqrt (magnitude z)) (/ (angle z) 2)))) (define (sinh z) (if (real? z) (real-sinh z) (let ((x (real-part z)) (y (imag-part z))) (make-rectangular (* (real-sinh x) (real-cos y)) (* (real-cosh x) (real-sin y)))))) (define (cosh z) (if (real? z) (real-cosh z) (let ((x (real-part z)) (y (imag-part z))) (make-rectangular (* (real-cosh x) (real-cos y)) (* (real-sinh x) (real-sin y)))))) (define (tanh z) (if (real? z) (real-tanh z) (let* ((x (* 2 (real-part z))) (y (* 2 (imag-part z))) (w (+ (real-cosh x) (real-cos y)))) (make-rectangular (/ (real-sinh x) w) (/ (real-sin y) w))))) (define (asinh z) (if (real? z) (real-asinh z) (log (+ z (sqrt (+ (* z z) 1)))))) (define (acosh z) (if (and (real? z) (>= z 1)) (real-acosh z) (log (+ z (sqrt (- (* z z) 1)))))) (define (atanh z) (if (and (real? z) (> z -1) (< z 1)) (real-atanh z) (/ (log (/ (+ 1 z) (- 1 z))) 2))) (define (sin z) (if (real? z) (real-sin z) (let ((x (real-part z)) (y (imag-part z))) (make-rectangular (* (real-sin x) (real-cosh y)) (* (real-cos x) (real-sinh y)))))) (define (cos z) (if (real? z) (real-cos z) (let ((x (real-part z)) (y (imag-part z))) (make-rectangular (* (real-cos x) (real-cosh y)) (- (* (real-sin x) (real-sinh y))))))) (define (tan z) (if (real? z) (real-tan z) (let* ((x (* 2 (real-part z))) (y (* 2 (imag-part z))) (w (+ (real-cos x) (real-cosh y)))) (make-rectangular (/ (real-sin x) w) (/ (real-sinh y) w))))) (define (asin z) (if (and (real? z) (>= z -1) (<= z 1)) (real-asin z) (* -i (asinh (* +i z))))) (define (acos z) (if (and (real? z) (>= z -1) (<= z 1)) (real-acos z) (+ (/ (angle -1) 2) (* +i (asinh (* +i z)))))) (define (atan z . y) (if (null? y) (if (real? z) (real-atan z) (/ (log (/ (- +i z) (+ +i z))) +2i)) ($atan2 z (car y)))) ;;;; SRFI-70 (define (expt z1 z2) (cond ((and (exact? z2) (not (and (zero? z1) (negative? z2)))) (integer-expt z1 z2)) ((zero? z2) (+ 1 (* z1 z2))) ((and (real? z2) (real? z1) (positive? z1)) (real-expt z1 z2)) (else (exp (* (if (zero? z1) (real-part z2) z2) (log z1)))))) (define (quo x1 x2) (if (and (exact? x1) (exact? x2)) (quotient x1 x2) (truncate (/ x1 x2)))) (define (rem x1 x2) (if (and (exact? x1) (exact? x2)) (remainder x1 x2) (- x1 (* x2 (quo x1 x2))))) (define (mod x1 x2) (if (and (exact? x1) (exact? x2)) (modulo x1 x2) (- x1 (* x2 (floor (/ x1 x2)))))) (define (exact-round x) (inexact->exact (round x))) (define (exact-floor x) (inexact->exact (floor x))) (define (exact-ceiling x) (inexact->exact (ceiling x))) (define (exact-truncate x) (inexact->exact (truncate x))) (define (infinite? z) (and (= z (* 2 z)) (not (zero? z)))) (define (finite? z) (not (infinite? z))) (provide 'math-real) (provide 'srfi-94) scm-5e5/xatoms.scm0000644001705200017500000000370310752242350012054 0ustar tbtb;; xgen.scm extracted definitions from /usr/include/X11/Xatom.h (define PRIMARY 1) (define SECONDARY 2) (define ARC 3) (define ATOM 4) (define BITMAP 5) (define CARDINAL 6) (define COLORMAP 7) (define CURSOR 8) (define CUT-BUFFER0 9) (define CUT-BUFFER1 10) (define CUT-BUFFER2 11) (define CUT-BUFFER3 12) (define CUT-BUFFER4 13) (define CUT-BUFFER5 14) (define CUT-BUFFER6 15) (define CUT-BUFFER7 16) (define DRAWABLE 17) (define FONT 18) (define INTEGER 19) (define PIXMAP 20) (define POINT 21) (define RECTANGLE 22) (define RESOURCE-MANAGER 23) (define RGB-COLOR-MAP 24) (define RGB-BEST-MAP 25) (define RGB-BLUE-MAP 26) (define RGB-DEFAULT-MAP 27) (define RGB-GRAY-MAP 28) (define RGB-GREEN-MAP 29) (define RGB-RED-MAP 30) (define STRING 31) (define VISUALID 32) (define WINDOW 33) (define WM-COMMAND 34) (define WM-HINTS 35) (define WM-CLIENT-MACHINE 36) (define WM-ICON-NAME 37) (define WM-ICON-SIZE 38) (define WM-NAME 39) (define WM-NORMAL-HINTS 40) (define WM-SIZE-HINTS 41) (define WM-ZOOM-HINTS 42) (define MIN-SPACE 43) (define NORM-SPACE 44) (define MAX-SPACE 45) (define END-SPACE 46) (define SUPERSCRIPT-X 47) (define SUPERSCRIPT-Y 48) (define SUBSCRIPT-X 49) (define SUBSCRIPT-Y 50) (define UNDERLINE-POSITION 51) (define UNDERLINE-THICKNESS 52) (define STRIKEOUT-ASCENT 53) (define STRIKEOUT-DESCENT 54) (define ITALIC-ANGLE 55) (define X-HEIGHT 56) (define QUAD-WIDTH 57) (define WEIGHT 58) (define POINT-SIZE 59) (define RESOLUTION 60) (define COPYRIGHT 61) (define NOTICE 62) (define FONT-NAME 63) (define FAMILY-NAME 64) (define FULL-NAME 65) (define CAP-HEIGHT 66) (define WM-CLASS 67) (define WM-TRANSIENT-FOR 68) (define LAST-PREDEFINED 68) ;; xgen.scm extracted definitions from /usr/include/X11/Xcms.h (define X:Undefined #x00000000) (define X:CIEXYZ #x00000001) (define X:CIEuvY #x00000002) (define X:CIExyY #x00000003) (define X:CIELab #x00000004) (define X:CIELuv #x00000005) (define X:TekHVC #x00000006) (define X:RGB #x80000000) (define X:RGBi #x80000001) scm-5e5/ecrt0.c0000644001705200017500000003567410750241062011227 0ustar tbtb/* C code startup routine. Copyright (C) 1985, 1986, 1992 Free Software Foundation, Inc. This file is part of GNU Emacs. GNU Emacs 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 3 of the License, or (at your option) any later version. GNU Emacs 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 GNU Emacs. If not, see . */ /* The standard Vax 4.2 Unix crt0.c cannot be used for Emacs because it makes `environ' an initialized variable. It is easiest to have a special crt0.c on all machines though I don't know whether other machines actually need it. */ /* On the vax and 68000, in BSD4.2 and USG5.2, this is the data format on startup: (vax) ap and fp are unpredictable as far as I know; don't use them. sp -> word containing argc word pointing to first arg string [word pointing to next arg string]... 0 or more times 0 Optionally: [word pointing to environment variable]... 1 or more times ... 0 And always: first arg string [next arg string]... 0 or more times */ /* On the 16000, at least in the one 4.2 system I know about, the initial data format is sp -> word containing argc word containing argp word pointing to first arg string, and so on as above */ #ifdef emacs #include #endif /* ******** WARNING ******** Do not insert any data definitions before data_start! Since this is the first file linked, the address of the following variable should correspond to the start of initialized data space. On some systems this is a constant that is independent of the text size for shared executables. On others, it is a function of the text size. In short, this seems to be the most portable way to discover the start of initialized data space dynamically at runtime, for either shared or unshared executables, on either swapping or virtual systems. It only requires that the linker allocate objects in the order encountered, a reasonable model for most Unix systems. Similarly, note that the address of _start() should be the start of text space. Fred Fish, UniSoft Systems Inc. */ int data_start = 0; #ifdef NEED_ERRNO int errno; #endif #ifndef DONT_NEED_ENVIRON char **environ; #endif #ifndef static /* On systems where the static storage class is usable, this function should be declared as static. Otherwise, the static keyword has been defined to be something else, and code for those systems must take care of this declaration appropriately. */ static start1 (); #endif #ifdef APOLLO extern char *malloc(), *realloc(), *(*_libc_malloc) (), *(*_libc_realloc)(); extern void free(), (*_libc_free) (); extern int main(); std_$call void unix_$main(); _start() { _libc_malloc = malloc; _libc_realloc = realloc; _libc_free = free; unix_$main(main); /* no return */ } #endif /* APOLLO */ #if defined(orion) || defined(pyramid) || defined(celerity) || defined(ALLIANT) || defined(clipper) || defined(sps7) #if defined(sps7) && defined(V3x) asm(" section 10"); asm(" ds.b 0xb0"); #endif #ifdef ALLIANT /* _start must initialize _curbrk and _minbrk on the first startup; when starting up after dumping, it must initialize them to what they were before the dumping, since they are in the shared library and are not dumped. See ADJUST_EXEC_HEADER in m-alliant.h. */ extern unsigned char *_curbrk, *_minbrk; extern unsigned char end; unsigned char *_setbrk = &end; #ifdef ALLIANT_2800 unsigned char *_end = &end; #endif #endif #ifndef DUMMIES #define DUMMIES #endif _start (DUMMIES argc, argv, envp) int argc; char **argv, **envp; { #ifdef ALLIANT #ifdef ALLIANT_2800 _curbrk = _end; _minbrk = _end; #else _curbrk = _setbrk; _minbrk = _setbrk; #endif #endif environ = envp; exit (main (argc, argv, envp)); } #endif /* orion or pyramid or celerity or alliant or clipper */ #if defined (ns16000) && !defined (sequent) && !defined (UMAX) && !defined (CRT0_DUMMIES) _start () { /* On 16000, _start pushes fp onto stack */ start1 (); } /* ignore takes care of skipping the fp value pushed in start. */ static start1 (ignore, argc, argv) int ignore; int argc; register char **argv; { environ = argv + argc + 1; if (environ == *argv) environ--; exit (main (argc, argv, environ)); } #endif /* ns16000, not sequent and not UMAX, and not the CRT0_DUMMIES method */ #ifdef UMAX _start() { asm(" exit [] # undo enter"); asm(" .set exitsc,1"); asm(" .set sigcatchall,0x400"); asm(" .globl _exit"); asm(" .globl start"); asm(" .globl __start"); asm(" .globl _main"); asm(" .globl _environ"); asm(" .globl _sigvec"); asm(" .globl sigentry"); asm("start:"); asm(" br .xstart"); asm(" .org 0x20"); asm(" .double p_glbl,0,0xf00000,0"); asm(" .org 0x30"); asm(".xstart:"); asm(" adjspb $8"); asm(" movd 8(sp),0(sp) # argc"); asm(" addr 12(sp),r0"); asm(" movd r0,4(sp) # argv"); asm("L1:"); asm(" movd r0,r1"); asm(" addqd $4,r0"); asm(" cmpqd $0,0(r1) # null args term ?"); asm(" bne L1"); asm(" cmpd r0,0(4(sp)) # end of 'env' or 'argv' ?"); asm(" blt L2"); asm(" addqd $-4,r0 # envp's are in list"); asm("L2:"); asm(" movd r0,8(sp) # env"); asm(" movd r0,@_environ # indir is 0 if no env ; not 0 if env"); asm(" movqd $0,tos # setup intermediate signal handler"); asm(" addr @sv,tos"); asm(" movzwd $sigcatchall,tos"); asm(" jsr @_sigvec"); asm(" adjspb $-12"); asm(" jsr @_main"); asm(" adjspb $-12"); asm(" movd r0,tos"); asm(" jsr @_exit"); asm(" adjspb $-4"); asm(" addr @exitsc,r0"); asm(" svc"); asm(" .align 4 # sigvec arg"); asm("sv:"); asm(" .double sigentry"); asm(" .double 0"); asm(" .double 0"); asm(" .comm p_glbl,1"); } #endif /* UMAX */ #ifdef CRT0_DUMMIES /* Define symbol "start": here; some systems want that symbol. */ #ifdef DOT_GLOBAL_START asm(" .text "); asm(" .globl start "); asm(" start: "); #endif /* DOT_GLOBAL_START */ #ifdef NODOT_GLOBAL_START asm(" text "); asm(" global start "); asm(" start: "); #endif /* NODOT_GLOBAL_START */ #ifdef m68000 /* GCC 2.1, when optimization is turned off, seems to want to push a word of garbage on the stack, which screws up the CRT0_DUMMIES hack. So we hand-code _start in assembly language. */ asm(".text "); asm(" .even "); asm(".globl __start "); asm("__start: "); asm(" link a6,#0 "); asm(" jbsr _start1 "); asm(" unlk a6 "); asm(" rts "); #else /* not m68000 */ _start () { /* On vax, nothing is pushed here */ /* On sequent, bogus fp is pushed here */ start1 (); } #endif /* possibly m68000 */ static start1 (CRT0_DUMMIES argc, xargv) int argc; char *xargv; { register char **argv = &xargv; environ = argv + argc + 1; if ((char *)environ == xargv) environ--; exit (main (argc, argv, environ)); /* Refer to `start1' so GCC will not think it is never called and optimize it out. */ (void) &start1; } #else /* not CRT0_DUMMIES */ /* "m68k" and "m68000" both stand for m68000 processors, but with different program-entry conventions. This is a kludge. Now that the CRT0_DUMMIES mechanism above exists, most of these machines could use the vax code above with some suitable definition of CRT0_DUMMIES. Then the symbol m68k could be flushed. But I don't want to risk breaking these machines in a version 17 patch release, so that change is being put off. */ #ifdef m68k /* Can't do it all from C */ asm (" global _start"); asm (" text"); asm ("_start:"); #ifndef NU #ifdef STRIDE asm (" comm havefpu%,2"); #else /* m68k, not STRIDE */ asm (" comm splimit%,4"); #endif /* STRIDE */ asm (" global exit"); asm (" text"); #ifdef STRIDE asm (" trap &3"); asm (" mov.w %d0,havefpu%"); #else /* m68k, not STRIDE */ asm (" mov.l %d0,splimit%"); #endif /* STRIDE */ #endif /* not NU */ asm (" jsr start1"); asm (" mov.l %d0,(%sp)"); asm (" jsr exit"); asm (" mov.l &1,%d0"); /* d0 = 1 => exit */ asm (" trap &0"); #else /* m68000, not m68k */ #ifdef m68000 #ifdef ISI68K /* Added by ESM Sun May 24 12:44:02 1987 to get new ISI library to work */ /* Edited by Ray Mon May 15 15:59:56 EST 1989 so we can compile with gcc */ #if defined(BSD4_3) && !defined(__GNUC__) static foo () { #endif asm (" .globl is68020"); asm ("is68020:"); #ifndef BSD4_3 asm (" .long 0x00000000"); asm (" .long 0xffffffff"); /* End of stuff added by ESM */ #endif asm (" .text"); asm (" .globl __start"); asm ("__start:"); asm (" .word 0"); asm (" link a6,#0"); asm (" jbsr _start1"); asm (" unlk a6"); asm (" rts"); #if defined(BSD4_3) && !defined(__GNUC__) } #endif #else /* not ISI68K */ _start () { #ifdef sun #ifdef LISP_FLOAT_TYPE finitfp_(); #endif #endif /* On 68000, _start pushes a6 onto stack */ start1 (); } #endif /* not ISI68k */ #endif /* m68000 */ #endif /* m68k */ #if defined(m68k) || defined(m68000) /* ignore takes care of skipping the a6 value pushed in start. */ static #if defined(m68k) start1 (argc, xargv) #else start1 (ignore, argc, xargv) #endif int argc; char *xargv; { register char **argv = &xargv; environ = argv + argc + 1; if ((char *)environ == xargv) environ--; #ifdef sun_68881 asm(" jsr f68881_used"); #endif #ifdef sun_fpa asm(" jsr ffpa_used"); #endif #ifdef sun_soft asm(" jsr start_float"); #endif exit (main (argc, argv, environ)); } #endif /* m68k or m68000 */ #endif /* not CRT0_DUMMIES */ #ifdef hp9000s300 int argc_value; char **argv_value; #ifdef OLD_HP_ASSEMBLER asm(" text"); asm(" globl __start"); asm(" globl _exit"); asm(" globl _main"); asm("__start"); asm(" dc.l 0"); asm(" subq.w #0x1,d0"); asm(" move.w d0,float_soft"); asm(" move.l 0x4(a7),d0"); asm(" beq.s skip_1"); asm(" move.l d0,a0"); asm(" clr.l -0x4(a0)"); asm("skip_1"); asm(" move.l a7,a0"); asm(" subq.l #0x8,a7"); asm(" move.l (a0),(a7)"); asm(" move.l (a0),_argc_value"); asm(" addq.l #0x4,a0"); asm(" move.l a0,0x4(a7)"); asm(" move.l a0,_argv_value"); asm("incr_loop"); asm(" tst.l (a0)+"); asm(" bne.s incr_loop"); asm(" move.l 0x4(a7),a1"); asm(" cmp.l (a1),a0"); asm(" blt.s skip_2"); asm(" subq.l #0x4,a0"); asm("skip_2"); asm(" move.l a0,0x8(a7)"); asm(" move.l a0,_environ"); asm(" jsr _main"); asm(" addq.l #0x8,a7"); asm(" move.l d0,-(a7)"); asm(" jsr _exit"); asm(" move.w #0x1,d0"); asm(" trap #0x0"); asm(" comm float_soft,4"); /* float_soft is allocated in this way because C would put an underscore character in its name otherwise. */ #else /* new hp assembler */ asm(" text"); asm(" global float_loc"); asm(" set float_loc,0xFFFFB000"); asm(" global fpa_loc"); asm(" set fpa_loc,0xfff08000"); asm(" global __start"); asm(" global _exit"); asm(" global _main"); asm("__start:"); asm(" byte 0,0,0,0"); asm(" subq.w &1,%d0"); asm(" mov.w %d0,float_soft"); asm(" mov.w %d1,flag_68881"); #ifndef HPUX_68010 asm(" beq.b skip_float"); asm(" fmov.l &0x7400,%fpcr"); /* asm(" fmov.l &0x7480,%fpcr"); */ #endif /* HPUX_68010 */ asm("skip_float:"); asm(" mov.l %a0,%d0"); asm(" add.l %d0,%d0"); asm(" subx.w %d1,%d1"); asm(" mov.w %d1,flag_68010"); asm(" add.l %d0,%d0"); asm(" subx.w %d1,%d1"); asm(" mov.w %d1,flag_fpa"); asm(" tst.l %d2"); asm(" ble.b skip_3"); asm(" lsl flag_68881"); asm(" lsl flag_fpa"); asm("skip_3:"); asm(" mov.l 4(%a7),%d0"); asm(" beq.b skip_1"); asm(" mov.l %d0,%a0"); asm(" clr.l -4(%a0)"); asm("skip_1:"); asm(" mov.l %a7,%a0"); asm(" subq.l &8,%a7"); asm(" mov.l (%a0),(%a7)"); asm(" mov.l (%a0),_argc_value"); asm(" addq.l &4,%a0"); asm(" mov.l %a0,4(%a7)"); asm(" mov.l %a0,_argv_value"); asm("incr_loop:"); asm(" tst.l (%a0)+"); asm(" bne.b incr_loop"); asm(" mov.l 4(%a7),%a1"); asm(" cmp.l %a0,(%a1)"); asm(" blt.b skip_2"); asm(" subq.l &4,%a0"); asm("skip_2:"); asm(" mov.l %a0,8(%a7)"); asm(" mov.l %a0,_environ"); asm(" jsr _main"); asm(" addq.l &8,%a7"); asm(" mov.l %d0,-(%a7)"); asm(" jsr _exit"); asm(" mov.w &1,%d0"); asm(" trap &0"); asm(" comm float_soft, 4"); asm(" comm flag_68881, 4"); asm(" comm flag_68010, 4"); asm(" comm flag_68040, 4"); asm(" comm flag_fpa, 4"); #endif /* new hp assembler */ #endif /* hp9000s300 */ #ifdef GOULD /* startup code has to be in near text rather than fartext as allocated by the C compiler. */ asm(" .text"); asm(" .align 2"); asm(" .globl __start"); asm(" .text"); asm("__start:"); /* setup base register b1 (function base). */ asm(" .using b1,."); asm(" tpcbr b1"); /* setup base registers b3 through b7 (data references). */ asm(" file basevals,b3"); /* setup base register b2 (stack pointer); it should be aligned on a 8-word boundary; but because it is pointing to argc, its value should be remembered (in r5). */ asm(" movw b2,r4"); asm(" movw b2,r5"); asm(" andw #~0x1f,r4"); asm(" movw r4,b2"); /* allocate stack frame to do some work. */ asm(" subea 16w,b2"); /* initialize signal catching for UTX/32 1.2; this is necessary to make restart from saved image work. */ asm(" movea sigcatch,r1"); asm(" movw r1,8w[b2]"); asm(" svc #1,#150"); /* setup address of argc for start1. */ asm(" movw r5,8w[b2]"); asm(" func #1,_start1"); asm(" halt"); /* space for ld to store base register initial values. */ asm(" .align 5"); asm("basevals:"); asm(" .word __base3,__base4,__base5,__base6,__base7"); static start1 (xargc) int *xargc; { register int argc; register char **argv; argc = *xargc; argv = (char **)(xargc) + 1; environ = argv + argc + 1; if (environ == argv) environ--; exit (main (argc, argv, environ)); } #endif /* GOULD */ #ifdef elxsi #include extern char **environ; extern int errno; extern void _init_doscan(), _init_iob(); extern char end[]; char *_init_brk = end; _start() { environ = exec_cache.ac_envp; brk (_init_brk); errno = 0; _init_doscan (); _init_iob (); _exit (exit (main (exec_cache.ac_argc, exec_cache.ac_argv, exec_cache.ac_envp))); } #endif /* elxsi */ #ifdef sparc asm (".global __start"); asm (".text"); asm ("__start:"); asm (" mov 0, %fp"); asm (" ld [%sp + 64], %o0"); asm (" add %sp, 68, %o1"); asm (" sll %o0, 2, %o2"); asm (" add %o2, 4, %o2"); asm (" add %o1, %o2, %o2"); asm (" sethi %hi(_environ), %o3"); asm (" st %o2, [%o3+%lo(_environ)]"); asm (" andn %sp, 7, %sp"); /* added by Denys Duchier */ #ifdef __svr4__ asm (" call main"); #else asm (" call _main"); #endif asm (" sub %sp, 24, %sp"); /* added by Denys Duchier */ #ifdef __svr4__ asm (" call _exit"); #else asm (" call __exit"); #endif asm (" nop"); #endif /* sparc */ #if __FreeBSD__ == 2 char *__progname; #endif #ifdef __bsdi__ #include /* for version number */ #if defined(_BSDI_VERSION) && (_BSDI_VERSION >= 199501) char *__progname; #endif #endif /* __bsdi__ */ scm-5e5/byte.c0000644001705200017500000001673310750223760011155 0ustar tbtb/* "byte.c" Strings as Bytes * Copyright (C) 2003, 2006 Free Software Foundation, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see * . */ /* Author: Aubrey Jaffer */ #include "scm.h" char s_make_bytes[] = "make-bytes"; SCM scm_make_bytes(k, n) SCM k, n; { SCM res; register unsigned char *dst; register long i; ASRTER(INUMP(k) && (k >= 0), k, ARG1, s_make_bytes); i = INUM(k); res = makstr(i); dst = UCHARS(res); if (!UNBNDP(n)) { ASRTER(INUMP(n) && 0 <= n && n <= MAKINUM(255), n, ARG2, s_make_bytes); for (i--;i >= 0;i--) dst[i] = INUM(n); } return res; } #define s_bytes (s_make_bytes+5) SCM scm_bytes(ints) SCM ints; { SCM res; register unsigned char *data; long i = ilength(ints); ASRTER(i >= 0, ints, ARG1, s_bytes); res = makstr(i); data = UCHARS(res); for (;NNULLP(ints);ints = CDR(ints)) { int n = INUM(CAR(ints)); ASRTER(INUMP(CAR(ints)) && 0 <= n && n <= 255, ints, ARG1, s_bytes); *data++ = n; } return res; } static char s_bt_ref[] = "byte-ref"; SCM scm_byte_ref(str, k) SCM str, k; { ASRTER(NIMP(str) && STRINGP(str), str, ARG1, s_bt_ref); ASRTER(INUMP(k), k, ARG2, s_bt_ref); ASRTER(0 <= INUM(k) && INUM(k) < LENGTH(str), k, OUTOFRANGE, s_bt_ref); return MAKINUM(UCHARS(str)[INUM(k)]); } static char s_bt_set[] = "byte-set!"; SCM scm_byte_set(str, k, n) SCM str, k, n; { ASRTER(NIMP(str) && STRINGP(str), str, ARG1, s_bt_set); ASRTER(INUMP(k), k, ARG2, s_bt_set); ASRTER(INUMP(n), n, ARG3, s_bt_set); ASRTER(0 <= INUM(k) && INUM(k) < LENGTH(str), k, OUTOFRANGE, s_bt_set); UCHARS(str)[INUM(k)] = INUM(n); return UNSPECIFIED; } static char s_bytes2list[] = "bytes->list"; SCM scm_bytes2list(str) SCM str; { long i; SCM res = EOL; unsigned char *src; ASRTER(NIMP(str) && STRINGP(str), str, ARG1, s_bytes2list); src = UCHARS(str); for (i = LENGTH(str)-1;i >= 0;i--) res = cons((SCM)MAKINUM(src[i]), res); return res; } static char s_bt_reverse[] = "bytes-reverse!"; SCM scm_bytes_reverse(str) SCM str; { register char *dst; register long k, len; ASRTER(NIMP(str) && STRINGP(str), str, ARG1, s_bt_reverse); len = LENGTH(str); dst = CHARS(str); for (k = (len - 1)/2;k >= 0;k--) { int tmp = dst[k]; dst[k] = dst[len - k - 1]; dst[len - k - 1] = tmp; } return str; } static char s_write_byte[] = "write-byte"; SCM scm_write_byte(chr, port) SCM chr, port; { int k = INUM(chr); if (UNBNDP(port)) port = cur_outp; else ASRTER(NIMP(port) && OPOUTPORTP(port), port, ARG2, s_write_byte); ASRTER(INUMP(chr) && 0 <= k && k <= 255, chr, ARG1, s_write_byte); lputc(k, port); return UNSPECIFIED; } static char s_read_byte[] = "read-byte"; SCM scm_read_byte(port) SCM port; { int c; if (UNBNDP(port)) port = cur_inp; ASRTER(NIMP(port) && OPINPORTP(port), port, ARG1, s_read_byte); c = lgetc(port); if (EOF==c) return EOF_VAL; return MAKINUM(c); } static char s_sub_rd[] = "subbytes-read!"; SCM scm_subbytes_read(sstr, start, args) SCM sstr, start, args; { SCM end, port; long len; long alen = ilength(args); ASRTER(1 <= alen && alen <= 2, args, WNA, s_sub_rd); end = CAR(args); port = (2==alen) ? CAR(CDR(args)) : cur_inp; ASRTER(NIMP(sstr) && STRINGP(sstr), sstr, ARG1, s_sub_rd); ASRTER(INUMP(start), start, ARG2, s_sub_rd); ASRTER(INUMP(end), end, ARG3, s_sub_rd); ASRTER(NIMP(port) && OPINFPORTP(port), port, ARG4, s_sub_rd); len = LENGTH(sstr); start = INUM(start); end = INUM(end); ASRTER(0 <= start && start <= len, MAKINUM(start), OUTOFRANGE, s_sub_rd); ASRTER(0 <= end && end <= len, MAKINUM(end), OUTOFRANGE, s_sub_rd); if (start==end) return INUM0; if (start < end) { long ans = 0; /* An ungetc before an fread will not work on some systems if setbuf(0), so we read one element char by char. */ if (CRDYP(port)) { CHARS(sstr)[start] = lgetc(port); start += 1; len -= 1; ans = 1; } SYSCALL(ans += fread(CHARS(sstr)+start, (sizet)1, (sizet)(end - start), STREAM(port));); return MAKINUM(ans); } else { long idx = start; while (end < idx) { int chr = lgetc(port); if (EOF==chr) return MAKINUM(start - idx); CHARS(sstr)[--idx] = chr; } return MAKINUM(start - end); } } static char s_sub_wr[] = "subbytes-write"; SCM scm_subbytes_write(sstr, start, args) SCM sstr, start, args; { SCM end, port; long len; long alen = ilength(args); ASRTER(1 <= alen && alen <= 2, args, WNA, s_sub_wr); end = CAR(args); port = (2==alen) ? CAR(CDR(args)) : cur_outp; ASRTER(NIMP(sstr) && STRINGP(sstr), sstr, ARG1, s_sub_wr); ASRTER(INUMP(start), start, ARG2, s_sub_wr); ASRTER(INUMP(end), end, ARG3, s_sub_wr); ASRTER(NIMP(port) && OPOUTFPORTP(port), port, ARG4, s_sub_wr); len = LENGTH(sstr); start = INUM(start); end = INUM(end); ASRTER(0 <= start && start <= len, MAKINUM(start), OUTOFRANGE, s_sub_wr); ASRTER(0 <= end && end <= len, MAKINUM(end), OUTOFRANGE, s_sub_wr); if (start==end) return INUM0; if (start < end) { long ans; SYSCALL(ans = lfwrite(CHARS(sstr)+start, (sizet)1, (sizet)(sizet)(end - start), port);); return MAKINUM(ans); } else { long idx = start; while (end <= --idx) { if (feof(STREAM(port))) return MAKINUM(start - idx - 1); lputc(CHARS(sstr)[idx], port); } return MAKINUM(start - end); } } static iproc subr1s[] = { {"list->bytes", scm_bytes}, {s_bytes2list, scm_bytes2list}, {s_bt_reverse, scm_bytes_reverse}, {0, 0}}; static iproc subr2os[] = { {s_write_byte, scm_write_byte}, {s_make_bytes, scm_make_bytes}, {0, 0}}; static iproc lsubr2s[] = { {s_sub_rd, scm_subbytes_read}, {s_sub_wr, scm_subbytes_write}, {0, 0}}; void init_byte() { init_iprocs(subr1s, tc7_subr_1); init_iprocs(subr2os, tc7_subr_2o); init_iprocs(lsubr2s, tc7_lsubr_2); make_subr(s_bytes, tc7_lsubr, scm_bytes); make_subr(s_read_byte, tc7_subr_1o, scm_read_byte); make_subr(s_bt_ref, tc7_subr_2, scm_byte_ref); make_subr(s_bt_set, tc7_subr_3, scm_byte_set); add_feature("byte"); scm_ldstr("\n\ (define bytes-length string-length)\n\ (define bytes-copy string-copy)\n\ (define bytes-append string-append)\n\ (define subbytes substring)\n\ (define bytes->string cr)\n\ (define string->bytes cr)\n\ (define (bytes-reverse bytes)\n\ (bytes-reverse! (bytes-copy bytes)))\n\ (define (read-bytes n . port)\n\ (let* ((len (abs n))\n\ (byts (make-bytes len))\n\ (cnt (if (positive? n)\n\ (apply subbytes-read! byts 0 n port)\n\ (apply subbytes-read! byts (- n) 0 port))))\n\ (if (= cnt len)\n\ byts\n\ (if (positive? n)\n\ (substring byts 0 cnt)\n\ (substring byts (- len cnt) len)))))\n\ (define (write-bytes bytes n . port)\n\ (if (positive? n)\n\ (apply subbytes-write bytes 0 n port)\n\ (apply subbytes-write bytes (- n) 0 port)))\n\ (define substring-read! subbytes-read!)\n\ (define substring-write subbytes-write)\n\ "); } scm-5e5/Macexp.scm0000644001705200017500000004327710750210226011763 0ustar tbtb;;;; "Macexp.scm", macro expansion, respecting hygiene. ;; Copyright (C) 1999 Free Software Foundation, Inc. ;; ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU Lesser General Public License as ;; published by the Free Software Foundation, either version 3 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 ;; Lesser General Public License for more details. ;; ;; You should have received a copy of the GNU Lesser General Public ;; License along with this program. If not, see ;; . ;;; Author: Radey Shouman ;; LLIST is a lambda list, BINDINGS an alist using the same identifiers. (define extended-environment (let ((env:annotation-marker 4)) (lambda (llist bindings env) (cons llist (cons env:annotation-marker (cons bindings env)))))) (define syntax-extended-environment (let ((env:syntax-marker 6)) ;;BINDINGS is an alist (lambda (bindings env) (cons (cons env:syntax-marker bindings) env)))) (define (environment-ref env id) (environment-annotation id env)) ;;(debind:if_ ?llist ?val ?body ?alt) ;;?alt should evaluate to a procedure taking two arguments, a pattern ;;and an object. This macro requires the (... ...) ellipsis quote ;;extension. (define-syntax debind:if (syntax-rules () ((_ "PARSE LLIST" () ?val ?body ?alt) (if (null? ?val) ?body (?alt '() ?val))) ((_ "PARSE LLIST" (?pattern (... ...)) ?val ?body ?alt) (let loop ((v ?val)) (cond ((null? v) (debind:if "PARSE ..." ?pattern ?val ?body)) ((pair? v) (let ((carv (car v))) (debind:if "PARSE LLIST" ?pattern carv (loop (cdr v)) ?alt))) (else (?alt '(?pattern (... ...)) ?val))))) ((_ "PARSE LLIST" (?first . ?rest) ?val ?body ?alt) (if (pair? ?val) (let ((carv (car ?val)) (cdrv (cdr ?val))) (debind:if "PARSE LLIST" ?first carv (debind:if "PARSE LLIST" ?rest cdrv ?body ?alt) ?alt)) (?alt '(?first . ?rest) ?val))) ((_ "PARSE LLIST" ?name ?val ?body ?alt) (let ((?name ?val)) ?body)) ((_ "PARSE ..." () ?val ?body) ?body) ((_ "PARSE ..." (?pattern (... ...)) ?val ?body) (debind:if "PARSE ..." ?pattern ?val ?body)) ((_ "PARSE ..." (?first . ?rest) ?val ?body) (debind:if "PARSE ..." ?first (map car ?val) (debind:if "PARSE ..." ?rest (map cdr ?val) ?body))) ((_ "PARSE ..." ?name ?val ?body) (let ((?name ?val)) ?body)) ((_ ?llist ?val ?body) (debind:if ?llist ?val ?body (lambda (pat val "debind:if" '?llist val "does not match" pat)))) ((_ ?llist ?val ?body ?alt) (let ((val ?val) (alt ?alt)) (debind:if "PARSE LLIST" ?llist val ?body alt))))) ;; Uncomment for DESTRUCTURING-BIND enhanced with ellipsis (...) patterns. ;(define-syntax destructuring-bind ; (syntax-rules () ; ((_ ?llist ?val ?body1 ?body ...) ; (debind:if ?llist ?val ; (let () ?body1 ?body ...) ; (lambda (pat val) ; (slib:error 'destructuring-bind '?llist ; val "does not match" pat)))))) ;; This should really dispatch on the keyword only, then ;; use destructuring-case for each keyword, that way errors ;; may be more accurately reported for primitives. ;; ;;(keyword-case expr env (pattern body ...) ...) (define-syntax keyword-case (syntax-rules (else) ((_ "RECURSE" ?expr ?env) (error 'keyword-case ?expr "not matched")) ((_ "RECURSE" ?expr ?env (else ?body1 ?body ...)) (let () ?body1 ?body ...)) ((_ "RECURSE" ?expr ?env ((?keyword . ?pattern) ?body1 ?body ...) ?clause ...) (let ((alt (lambda (ignore1 ignore2) (keyword-case "RECURSE" ?expr ?env ?clause ...)))) ;;Keywords are renamed in the top-level environment for each ;;comparison, this is wasteful and somewhat ugly. (if (identifier-equal? (renamed-identifier '?keyword '()) (car ?expr) ?env) (debind:if ?pattern (cdr ?expr) (let () ?body1 ?body ...) alt) (alt #f #f)))) ((_ ?expr ?env ?clause1 ?clause ...) (let ((expr ?expr)) (if (or (not (pair? expr)) (not (identifier? (car expr)))) (error 'keyword-case expr "bad form") (keyword-case "RECURSE" expr ?env ?clause1 ?clause ...)))))) ;; This is still not safe when ENV has non-macro bindings in it. ;; It could be made safe by rebuilding an equivalent environment, ;; retaining values only for syntactic bindings. (define (macro:expand-syntax form env pretty? verbose?) (define globals '()) (define shadowed-globals '()) (define top-lambda (renamed-identifier 'LAMBDA #f)) (define top-let (renamed-identifier 'LET #f)) (define top-let* (renamed-identifier 'LET* #f)) (define top-letrec (renamed-identifier 'LETREC #f)) (define top-arrow (renamed-identifier '=> #f)) (define top-else (renamed-identifier 'ELSE #f)) (define top-define (renamed-identifier 'DEFINE #f)) (define top-begin (renamed-identifier 'BEGIN #f)) (define (arrow? id env) (and (identifier? id) (identifier-equal? id top-arrow env))) (define (else? id env) (and (identifier? id) (identifier-equal? id top-else env))) (define (define? form env) (and (list? form) ;FORM will have been expanded. (identifier? (car form)) (identifier-equal? top-define (car form) env))) (define (begin? form env) (and (list? form) (identifier? (car form)) (identifier-equal? (car form) top-begin env))) (define locally-bound? environment-annotation) (define pretty-name (if pretty? (letrec ((counter 0) (genname (lambda (sym) (set! counter (+ counter 1)) (string->symbol (string-append (symbol->string sym) "|" (number->string counter)))))) (lambda (name env) (if (symbol? name) (if (or (memq name '(LAMBDA LET LET* LETREC DO DEFINE SET! BEGIN IF COND CASE AND OR QUOTE QUASIQUOTE UNQUOTE UNQUOTE-SPLICING DEFINE-SYNTAX LET-SYNTAX LETREC-SYNTAX SYNTAX-QUOTE ELSE =>)) (locally-bound? name env)) (genname name) name) (genname (identifier->symbol name))))) identity)) ;; Local bindings -> (identifier pretty-name (usage-context ...)) ;; This will change. (define (initial-binding name env) (or (identifier? name) (slib:error 'macro:expand name "not identifier")) (list name (pretty-name name env) '())) (define binding->name cadr) (define binding->contexts caddr) (define (binding-add-context! b context) (let ((ctx (caddr b))) (if (not (list? ctx)) (error 'not-a-list ctx)) (or (memq context ctx) (set-car! (cddr b) (cons context ctx))))) ;; Produces an alist (define (llist->bindings llist env) (let recurse ((ll llist)) (cond ((pair? ll) (cons (initial-binding (car ll) env) (recurse (cdr ll)))) ((identifier? ll) (list (initial-binding ll env))) ((null? ll) ll) (else (error 'strange-lambda-list llist))))) (define (expand-begin forms env context) (if (null? forms) '() (let recurse ((forms forms)) (if (null? (cdr forms)) (list (expand (car forms) env context)) (cons (expand (car forms) env 'SIDE-EFFECT) (recurse (cdr forms))))))) (define (expand-body forms env context) (define (rewrite forms defs) (if (null? defs) (expand-begin forms env context) (list (expand-primitive `(,top-letrec ,(reverse defs) ;reverse just to make it pretty ,@forms) env context)))) (let loop ((forms forms) (defs '())) (if (null? (cdr forms)) (rewrite forms defs) (let ((form1 (expand (car forms) env 'SIDE-EFFECT))) (cond ((define? form1 env) (loop (cdr forms) (cons (cdr form1) defs))) ((begin? form1 env) (loop (append (cdr form1) (cdr forms)) defs)) (else (rewrite forms defs))))))) (define (lookup id env) (or (environment-ref env id) (let* ((sym (identifier->symbol id)) (binding (cond ((assq sym globals)) (else (let ((b (initial-binding sym env))) (set! globals (cons b globals)) b))))) (cond ((not pretty?) id) ((not (locally-bound? sym env))) ((assq sym shadowed-globals)) (else (set! shadowed-globals (cons (cons sym (binding->name binding)) shadowed-globals)))) binding))) (define pretty-varref (if pretty? (lambda (id env) (if (symbol? id) id (let ((sym (identifier->symbol id))) (if (identifier-equal? id sym env) sym id)))) (lambda (id env) id))) (define unpaint (if pretty? (lambda (x) (cond ((symbol? x) x) ((identifier? x) (identifier->symbol x)) ((pair? x) (cons (unpaint (car x)) (unpaint (cdr x)))) ((vector? x) (let* ((n (vector-length x)) (v (make-vector n))) (do ((i 0 (+ i 1))) ((>= i n) v) (vector-set! v i (unpaint (vector-ref x i)))))) (else x))) identity)) (define (expand* forms env context) (map (lambda (form) (expand form env context)) forms)) (define (expand-primitive form env context) (define keyword (and (pair? form) (if pretty? (identifier->symbol (car form)) (car form)))) (keyword-case form env ;;Binding forms ((LAMBDA llist body1 body ...) (let* ((bindings (llist->bindings llist env)) (env (extended-environment llist bindings env)) (body (expand-body (cons body1 body) env context)) (llist (let recurse ((ll llist) (bl bindings)) (cond ((null? ll) '()) ((pair? ll) (cons (binding->name (car bl)) (recurse (cdr ll) (cdr bl)))) (else (binding->name bl)))))) `(,keyword ,llist ,@body))) ((LET ((names values) ...) body1 body ...) (let* ((values (expand* values env 'VALUE)) (bindings (llist->bindings names env)) (env (extended-environment names bindings env)) (body (expand-body (cons body1 body) env context))) `(,keyword ,(map (lambda (b val) (list (binding->name b) val)) bindings values) ,@body))) ((LET name1 ((names values) ...) body1 body ...) (expand `((,top-letrec ((,name1 (,(pretty-varref top-lambda env) ,names ,@(cons body1 body)))) ,name1) ,@values) env context)) ((LETREC ((names values) ...) body1 body ...) (let* ((bindings (llist->bindings names env)) (env (extended-environment names bindings env)) (values (expand* values env 'VALUE)) (body (expand-body (cons body1 body) env context))) `(,keyword ,(map (lambda (b val) (list (binding->name b) val)) bindings values) ,@body))) ((LET* ((names values) ...) body1 body ...) (let recurse ((ns names) (vs values) (env env) (bs '())) (if (null? ns) (let ((body (expand-body (cons body1 body) env context))) `(,keyword ,(reverse bs) ,@body)) (let ((binding (initial-binding (car ns) env))) (recurse (cdr ns) (cdr vs) (extended-environment (car ns) (list binding) env) (cons (list (binding->name binding) (expand (car vs) env 'VALUE)) bs)))))) ((DO ((names inits . steps) ...) (test exit ...) body ...) (let* ((steps (map (lambda (name step) (if (null? step) name (car step))) names steps)) (inits (expand* inits env 'VALUE)) (bindings (llist->bindings names env)) (env (extended-environment names bindings env)) (steps (expand* steps env 'VALUE)) (test (expand test env 'BOOLEAN)) (exit (expand-begin exit env context)) (body (expand-begin body env 'SIDE-EFFECT))) `(,keyword ,(map (lambda (binding init step) (list (binding->name binding) init step)) bindings inits steps) ,(cons test exit) ,@body))) ((DEFINE (name . llist) body ...) (expand-primitive `(,keyword ,name (,top-lambda ,llist ,@body)) env context)) ((DEFINE name value) (cond ((null? env) ;Top level (binding-add-context! (lookup name env) 'DEFINE) `(,keyword ,(pretty-varref name env) ,(expand value env 'VALUE))) (else `(,keyword ,name ,value)))) ;Expansion will be done by expand-body. ((SET! var value) (let ((b (lookup var env))) (binding-add-context! b 'SET!) `(,keyword ,(binding->name b) ,(expand value env 'VALUE)))) ;;Non-binding forms ((BEGIN body ...) (let ((body (expand-begin body env context))) (if (null? (cdr body)) (car body) `(,keyword ,@body)))) ((IF test conseq . alt) `(,keyword ,(expand test env 'BOOLEAN) ,(expand conseq env context) ,@(if (pair? alt) (list (expand (car alt) env context)) '()))) ((COND (test exprs ...) ...) `(,keyword ,@(map (lambda (test exprs) (cond ((null? exprs) (list (expand test env context))) ((arrow? (car exprs) env) (list (expand test env 'VALUE) (pretty-varref top-arrow env) (expand (cadr exprs) env 'PROCEDURE))) ((else? test env) (cons (pretty-varref top-else env) (expand-begin exprs env context))) (else (cons (expand test env 'BOOLEAN) (expand-begin exprs env context))))) test exprs))) ((CASE obj (datums exprs ...) ...) `(,keyword ,(expand obj env 'VALUE) ,@(map (lambda (datums exprs) (cons (if (else? datums env) (pretty-varref datums env) (unpaint datums)) (expand-begin exprs env context))) datums exprs))) ((AND forms ...) `(,keyword ,@(expand* forms env context))) ((OR forms ...) `(,keyword ,@(expand* forms env context))) ;; Should unpaint synthetic identifiers ((QUOTE obj) `(,keyword ,(unpaint obj))) ((QUASIQUOTE obj) `(,keyword ,(let qexp ((obj obj) (depth 0)) (cond ((not (pair? obj)) (unpaint obj)) ((identifier? (car obj)) (let ((keyword (car obj))) (keyword-case obj env ((QUASIQUOTE arg) (list keyword (qexp arg (+ depth 1)))) ((UNQUOTE arg) (list keyword (if (zero? depth) (expand arg env context) (qexp arg (- depth 1))))) ((UNQUOTE-SPLICING arg) (list keyword (if (zero? depth) (expand arg env context) (qexp arg (- depth 1))))) (else (cons (unpaint keyword) (qexp (cdr obj) depth)))))) (else (cons (qexp (car obj) depth) (qexp (cdr obj) depth))))))) ((DEFINE-SYNTAX name def) form) ((LET-SYNTAX ((names defs) ...) body1 body ...) (let* ((env (syntax-extended-environment '() env)) (defs (map (lambda (name def) (cons name (eval-syntax def env))) names defs)) (env (syntax-extended-environment defs env)) (body (expand-body (cons body1 body) env context))) (if pretty? `(,(pretty-varref top-let env) () ,@body) `(,top-let* (,(list marker #f)) ,@body)))) ((LETREC-SYNTAX ((names defs) ...) body1 body ...) (let* ((eframe (map (lambda (name) (cons name #f)) names)) (env (syntax-extended-environment eframe env))) (do ((ds defs (cdr ds)) (ef eframe (cdr ef))) ((null? ds)) (set-cdr! (car ef) (eval-syntax (car ds) env))) (let ((body (expand-body (cons body1 body) env context))) (if pretty? `(,(pretty-varref top-let env) () ,@body) `(,top-let* (,(list marker #f)) ,@body))))) ;;SCM extension ((SYNTAX-QUOTE obj) `(,keyword ,obj)) (else (warn 'expand-syntax "Unexpected primitive syntax" form) form))) (define (handle-shadowed form env) (if (define? form env) (list (car form) (cadr form) (handle-shadowed (caddr form))) `(,(pretty-varref top-let env) ,(map (lambda (s) (list (cdr s) (if (environment-ref env (car s)) (renamed-identifier (car s) #f) (car s)))) shadowed-globals) ,form))) (define (expand form env context) (cond ((identifier? form) (let ((expanded (@macroexpand1 form env))) (cond ((eq? form expanded) form) ((not expanded) (let* ((b (lookup form env)) (name (binding->name b))) (binding-add-context! b context) name)) (else expanded)))) ((number? form) form) ((char? form) form) ((boolean? form) form) ((null? form) form) ((string? form) form) ((list? form) (if (identifier? (car form)) (let ((expanded (@macroexpand1 form env))) (cond ((eq? expanded form) (expand-primitive form env context)) ((not expanded) (cons (expand (car form) env 'PROCEDURE) (map (lambda (arg) (expand arg env 'VALUE)) (cdr form)))) (else (expand expanded env context)))) (cons (expand (car form) env 'PROCEDURE) (expand* (cdr form) env 'VALUE)))) (else (warn 'expand-syntax "Unexpected type of form" form) form))) (let ((res (expand form env 'TOP))) (cond (verbose? (display "Globals: ") (pretty-print globals) (display "Shadowed Globals: ") (pretty-print shadowed-globals))) (cond ((null? shadowed-globals) res) ((not (begin? res env)) (handle-shadowed res env)) (else (cons (car res) (map (lambda (form) (handle-shadowed form env)) (cdr res))))))) (define (macro:expand form . opt) (macro:expand-syntax form '() (not (memq 'not-pretty opt)) (memq 'verbose opt))) ;; Debugging fodder. (begin (define (read* filename) (call-with-input-file filename (lambda (p) (let loop ((forms '())) (let ((form (read p))) (if (eof-object? form) (cons 'BEGIN (reverse forms)) (loop (cons form forms)))))))) (define (expand-file filename . opt) (apply macro:expand (read* filename) '() opt)) (define s (read* (or *load-pathname* "Macexp.scm")))) ;;; Local Variables: ;;; mode:scheme ;;; eval:(put 'destructuring-bind 'scheme-indent-function 1) ;;; eval:(put 'destructuring-case 'scheme-indent-function 1) ;;; End: scm-5e5/rwb-isam.scm0000644001705200017500000005265010106533154012265 0ustar tbtb;;; "rwb-isam.scm" Relational WB database with sequential indexes. ; Copyright 1996, 2000, 2001, 2003 Aubrey Jaffer ; ;Permission to copy this software, to modify it, to redistribute it, ;to distribute modified versions, and to use it for any purpose is ;granted, subject to the following restrictions and understandings. ; ;1. Any copy made of this software must include this copyright notice ;in full. ; ;2. I have made no warranty or representation that the operation of ;this software will be error-free, and I am under no obligation to ;provide any services, by way of maintenance, update, or otherwise. ; ;3. In conjunction with products arising from the use of this ;material, there shall be no use of my name in any advertising, ;promotional, or sales literature without prior written consent in ;each case. ;;;; *catalog* is informed of 'rwb-isam binding by "scm/mkimpcat.scm". (require 'wb) (require 'byte) (require 'byte-number) (require 'relational-database) ;for make-relational-system ;;; WB-SEG:LOCKS has one extra location at end for loop end test (defvar wb-seg:locks (let ((locks (make-vector (+ 1 wb:num-segs) #f))) (do ((i (+ -2 (vector-length locks)) (+ -1 i))) ((negative? i) locks) (vector-set! locks i (make-arbiter i))))) (defvar wb-seg:files (make-vector (+ 1 wb:num-segs) #f)) (defvar wb-seg:roots (make-vector (+ 1 wb:num-segs) #f)) (defvar wb-seg:mut?s (make-vector (+ 1 wb:num-segs) #f)) ;@ (define rwb-isam ;; foiled indentation so etags will recognize definitions (let ((make-handle list) (handle->base-id car) (handle->bt cadr) (catalog-id 0) (free-id "") (root-name "rwb") (key:s255 (bytes 255)) (key:col1 (bytes 1)) (key:col0 (bytes 0)) (key:null (bytes 0)) (key:col-field bytes)) ;;;The least-upper-bound of a composite key. (define (key:incr key) (string-append key key:s255)) ;;;Return key sans prefix and column suffix if first column. (define (key:match-prefix? prefix ckey) (define sdx (+ -1 (string-length ckey))) (define prelen (string-length prefix)) (and (<= prelen sdx) (string=? prefix (substring ckey 0 prelen)) (substring ckey prelen sdx))) ;;;Detects when all match-keys given are false. (define (list-all-false? lst) (cond ((null? lst) #t) ((car lst) #f) (else (list-all-false? (cdr lst))))) ;;; These two NTHCDR procedures replicate those in "comlist.scm". (define (nthcdr k list) (do ((i k (+ -1 i)) (lst list (cdr lst))) ((<= i 0) lst))) (define (butnthcdr k lst) (cond ((or (zero? k) (null? lst)) '()) (else (let ((ans (list (car lst)))) (do ((lst (cdr lst) (cdr lst)) (tail ans (cdr tail)) (k (+ -2 k) (+ -1 k))) ((or (negative? k) (null? lst)) ans) (set-cdr! tail (list (car lst)))))))) ;;;; Segments (define (find-free-seg) (do ((i 0 (+ 1 i)) (arb (vector-ref wb-seg:locks 0) (vector-ref wb-seg:locks (+ 1 i)))) ((or (not arb) (try-arbiter arb)) (and arb i)))) (define (release-seg seg) (and seg (release-arbiter (vector-ref wb-seg:locks seg)) #f)) ;;;; Create, open, write, sync, or close database. (define (seg-open-base seg filename writable?) (vector-set! wb-seg:files seg filename) (vector-set! wb-seg:mut?s seg writable?) (vector-set! wb-seg:roots seg (open-db seg root-name)) (cond ((wb:err? (vector-ref wb-seg:roots seg)) (close-base seg) #f) (else seg))) ;;; Because B-trees grow in depth only very slowly, we might as well ;;; put everything into one B-tree named "rwb". (define (make-base filename dim types) (define seg (find-free-seg)) (cond ((not seg) #f) ((wb:err? (make-seg seg filename 2048)) (release-seg seg) #f) ((wb:err? (open-seg seg filename 2)) (release-seg seg) #f) ((or (wb:err? (bt:put! (create-db seg #\T root-name) free-id "1")) (wb:err? (bt:put! (open-bt seg 0 1) "base-table" "rwb-isam"))) (release-seg seg) (slib:error 'make-base "couldn't modify new base" filename) #f) (else (seg-open-base seg filename #t)))) (define (open-base filename writable?) (define seg (find-free-seg)) (cond ((wb:err? (open-seg seg filename (if writable? 2 0))) (release-seg seg) #f) (else (seg-open-base seg filename writable?)))) (define (write-base seg filename) (cond ((and filename (equal? filename (vector-ref wb-seg:files seg))) (let ((status (close-seg seg #f))) (cond ((wb:err? status) #f) ((wb:err? (open-seg seg filename 2)) #f) (else #t)))) (else ;;(slib:error 'write-base "WB can't change database filename" filename) #f))) (define (sync-base seg) (and seg (write-base seg (vector-ref wb-seg:files seg)))) (define (close-base seg) (cond ((wb:err? (close-seg seg #f)) (let ((status (close-seg seg #t))) (release-seg seg) (not (wb:err? status)))) (else (release-seg seg) #t))) ;;;; Make, open, and destroy tables. (define (make-table seg dim types) (and (vector-ref wb-seg:mut?s seg) (let* ((tns (bt:rem (vector-ref wb-seg:roots seg) free-id)) (base-id (and (string? tns) (string->number tns)))) (cond ((not tns) (slib:error 'make-table 'free-id "in use?") #f) ((not base-id) (bt:put (vector-ref wb-seg:roots seg) free-id tns) (slib:error 'make-table "free-id corrupted" base-id) #f) ((not (bt:put (vector-ref wb-seg:roots seg) free-id (number->string (+ 1 base-id)))) (slib:error 'make-table "free-id lock broken") #f) (else base-id))))) ;;; OPEN-TABLE allocates a new handle (in call to open-db) so each ;;; table handle will have its own last-block-used (define (open-table seg base-id dim types) (define (base-id->prefix base-id) (define nstr (number->string base-id)) (string-append (string #\T (integer->char (string-length nstr))) nstr (string (integer->char 1) #\D))) (make-handle (base-id->prefix base-id) (open-db seg root-name))) (define (kill-table seg base-id dim types) (let* ((handle (open-table seg base-id dim types)) (prefix (handle->base-id handle))) (not (wb:err? (bt:rem* (handle->bt handle) prefix (key:incr prefix)))))) ;;;; Conversions from Scheme objects into and from strings. (define (object->wb-string type) (case type ((string) identity) ((symbol) symbol->string) ((integer number ordinal) number->string) ((boolean) (lambda (b) (if b "T" "F"))) ((c64) (lambda (x) (string-append (ieee-double->bytes (real-part x)) (ieee-double->bytes (imag-part x))))) ((c32) (lambda (x) (string-append (ieee-float->bytes (real-part x)) (ieee-float->bytes (imag-part x))))) ((r64) (lambda (x) (ieee-double->bytes x))) ((r32) (lambda (x) (ieee-float->bytes x))) ((s64) (lambda (n) (integer->bytes n -8))) ((s32) (lambda (n) (integer->bytes n -4))) ((s16) (lambda (n) (integer->bytes n -2))) (( s8) (lambda (n) (integer->bytes n -1))) ((u64) (lambda (n) (integer->bytes n 8))) ((u32) (lambda (n) (integer->bytes n 4))) ((u16) (lambda (n) (integer->bytes n 2))) (( u8) (lambda (n) (integer->bytes n 1))) ((atom) (lambda (obj) (if (not obj) "#f" (symbol->string obj)))) ((expression) (lambda (obj) (call-with-output-string (lambda (port) (write obj port))))) (else #f))) (define (wb-string->object type) (case type ((string) identity) ((symbol) string->symbol) ((integer number ordinal) string->number) ((boolean) (lambda (str) (not (equal? str "F")))) ((c64) (lambda (str) (make-rectangular (bytes->ieee-double (substring str 0 8)) (bytes->ieee-double (substring str 8 16))))) ((c32) (lambda (str) (make-rectangular (bytes->ieee-float (substring str 0 4)) (bytes->ieee-float (substring str 4 8))))) ((r64) (lambda (str) (bytes->ieee-double str))) ((r32) (lambda (str) (bytes->ieee-float str))) ((s64) (lambda (str) (bytes->integer str -8))) ((s32) (lambda (str) (bytes->integer str -4))) ((s16) (lambda (str) (bytes->integer str -2))) (( s8) (lambda (str) (bytes->integer str -1))) ((u64) (lambda (str) (bytes->integer str 8))) ((u32) (lambda (str) (bytes->integer str 4))) ((u16) (lambda (str) (bytes->integer str 2))) (( u8) (lambda (str) (bytes->integer str 1))) ((atom) (lambda (str) (if (string-ci=? "#f" str) #f (string->symbol str)))) ((expression) (lambda (str) (call-with-input-string str read))) (else #f))) (define (supported-type? type) (case type ((ordinal atom integer number boolean string symbol expression c64 c32 r64 r32 s64 s32 s16 s8 u64 u32 u16 u8) #t) (else #f))) (define (supported-key-type? type) (case type ((atom ordinal integer number symbol string boolean r64 r32 s64 s32 s16 s8 u64 u32 u16 u8) #t) (else #f))) ;;;; Keys ;;;Keys are composed of one to many fields. ;;; ;;;* The binary number formats r64, r32, s64, s32, s16, s8, u64, u32, ;;; u16, and u8 have fixed widths and are encoded so that the key ;;; sort order is the same as numerical order. ;;; ;;;* Booleans occupy one byte: 'T' or 'F'. ;;; ;;;* Strings, symbols, and atoms (symbol or #f) are variable width ;;; fields terminated by a null byte. They sort in lexicographic ;;; (dictionary) order. A #f atom is represented by the null string. ;;; ;;;* The integer, number, and ordinal formats are strings of decimal ;;; digits preceeded by a length byte. Nonnegative integers sort ;;; correctly. ;;; ;;;Use of null bytes in string, symbol, or atom key-fields will break ;;;this encoding. (define (string-number-keyifier n) (define str (number->string n)) (string-append (bytes (string-length str)) str)) (define (string-keyifier str) (string-append str key:null)) (define (key:shorten-1 str) (substring str 0 (+ -1 (string-length str)))) ;;; unitary composite-key maker (define (make-keyifier-1 type) (case type ((string) string-keyifier) ((symbol) (lambda (s) (string-keyifier (symbol->string s)))) ((atom) (lambda (obj) (string-keyifier (if obj (symbol->string obj) "")))) ((boolean) (lambda (b) (if b "T" "F"))) ((integer number ordinal) string-number-keyifier) ;; binary number formats ((r64) (lambda (x) (ieee-byte-collate! (ieee-double->bytes x)))) ((r32) (lambda (x) (ieee-byte-collate! (ieee-float->bytes x)))) ((s64) (lambda (n) (integer-byte-collate! (integer->bytes n -8)))) ((s32) (lambda (n) (integer-byte-collate! (integer->bytes n -4)))) ((s16) (lambda (n) (integer-byte-collate! (integer->bytes n -2)))) (( s8) (lambda (n) (integer->bytes n -1))) ((u64) (lambda (n) (integer-byte-collate! (integer->bytes n 8)))) ((u32) (lambda (n) (integer-byte-collate! (integer->bytes n 4)))) ((u16) (lambda (n) (integer-byte-collate! (integer->bytes n 2)))) (( u8) (lambda (n) (integer->bytes n 1))) (else (slib:error 'make-keyifier-1 'unsupported-type type)))) ;;; composite-key maker (define (key-polymerase prinum types) (set! types (butnthcdr prinum types)) ;; Special case when there is just one primary key. (if (= 1 prinum) (let ((proc (make-keyifier-1 (car types)))) (lambda (lst) (proc (car lst)))) (let ((procs (map make-keyifier-1 types))) (lambda (lst) (apply string-append (map (lambda (p v) (p v)) procs lst)))))) (define (key:width type) (case type ((r64 s64 u64) 8) ((r32 s32 u32) 4) ((s16 u16) 2) ((s8 u8 boolean) 1) ((integer number ordinal) (lambda (key pos) (+ 1 (byte-ref key pos)))) ((string symbol atom) ;null terminated (lambda (key pos) (do ((i pos (+ 1 i))) ((zero? (byte-ref key i)) (- i pos -1))))) (else #f))) (define (exokeyase type) (case type ((string) key:shorten-1) ((symbol) (lambda (str) (string->symbol (key:shorten-1 str)))) ((atom) (lambda (str) (if (string=? "" str) #f (string->symbol (key:shorten-1 str))))) ((boolean) (lambda (str) (not (string=? "F" str)))) ((integer number ordinal) (lambda (str) (string->number (substring str 1 (string-length str))))) ;; binary number formats ((r64) (lambda (str) (bytes->ieee-double (ieee-byte-decollate! str)))) ((r32) (lambda (str) (bytes->ieee-float (ieee-byte-decollate! str)))) ((s64) (lambda (str) (bytes->integer (integer-byte-collate! str) -8))) ((s32) (lambda (str) (bytes->integer (integer-byte-collate! str) -4))) ((s16) (lambda (str) (bytes->integer (integer-byte-collate! str) -2))) (( s8) (lambda (str) (bytes->integer str -1))) ((u64) (lambda (str) (bytes->integer (integer-byte-collate! str) 8))) ((u32) (lambda (str) (bytes->integer (integer-byte-collate! str) 4))) ((u16) (lambda (str) (bytes->integer (integer-byte-collate! str) 2))) (( u8) (lambda (str) (bytes->integer str 1))) (else #f))) ;;; extracts one key-field from composite-key (define (make-key-extractor primary-limit types index) (define (wither type) (or (key:width type) (slib:error 'make-key-extractor 'unsupported-type type))) (let ((proc (exokeyase (list-ref types (+ -1 index)))) (skips (map wither (butnthcdr index types)))) (lambda (key) (let loop ((pos 0) (skips skips)) (define flen (car skips)) (if (procedure? flen) (set! flen (flen key pos))) (if (null? (cdr skips)) (proc (substring key pos (+ pos flen))) (loop (+ pos flen) (cdr skips))))))) ;;; composite-key to list (define (make-key->list primary-limit types) (define (wither type) (or (key:width type) (slib:error 'make-key->list 'unsupported-type type))) (define typs (butnthcdr primary-limit types)) (let ((procs (map exokeyase typs)) (skips (map wither typs))) (lambda (key) (let loop ((pos 0) (skips skips) (procs procs)) (define flen (car skips)) (if (procedure? flen) (set! flen (flen key pos))) ;;(print 'key->list pos flen typs key) (cons ((car procs) (substring key pos (+ pos flen))) (if (null? (cdr skips)) '() (loop (+ pos flen) (cdr skips) (cdr procs)))))))) ;;;; for-each-key, ordered-for-each-key, and map-key (define (make-key-match? key-dimension column-types match-keys) (if (list-all-false? match-keys) (lambda (ckey) #t) (let ((keyploder (make-key->list key-dimension column-types))) (lambda (ckey) (define (key-match? match-keys keys) (cond ((null? match-keys) #t) ((not (car match-keys)) (key-match? (cdr match-keys) (cdr keys))) ((equal? (car match-keys) (car keys)) (key-match? (cdr match-keys) (cdr keys))) ((not (procedure? (car match-keys))) #f) (((car match-keys) (car keys)) (key-match? (cdr match-keys) (cdr keys))) (else #f))) (key-match? match-keys (keyploder ckey)))))) (define (map-key handle operation key-dimension column-types match-keys) (define lst (list 'dummy)) (let ((tail lst)) (ordered-for-each-key handle (lambda (k) (set-cdr! tail (list (operation k))) (set! tail (cdr tail))) key-dimension column-types match-keys) (cdr lst))) ;;;; Indexed Sequential Access Methods (define (ordered-for-each-key handle operation key-dimension column-types match-keys) (let ((bt (handle->bt handle)) (prefix (handle->base-id handle)) (key-match? (make-key-match? key-dimension column-types match-keys))) (case (- (length column-types) key-dimension) ((0) (let ((prefix+ (key:incr prefix)) (maproc (lambda (ckey val) (define fkey (key:match-prefix? prefix ckey)) ;;(print 'ordered-for-each-key ckey fkey) (and fkey (key-match? fkey) (operation fkey)) #f))) (do ((res (bt:scan bt 0 prefix prefix+ maproc 1) (bt:scan bt 0 (caddr res) prefix+ maproc 1))) ((not (= -1 (car res))))))) (else (let ((prelen (string-length prefix))) (do ((nkey (bt:next bt prefix) (bt:next bt (key:incr (key:shorten-1 nkey))))) ((or (not nkey) (not (string=? prefix (substring nkey 0 prelen)))) #f) ;;(print 'ordered-for-each-key nkey (key:match-prefix? prefix nkey)) (let ((fkey (key:match-prefix? prefix nkey))) (and fkey (key-match? fkey) (operation fkey))))))))) (define (make-nexter handle key-dimension column-types index) (define bt (handle->bt handle)) (define prefix (handle->base-id handle)) (define key->list (make-key->list key-dimension column-types)) (define list->key (key-polymerase key-dimension column-types)) (lambda keys (define nkey (bt:next bt (string-append prefix (list->key (butnthcdr index keys)) key:s255))) (and nkey (let ((ckey (key:match-prefix? prefix nkey))) (and ckey (key->list ckey)))))) (define (make-prever handle key-dimension column-types index) (define bt (handle->bt handle)) (define ldx (- (length column-types) key-dimension)) (define prefix (handle->base-id handle)) (define key->list (make-key->list key-dimension column-types)) (define list->key (key-polymerase key-dimension column-types)) (lambda keys (define pkey (bt:prev bt (string-append prefix (list->key (butnthcdr index keys))))) (and pkey (let ((ckey (key:match-prefix? prefix pkey))) (and ckey (key->list ckey)))))) ;;;; getters and putters ;;;Records are stored as multiple copies of the key to which a ;;;one-byte code is appended, identifying the field. If all fields ;;;are primary keys, then KEY:COL0 (a 0 byte) is appended. (define (make-getter-1 prinum types index) (define type (list-ref types (- index prinum))) (let ((proc (or (wb-string->object type) (slib:error 'make-getter-1 'unsupported-type type))) (ci (key:col-field (- index prinum)))) (lambda (handle key) (define val (db:get (handle->bt handle) (string-append (handle->base-id handle) key ci))) ; (print 'ckey ) (and val (proc val))))) ;;;If more than one non-primary value is stored, then use SCAN to ;;;extract the values. (define (make-getter prinum types) (define (wbstr->obj type) (or (wb-string->object type) (slib:error 'make-getter 'unsupported-type type))) (case (- (length types) prinum) ((0) (lambda (handle key) (and (db:get (handle->bt handle) (string-append (handle->base-id handle) key key:col0)) '()))) ((1) (let ((proc (wbstr->obj (list-ref types prinum)))) (lambda (handle key) (define val (db:get (handle->bt handle) (string-append (handle->base-id handle) key key:col1))) (and val (list (proc val)))))) (else (let ((procs (map wbstr->obj (nthcdr prinum types)))) (lambda (handle key) (define lst (list 'dummy)) (define idx 1) (let ((bt (handle->bt handle)) (prefix (string-append (handle->base-id handle) key)) (tail lst)) (define (loop procs) (define val (db:get bt (string-append prefix (bytes idx)))) (cond (val (set-cdr! tail (list ((car procs) val))) (set! tail (cdr tail)) (set! idx (+ 1 idx)) (if (null? (cdr procs)) (cdr lst) (loop (cdr procs)))) (else #f))) (loop procs))))))) (define (make-putter prinum types) (define (obj->wbstr type) (or (object->wb-string type) (slib:error 'make-putter 'unsupported-type type))) (case (- (length types) prinum) ((0) (lambda (handle ckey restcols) (bt:put! (handle->bt handle) (string-append (handle->base-id handle) ckey key:col0) ""))) ((1) (let ((proc (obj->wbstr (list-ref types prinum)))) (lambda (handle ckey restcols) (db:put! (handle->bt handle) (string-append (handle->base-id handle) ckey key:col1) (proc (car restcols)))))) (else (let ((procs (map obj->wbstr (nthcdr prinum types)))) (lambda (handle ckey restcols) (define i 0) (for-each (lambda (proc val) (set! i (+ 1 i)) (db:put! (handle->bt handle) (string-append (handle->base-id handle) ckey (key:col-field i)) (proc val))) procs restcols)))))) ;;;; other table methods. (define (present? handle key) (let* ((kc (string-append (handle->base-id handle) key)) (kcl (string-length kc)) (n (bt:next (handle->bt handle) kc))) (and n (<= (+ 1 kcl) (string-length n) (+ 2 kcl)) (string=? kc (substring n 0 kcl))))) (define (delete handle key) (let ((prefix (string-append (handle->base-id handle) key))) (not (wb:err? (bt:rem* (handle->bt handle) prefix (key:incr prefix)))))) (define (delete* handle key-dimension column-types match-keys) (let ((prefix (string-append (handle->base-id handle) match-keys))) (not (wb:err? (bt:rem* (handle->bt handle) prefix (key:incr prefix)))))) (lambda (operation-name) ;;(require 'trace) #+foo ; To trace methods use this wrapper: ((lambda (proc) (if (procedure? proc) (lambda args (let ((ans (apply proc args))) (if (procedure? ans) (tracef ans operation-name) ans))) proc)) ) (case operation-name ((make-base) make-base) ((open-base) open-base) ((write-base) write-base) ((sync-base) sync-base) ((close-base) close-base) ((make-table) make-table) ((open-table) open-table) ((kill-table) kill-table) ((make-keyifier-1) make-keyifier-1) ((make-list-keyifier) key-polymerase) ((make-key->list) make-key->list) ((make-key-extractor) make-key-extractor) ((supported-type?) supported-type?) ((supported-key-type?) supported-key-type?) ((present?) present?) ((make-putter) make-putter) ((make-getter) make-getter) ((make-getter-1) make-getter-1) ((delete) delete) ((delete*) delete*) ((for-each-key) ordered-for-each-key) ((map-key) map-key) ((ordered-for-each-key) ordered-for-each-key) ((make-nexter) make-nexter) ((make-prever) make-prever) ((catalog-id) catalog-id) (else #f)) ))) (set! *base-table-implementations* (cons (list 'rwb-isam (make-relational-system rwb-isam)) *base-table-implementations*)) ;;(trace bt:scan bt:get make-getter map-key ordered-for-each-key make-key-extractor make-key->list) (set! *qp-width* 333) ;;(trace-all "rwb-isam.scm") scm-5e5/syntest2.scm0000644001705200017500000001100010750212630012315 0ustar tbtb;;;; "syntest2.scm" Test macros. ;; Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. ;; ;; 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 3 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, see ;; . (require 'macro) ;; Redefine some derived special forms. (define-syntax let (syntax-rules () ((let ((?name ?val) ...) . ?body) ((lambda (?name ...) . ?body) ?val ...)) ((let ?proc ((?name ?val) ...) . ?body) (let ((?proc #f) (?name ?val) ...) (set! ?proc (lambda (?name ...) . ?body)) (?proc ?name ...))))) (define-syntax let* (syntax-rules () ((let* () . ?body) ((lambda () . ?body))) ((let* ((?name ?val)) . ?body) ((lambda (?name) . ?body) ?val)) ((let* ((?name ?val) ?binding ...) . ?body) (let* ((?name ?val)) (let* (?binding ...) . ?body))))) (define-syntax letrec (syntax-rules () ((letrec ((?name ?val) ...) . ?body) (let ((?name #f) ...) (set! ?name ?val) ... (let () . ?body))))) (define-syntax and (syntax-rules () ((and) #t) ((and ?exp) (let ((x ?exp)) (if x x #f))) ((and ?exp . ?rest) (let ((x ?exp)) (if x (and . ?rest) #f))))) (define-syntax or (syntax-rules () ((or) #f) ((or ?exp) (let ((x ?exp)) (if x x #f))) ((or ?exp . ?rest) (let ((x ?exp)) (if x x (or . ?rest)))))) (define (force promise) (promise)) (define (make-promise proc) (let ((result #f)) (lambda () (if result (car result) (let ((x (proc))) (if result (car result) (begin (set! result (list x)) x))))))) (define-syntax delay (syntax-rules () ((delay ?expr) (make-promise (lambda () ?expr))))) (define-syntax do (syntax-rules () ((do ((?name ?init . ?step) ...) (?test . ?result) ?body ...) (let-syntax ((do-step (syntax-rules () ((do-step ?n) ?n) ((do-step ?n ?s) ?s))) (do-result (syntax-rules () ((do-result) (if #f #f)) ((do-result . ?r) (begin . ?r))))) (let loop ((?name ?init) ...) (if ?test (do-result . ?result) (begin ?body ... (loop (do-step ?name . ?step) ...)))))))) (define-syntax case (syntax-rules (else) ((case ?x (else . ?conseq)) (begin . ?conseq)) ((case ?x (?lst . ?conseq)) (if (memv ?x '?lst) (begin . ?conseq))) ((case ?x (?lst . ?conseq) . ?rest) (if (memv ?x '?lst) (begin . ?conseq) (case ?x . ?rest))))) (define-syntax cond (syntax-rules (else =>) ((cond ?clause0 . ?clauses) (letrec-syntax ((cond-aux (syntax-rules (else =>) ((cond-aux) (if #f #f)) ((cond-aux (else . ?conseq)) (begin . ?conseq)) ((cond-aux (?test => ?proc) . ?rest) (let ((val ?test)) (if val (?proc val) (cond-aux . ?rest)))) ((cond-aux (?test) . ?rest) (or ?test (cond-aux . ?rest))) ((cond-aux (?test . ?conseq) . ?rest) (if ?test (begin . ?conseq) (cond-aux . ?rest)))))) (cond-aux ?clause0 . ?clauses))))) ;; This may fail if you redefine CONS, LIST, APPEND, or LIST->VECTOR ;; It uses the (... ...) escape. ;; All forms are evaluated inside a LETREC-SYNTAX body (is this a problem?). (define-syntax quasiquote (syntax-rules () ((_ ?template) (letrec-syntax ((qq (syntax-rules (unquote unquote-splicing quasiquote) ((_ (unquote ?form) ()) ?form) ((_ (unquote ?form) (?depth)) (list 'unquote (qq ?form ?depth))) ((_ (quasiquote ?form) ?depth) (list 'quasiquote (qq ?form (?depth)))) ((_ ((unquote-splicing ?form) . ?rest) ()) (append ?form (qq ?rest ()))) ((_ ((unquote-splicing ?form) . ?rest) (?depth)) (append (list 'unquote-splicing (qq ?form ?depth)) (qq ?rest (?depth)))) ((_ (?car . ?cdr) ?depth) (cons (qq ?car ?depth) (qq ?cdr ?depth))) ((_ #(?elt (... ...)) ?depth) (list->vector (qq (?elt (... ...)) ?depth))) ((_ ?atom ?depth) '?atom)))) (qq ?template ()))))) ;;(load "r4rstest.scm") scm-5e5/rope.c0000644001705200017500000002434310750224171011150 0ustar tbtb/* "rope.c" interface between C and SCM. * Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1997, 2006 Free Software Foundation, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see * . */ /* Author: Aubrey Jaffer */ #include "scm.h" /* Numeric conversions */ /* Convert longs to SCM */ SCM long2num(sl) long sl; { if (!FIXABLE(sl)) { # ifdef BIGDIG return long2big(sl); # else # ifdef FLOATS return makdbl((double) sl, 0.0); # else return BOOL_F; # endif # endif } return MAKINUM(sl); } SCM ulong2num(sl) unsigned long sl; { if (!POSFIXABLE(sl)) { #ifdef BIGDIG return ulong2big(sl); #else # ifdef FLOATS return makdbl((double) sl, 0.0); # else return BOOL_F; # endif #endif } return MAKINUM(sl); } /* Convert SCM to numbers */ unsigned char num2uchar(num, pos, s_caller) SCM num; char *pos, *s_caller; { unsigned long res = INUM(num); ASRTER(INUMP(num) && (255L >= res), num, pos, s_caller); return (unsigned char) res; } unsigned short num2ushort(num, pos, s_caller) SCM num; char *pos, *s_caller; { unsigned long res = INUM(num); ASRTER(INUMP(num) && (65535L >= res), num, pos, s_caller); return (unsigned short) res; } unsigned long num2ulong(num, pos, s_caller) SCM num; char *pos, *s_caller; { unsigned long res; if (INUMP(num)) { ASRTGO(0 < num, errout); res = INUM((unsigned long)num); return res; } ASRTGO(NIMP(num), errout); #ifdef FLOATS if (REALP(num)) { double u = REALPART(num); if ((0 <= u) && (u <= (unsigned long)~0L)) { res = u; return res; } } #endif #ifdef BIGDIG if (TYP16(num)==tc16_bigpos) { sizet l = NUMDIGS(num); ASRTGO(DIGSPERLONG >= l, errout); res = 0; for (;l--;) res = BIGUP(res) + BDIGITS(num)[l]; return res; } #endif errout: wta(num, pos, s_caller); } long num2long(num, pos, s_caller) SCM num; char *pos, *s_caller; { long res; if (INUMP(num)) { res = INUM((long)num); return res; } ASRTGO(NIMP(num), errout); # ifdef FLOATS if (REALP(num)) { double u = REALPART(num); if (((MOST_NEGATIVE_FIXNUM * 4) <= u) && (u <= (MOST_POSITIVE_FIXNUM * 4 + 3))) { res = u; return res; } } # endif # ifdef BIGDIG if (BIGP(num)) { sizet l = NUMDIGS(num); ASRTGO(DIGSPERLONG >= l, errout); res = 0; for (;l--;) res = BIGUP(res) + BDIGITS(num)[l]; ASRTGO(0 i) for (i = 0; argv[i]; i++); while (i--) lst = cons(makfrom0str(argv[i]), lst); return lst; } /* Converts SCM list of strings to NULL terminated array of strings. */ /* INTS must be DEFERed around this call and the use of the returned array. */ char **makargvfrmstrs(args, s_name) SCM args; const char *s_name; { char ** argv; int argc = ilength(args); argv = (char **)must_malloc((1L+argc)*sizeof(char *), s_vector); for (argc = 0; NNULLP(args); args=CDR(args), ++argc) { ASRTER(NIMP(CAR(args)) && STRINGP(CAR(args)), CAR(args), ARG2, s_name); { sizet len = 1 + LENGTH(CAR(args)); char *dst = (char *)must_malloc((long)len, s_string); char *src = CHARS(CAR(args)); while (len--) dst[len] = src[len]; argv[argc] = dst; } } argv[argc] = 0; return argv; } void must_free_argv(argv) char **argv; { sizet i; for (i = 0; argv[i]; i++) { must_free(argv[i], 1+strlen(argv[i])); } must_free((char *)argv, i*sizeof(char *)); } /* Hooks to call SCM from C */ SCM scm_evstr(str) char *str; { SCM lsym; NEWCELL(lsym); SETLENGTH(lsym, strlen(str), tc7_ssymbol); SETCHARS(lsym, str); return scm_eval_string(lsym); } void scm_ldstr(str) char *str; { SCM lsym; NEWCELL(lsym); SETLENGTH(lsym, strlen(str), tc7_ssymbol); SETCHARS(lsym, str); scm_load_string(lsym); } int scm_ldfile(path) char *path; { SCM name = makfrom0str(path); *loc_errobj = name; return BOOL_F==tryload(name, UNDEFINED); } int scm_ldprog(path) char *path; { SCM name = makfrom0str(path); *loc_errobj = name; return BOOL_F==scm_evstr("(try-load (in-vicinity (program-vicinity) errobj))"); } /* Get byte address of SCM array */ #ifdef ARRAYS long aind P((SCM ra, SCM args, const char *what)); unsigned long scm_addr(args, s_name) SCM args; const char *s_name; { long pos; unsigned long ptr = 0; /* gratuitous assignment squelches cc warn. */ SCM v; ASRTGO(NIMP(args), wna); v = CAR(args); args = CDR(args); if (IMP(v)) {goto badarg;} else if (ARRAYP(v)) { pos = aind(v, args, s_name); v = ARRAY_V(v); } else { if (NIMP(args)) { ASRTER(CONSP(args) && INUMP(CAR(args)), args, ARG2, s_name); pos = INUM(CAR(args)); ASRTGO(NULLP(CDR(args)), wna); } else if (NULLP(args)) pos = 0; else { ASRTER(INUMP(args), args, ARG2, s_name); pos = INUM(args); } ASRTGO(pos >= 0 && pos < LENGTH(v), outrng); } switch TYP7(v) { case tc7_string: ptr = (unsigned long)&(CHARS(v)[pos]); break; # ifdef FLOATS # ifdef SINGLES case tc7_VfloC32: pos = 2 * pos; case tc7_VfloR32: ptr = (unsigned long)&(((float *)CDR(v))[pos]); break; # endif case tc7_VfloC64: pos = 2 * pos; case tc7_VfloR64: ptr = (unsigned long)&(((double *)CDR(v))[pos]); break; # endif case tc7_Vbool: ASRTGO(0==(pos%LONG_BIT), outrng); pos = pos/LONG_BIT; case tc7_VfixN32: case tc7_VfixZ32: case tc7_vector: ptr = (unsigned long)&(VELTS(v)[pos]); break; case tc7_VfixN16: case tc7_VfixZ16: ptr = (unsigned long)&(((short *)CDR(v))[pos]); break; case tc7_VfixN8: case tc7_VfixZ8: ptr = (unsigned long)&(((char *)CDR(v))[pos]); break; outrng: wta(MAKINUM(pos), (char *)OUTOFRANGE, s_name); default: badarg: wta(v, (char *)ARG1, s_name); wna: wta(UNDEFINED, (char *)WNA, s_name); } return ptr; } unsigned long scm_base_addr(v, s_name) SCM v; const char *s_name; { long pos = 0; unsigned long ptr = 0; /* gratuitous assignment squelches cc warn. */ if (IMP(v)) {goto badarg;} else if (ARRAYP(v)) { pos = ARRAY_BASE(v); v = ARRAY_V(v); } switch TYP7(v) { case tc7_string: ptr = (unsigned long)&(CHARS(v)[pos]); break; # ifdef FLOATS # ifdef SINGLES case tc7_VfloC32: pos = 2 * pos; case tc7_VfloR32: ptr = (unsigned long)&(((float *)CDR(v))[pos]); break; # endif case tc7_VfloC64: pos = 2 * pos; case tc7_VfloR64: ptr = (unsigned long)&(((double *)CDR(v))[pos]); break; # endif case tc7_Vbool: ASRTGO(0==(pos%LONG_BIT), outrng); pos = pos/LONG_BIT; case tc7_VfixN32: case tc7_VfixZ32: case tc7_vector: ptr = (unsigned long)&(VELTS(v)[pos]); break; case tc7_VfixN16: case tc7_VfixZ16: ptr = (unsigned long)&(((short *)CDR(v))[pos]); break; case tc7_VfixN8: case tc7_VfixZ8: ptr = (unsigned long)&(((char *)CDR(v))[pos]); break; outrng: wta(MAKINUM(pos), (char *)OUTOFRANGE, s_name); default: badarg: wta(v, (char *)ARG1, s_name); } return ptr; } #endif /* ARRAYS */ extern sizet hplim_ind; extern CELLPTR *hplims; /* scm_cell_p() returns !0 if the SCM argument `x' is cell-aligned and points into a valid heap segment. This code is duplicated from mark_locations() and obunhash() in "sys.c", which means that changes to these routines must be coordinated. */ int scm_cell_p(x) SCM x; { register int i, j; register CELLPTR ptr; if (NCELLP(x)) return 0; ptr = (CELLPTR)SCM2PTR(x); i = 0; j = hplim_ind; do { if (PTR_GT(hplims[i++], ptr)) break; if (PTR_LE(hplims[--j], ptr)) break; if ((i != j) && PTR_LE(hplims[i++], ptr) && PTR_GT(hplims[--j], ptr)) continue; return !0; /* NFREEP(x) */ } while(i= len) resizuve(scm_uprotects, MAKINUM(len + (len>>2))); VELTS(scm_uprotects)[scm_protidx++] = obj; return obj; } void init_rope() { scm_protidx = 0; scm_uprotects = make_vector(MAKINUM(20), UNDEFINED); } scm-5e5/scm.spec0000644001705200017500000001370010751430437011475 0ustar tbtb%define name scm %define version 5e5 %define release 1 %define implpath %{prefix}/lib/scm %define slibpath %{prefix}/lib/slib %define dumparch setarch i386 # rpm seems to require all on one line, bleah. %define features cautious bignums arrays inexact dump dynamic-linking macro engineering-notation Name: %{name} Release: %{release} Version: %{version} Packager: Aubrey Jaffer License: GPL Vendor: Aubrey Jaffer Group: Development/Languages Provides: scm Requires: slib Summary: SCM Scheme implementation Source: ftp://swiss.csail.mit.edu/pub/scm/scm-%{version}.zip URL: http://swiss.csail.mit.edu/~jaffer/SCM BuildRoot: %{_tmppath}/%{name}-%{version} Prefix: /usr %description Scm conforms to Revised^5 Report on the Algorithmic Language Scheme and the IEEE P1178 specification. Scm provides a machine independent platform for JACAL, a symbolic algebra system. This distribution requires libdl.so from the glibc-devel package and the slib Scheme library package. If your machine lacks XFree86 or readline, install with --nodeps. %define __os_install_post /usr/lib/rpm/brp-compress %prep rm -rf /var/tmp/%{name}-%{version} %setup -n scm -c -T cd .. unzip $RPM_SOURCE_DIR/scm-%{version}.zip %build # SLIB is required to build SCM. if [ -n "$SCHEME_LIBRARY_PATH" ]; then echo using SLIB $SCHEME_LIBRARY_PATH elif [ -d %{slibpath} ]; then export SCHEME_LIBRARY_PATH=%{slibpath}/ elif [ -d %{prefix}/share/slib ]; then export SCHEME_LIBRARY_PATH=%{prefix}/share/slib/ fi make scmlit make clean export PATH=.:$PATH # to get scmlit in the path. # Build the executable. ./build -h system -o udscm5 --compiler-options="-O3" -l debug -s %{implpath} -F %{features} echo "(quit)" | ./udscm5 -no-init-file -r5 -o scm make check # Build dlls make x.so ./build -h system -t dll -F curses --compiler-options="-O3" ./build -h system -t dll -c differ.c --compiler-options="-O3" ./build -h system -t dll -c sc2.c --compiler-options="-O3" ./build -h system -t dll -c rgx.c --compiler-options="-O3" ./build -h system -t dll -c record.c --compiler-options="-O3" ./build -h system -t dll -c gsubr.c --compiler-options="-O3" ./build -h system -t dll -c ioext.c --compiler-options="-O3" ./build -h system -t dll -c posix.c --compiler-options="-O3" ./build -h system -t dll -c unix.c --compiler-options="-O3" ./build -h system -t dll -c socket.c --compiler-options="-O3" ./build -h system -t dll -c ramap.c --compiler-options="-O3" ./build -h system -t dll -c byte.c --compiler-options="-O3" ./build -h system -t dll -F edit-line --compiler-options="-O3" ./build -h system -t dll -F x --compiler-options="-O3" # Build libscm.a static library ./build -h system -F cautious bignums arrays inexact dynamic-linking -t lib \ --compiler-options="-O3" %install mkdir -p ${RPM_BUILD_ROOT}%{prefix}/bin mkdir -p ${RPM_BUILD_ROOT}%{prefix}/lib/scm mkdir -p ${RPM_BUILD_ROOT}%{prefix}/man/man1 make prefix=${RPM_BUILD_ROOT}%{prefix}/ install make prefix=${RPM_BUILD_ROOT}%{prefix}/ installlib rm -f ${RPM_BUILD_ROOT}%{prefix}/bin/scm cp udscm5 ${RPM_BUILD_ROOT}%{prefix}/bin/ # Assume SLIB is in %{slibpath}, as installed by the slib rpm. cat > ${RPM_BUILD_ROOT}%{prefix}/lib/scm/require.scm < %{prefix}/bin/scm"; then rm -f %{prefix}/local/bin/scm fi if [ -L %{prefix}/local/lib/scm ] && \ ls -l %{prefix}/local/lib/scm | grep -q "> %{prefix}/lib/scm"; then rm -f %{prefix}/local/lib/scm fi rm -f %{prefix}/bin/scm %files %defattr(-, root, root) %{prefix}/bin/scmlit %{prefix}/bin/udscm5 %dir %{prefix}/lib/scm # No wildcards here because we need to segregate files by package. %{prefix}/lib/scm/crs.so %{prefix}/lib/scm/gsubr.so %{prefix}/lib/scm/posix.so %{prefix}/lib/scm/record.so %{prefix}/lib/scm/sc2.so %{prefix}/lib/scm/unix.so %{prefix}/lib/scm/ioext.so %{prefix}/lib/scm/ramap.so %{prefix}/lib/scm/socket.so %{prefix}/lib/scm/rgx.so %{prefix}/lib/scm/Init%{version}.scm %{prefix}/lib/scm/require.scm %{prefix}/lib/scm/Macexp.scm %{prefix}/lib/scm/Macro.scm %{prefix}/lib/scm/Tscript.scm %{prefix}/lib/scm/Transcen.scm %{prefix}/lib/scm/mkimpcat.scm %{prefix}/lib/scm/Link.scm %{prefix}/lib/scm/compile.scm %{prefix}/lib/scm/hobbit.scm %{prefix}/lib/scm/scmhob.scm %{prefix}/lib/scm/scmhob.h %{prefix}/lib/scm/patchlvl.h %{prefix}/lib/scm/build.scm %{prefix}/lib/scm/build %{prefix}/lib/scm/Iedline.scm %{prefix}/lib/scm/edline.so %{prefix}/lib/scm/Idiffer.scm %{prefix}/lib/scm/differ.so %{prefix}/lib/scm/x.so %{prefix}/lib/scm/xevent.scm %{prefix}/lib/scm/xatoms.scm %{prefix}/lib/scm/x11.scm %{prefix}/lib/scm/keysymdef.scm %{prefix}/lib/scm/r4rstest.scm %{prefix}/lib/scm/byte.so # %{prefix}/lib/scm/db.so %{prefix}/lib/scm/wbtab.scm %{prefix}/lib/scm/rwb-isam.scm %{prefix}/lib/scm/COPYING %{prefix}/lib/scm/COPYING.LESSER %{prefix}/info/Xlibscm.info.gz %{prefix}/info/hobbit.info.gz %{prefix}/info/scm.info.gz %{prefix}/man/man1/scm.1.gz %{prefix}/lib/libscm.a %{prefix}/include/scm.h %{prefix}/include/scmfig.h %{prefix}/include/scmflags.h %doc ANNOUNCE COPYING COPYING.LESSER QUICKREF README ChangeLog %changelog scm-5e5/Macro.scm0000644001705200017500000003435410750210226011603 0ustar tbtb;;;; "Macro.scm", Support for syntax-rules macros. ;; Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc. ;; ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU Lesser General Public License as ;; published by the Free Software Foundation, either version 3 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 ;; Lesser General Public License for more details. ;; ;; You should have received a copy of the GNU Lesser General Public ;; License along with this program. If not, see ;; . ;;; Author: Radey Shouman ;; ;; As in SYNTAX-CASE, the identifier ... may be quoted in a ;; SYNTAX-RULES pattern or template as (... ...). ;; ;; THE-MACRO may be used to define macros, eg ;; (define-syntax foo (the-macro and)) ;; defines the syntactic keyword FOO to have the same transformer ;; as the macro AND. (require 'rev2-procedures) ;append! (require 'record) (define macro:compile-syntax-rules ;; We keep local copies of these standard special forms, otherwise, ;; redefining them before they are memoized below can lead to ;; infinite recursion. (let-syntax ((lambda (the-macro lambda)) (begin (the-macro begin)) (quote (the-macro quote)) (let (the-macro let)) (let* (the-macro let*)) (letrec (the-macro letrec)) (and (the-macro and)) (or (the-macro or)) (delay (the-macro delay)) (do (the-macro do)) (case (the-macro case)) (cond (the-macro cond)) (quasiquote (the-macro quasiquote))) (let ((var-rtd (make-record-type '? '(name rank))) (e-pat-rtd (make-record-type '... '(pattern vars))) (rule-rtd (make-record-type 'rule '(pattern inserted template)))) (define pattern-variable (record-constructor var-rtd '(name rank))) (define pattern-variable? (record-predicate var-rtd)) (define pattern-variable->name (let ((acc (record-accessor var-rtd 'name))) (lambda (x) (identifier->symbol (acc x))))) (define pattern-variable->rank (record-accessor var-rtd 'rank)) ;; An ellipsis-pattern is used both for ellipses in patterns and ;; ellipses in templates. In a pattern, VARS is the list of variables ;; bound by the ellipsis pattern. In a template, VARS is the list of ;; variables opened by the ellipsis template. (define ellipsis-pattern (record-constructor e-pat-rtd '(pattern vars))) (define ellipsis-pattern? (record-predicate e-pat-rtd)) (define ellipsis-pattern->pattern (record-accessor e-pat-rtd 'pattern)) (define ellipsis-pattern->vars (record-accessor e-pat-rtd 'vars)) (define make-rule (record-constructor rule-rtd '(pattern inserted template))) (define rule->pattern (record-accessor rule-rtd 'pattern)) (define rule->inserted (record-accessor rule-rtd 'inserted)) (define rule->template (record-accessor rule-rtd 'template)) (define (append2 x y) (if (null? y) x (append x y))) (define (append-if pred x y) (let recur ((x x)) (cond ((null? x) y) ((pred (car x)) (cons (car x) (recur (cdr x)))) (else (recur (cdr x)))))) (define ellipsis? (let (($... (renamed-identifier '... #f))) (lambda (x env) (and (identifier? x) (identifier-equal? x $... env))))) ;; Yeah, it's quadratically slow. (define (duplicates? vars) (if (null? vars) #f (if (memq (car vars) (cdr vars)) (car vars) (duplicates? (cdr vars))))) (define (compile-pattern literals rule-exp env-def) (define (compile1 pat vars rank ell? k) (cond ((null? pat) (k pat vars)) ((identifier? pat) (if (or (memq pat literals) (and (not ell?) (ellipsis? pat env-def))) (k (renamed-identifier pat env-def) vars) (let ((var (pattern-variable pat rank))) (k var (cons (cons pat var) vars))))) ((vector? pat) (compile1 (vector->list pat) vars rank ell? (lambda (comp vars) (k (list->vector comp) vars)))) ((not (pair? pat)) (k pat vars)) ((and ell? (ellipsis? (car pat) env-def)) (or (and (pair? (cdr pat)) (null? (cddr pat))) (error "bad ellipsis quote:" pat)) (compile1 (cadr pat) vars rank #f k)) ((and ell? (pair? (cdr pat)) (ellipsis? (cadr pat) env-def)) (or (null? (cddr pat)) (error "bad ellipsis:" pat)) (compile1 (car pat) '() (+ rank 1) ell? (lambda (comp1 vars1) (k (list (ellipsis-pattern comp1 (map cdr vars1))) (append2 vars1 vars))))) (else ; pat is a pair (compile1 (car pat) '() rank ell? (lambda (comp1 vars1) (compile1 (cdr pat) vars rank ell? (lambda (comp2 vars2) (k (cons comp1 comp2) (append2 vars1 vars2))))))))) (let ((pat (car rule-exp)) (tmpl (cadr rule-exp))) (if (identifier? pat) (apply make-rule #f (rewrite-template tmpl '() env-def)) (compile1 (cdr pat) '() 0 #t (lambda (compiled vars) (let ((dup (duplicates? (map car vars)))) (if dup (error "syntax-rules: duplicate pattern variable:" dup " in rule " rule-exp) (apply make-rule (cons #f compiled) (rewrite-template tmpl vars env-def))))))))) (define (rewrite-template template vars env-def) (let rewrite1 ((tmpl template) (rank 0) (inserted '()) (ell? #t) (k (lambda (compiled inserted opened) (list inserted compiled)))) (cond ((null? tmpl) (k tmpl '() '())) ((identifier? tmpl) (let ((v (assq tmpl vars))) (cond ((not v) (k tmpl (list tmpl) '())) ((zero? (pattern-variable->rank (cdr v))) (k (cdr v) '() '())) ((>= rank (pattern-variable->rank (cdr v))) (k (cdr v) '() (list (cdr v)))) (else (error "pattern variable rank mismatch:" tmpl " in " template))))) ((vector? tmpl) (rewrite1 (vector->list tmpl) rank inserted ell? (lambda (compiled inserted opened) (k (list->vector compiled) inserted opened)))) ((not (pair? tmpl)) (k tmpl '() '())) ((and ell? (ellipsis? (car tmpl) env-def)) ;; (... ...) escape (or (and (pair? (cdr tmpl)) (null? (cddr tmpl))) (error "Bad ellpsis quote:" tmpl " in template " template)) (rewrite1 (cadr tmpl) rank inserted #f k)) ((and ell? (pair? (cdr tmpl)) (ellipsis? (cadr tmpl) env-def)) (rewrite1 (car tmpl) (+ rank 1) '() ell? (lambda (comp1 ins1 op1) (if (null? op1) (error "Bad ellipsis:" tmpl " in template " template)) (rewrite1 (cddr tmpl) rank inserted ell? (lambda (comp2 ins2 op2) (k (cons (ellipsis-pattern comp1 op1) comp2) (append2 ins1 ins2) (append-if (lambda (op) (> (pattern-variable->rank op) rank)) op1 op2))))))) (else ; tmpl is a pair (rewrite1 (car tmpl) rank '() ell? (lambda (comp1 ins1 op1) (rewrite1 (cdr tmpl) rank inserted ell? (lambda (comp2 ins2 op2) (k (cons comp1 comp2) (append2 ins1 ins2) (append2 op1 op2)))))))))) ;;; Match EXP to RULE, returning alist of variable bindings or #f. (define (match rule exp env-use) (define (match1 r x) (cond ((null? r) (and (null? x) '())) ((pair? r) (if (ellipsis-pattern? (car r)) (and (list? x) (let ((pat (ellipsis-pattern->pattern (car r)))) (let match-list ((x x) (vals '())) (if (null? x) (if (null? vals) (map list (ellipsis-pattern->vars (car r))) (let ((vars (map car (car vals)))) (apply map list vars (map (lambda (al) (map cdr al)) (reverse vals))))) (let ((val (match1 pat (car x)))) (and val (match-list (cdr x) (cons val vals)))))))) (and (pair? x) (let ((v1 (match1 (car r) (car x)))) (and v1 (let ((v2 (match1 (cdr r) (cdr x)))) (and v2 (append2 v1 v2)))))))) ((identifier? r) ;literal (and (identifier? x) (identifier-equal? r x env-use) '())) ((pattern-variable? r) (list (cons r x))) ((vector? r) (and (vector? x) (match1 (vector->list r) (vector->list x)))) (else (and (equal? r x) '())))) (let ((pat (rule->pattern rule))) (if (pair? pat) (and (pair? exp) (match1 (cdr pat) (cdr exp))) (if (pair? exp) #f '())))) (define (substitute-in-template x-use rule vars env-def) (define (length-error pats vals) (apply error "syntax-rules: pattern variable length mismatch:\n" x-use (map (lambda (name val) `(,(pattern-variable->name name) -> ,val)) pats vals))) (let ((ins (map (lambda (id) (cons id (renamed-identifier id env-def))) (rule->inserted rule)))) (let subst1 ((tmpl (rule->template rule)) (vars vars)) (cond ((null? tmpl) tmpl) ((pair? tmpl) (if (ellipsis-pattern? (car tmpl)) (let* ((enames (ellipsis-pattern->vars (car tmpl))) (etmpl (ellipsis-pattern->pattern (car tmpl))) (evals (map (lambda (nam) (cdr (assq nam vars))) enames)) (n (length (car evals)))) (let check ((es (cdr evals))) (if (pair? es) (if (= n (length (car es))) (check (cdr es)) (length-error enames evals)))) (append! (map (lambda (eval) (subst1 etmpl (append! (map cons enames eval) vars))) (apply map list evals)) (subst1 (cdr tmpl) vars))) (cons (subst1 (car tmpl) vars) (subst1 (cdr tmpl) vars)))) ((identifier? tmpl) (let ((a (assq tmpl ins))) (if a (cdr a) tmpl))) ((pattern-variable? tmpl) (@copy-tree (cdr (assq tmpl vars)))) ((vector? tmpl) (list->vector (subst1 (vector->list tmpl) vars))) (else tmpl))))) ;; MACRO:COMPILE-SYNTAX-RULES (lambda (x-def env-def) (let ((x-def (remove-line-numbers! x-def))) (or (and (list? x-def) (< 2 (length x-def)) (list? (cadr x-def))) (error "Malformed syntax-rules:" x-def)) (let ((literals (cadr x-def))) (for-each (lambda (x) (or (identifier? x) (error "Bad literals list:" x-def))) literals) (let ((rules (map (lambda (rule-expr) (or (and (list? rule-expr) (= 2 (length rule-expr)) (let ((pat (car rule-expr))) (or (pair? pat) (identifier? pat)))) (error "Bad rule:" rule-expr)) (compile-pattern literals rule-expr env-def)) (cddr x-def)))) (lambda (x-use env-use) ;;FIXME We should use the line numbers. (let ((x-use (remove-line-numbers! x-use))) (let loop ((rules rules)) (cond ((null? rules) (error "macro use does not match definition:" x-use)) ((match (car rules) x-use env-use) => (lambda (vars) (substitute-in-template x-use (car rules) vars env-def))) (else (loop (cdr rules)))))))))))))) (define-syntax syntax-rules (procedure->syntax (lambda (expr env-def) (let ((transformer (macro:compile-syntax-rules expr env-def))) (let loop ((rules (cddr expr))) (cond ((null? rules) (procedure->memoizing-macro transformer)) ((identifier? (caar rules)) (procedure->identifier-macro transformer)) (else (loop (cdr rules))))))))) ;; Explicit renaming macro facility, as in ;; W. Clinger, "Hygienic Macros Through Explicit Renaming" (define (macro:renaming-transformer-procedure proc env-def) (procedure->memoizing-macro (lambda (expr env-use) (proc (@copy-tree expr) (let ((al '())) (lambda (id) (cond ((not (identifier? id)) (error id "non-identifier passed to rename procedure" expr)) ((assq id al) => cdr) (else (let ((r-id (renamed-identifier id env-def))) (set! al (cons id r-id)) r-id))))) (lambda (id1 id2) (or (and (identifier? id1) (identifier? id2) (error (if (identifier? id1) id2 id1) "non-identifier passed to compare procedure" expr))) (identifier-equal? id1 id2 env-use)))))) (define renaming-transformer (let ((?transformer (renamed-identifier 'macro:renaming-transformer-procedure #f)) (?syntax-quote (renamed-identifier 'syntax-quote #f))) (procedure->memoizing-macro (lambda (exp env-def) `(,?transformer ,(cadr exp) (,?syntax-quote ,env-def)))))) (define macro:load load) (define macro:eval eval) (define (macro:expand . args) (load (in-vicinity (implementation-vicinity) "Macexp")) (apply macro:expand args)) (provide 'macro) ;; These are not part of the SYNTAX-RULES implementation, but I see ;; no better place to put them: ;; A debugging utility macro that is easy to grep for. (define-syntax @print (syntax-rules (quote) ((_ '?arg) (begin (write '?arg) (newline))) ((_ ?arg) (begin (write '?arg) (display " => ") (let ((x ?arg)) (write x) (newline) x))) ((_ ?arg1 ?arg ...) (begin (@print ?arg1) (begin (display " ") (@print ?arg)) ...)))) (define-syntax @pprint (syntax-rules (quote) ((_ '?arg) (begin (write '?arg) (newline))) ((_ ?arg) (begin (write '?arg) (display " => ") (let ((x ?arg)) (pprint x) (newline) x))) ((_ ?arg1 ?arg ...) (begin (@pprint ?arg1) (begin (display " ") (@pprint ?arg)) ...)))) ;; Better run time error reporting than the version in Init*.scm, ;; also only takes a given car or cdr once. (define-syntax destructuring-bind (syntax-rules () ((_ "PARSE-LLIST" () ?val ?body ?err) (if (null? ?val) ?body (?err '() ?val))) ((_ "PARSE-LLIST" (?name1 . ?rest) ?val ?body ?err) (if (pair? ?val) (let ((carv (car ?val)) (cdrv (cdr ?val))) (destructuring-bind "PARSE-LLIST" ?name1 carv (destructuring-bind "PARSE-LLIST" ?rest cdrv ?body ?err) ?err)) (?err '(?name1 . ?rest) ?val))) ((_ "PARSE-LLIST" ?name ?val ?body ?err) (let ((?name ?val)) ?body)) ((_ ?llist ?val ?body1 ?body ...) (let ((err (lambda (pat val) (slib:error 'destructuring-bind '?llist val "does not match" pat))) (val ?val)) (destructuring-bind "PARSE-LLIST" ?llist val ;;Use LET to allow internal DEFINE in body. (let () ?body1 ?body ...) err))))) scm-5e5/pi.c0000644001705200017500000000320710750231232010603 0ustar tbtb/* "pi.c", program for computing digits of numerical value of PI. * Copyright (C) 1991 1995 Free Software Foundation, Inc. * * 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 3 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, see * . */ /* Author: Aubrey Jaffer pi prints out digits of pi in groups of digits. 'Spigot' algorithm origionally due to Stanly Rabinowitz. This algorithm takes time proportional to the square of /. This fact can make comparisons of computational speed between systems of vastly differring performances quicker and more accurate. Try: pi 100 5 The digit size will have to be reduced for larger or an error due to overflow will occur. */ short *calloc(); main(c,v) int c;char **v;{ int n=200,j=0,m,b=2,k=0,t,r=1,d=5; long q; short *a; if(c>1)n=atoi(v[1]); if(c>2)d=atoi(v[2]); while(k++. ;;; Author: Aubrey Jaffer. (require 'transcript) (require-if 'inexact 'root) (require-if 'inexact 'printf) (require 'random) (require 'array) ;;(load (in-vicinity (implementation-vicinity) "prng-v.scm")) (load (in-vicinity (implementation-vicinity) "pi.scm")) (define isqrt (cond ((provided? 'inexact) sqrt) (else (require 'root) integer-sqrt))) (define i/ (cond ((provided? 'inexact) /) (else quotient))) (define around (cond ((provided? 'inexact) (let () (require 'printf) (lambda (x prec) (sprintf #f "%.*g" prec x)))) (else (lambda (x prec) x)))) (define (time-call proc . args) (let ((start-time (get-internal-run-time))) (apply proc args) (i/ (* 1000 (- (get-internal-run-time) start-time)) internal-time-units-per-second))) (define (benchmark-pi . arg) (define file (if (null? arg) "pi.log" (car arg))) (do ((digits 50 (+ digits digits)) (t 0 (time-call pi (+ digits digits) 4))) ((> t 3600) (do ((tl '() (cons (time-call pi digits 4) tl)) (j 12 (+ -1 j))) ((zero? j) (let* ((avg (i/ (apply + tl) (length tl))) (dev (isqrt (i/ (apply + (map (lambda (x) (* (- x avg) (- x avg))) tl)) (length tl))))) (and file (transcript-on file)) (for-each display (list digits " digits of pi took " (around avg 4) ".ms" " +/- " (around dev 2) ".ms")) (newline) (let ((scaled-avg (i/ (* (i/ (* avg 1000) digits) 1000) digits)) (scaled-dev (i/ (* (i/ (* dev 1000) digits) 1000) digits))) (for-each display (list " That is about " (around scaled-avg 4) ".ms/(kB)^2" " +/- " (around scaled-dev 2) ".ms/(kB)^2")) (newline) (and file (transcript-off))) )))))) (define (prng samples modu sta) (define sra (make-array (A:fixN32b) samples)) (do ((cnt (+ -1 samples) (+ -1 cnt)) (num (random modu sta) (random modu sta)) (sum 0 (+ sum num))) ((negative? cnt) (set! sum (+ sum num)) (let ((mean (i/ sum samples))) (define (square-diff x) (define z (- x mean)) (* z z)) (do ((cnt (+ -1 samples) (+ -1 cnt)) (var2 0 (+ (square-diff (array-ref sra cnt)) var2))) ((negative? cnt) (for-each display (list sum " / " samples " = " mean " +/- " (isqrt (i/ var2 samples)))) (newline))))) (array-set! sra num cnt))) (define (benchmark-prng . arg) (define file (if (null? arg) "prng.log" (car arg))) (define sta (seed->random-state "http://swissnet.ai.mit.edu/~jaffer/SLIB.html")) (do ((samples 125 (* 4 samples)) (t 0 (time-call prng (* 2 samples) 999 sta))) ((or (> t 1000) (and (not (provided? 'bignum)) (> samples 1000))) (do ((tl '() (cons (time-call prng samples 999 sta) tl)) (j 12 (+ -1 j))) ((zero? j) (let* ((avg (i/ (apply + tl) (length tl))) (dev (isqrt (i/ (apply + (map (lambda (x) (* (- x avg) (- x avg))) tl)) (length tl))))) (and file (transcript-on file)) (for-each display (list samples " random samples took " (around avg 4) ".ms" " +/- " (around dev 2) ".ms")) (newline) (let ((scaled-avg (i/ (* avg 1000) samples)) (scaled-dev (i/ (* dev 1000) samples))) (for-each display (list " That is about " (around scaled-avg 4) ".ms/kB" " +/- " (around scaled-dev 2) ".ms/kB")) (newline) (and file (transcript-off))))))))) (benchmark-prng) (newline) (benchmark-pi) scm-5e5/Xlibscm.info0000644001705200017500000030566510750527323012333 0ustar tbtbThis is Xlibscm.info, produced by makeinfo version 4.8 from Xlibscm.texi. This manual documents the X Interface for SCM Language (version 5e5, February 2008). Copyright (C) 1999 Free Software Foundation, Inc. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the author. INFO-DIR-SECTION The Algorithmic Language Scheme START-INFO-DIR-ENTRY * XlibScm: (XlibScm). SCM Language X Interface. END-INFO-DIR-ENTRY  File: Xlibscm.info, Node: Top, Next: XlibScm, Prev: (dir), Up: (dir) XlibScm ******* This manual documents the X Interface for SCM Language (version 5e5, February 2008). Copyright (C) 1999 Free Software Foundation, Inc. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the author. * Menu: * XlibScm:: * Display and Screens:: * Drawables:: * Graphics Context:: * Cursor:: * Colormap:: * Rendering:: * Images:: * Event:: * Indexes::  File: Xlibscm.info, Node: XlibScm, Next: Display and Screens, Prev: Top, Up: Top 1 XlibScm ********* "XlibScm" is a SCM interface to "X". The X Window System is a network-transparent window system that was designed at MIT. SCM is a portable Scheme implementation written in C. The interface can be compiled into SCM or, on those platforms supporting dynamic linking, compiled separately and loaded with `(require 'Xlib)'. Much of this X documentation is dervied from: Xlib - C Language X Interface X Consortium Standard X Version 11, Release 6.3 The X Window System is a trademark of X Consortium, Inc. TekHVC is a trademark of Tektronix, Inc. Copyright (C) 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1994, 1996 X Consortium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium. Copyright (C) 1985, 1986, 1987, 1988, 1989, 1990, 1991 by Digital Equipment Corporation Portions Copyright (C) 1990, 1991 by Tektronix, Inc. Permission to use, copy, modify and distribute this documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appears in all copies and that both that copyright notice and this permission notice appear in all copies, and that the names of Digital and Tektronix not be used in in advertising or publicity pertaining to this documentation without specific, written prior permission. Digital and Tektronix makes no representations about the suitability of this documentation for any purpose. It is provided "as is" without express or implied warranty.  File: Xlibscm.info, Node: Display and Screens, Next: Drawables, Prev: XlibScm, Up: Top 2 Display and Screens ********************* -- Function: x:open-display display-name DISPLAY-NAME Specifies the hardware display name, which determines the display and communications domain to be used. On a POSIX-conformant system, if the display-name is #f, it defaults to the value of the DISPLAY environment variable. The encoding and interpretation of DISPLAY-NAME is implementation-dependent. On POSIX-conformant systems, the DISPLAY-NAME or DISPLAY environment variable can be a string in the format: -- Special Form: hostname:number.screen-number HOSTNAME specifies the name of the host machine on which the display is physically attached. Follow the HOSTNAME with either a single colon (:) or a double colon (::). NUMBER specifies the number of the display server on that host machine. You may optionally follow this display number with a period (.). A single CPU can have more than one display. Multiple displays are usually numbered starting with zero. SCREEN-NUMBER specifies the screen to be used on that server. Multiple screens can be controlled by a single X server. The SCREEN-NUMBER sets an internal variable that can be accessed by using the x:default-screen procedure. -- Function: x:close display DISPLAY specifies the connection to the X server. The `x:close' function closes the connection to the X server for the DISPLAY specified and destroys all windows, resource IDs (Window, Font, Pixmap, Colormap, Cursor, and GContext), or other resources that the client has created on this display, unless the close-down mode of the resource has been changed (see `x:set-close-down-mode'). Therefore, these windows, resource IDs, and other resources should not be used again or an error will be generated. Before exiting, you should call X:CLOSE-DISPLAY or X:FLUSH explicitly so that any pending errors are reported. -- Function: x:protocol-version display Returns cons of the major version number (11) of the X protocol associated with the connected DISPLAY and the minor protocol revision number of the X server. -- Function: x:server-vendor display Returns a string that provides some identification of the owner of the X server implementation. The contents of the string are implementation-dependent. -- Function: x:vendor-release display Returns a number related to a vendor's release of the X server. A display consists of one or more "Screen"s. Each screen has a "root-window", "default-graphics-context", and "colormap". -- Function: x:screen-count display Returns the number of available screens. -- Function: x:default-screen display Returns the default screen number specified by the `x:open-display' function. Use this screen number in applications which will use only a single screen. -- Function: x:root-window display screen-number -- Function: x:root-window display SCREEN-NUMBER, if givien, specifies the appropriate screen number on the host server. Otherwise the default-screen for DISPLAY is used. Returns the root window for the specified SCREEN-NUMBER. Use `x:root-window' for functions that need a drawable of a particular screen or for creating top-level windows. -- Function: x:root-window window Returns the root window for the specified WINDOW's screen. -- Function: x:default-colormap display screen-number -- Function: x:default-colormap display -- Function: x:default-colormap window Returns the default colormap of the specified screen. -- Function: x:default-ccc display screen-number -- Function: x:default-ccc display -- Function: x:default-ccc window Returns the default Color-Conversion-Context (ccc) of the specified screen. -- Function: x:default-gc display screen-number -- Function: x:default-gc display -- Function: x:default-gc window Returns the default graphics-context of the specified screen. -- Function: x:screen-depths display screen-number -- Function: x:screen-depths display -- Function: x:screen-depths window Returns an array of depths supported by the specified screen. The "Visual" type describes possible colormap depths and arrangements. -- Function: x:default-visual display screen-number -- Function: x:default-visual display -- Function: x:default-visual window Returns the default Visual type for the specified screen. -- Function: x:make-visual display depth class -- Function: x:make-visual window depth class The integer DEPTH specifies the number of bits per pixel. The CLASS argument specifies one of the possible visual classes for a screen: * x:Static-Gray * x:Static-Color * x:True-Color * x:Gray-Scale * x:Pseudo-Color * x:Direct-Color `X:make-visual' returns a visual type for the screen specified by DISPLAY or WINDOW if successful; #f if not. -- Function: x:visual-class visual -- Function: x:visual-class screen -- Function: x:visual-class display Returns the (integer) visual class of its argument. -- Function: x:visual-geometry visual -- Function: x:visual-geometry screen -- Function: x:visual-geometry display Returns a list of the: * red_mask * green_mask * blue_mask * colormap_size -- Function: x:screen-cells display screen-number -- Function: x:screen-cells display -- Function: x:screen-cells window Returns the number of entries in the default colormap. -- Function: x:screen-depth display screen-number Returns the depth of the root window of the specified screen. -- Function: x:screen-depth display -- Function: x:screen-depth window -- Function: x:screen-depth visual Returns the depth of argument. The "depth" of a window or pixmap is the number of bits per pixel it has. The "depth" of a graphics context is the depth of the drawables it can be used in conjunction with graphics output. -- Function: x:screen-size display screen-number -- Function: x:screen-size display -- Function: x:screen-size window Returns a list of integer height and width of the screen in pixels. -- Function: x:screen-dimensions display screen-number -- Function: x:screen-dimensions display -- Function: x:screen-dimensions window Returns a list of integer height and width of the screen in millimeters. -- Function: x:screen-white display screen-number -- Function: x:screen-white display -- Function: x:screen-white window Returns the white pixel value of the specified screen. -- Function: x:screen-black display screen-number -- Function: x:screen-black display -- Function: x:screen-black window Returns the black pixel value of the specified screen.  File: Xlibscm.info, Node: Drawables, Next: Graphics Context, Prev: Display and Screens, Up: Top 3 Drawables *********** A "Drawable" is either a window or pixmap. * Menu: * Windows and Pixmaps:: * Window Attributes:: * Window Properties and Visibility::  File: Xlibscm.info, Node: Windows and Pixmaps, Next: Window Attributes, Prev: Drawables, Up: Drawables 3.1 Windows and Pixmaps ======================= -- Function: x:create-window window position size border-width depth class visual field-name value ... Creates and returns an unmapped Input-Output subwindow for a specified parent WINDOW and causes the X server to generate a CreateNotify event. The created window is placed on top in the stacking order with respect to siblings. Any part of the window that extends outside its parent WINDOW is clipped. The BORDER-WIDTH for an x:Input-Only window must be zero. The coordinate system has the X axis horizontal and the Y axis vertical with the origin [0, 0] at the upper-left corner. Coordinates are integral, in terms of pixels, and coincide with pixel centers. Each window and pixmap has its own coordinate system. For a window, the origin is inside the border at the inside, upper-left corner. CLASS can be x:Input-Output, x:Input-Only, or x:Copy-From-Parent. For class x:Input-Output, the VISUAL type and DEPTH must be a combination supported for the screen. The DEPTH need not be the same as the parent, but the parent must not be a window of class x:Input-Only. For an x:Input-Only window, the DEPTH must be zero, and the VISUAL must be one supported by the screen. The returned window will have the attributes specified by FIELD-NAMEs and VALUE. -- Function: x:create-window window position size border-width border background The returned window inherits its depth, class, and visual from its parent. All other window attributes, except BACKGROUND and BORDER, have their default values. -- Function: x:create-pixmap drawable size depth -- Function: x:create-pixmap display size depth SIZE is a list, vector, or pair of nonzero integers specifying the width and height desired in the new pixmap. X:CREATE-PIXMAP returns a new pixmap of the width, height, and DEPTH specified. It is valid to pass an x:Input-Only window to the drawable argument. The DEPTH argument must be one of the depths supported by the screen of the specified DRAWABLE. -- Function: x:close window Destroys the specified WINDOW as well as all of its subwindows and causes the X server to generate a DestroyNotify event for each window. The window should not be used again. If the window specified by the WINDOW argument is mapped, it is unmapped automatically. The ordering of the DestroyNotify events is such that for any given window being destroyed, DestroyNotify is generated on any inferiors of the window before being generated on the window itself. The ordering among siblings and across subhierarchies is not otherwise constrained. If the WINDOW you specified is a root window, an error is signaled. Destroying a mapped WINDOW will generate x:Expose events on other windows that were obscured by the window being destroyed. -- Function: x:close pixmap Deletes the association between the PIXMAP and its storage. The X server frees the pixmap storage when there are no references to it. -- Function: x:window-geometry drawable Returns a list of: coordinates `list' of x and y coordinates that define the location of the DRAWABLE. For a window, these coordinates specify the upper-left outer corner relative to its parent's origin. For pixmaps, these coordinates are always zero. size `list' of the DRAWABLE's dimensions (width and height). For a window, these dimensions specify the inside size, not including the border. border-width The border width in pixels. If the DRAWABLE is a pixmap, this is zero. depth The depth of the DRAWABLE (bits per pixel for the object). -- Function: x:window-geometry-set! window field-name value ... Changes the "Configuration" components specified by FIELD-NAMEs for the specified WINDOW. These are the attributes settable by `x:window-geometry-set!'. That these attributes are encoded by small integers - just like those of the next section. Be warned therefore that confusion of attribute names will likely not signal errors, just cause mysterious behavior. -- Attribute: x:CWX -- Attribute: x:CWY -- Attribute: x:CW-Width -- Attribute: x:CW-Height The x:CWX and x:CYY members are used to set the window's x and y coordinates, which are relative to the parent's origin and indicate the position of the upper-left outer corner of the window. The x:CW-Width and x:CW-Height members are used to set the inside size of the window, not including the border, and must be nonzero. Attempts to configure a root window have no effect. If a window's size actually changes, the window's subwindows move according to their window gravity. Depending on the window's bit gravity, the contents of the window also may be moved -- Attribute: x:CW-Border-Width The integer x:CW-Border-Width is used to set the width of the border in pixels. Note that setting just the border width leaves the outer-left corner of the window in a fixed position but moves the absolute position of the window's origin. It is an error to set the border-width attribute of an InputOnly window nonzero. -- Attribute: x:CW-Sibling The sibling member is used to set the sibling window for stacking operations. -- Attribute: x:CW-Stack-Mode The x:CW-Stack-Mode member is used to set how the window is to be restacked and can be set to x:Above, x:Below, x:Top-If, x:Bottom-If, or x:Opposite. If a sibling and a stack-mode are specified, the window is restacked as follows: `x:Above' The window is placed just above the sibling. `x:Below' The window is placed just below the sibling. `x:Top-If' If the sibling occludes the window, the window is placed at the top of the stack. `x:Bottom-If' If the window occludes the sibling, the window is placed at the bottom of the stack. `x:Opposite' If the sibling occludes the window, the window is placed at the top of the stack. If the window occludes the sibling, the window is placed at the bottom of the stack. If a stack-mode is specified but no sibling is specified, the window is restacked as follows: `x:Above' The window is placed at the top of the stack. `x:Below' The window is placed at the bottom of the stack. `x:Top-If' If any sibling occludes the window, the window is placed at the top of the stack. `x:Bottom-If' If the window occludes any sibling, the window is placed at the bottom of the stack. `x:Opposite' If any sibling occludes the window, the window is placed at the top of the stack. If the window occludes any sibling, the window is placed at the bottom of the stack.  File: Xlibscm.info, Node: Window Attributes, Next: Window Properties and Visibility, Prev: Windows and Pixmaps, Up: Drawables 3.2 Window Attributes ===================== -- Function: x:window-set! window field-name value ... Changes the components specified by FIELD-NAMEs for the specified WINDOW. The restrictions are the same as for `x:create-window'. The order in which components are verified and altered is server dependent. If an error occurs, a subset of the components may have been altered. The `x:create-window' and `x:window-set!' procedures take five and one argument (respectively) followed by pairs of arguments, where the first is one of the property-name symbols (or its top-level value) listed below; and the second is the value to associate with that property. -- Attribute: x:CW-Back-Pixmap Sets the background pixmap of the WINDOW to the specified pixmap. The background pixmap can immediately be freed if no further explicit references to it are to be made. If x:Parent-Relative is specified, the background pixmap of the window's parent is used, or on the root window, the default background is restored. It is an error to perform this operation on an x:Input-Only window. If the background is set to #f or None, the window has no defined background. -- Attribute: x:CW-Back-Pixel Sets the background of the WINDOW to the specified pixel value. Changing the background does not cause the WINDOW contents to be changed. It is an error to perform this operation on an x:Input-Only window. -- Attribute: x:CW-Border-Pixmap Sets the border pixmap of the WINDOW to the pixmap you specify. The border pixmap can be freed if no further explicit references to it are to be made. If you specify x:Copy-From-Parent, a copy of the parent window's border pixmap is used. It is an error to perform this operation on an x:Input-Only WINDOW. -- Attribute: x:CW-Border-Pixel Sets the border of the WINDOW to the pixel VALUE. It is an error to perform this operation on an x:Input-Only window. -- Attribute: x:CW-Bit-Gravity -- Attribute: x:CW-Win-Gravity The bit gravity of a window defines which region of the window should be retained when an x:Input-Output window is resized. The default value for the bit-gravity attribute is x:Forget-Gravity. The window gravity of a window allows you to define how the x:Input-Output or x:Input-Only window should be repositioned if its parent is resized. The default value for the win-gravity attribute is x:North-West-Gravity. If the inside width or height of a window is not changed and if the window is moved or its border is changed, then the contents of the window are not lost but move with the window. Changing the inside width or height of the window causes its contents to be moved or lost (depending on the bit-gravity of the window) and causes children to be reconfigured (depending on their win-gravity). For a change of width and height, the (x, y) pairs are defined: Gravity Direction Coordinates x:North-West-Gravity (0, 0) x:North-Gravity (Width/2, 0) x:North-East-Gravity (Width, 0) x:West-Gravity (0, Height/2) x:Center-Gravity (Width/2, Height/2) x:East-Gravity (Width, Height/2) x:South-West-Gravity (0, Height) x:South-Gravity (Width/2, Height) x:South-East-Gravity (Width, Height) When a window with one of these bit-gravity values is resized, the corresponding pair defines the change in position of each pixel in the window. When a window with one of these win-gravities has its parent window resized, the corresponding pair defines the change in position of the window within the parent. When a window is so repositioned, a x:Gravity-Notify event is generated (see section 10.10.5). A bit-gravity of x:Static-Gravity indicates that the contents or origin should not move relative to the origin of the root window. If the change in size of the window is coupled with a change in position (x, y), then for bit-gravity the change in position of each pixel is (-x, -y), and for win-gravity the change in position of a child when its parent is so resized is (-x, -y). Note that x:Static-Gravity still only takes effect when the width or height of the window is changed, not when the window is moved. A bit-gravity of x:Forget-Gravity indicates that the window's contents are always discarded after a size change, even if a backing store or save under has been requested. The window is tiled with its background and zero or more x:Expose events are generated. If no background is defined, the existing screen contents are not altered. Some X servers may also ignore the specified bit-gravity and always generate x:Expose events. The contents and borders of inferiors are not affected by their parent's bit-gravity. A server is permitted to ignore the specified bit-gravity and use x:Forget-Gravity instead. A win-gravity of x:Unmap-Gravity is like x:North-West-Gravity (the window is not moved), except the child is also unmapped when the parent is resized, and an x:Unmap-Notify event is generated. -- Attribute: x:CW-Backing-Store Some implementations of the X server may choose to maintain the contents of x:Input-Output windows. If the X server maintains the contents of a window, the off-screen saved pixels are known as backing store. The backing store advises the X server on what to do with the contents of a window. The backing-store attribute can be set to x:Not-Useful (default), x:When-Mapped, or x:Always. A backing-store attribute of x:Not-Useful advises the X server that maintaining contents is unnecessary, although some X implementations may still choose to maintain contents and, therefore, not generate x:Expose events. A backing-store attribute of x:When-Mapped advises the X server that maintaining contents of obscured regions when the window is mapped would be beneficial. In this case, the server may generate an x:Expose event when the window is created. A backing-store attribute of x:Always advises the X server that maintaining contents even when the window is unmapped would be beneficial. Even if the window is larger than its parent, this is a request to the X server to maintain complete contents, not just the region within the parent window boundaries. While the X server maintains the window's contents, x:Expose events normally are not generated, but the X server may stop maintaining contents at any time. When the contents of obscured regions of a window are being maintained, regions obscured by noninferior windows are included in the destination of graphics requests (and source, when the window is the source). However, regions obscured by inferior windows are not included. -- Attribute: x:CW-Backing-Planes -- Attribute: x:CW-Backing-Pixel You can set backing planes to indicate (with bits set to 1) which bit planes of an x:Input-Output window hold dynamic data that must be preserved in backing store and during save unders. The default value for the backing-planes attribute is all bits set to 1. You can set backing pixel to specify what bits to use in planes not covered by backing planes. The default value for the backing-pixel attribute is all bits set to 0. The X server is free to save only the specified bit planes in the backing store or the save under and is free to regenerate the remaining planes with the specified pixel value. Any extraneous bits in these values (that is, those bits beyond the specified depth of the window) may be simply ignored. If you request backing store or save unders, you should use these members to minimize the amount of off-screen memory required to store your window. -- Attribute: x:CW-Override-Redirect To control window placement or to add decoration, a window manager often needs to intercept (redirect) any map or configure request. Pop-up windows, however, often need to be mapped without a window manager getting in the way. To control whether an x:Input-Output or x:Input-Only window is to ignore these structure control facilities, use the override-redirect flag. The override-redirect flag specifies whether map and configure requests on this window should override a x:Substructure-Redirect-Mask on the parent. You can set the override-redirect flag to #t or #f (default). Window managers use this information to avoid tampering with pop-up windows. -- Attribute: x:CW-Save-Under Some server implementations may preserve contents of x:Input-Output windows under other x:Input-Output windows. This is not the same as preserving the contents of a window for you. You may get better visual appeal if transient windows (for example, pop-up menus) request that the system preserve the screen contents under them, so the temporarily obscured applications do not have to repaint. You can set the save-under flag to True or False (default). If save-under is True, the X server is advised that, when this window is mapped, saving the contents of windows it obscures would be beneficial. -- Attribute: x:CW-Event-Mask The event mask defines which events the client is interested in for this x:Input-Output or x:Input-Only window (or, for some event types, inferiors of this window). The event mask is the bitwise inclusive OR of zero or more of the valid event mask bits. You can specify that no maskable events are reported by setting x:No-Event-Mask (default). The following table lists the event mask constants you can pass to the event-mask argument and the circumstances in which you would want to specify the event mask: Event Mask Circumstances x:No-Event-Mask No events wanted x:Key-Press-Mask Keyboard down events wanted x:Key-Release-Mask Keyboard up events wanted x:Button-Press-Mask Pointer button down events wanted x:Button-Release-Mask Pointer button up events wanted x:Enter-Window-Mask Pointer window entry events wanted x:Leave-Window-Mask Pointer window leave events wanted x:Pointer-Motion-Mask Pointer motion events wanted x:Pointer-Motion-Hint-Mask If x:Pointer-Motion-Hint-Mask is selected in combination with one or more motion-masks, the X server is free to send only one x:Motion-Notify event (with the is_hint member of the X:Pointer-Moved-Event structure set to x:Notify-Hint) to the client for the event window, until either the key or button state changes, the pointer leaves the event window, or the client calls X:Query-Pointer or X:Get-Motion-Events. The server still may send x:Motion-Notify events without is_hint set to x:Notify-Hint. x:Button1-Motion-Mask Pointer motion while button 1 down x:Button2-Motion-Mask Pointer motion while button 2 down x:Button3-Motion-Mask Pointer motion while button 3 down x:Button4-Motion-Mask Pointer motion while button 4 down x:Button5-Motion-Mask Pointer motion while button 5 down x:Button-Motion-Mask Pointer motion while any button down x:Keymap-State-Mask Keyboard state wanted at window entry and focus in x:Exposure-Mask Any exposure wanted x:Visibility-Change-Mask Any change in visibility wanted x:Structure-Notify-Mask Any change in window structure wanted x:Resize-Redirect-Mask Redirect resize of this window x:Substructure-Notify-Mask Substructure notification wanted x:Substructure-Redirect-Mask Redirect structure requests on children x:Focus-Change-Mask Any change in input focus wanted x:Property-Change-Mask Any change in property wanted x:Colormap-Change-Mask Any change in colormap wanted x:Owner-Grab-Button-Mask Automatic grabs should activate with owner_events set to True -- Attribute: x:CW-Dont-Propagate The do-not-propagate-mask attribute defines which events should not be propagated to ancestor windows when no client has the event type selected in this x:Input-Output or x:Input-Only window. The do-not-propagate-mask is the bitwise inclusive OR of zero or more of the following masks: x:Key-Press, x:Key-Release, x:Button-Press, x:Button-Release, x:Pointer-Motion, x:Button1Motion, x:Button2Motion, x:Button3Motion, x:Button4Motion, x:Button5Motion, and x:Button-Motion. You can specify that all events are propagated by setting x:No-Event-Mask (default). -- Attribute: x:CW-Colormap The colormap attribute specifies which colormap best reflects the true colors of the x:Input-Output window. The colormap must have the same visual type as the window. X servers capable of supporting multiple hardware colormaps can use this information, and window managers can use it for calls to X:Install-Colormap. You can set the colormap attribute to a colormap or to x:Copy-From-Parent (default). If you set the colormap to x:Copy-From-Parent, the parent window's colormap is copied and used by its child. However, the child window must have the same visual type as the parent. The parent window must not have a colormap of x:None. The colormap is copied by sharing the colormap object between the child and parent, not by making a complete copy of the colormap contents. Subsequent changes to the parent window's colormap attribute do not affect the child window. -- Attribute: x:CW-Cursor The cursor attribute specifies which cursor is to be used when the pointer is in the x:Input-Output or x:Input-Only window. You can set the cursor to a cursor or x:None (default). If you set the cursor to x:None, the parent's cursor is used when the pointer is in the x:Input-Output or x:Input-Only window, and any change in the parent's cursor will cause an immediate change in the displayed cursor. On the root window, the default cursor is restored. -- Function: x:window-ref window field-name ... Returns a list of the components specified by FIELD-NAMEs for the specified WINDOW. Allowable FIELD-NAMEs are a subset of those for `x:window-set!': * x:CW-Back-Pixel * x:CW-Bit-Gravity * x:CW-Win-Gravity * x:CW-Backing-Store * x:CW-Backing-Planes * x:CW-Backing-Pixel * x:CW-Override-Redirect * x:CW-Save-Under * x:CW-Event-Mask * x:CW-Dont-Propagate * x:CW-Colormap  File: Xlibscm.info, Node: Window Properties and Visibility, Prev: Window Attributes, Up: Drawables 3.3 Window Properties and Visibility ==================================== -- Function: x:get-window-property window property Returns the (string or list of numbers) value of PROPERTY of WINDOW. -- Function: x:get-window-property window property #t Removes and returns the (string or list of numbers) value of PROPERTY of WINDOW. -- Function: x:list-properties window Returns a list of the properties (strings) defined for WINDOW. In X parlance, a window which is hidden even when not obscured by other windows is "unmapped"; one which shows is "mapped". It is an unfortunate name-collision with Scheme, and is ingrained in the attribute names. -- Function: x:map-window window Maps the WINDOW and all of its subwindows that have had map requests. Mapping a window that has an unmapped ancestor does not display the window but marks it as eligible for display when the ancestor becomes mapped. Such a window is called unviewable. When all its ancestors are mapped, the window becomes viewable and will be visible on the screen if it is not obscured by another window. This function has no effect if the WINDOW is already mapped. If the override-redirect of the window is False and if some other client has selected x:Substructure-Redirect-Mask on the parent window, then the X server generates a MapRequest event, and the `x:map-window' function does not map the WINDOW. Otherwise, the WINDOW is mapped, and the X server generates a MapNotify event. If the WINDOW becomes viewable and no earlier contents for it are remembered, the X server tiles the WINDOW with its background. If the window's background is undefined, the existing screen contents are not altered, and the X server generates zero or more x:Expose events. If backing-store was maintained while the WINDOW was unmapped, no x:Expose events are generated. If backing-store will now be maintained, a full-window exposure is always generated. Otherwise, only visible regions may be reported. Similar tiling and exposure take place for any newly viewable inferiors. If the window is an Input-Output window, `x:map-window' generates x:Expose events on each Input-Output window that it causes to be displayed. If the client maps and paints the window and if the client begins processing events, the window is painted twice. To avoid this, first ask for x:Expose events and then map the window, so the client processes input events as usual. The event list will include x:Expose for each window that has appeared on the screen. The client's normal response to an x:Expose event should be to repaint the window. This method usually leads to simpler programs and to proper interaction with window managers. -- Function: x:map-subwindows window Maps all subwindows of a specified WINDOW in top-to-bottom stacking order. The X server generates x:Expose events on each newly displayed window. This may be much more efficient than mapping many windows one at a time because the server needs to perform much of the work only once, for all of the windows, rather than for each window. -- Function: x:unmap-window window Unmaps the specified WINDOW and causes the X server to generate an UnmapNotify event. If the specified WINDOW is already unmapped, `x:unmap-window' has no effect. Normal exposure processing on formerly obscured windows is performed. Any child window will no longer be visible until another map call is made on the parent. In other words, the subwindows are still mapped but are not visible until the parent is mapped. Unmapping a WINDOW will generate x:Expose events on windows that were formerly obscured by it. -- Function: x:unmap-subwindows window Unmaps all subwindows for the specified WINDOW in bottom-to-top stacking order. It causes the X server to generate an UnmapNotify event on each subwindow and x:Expose events on formerly obscured windows. Using this function is much more efficient than unmapping multiple windows one at a time because the server needs to perform much of the work only once, for all of the windows, rather than for each window.  File: Xlibscm.info, Node: Graphics Context, Next: Cursor, Prev: Drawables, Up: Top 4 Graphics Context ****************** Most attributes of graphics operations are stored in "GC"s. These include line width, line style, plane mask, foreground, background, tile, stipple, clipping region, end style, join style, and so on. Graphics operations (for example, drawing lines) use these values to determine the actual drawing operation. -- Function: x:create-gc drawable field-name value ... Creates and returns graphics context. The graphics context can be used with any destination drawable having the same root and depth as the specified DRAWABLE. -- Function: x:gc-set! graphics-context field-name value ... Changes the components specified by FIELD-NAMEs for the specified GRAPHICS-CONTEXT. The restrictions are the same as for `x:create-gc'. The order in which components are verified and altered is server dependent. If an error occurs, a subset of the components may have been altered. -- Function: x:copy-gc-fields! gcontext-src gcontext-dst field-name ... Copies the components specified by FIELD-NAMEs from GCONTEXT-SRC to GCONTEXT-DST. GCONTEXT-SRC and GCONTEXT-DST must have the same root and depth. -- Function: x:gc-ref graphics-context field-name ... Returns a list of the components specified by FIELD-NAMEs ... from the specified GRAPHICS-CONTEXT. GC Attributes ============= Both `x:create-gc' and `x:change-gc' take one argument followed by pairs of arguments, where the first is one of the property-name symbols (or its top-level value) listed below; and the second is the value to associate with that property. -- Attribute: x:GC-Function The function attributes of a GC are used when you update a section of a drawable (the destination) with bits from somewhere else (the source). The function in a GC defines how the new destination bits are to be computed from the source bits and the old destination bits. x:G-Xcopy is typically the most useful because it will work on a color display, but special applications may use other functions, particularly in concert with particular planes of a color display. The 16 functions are: x:G-Xclear 0 x:G-Xand (AND src dst) x:G-Xand-Reverse (AND src (NOT dst)) x:G-Xcopy src x:G-Xand-Inverted (AND (NOT src) dst) x:G-Xnoop dst x:G-Xxor (XOR src dst) x:G-Xor (OR src dst) x:G-Xnor (AND (NOT src) (NOT dst)) x:G-Xequiv (XOR (NOT src) dst) x:G-Xinvert (NOT dst) x:G-Xor-Reverse (OR src (NOT dst)) x:G-Xcopy-Inverted (NOT src) x:G-Xor-Inverted (OR (NOT src) dst) x:G-Xnand (OR (NOT src) (NOT dst)) x:G-Xset 1 -- Attribute: x:GC-Plane-Mask Many graphics operations depend on either pixel values or planes in a GC. The planes attribute is an integer which specifies which planes of the destination are to be modified, one bit per plane. A monochrome display has only one plane and will be the least significant bit of the integer. As planes are added to the display hardware, they will occupy more significant bits in the plane mask. In graphics operations, given a source and destination pixel, the result is computed bitwise on corresponding bits of the pixels. That is, a Boolean operation is performed in each bit plane. The plane-mask restricts the operation to a subset of planes. `x:All-Planes' can be used to refer to all planes of the screen simultaneously. The result is computed by the following: (OR (AND (FUNC src dst) plane-mask) (AND dst (NOT plane-mask))) Range checking is not performed on a plane-mask value. It is simply truncated to the appropriate number of bits. -- Attribute: x:GC-Foreground -- Attribute: x:GC-Background Range checking is not performed on the values for foreground or background. They are simply truncated to the appropriate number of bits. Note that foreground and background are not initialized to any values likely to be useful in a window. -- Attribute: x:GC-Line-Width The line-width is measured in pixels and either can be greater than or equal to one (wide line) or can be the special value zero (thin line). Thin lines (zero line-width) are one-pixel-wide lines drawn using an unspecified, device-dependent algorithm. There are only two constraints on this algorithm. * If a line is drawn unclipped from [x1,y1] to [x2,y2] and if another line is drawn unclipped from [x1+dx,y1+dy] to [x2+dx,y2+dy], a point [x,y] is touched by drawing the first line if and only if the point [x+dx,y+dy] is touched by drawing the second line. * The effective set of points comprising a line cannot be affected by clipping. That is, a point is touched in a clipped line if and only if the point lies inside the clipping region and the point would be touched by the line when drawn unclipped. A wide line drawn from [x1,y1] to [x2,y2] always draws the same pixels as a wide line drawn from [x2,y2] to [x1,y1], not counting cap-style and join-style. It is recommended that this property be true for thin lines, but this is not required. A line-width of zero may differ from a line-width of one in which pixels are drawn. This permits the use of many manufacturers' line drawing hardware, which may run many times faster than the more precisely specified wide lines. In general, drawing a thin line will be faster than drawing a wide line of width one. However, because of their different drawing algorithms, thin lines may not mix well aesthetically with wide lines. If it is desirable to obtain precise and uniform results across all displays, a client should always use a line-width of one rather than a linewidth of zero. -- Attribute: x:GC-Line-Style The line-style defines which sections of a line are drawn: x:Line-Solid The full path of the line is drawn. x:Line-Double-Dash The full path of the line is drawn, but the even dashes are filled differently from the odd dashes (see fill-style) with x:Cap-Butt style used where even and odd dashes meet. x:Line-On-Off-Dash Only the even dashes are drawn, and cap-style applies to all internal ends of the individual dashes, except x:Cap-Not-Last is treated as x:Cap-Butt. -- Attribute: x:GC-Cap-Style The cap-style defines how the endpoints of a path are drawn: x:Cap-Not-Last This is equivalent to x:Cap-Butt except that for a line-width of zero the final endpoint is not drawn. x:Cap-Butt The line is square at the endpoint (perpendicular to the slope of the line) with no projection beyond. x:Cap-Round The line has a circular arc with the diameter equal to the line-width, centered on the endpoint. (This is equivalent to x:Cap-Butt for line-width of zero). x:Cap-Projecting The line is square at the end, but the path continues beyond the endpoint for a distance equal to half the line-width. (This is equivalent to x:Cap-Butt for line-width of zero). -- Attribute: x:GC-Join-Style The join-style defines how corners are drawn for wide lines: x:Join-Miter The outer edges of two lines extend to meet at an angle. However, if the angle is less than 11 degrees, then a x:Join-Bevel join-style is used instead. x:Join-Round The corner is a circular arc with the diameter equal to the line-width, centered on the x:Join-point. x:Join-Bevel The corner has x:Cap-Butt endpoint styles with the triangular notch filled. -- Attribute: x:GC-Fill-Style The fill-style defines the contents of the source for line, text, and fill requests. For all text and fill requests (for example, X:Draw-Text, X:Fill-Rectangle, X:Fill-Polygon, and X:Fill-Arc); for line requests with linestyle x:Line-Solid (for example, X:Draw-Line, X:Draw-Segments, X:Draw-Rectangle, X:Draw-Arc); and for the even dashes for line requests with line-style x:Line-On-Off-Dash or x:Line-Double-Dash, the following apply: x:Fill-Solid Foreground x:Fill-Tiled Tile x:Fill-Opaque-Stippled A tile with the same width and height as stipple, but with background everywhere stipple has a zero and with foreground everywhere stipple has a one x:Fill-Stippled Foreground masked by stipple When drawing lines with line-style x:Line-Double-Dash, the odd dashes are controlled by the fill-style in the following manner: x:Fill-Solid Background x:Fill-Tiled Same as for even dashes x:Fill-Opaque-Stippled Same as for even dashes x:Fill-Stippled Background masked by stipple -- Attribute: x:GC-Fill-Rule The fill-rule defines what pixels are inside (drawn) for paths given in X:Fill-Polygon requests and can be set to x:Even-Odd-Rule or x:Winding-Rule. x:Even-Odd-Rule A point is inside if an infinite ray with the point as origin crosses the path an odd number of times. x:Winding-Rule A point is inside if an infinite ray with the point as origin crosses an unequal number of clockwise and counterclockwise directed path segments. A clockwise directed path segment is one that crosses the ray from left to right as observed from the point. A counterclockwise segment is one that crosses the ray from right to left as observed from the point. The case where a directed line segment is coincident with the ray is uninteresting because you can simply choose a different ray that is not coincident with a segment. For both x:Even-Odd-Rule and x:Winding-Rule, a point is infinitely small, and the path is an infinitely thin line. A pixel is inside if the center point of the pixel is inside and the center point is not on the boundary. If the center point is on the boundary, the pixel is inside if and only if the polygon interior is immediately to its right (x increasing direction). Pixels with centers on a horizontal edge are a special case and are inside if and only if the polygon interior is immediately below (y increasing direction). -- Attribute: x:GC-Tile -- Attribute: x:GC-Stipple The tile/stipple represents an infinite two-dimensional plane, with the tile/stipple replicated in all dimensions. The tile pixmap must have the same root and depth as the GC, or an error results. The stipple pixmap must have depth one and must have the same root as the GC, or an error results. For stipple operations where the fill-style is x:Fill-Stippled but not x:Fill-Opaque-Stippled, the stipple pattern is tiled in a single plane and acts as an additional clip mask to be ANDed with the clip-mask. Although some sizes may be faster to use than others, any size pixmap can be used for tiling or stippling. -- Attribute: x:GC-Tile-Stip-X-Origin -- Attribute: x:GC-Tile-Stip-Y-Origin When the tile/stipple plane is superimposed on a drawable for use in a graphics operation, the upper-left corner of some instance of the tile/stipple is at the coordinates within the drawable specified by the tile/stipple origin. The tile/stipple origin is interpreted relative to the origin of whatever destination drawable is specified in a graphics request. -- Attribute: x:GC-Font The font to be used for drawing text. -- Attribute: x:GC-Subwindow-Mode You can set the subwindow-mode to x:Clip-By-Children or x:Include-Inferiors. x:Clip-By-Children Both source and destination windows are additionally clipped by all viewable Input-Output children. x:Include-Inferiors Neither source nor destination window is clipped by inferiors. This will result in including subwindow contents in the source and drawing through subwindow boundaries of the destination. The use of `x:Include-Inferiors' on a window of one depth with mapped inferiors of differing depth is not illegal, but the semantics are undefined by the core protocol. -- Attribute: x:GC-Graphics-Exposures The graphics-exposure flag controls x:Graphics-Expose event generation for X:Copy-Area and X:Copy-Plane requests (and any similar requests defined by extensions). -- Attribute: x:GC-Clip-X-Origin -- Attribute: x:GC-Clip-Y-Origin The clip-mask origin is interpreted relative to the origin of whatever destination drawable is specified in a graphics request. -- Attribute: x:GC-Clip-Mask The clip-mask restricts writes to the destination drawable. If the clip-mask is set to a pixmap, it must have depth one and have the same root as the GC, or an error results. If clip-mask is set to "x:None", the pixels are always drawn regardless of the clip origin. The clip-mask also can be set by calling `X:Set-Region'. Only pixels where the clip-mask has a bit set to 1 are drawn. Pixels are not drawn outside the area covered by the clip-mask or where the clip-mask has a bit set to 0. The clip-mask affects all graphics requests. The clip-mask does not clip sources. The clip-mask origin is interpreted relative to the origin of whatever destination drawable is specified in a graphics request. -- Attribute: x:GC-Dash-Offset Defines the phase of the pattern, specifying how many pixels into the dash-list the pattern should actually begin in any single graphics request. Dashing is continuous through path elements combined with a join-style but is reset to the dash-offset between each sequence of joined lines. The unit of measure for dashes is the same for the ordinary coordinate system. Ideally, a dash length is measured along the slope of the line, but implementations are only required to match this ideal for horizontal and vertical lines. Failing the ideal semantics, it is suggested that the length be measured along the major axis of the line. The major axis is defined as the x axis for lines drawn at an angle of between -45 and +45 degrees or between 135 and 225 degrees from the x axis. For all other lines, the major axis is the y axis. -- Attribute: x:GC-Dash-List There must be at least one element in the specified DASH-LIST. The initial and alternating elements (second, fourth, and so on) of the DASH-LIST are the even dashes, and the others are the odd dashes. Each element specifies a dash length in pixels. All of the elements must be nonzero. Specifying an odd-length list is equivalent to specifying the same list concatenated with itself to produce an even-length list. -- Attribute: x:GC-Arc-Mode The arc-mode controls filling in the X:Fill-Arcs function and can be set to x:Arc-Pie-Slice or x:Arc-Chord. x:Arc-Pie-Slice The arcs are pie-slice filled. x:Arc-Chord The arcs are chord filled.  File: Xlibscm.info, Node: Cursor, Next: Colormap, Prev: Graphics Context, Up: Top 5 Cursor ******** -- Function: x:create-cursor display shape X provides a set of standard cursor shapes in a special font named "cursor". Applications are encouraged to use this interface for their cursors because the font can be customized for the individual display type. The SHAPE argument specifies which glyph of the standard fonts to use. The hotspot comes from the information stored in the cursor font. The initial colors of a cursor are a black foreground and a white background (see X:Recolor-Cursor). The names of all cursor shapes are defined with the prefix XC: in `x11.scm'. -- Function: x:create-cursor source-font source-char mask-font mask-char fgc bgc Creates a cursor from the source and mask bitmaps obtained from the specified font glyphs. The integer SOURCE-CHAR must be a defined glyph in SOURCE-FONT. The integer MASK-CHAR must be a defined glyph in MASK-FONT. The origins of the SOURCE-CHAR and MASK-CHAR glyphs are positioned coincidently and define the hotspot. The SOURCE-CHAR and MASK-CHAR need not have the same bounding box metrics, and there is no restriction on the placement of the hotspot relative to the bounding boxes. -- Function: x:create-cursor source-font source-char #f #f fgc bgc If MASK-FONT and MASK-CHAR are #f, all pixels of the source are displayed. -- Function: x:create-cursor source-pixmap mask-pixmap fgc bgc origin MASK-PIXMAP must be the same size as the pixmap defined by the SOURCE-PIXMAP argument. The foreground and background RGB values must be specified using FOREGROUND-COLOR and BACKGROUND-COLOR, even if the X server only has a x:Static-Gray or x:Gray-Scale screen. The hotspot must be a point within the SOURCE-PIXMAP. `X:Create-Cursor' creates and returns a cursor. The FOREGROUND-COLOR is used for the pixels set to 1 in the source, and the BACKGROUND-COLOR is used for the pixels set to 0. Both source and mask must have depth one but can have any root. The MASK-PIXMAP defines the shape of the cursor. The pixels set to 1 in MASK-PIXMAP define which source pixels are displayed, and the pixels set to 0 define which pixels are ignored. -- Function: x:create-cursor source-pixmap #f fgc bgc origin If MASK-PIXMAP is #f, all pixels of the source are displayed.  File: Xlibscm.info, Node: Colormap, Next: Rendering, Prev: Cursor, Up: Top 6 Colormap ********** A "colormap" maps pixel values to "RGB" color space values. -- Function: x:create-colormap window visual alloc-policy WINDOW specifies the window on whose screen you want to create a colormap. VISUAL specifies a visual type supported on the screen. ALLOC-POLICY Specifies the colormap entries to be allocated. You can pass `X:Alloc-None' or `X:Alloc-All'. The `X:Create-Colormap' function creates and returns a colormap of the specified VISUAL type for the screen on which WINDOW resides. Note that WINDOW is used only to determine the screen. `X:Gray-Scale' `X:Pseudo-Color' `X:Direct-Color' The initial values of the colormap entries are undefined. `X:Static-Gray' `X:Static-Color' `X:True-Color' The entries have defined values, but those values are specific to VISUAL and are not defined by X. The ALLOC-POLICY must be `X:Alloc-None'. For the other visual classes, if ALLOC-POLICY is `X:Alloc-None', the colormap initially has no allocated entries, and clients can allocate them. If ALLOC-POLICY is `X:Alloc-All', the entire colormap is allocated writable. The initial values of all allocated entries are undefined. `X:Gray-Scale' `X:Pseudo-Color' The effect is as if an `XAllocColorCells' call returned all pixel values from zero to N - 1, where N is the colormap entries value in VISUAL. `X:Direct-Color' The effect is as if an `XAllocColorPlanes' call returned a pixel value of zero and red_mask, green_mask, and blue_mask values containing the same bits as the corresponding masks in the specified visual. To create a new colormap when the allocation out of a previously shared colormap has failed because of resource exhaustion, use: -- Function: x:copy-colormap-and-free colormap Creates and returns a colormap of the same visual type and for the same screen as the specified COLORMAP. It also moves all of the client's existing allocation from the specified COLORMAP to the new colormap with their color values intact and their read-only or writable characteristics intact and frees those entries in the specified colormap. Color values in other entries in the new colormap are undefined. If the specified colormap was created by the client with alloc set to `X:Alloc-All', the new colormap is also created with `X:Alloc-All', all color values for all entries are copied from the specified COLORMAP, and then all entries in the specified COLORMAP are freed. If the specified COLORMAP was not created by the client with `X:Alloc-All', the allocations to be moved are all those pixels and planes that have been allocated by the client and that have not been freed since they were allocated. A "colormap" maps pixel values to elements of the "RGB" datatype. An RGB is a list or vector of 3 integers, describing the red, green, and blue intensities respectively. The integers are in the range 0 - 65535. -- Function: x:alloc-colormap-cells colormap ncolors nplanes -- Function: x:alloc-colormap-cells colormap ncolors nplanes contiguous? The `X:Alloc-Color-Cells' function allocates read/write color cells. The number of colors, NCOLORS must be positive and the number of planes, NPLANES nonnegative. If NCOLORS and nplanes are requested, then NCOLORS pixels and nplane plane masks are returned. No mask will have any bits set to 1 in common with any other mask or with any of the pixels. By ORing together each pixel with zero or more masks, NCOLORS * 2^NPLANES distinct pixels can be produced. All of these are allocated writable by the request. `x:Gray-Scale' `x:Pseudo-Color' Each mask has exactly one bit set to 1. If CONTIGUOUS? is non-false and if all masks are ORed together, a single contiguous set of bits set to 1 is formed. `x:Direct-Color' Each mask has exactly three bits set to 1. If CONTIGUOUS? is non-false and if all masks are ORed together, three contiguous sets of bits set to 1 (one within each pixel subfield) is formed. The RGB values of the allocated entries are undefined. `X:Alloc-Color-Cells' returns a list of two uniform arrays if it succeeded or #f if it failed. The first array has the pixels allocated and the second has the plane-masks. -- Function: x:alloc-colormap-cells colormap ncolors rgb -- Function: x:alloc-colormap-cells colormap ncolors rgb contiguous? The specified NCOLORS must be positive; and RGB a list or vector of 3 nonnegative integers. If NCOLORS colors, NREDS reds, NGREENS greens, and NBLUES blues are requested, NCOLORS pixels are returned; and the masks have NREDS, NGREENS, and NBLUES bits set to 1, respectively. If CONTIGUOUS? is non-false, each mask will have a contiguous set of bits set to 1. No mask will have any bits set to 1 in common with any other mask or with any of the pixels. Each mask will lie within the corresponding pixel subfield. By ORing together subsets of masks with each pixel value, NCOLORS * 2(NREDS+NGREENS+NBLUES) distinct pixel values can be produced. All of these are allocated by the request. However, in the colormap, there are only NCOLORS * 2^NREDS independent red entries, NCOLORS * 2^NGREENS independent green entries, and NCOLORS * 2^NBLUES independent blue entries. `X:Alloc-Color-Cells' returns a list if it succeeded or #f if it failed. The first element of the list has an array of the pixels allocated. The second, third, and fourth elements are the red, green, and blue plane-masks. -- Function: x:free-colormap-cells colormap pixels planes -- Function: x:free-colormap-cells colormap pixels Frees the cells represented by pixels whose values are in the PIXELS unsigned-integer uniform-vector. The PLANES argument should not have any bits set to 1 in common with any of the pixels. The set of all pixels is produced by ORing together subsets of the PLANES argument with the pixels. The request frees all of these pixels that were allocated by the client. Note that freeing an individual pixel obtained from `X:Alloc-Colormap-Cells' with a planes argument may not actually allow it to be reused until all of its related pixels are also freed. Similarly, a read-only entry is not actually freed until it has been freed by all clients, and if a client allocates the same read-only entry multiple times, it must free the entry that many times before the entry is actually freed. All specified pixels that are allocated by the client in the COLORMAP are freed, even if one or more pixels produce an error. It is an error if a specified pixel is not allocated by the client (that is, is unallocated or is only allocated by another client) or if the colormap was created with all entries writable (by passing `x:Alloc-All' to `X:Create-Colormap'). If more than one pixel is in error, the one that gets reported is arbitrary. -- Function: x:colormap-find-color colormap rgb RGB is a list or vector of 3 integers, describing the red, green, and blue intensities respectively; or an integer `#xrrggbb', packing red, green and blue intensities in the range 0 - 255. -- Function: x:colormap-find-color colormap color-name The case-insensitive string COLOR_NAME specifies the name of a color (for example, `red') `X:Colormap-Find-Color' allocates a read-only colormap entry corresponding to the closest RGB value supported by the hardware. `X:Colormap-Find-Color' returns the pixel value of the color closest to the specified RGB or COLOR_NAME elements supported by the hardware, if successful; otherwise `X:Colormap-Find-Color' returns #f. Multiple clients that request the same effective RGB value can be assigned the same read-only entry, thus allowing entries to be shared. When the last client deallocates a shared cell, it is deallocated. -- Function: x:color-ref colormap pixel Returns a list of 3 integers, describing the red, green, and blue intensities respectively of the COLORMAP entry of the cell indexed by PIXEL. The integer PIXEL must be a valid index into COLORMAP. -- Function: X:Color-Set! colormap pixel rgb RGB is a list or vector of 3 integers, describing the red, green, and blue intensities respectively; or an integer `#xrrggbb', packing red, green and blue intensities in the range 0 - 255. -- Function: X:Color-Set! colormap pixel color-name The case-insensitive string COLOR_NAME specifies the name of a color (for example, `red') The integer PIXEL must be a valid index into COLORMAP. `X:Color-Set!' changes the COLORMAP entry of the read/write cell indexed by PIXEL. If the COLORMAP is an installed map for its screen, the changes are visible immediately. -- Function: x:install-colormap colormap Installs the specified COLORMAP for its associated screen. All windows associated with COLORMAP immediately display with true colors. A colormap is associated with a window when the window is created or its attributes changed. If the specified colormap is not already an installed colormap, the X server generates a ColormapNotify event on each window that has that colormap. -- Function: x:ccc colormap Returns the Color-Conversion-Context of COLORMAP.  File: Xlibscm.info, Node: Rendering, Next: Images, Prev: Colormap, Up: Top 7 Rendering *********** -- Function: x:flush display -- Function: x:flush window Flushes the output buffer. Some client applications need not use this function because the output buffer is automatically flushed as needed by calls to X:Pending, X:Next-Event, and X:Window-Event. Events generated by the server may be enqueued into the library's event queue. -- Function: x:flush gc Forces sending of GC component changes. Xlib usually defers sending changes to the components of a GC to the server until a graphics function is actually called with that GC. This permits batching of component changes into a single server request. In some circumstances, however, it may be necessary for the client to explicitly force sending the changes to the server. An example might be when a protocol extension uses the GC indirectly, in such a way that the extension interface cannot know what GC will be used. -- Function: x:clear-area window (x-pos y-pos) (width height) expose? Paints a rectangular area in the specified WINDOW according to the specified dimensions with the WINDOW's background pixel or pixmap. The subwindow-mode effectively is `x:Clip-By-Children'. If width is zero, it is replaced with the current width of the WINDOW minus x. If height is zero, it is replaced with the current height of the WINDOW minus y. If the WINDOW has a defined background tile, the rectangle clipped by any children is filled with this tile. If the WINDOW has background x:None, the contents of the WINDOW are not changed. In either case, if EXPOSE? is True, one or more x:Expose events are generated for regions of the rectangle that are either visible or are being retained in a backing store. If you specify a WINDOW whose class is x:Input-Only, an error results. -- Function: x:fill-rectangle window gcontext position size Draw Strings ============ -- Function: x:draw-string drawable gc position string POSITION specifies coordinates relative to the origin of DRAWABLE of the origin of the first character to be drawn. `x:draw-string' draws the characters of STRING, starting at POSITION. -- Function: x:image-string drawable gc position string POSITION specifies coordinates relative to the origin of DRAWABLE of the origin of the first character to be drawn. `x:image-string' draws the characters _and background_ of STRING, starting at POSITION. Draw Shapes =========== -- Function: x:draw-points drawable gc position ... POSITION ... specifies coordinates of the point to be drawn. -- Function: x:draw-points drawable gc x y ... (X, Y) ... specifies coordinates of the point to be drawn. -- Function: x:draw-points drawable gc point-array POINT-ARRAY is a uniform short array of rank 2, whose rightmost index spans a range of 2. The `X:Draw-Points' procedure uses the foreground pixel and function components of the GC to draw points into DRAWABLE at the positions (relative to the origin of DRAWABLE) specified. `X:Draw-Points' uses these GC components: function, planemask, foreground, subwindow-mode, clip-x-origin, clip-y-origin, and clip-mask. -- Function: x:draw-segments drawable gc pos1 pos2 ... POS1, POS2, ... specify coordinates to be connected by segments. -- Function: x:draw-segments drawable gc x1 y1 x2 y2 ... (X1, Y1), (X2, Y2) ... specify coordinates to be connected by segments. -- Function: x:draw-segments drawable gc point-array POINT-ARRAY is a uniform short array of rank 2, whose rightmost index spans a range of 2. The `X:Draw-Segments' procedure uses the components of the specified GC to draw multiple unconnected lines between disjoint adjacent pair of points passed as arguments. It draws the segments in order and does not perform joining at coincident endpoints. For any given line, `X:Draw-Segments' does not draw a pixel more than once. If thin (zero line-width) segments intersect, the intersecting pixels are drawn multiple times. If wide segments intersect, the intersecting pixels are drawn only once, as though the entire PolyLine protocol request were a single, filled shape. `X:Draw-Segments' treats all coordinates as relative to the origin of DRAWABLE. `X:Draw-Segments' uses these GC components: function, plane-mask, line-width, line-style, cap-style, fill-style, subwindow-mode, clip-x-origin, clip-y-origin, and clip-mask, join-style. It also use these GC mode-dependent components: foreground, background, tile, stipple, tilestipple-x-origin, tile-stipple-y-origin, dash-offset, and dash-list. -- Function: x:draw-lines drawable gc pos1 pos2 ... POS1, POS2, ... specify coordinates to be connected by lines. -- Function: x:draw-lines drawable gc x1 y1 x2 y2 ... (X1, Y1), (X2, Y2) ... specify coordinates to be connected by lines. -- Function: x:draw-lines drawable gc point-array POINT-ARRAY is a uniform short array of rank 2, whose rightmost index spans a range of 2. The `X:Draw-Lines' procedure uses the components of the specified GC to draw lines between each adjacent pair of points passed as arguments. It draws the lines in order. The lines join correctly at all intermediate points, and if the first and last points coincide, the first and last lines also join correctly. For any given line, `X:Draw-Lines' does not draw a pixel more than once. If thin (zero line-width) lines intersect, the intersecting pixels are drawn multiple times. If wide lines intersect, the intersecting pixels are drawn only once, as though the entire PolyLine protocol request were a single, filled shape. `X:Draw-Lines' treats all coordinates as relative to the origin of DRAWABLE. `X:Draw-Lines' uses these GC components: function, plane-mask, line-width, line-style, cap-style, fill-style, subwindow-mode, clip-x-origin, clip-y-origin, and clip-mask, join-style. It also use these GC mode-dependent components: foreground, background, tile, stipple, tilestipple-x-origin, tile-stipple-y-origin, dash-offset, and dash-list. -- Function: x:fill-polygon drawable gc pos1 pos2 ... POS1, POS2, ... specify coordinates of the border path. -- Function: x:fill-polygon drawable gc x1 y1 x2 y2 ... (X1, Y1), (X2, Y2) ... specify coordinates of the border path. -- Function: x:fill-polygon drawable gc point-array POINT-ARRAY is a uniform short array of rank 2, whose rightmost index spans a range of 2. The path is closed automatically if the last point in the list or POINT-ARRAY does not coincide with the first point. The `X:Fill-Polygon' procedure uses the components of the specified GC to fill the region closed by the specified path. `X:Fill-Polygon' does not draw a pixel of the region more than once. `X:Fill-Polygon' treats all coordinates as relative to the origin of DRAWABLE. `X:Fill-Polygon' uses these GC components: function, planemask, fill-style, fill-rule, subwindow-mode, clip-x-origin, clip-y-origin, and clip-mask. It also use these GC mode-dependent components: foreground, background, tile, stipple, tile-stipple-x-origin, and tile-stipple-y-origin.  File: Xlibscm.info, Node: Images, Next: Event, Prev: Rendering, Up: Top 8 Images ******** -- Function: x:read-bitmap-file drawable file  File: Xlibscm.info, Node: Event, Next: Indexes, Prev: Images, Up: Top 9 Event ******* These three status routines always return immediately if there are events already in the queue. -- Function: x:q-length display Returns the length of the event queue for the connected DISPLAY. Note that there may be more events that have not been read into the queue yet (see X:Events-Queued). -- Function: x:pending display Returns the number of events that have been received from the X server but have not been removed from the event queue. -- Function: x:events-queued display Returns the number of events already in the queue if the number is nonzero. If there are no events in the queue, `X:Events-Queued' attempts to read more events out of the application's connection without flushing the output buffer and returns the number read. Both of these routines return an object of type "event". -- Function: x:next-event display Removes and returns the first event from the event queue. If the event queue is empty, `X:Next-Event' flushes the output buffer and blocks until an event is received. -- Function: x:peek-event display Returns the first event from the event queue, but it does not remove the event from the queue. If the queue is empty, `X:Peek-Event' flushes the output buffer and blocks until an event is received. Each event object has fields dependent on its sub-type. -- Function: x:event-ref event field-name window The window on which EVENT was generated and is referred to as the event window. root is the event window's root window. subwindow If the source window is an inferior of the event window, the SUBWINDOW is the child of the event window that is the source window or the child of the event window that is an ancestor of the source window. Otherwise, `None'. X-event:type An integer: X:KEY-PRESS, X:KEY-RELEASE, X:BUTTON-PRESS, X:BUTTON-RELEASE, X:MOTION-NOTIFY, X:ENTER-NOTIFY, X:LEAVE-NOTIFY, X:FOCUS-IN, X:FOCUS-OUT, X:KEYMAP-NOTIFY, X:EXPOSE, X:GRAPHICS-EXPOSE, X:NO-EXPOSE, X:VISIBILITY-NOTIFY, X:CREATE-NOTIFY, X:DESTROY-NOTIFY, X:UNMAP-NOTIFY, X:MAP-NOTIFY, X:MAP-REQUEST, X:REPARENT-NOTIFY, X:CONFIGURE-NOTIFY, X:CONFIGURE-REQUEST, X:GRAVITY-NOTIFY, X:RESIZE-REQUEST, X:CIRCULATE-NOTIFY, X:CIRCULATE-REQUEST, X:PROPERTY-NOTIFY, X:SELECTION-CLEAR, X:SELECTION-REQUEST, X:SELECTION-NOTIFY, X:COLORMAP-NOTIFY, X:CLIENT-MESSAGE, or X:MAPPING-NOTIFY. X-event:serial The serial number of the protocol request that generated the EVENT. X-event:send-event Boolean that indicates whether the event was sent by a different client. X-event:time The time when the EVENT was generated expressed in milliseconds. X-event:x X-event:y For window entry/exit events the X and Y members are set to the coordinates of the pointer position in the event window. This position is always the pointer's final position, not its initial position. If the event window is on the same screen as the root window, X and Y are the pointer coordinates relative to the event window's origin. Otherwise, X and Y are set to zero. For expose events The X and Y members are set to the coordinates relative to the drawable's origin and indicate the upper-left corner of the rectangle. For configure, create, gravity, and reparent events the X and Y members are set to the window's coordinates relative to the parent window's origin and indicate the position of the upper-left outside corner of the created window. X-event:x-root X-event:y-root The pointer's coordinates relative to the root window's origin at the time of the EVENT. X-event:state For keyboard, pointer and window entry/exit events, the state member is set to indicate the logical state of the pointer buttons and modifier keys just prior to the EVENT, which is the bitwise inclusive OR of one or more of the button or modifier key masks: X:BUTTON1-MASK, X:BUTTON2-MASK, X:BUTTON3-MASK, X:BUTTON4-MASK, X:BUTTON5-MASK, X:SHIFT-MASK, X:LOCK-MASK, X:CONTROL-MASK, X:MOD1-MASK, X:MOD2-MASK, X:MOD3-MASK, X:MOD4-MASK, and X:MOD5-MASK. For visibility events, the state of the window's visibility: X:VISIBILITY-UNOBSCURED, X:VISIBILITY-PARTIALLY-OBSCURED, or X:VISIBILITY-FULLY-OBSCURED. For colormap events, indicates whether the colormap is installed or uninstalled: x:Colormap-Installed or x:Colormap-Uninstalled. For property events, indicates whether the property was changed to a new value or deleted: x:Property-New-Value or x:Property-Delete. X-event:keycode An integer that represents a physical key on the keyboard. X-event:same-screen Indicates whether the event window is on the same screen as the root window. If #t, the event and root windows are on the same screen. If #f, the event and root windows are not on the same screen. X-event:button The pointer button that changed state; can be the X:BUTTON1, X:BUTTON2, X:BUTTON3, X:BUTTON4, or X:BUTTON5 value. X-event:is-hint Detail of motion-notify events: X:NOTIFY-NORMAL or X:NOTIFY-HINT. X-event:mode Indicates whether the EVENT is a normal event, pseudo-motion event when a grab activates, or a pseudo-motion event when a grab deactivates: X:NOTIFY-NORMAL, X:NOTIFY-GRAB, or X:NOTIFY-UNGRAB. X-event:detail Indicates the notification detail: X:NOTIFY-ANCESTOR, X:NOTIFY-VIRTUAL, X:NOTIFY-INFERIOR, X:NOTIFY-NONLINEAR, or X:NOTIFY-NONLINEAR-VIRTUAL. X-event:focus If the event window is the focus window or an inferior of the focus window, #t; otherwise #f. X-event:width X-event:height The size (extent) of the rectangle. X-event:count For mapping events is the number of keycodes altered. For expose events Is the number of Expose or GraphicsExpose events that are to follow. If count is zero, no more Expose events follow for this window. However, if count is nonzero, at least that number of Expose events (and possibly more) follow for this window. Simple applications that do not want to optimize redisplay by distinguishing between subareas of its window can just ignore all Expose events with nonzero counts and perform full redisplays on events with zero counts. X-event:major-code The major_code member is set to the graphics request initiated by the client and can be either X_CopyArea or X_CopyPlane. If it is X_CopyArea, a call to XCopyArea initiated the request. If it is X_CopyPlane, a call to XCopyPlane initiated the request. X-event:minor-code Not currently used. X-event:border-width For configure events, the width of the window's border, in pixels. X-event:override-redirect The override-redirect attribute of the window. Window manager clients normally should ignore this window if it is #t. X-event:from-configure True if the event was generated as a result of a resizing of the window's parent when the window itself had a win-gravity of x:Unmap-Gravity. X-event:value-mask Indicates which components were specified in the ConfigureWindow protocol request. The corresponding values are reported as given in the request. The remaining values are filled in from the current geometry of the window, except in the case of above (sibling) and detail (stack-mode), which are reported as None and Above, respectively, if they are not given in the request. X-event:place The window's position after the restack occurs and is either x:Place-On-Top or x:Place-On-Bottom. If it is x:Place-On-Top, the window is now on top of all siblings. If it is x:Place-On-Bottom, the window is now below all siblings. X-event:new indicate whether the colormap for the specified window was changed or installed or uninstalled and can be True or False. If it is True, the colormap was changed. If it is False, the colormap was installed or uninstalled. X-event:format Is 8, 16, or 32 and specifies whether the data should be viewed as a list of bytes, shorts, or longs X-event:request Indicates the kind of mapping change that occurred and can be X:MAPPING-MODIFIER, X:MAPPING-KEYBOARD, or X:MAPPING-POINTER. If it is X:MAPPING-MODIFIER, the modifier mapping was changed. If it is X:MAPPING-KEYBOARD, the keyboard mapping was changed. If it is X:MAPPING-POINTER, the pointer button mapping was changed. X-event:first-keycode The X-event:first-keycode is set only if the X-event:request was set to X:MAPPING-KEYBOARD. The number in X-event:first-keycode represents the first number in the range of the altered mapping, and X-event:count represents the number of keycodes altered.  File: Xlibscm.info, Node: Indexes, Prev: Event, Up: Top Indexes ******* * Menu: * Procedure and Macro Index:: * Variable Index:: * Concept Index::  File: Xlibscm.info, Node: Procedure and Macro Index, Next: Variable Index, Prev: Indexes, Up: Indexes Procedure and Macro Index ========================= [index] * Menu: * hostname:number.screen-number: Display and Screens. (line 18) * x:alloc-colormap-cells: Colormap. (line 83) * x:ccc: Colormap. (line 218) * x:clear-area: Rendering. (line 27) * x:close <1>: Windows and Pixmaps. (line 49) * x:close: Display and Screens. (line 33) * x:color-ref: Colormap. (line 184) * X:Color-Set!: Colormap. (line 191) * x:colormap-find-color: Colormap. (line 162) * x:copy-colormap-and-free: Colormap. (line 61) * x:copy-gc-fields!: Graphics Context. (line 25) * x:create-colormap: Colormap. (line 9) * x:create-cursor: Cursor. (line 7) * x:create-gc: Graphics Context. (line 13) * x:create-pixmap: Windows and Pixmaps. (line 39) * x:create-window: Windows and Pixmaps. (line 8) * x:default-ccc: Display and Screens. (line 88) * x:default-colormap: Display and Screens. (line 83) * x:default-gc: Display and Screens. (line 94) * x:default-screen: Display and Screens. (line 65) * x:default-visual: Display and Screens. (line 106) * x:draw-lines: Rendering. (line 111) * x:draw-points: Rendering. (line 63) * x:draw-segments: Rendering. (line 81) * x:draw-string: Rendering. (line 46) * x:event-ref: Event. (line 40) * x:events-queued: Event. (line 19) * x:fill-polygon: Rendering. (line 142) * x:fill-rectangle: Rendering. (line 41) * x:flush: Rendering. (line 7) * x:free-colormap-cells: Colormap. (line 138) * x:gc-ref: Graphics Context. (line 30) * x:gc-set!: Graphics Context. (line 18) * x:get-window-property: Window Properties and Visibility. (line 7) * x:image-string: Rendering. (line 53) * x:install-colormap: Colormap. (line 207) * x:list-properties: Window Properties and Visibility. (line 15) * x:make-visual: Display and Screens. (line 112) * x:map-subwindows: Window Properties and Visibility. (line 60) * x:map-window: Window Properties and Visibility. (line 23) * x:next-event: Event. (line 27) * x:open-display: Display and Screens. (line 7) * x:peek-event: Event. (line 32) * x:pending: Event. (line 15) * x:protocol-version: Display and Screens. (line 46) * x:q-length: Event. (line 10) * x:read-bitmap-file: Images. (line 7) * x:root-window: Display and Screens. (line 70) * x:screen-black: Display and Screens. (line 182) * x:screen-cells: Display and Screens. (line 149) * x:screen-count: Display and Screens. (line 62) * x:screen-depth: Display and Screens. (line 154) * x:screen-depths: Display and Screens. (line 99) * x:screen-dimensions: Display and Screens. (line 171) * x:screen-size: Display and Screens. (line 166) * x:screen-white: Display and Screens. (line 177) * x:server-vendor: Display and Screens. (line 51) * x:unmap-subwindows: Window Properties and Visibility. (line 79) * x:unmap-window: Window Properties and Visibility. (line 68) * x:vendor-release: Display and Screens. (line 56) * x:visual-class: Display and Screens. (line 132) * x:visual-geometry: Display and Screens. (line 137) * x:window-geometry: Windows and Pixmaps. (line 67) * x:window-geometry-set!: Windows and Pixmaps. (line 88) * x:window-ref: Window Attributes. (line 280) * x:window-set!: Window Attributes. (line 7)  File: Xlibscm.info, Node: Variable Index, Next: Concept Index, Prev: Procedure and Macro Index, Up: Indexes Variable Index ============== [index] * Menu: * x:CW-Back-Pixel: Window Attributes. (line 29) * x:CW-Back-Pixmap: Window Attributes. (line 19) * x:CW-Backing-Pixel: Window Attributes. (line 138) * x:CW-Backing-Planes: Window Attributes. (line 137) * x:CW-Backing-Store: Window Attributes. (line 108) * x:CW-Bit-Gravity: Window Attributes. (line 46) * x:CW-Border-Pixel: Window Attributes. (line 42) * x:CW-Border-Pixmap: Window Attributes. (line 35) * x:CW-Border-Width: Windows and Pixmaps. (line 112) * x:CW-Colormap: Window Attributes. (line 251) * x:CW-Cursor: Window Attributes. (line 269) * x:CW-Dont-Propagate: Window Attributes. (line 240) * x:CW-Event-Mask: Window Attributes. (line 182) * x:CW-Height: Windows and Pixmaps. (line 100) * x:CW-Override-Redirect: Window Attributes. (line 154) * x:CW-Save-Under: Window Attributes. (line 168) * x:CW-Sibling: Windows and Pixmaps. (line 119) * x:CW-Stack-Mode: Windows and Pixmaps. (line 123) * x:CW-Width: Windows and Pixmaps. (line 99) * x:CW-Win-Gravity: Window Attributes. (line 47) * x:CWX: Windows and Pixmaps. (line 97) * x:CWY: Windows and Pixmaps. (line 98) * x:GC-Arc-Mode: Graphics Context. (line 348) * x:GC-Background: Graphics Context. (line 92) * x:GC-Cap-Style: Graphics Context. (line 153) * x:GC-Clip-Mask: Graphics Context. (line 309) * x:GC-Clip-X-Origin: Graphics Context. (line 304) * x:GC-Clip-Y-Origin: Graphics Context. (line 305) * x:GC-Dash-List: Graphics Context. (line 339) * x:GC-Dash-Offset: Graphics Context. (line 322) * x:GC-Fill-Rule: Graphics Context. (line 228) * x:GC-Fill-Style: Graphics Context. (line 190) * x:GC-Font: Graphics Context. (line 281) * x:GC-Foreground: Graphics Context. (line 91) * x:GC-Function: Graphics Context. (line 42) * x:GC-Graphics-Exposures: Graphics Context. (line 299) * x:GC-Join-Style: Graphics Context. (line 174) * x:GC-Line-Style: Graphics Context. (line 137) * x:GC-Line-Width: Graphics Context. (line 100) * x:GC-Plane-Mask: Graphics Context. (line 70) * x:GC-Stipple: Graphics Context. (line 259) * x:GC-Subwindow-Mode: Graphics Context. (line 284) * x:GC-Tile: Graphics Context. (line 258) * x:GC-Tile-Stip-X-Origin: Graphics Context. (line 272) * x:GC-Tile-Stip-Y-Origin: Graphics Context. (line 273)  File: Xlibscm.info, Node: Concept Index, Prev: Variable Index, Up: Indexes Concept Index ============= [index] * Menu: * colormap: Colormap. (line 6) * cursor: Cursor. (line 7) * depth: Display and Screens. (line 161) * drawable: Drawables. (line 6) * Drawable: Drawables. (line 6) * map: Window Properties and Visibility. (line 18) * mapped: Window Properties and Visibility. (line 18) * none: Graphics Context. (line 311) * RGB: Colormap. (line 6) * unmap: Window Properties and Visibility. (line 18) * unmapped: Window Properties and Visibility. (line 18) * Visual: Display and Screens. (line 110) * visual: Display and Screens. (line 110) * X: XlibScm. (line 6) * x:None: Graphics Context. (line 311) * Xlib: XlibScm. (line 10)  Tag Table: Node: Top1054 Node: XlibScm2138 Node: Display and Screens4932 Node: Drawables11974 Node: Windows and Pixmaps12239 Node: Window Attributes19341 Node: Window Properties and Visibility35346 Node: Graphics Context39818 Node: Cursor55558 Node: Colormap58069 Node: Rendering67964 Node: Images75544 Node: Event75690 Node: Indexes90177 Node: Procedure and Macro Index90333 Node: Variable Index95785 Node: Concept Index99238  End Tag Table scm-5e5/build.bat0000755001705200017500000000015010173362263011623 0ustar tbtbscmlit -fbuild -e(bi) build %* @IF NOT ERRORLEVEL 1 GOTO ok @ECHO **** build.bat FAILED! **** :ok scm-5e5/unexsunos4.c0000644001705200017500000002522610750241355012342 0ustar tbtb/* Unexec for Sunos 4 using shared libraries. Copyright (C) 1990, 1994 Free Software Foundation, Inc. This file is part of GNU Emacs. GNU Emacs 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 3 of the License, or (at your option) any later version. GNU Emacs 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 GNU Emacs. If not, see . */ /* Contributed by Viktor Dukhovni. */ /* * Unexec for Berkeley a.out format + SUNOS shared libraries * The unexeced executable contains the __DYNAMIC area from the * original text file, and then the rest of data + bss + malloced area of * the current process. (The __DYNAMIC area is at the top of the process * data segment, we use "data_start" defined externally to mark the start * of the "real" data segment.) * * For programs that want to remap some of the data segment read only * a run_time_remap is provided. This attempts to remap largest area starting * and ending on page boundaries between "data_start" and "bndry" * For this it to figure out where the text file is located. A path search * is attempted after trying argv[0] and if all fails we simply do not remap * * One feature of run_time_remap () is mandatory: reseting the break. * * Note that we can no longer map data into the text segment, as this causes * the __DYNAMIC struct to become read only, breaking the runtime loader. * Thus we no longer need to mess with a private crt0.c, the standard one * will do just fine, since environ can live in the writable area between * __DYNAMIC and data_start, just make sure that pre-crt0.o (the name * is somewhat abused here) is loaded first! * */ #include #include #include #include #include #include #include /* Do this after the above #include's in case a configuration file wants to define things for this file based on what defines. */ #ifdef emacs #include #endif #if defined (SUNOS4) || defined (__FreeBSD__) || defined (__NetBSD__) #define UNDO_RELOCATION #endif #ifdef UNDO_RELOCATION #include #endif #ifdef HAVE_UNISTD_H #include #endif /* NetBSD needs this bit, but SunOS does not have it. */ #ifndef MAP_FILE #define MAP_FILE 0 #endif /* * for programs other than emacs * define data_start + initialized here, and make sure * this object is loaded first! * emacs will define these elsewhere, and load the object containing * data_start (pre-crt0.o or firstfile.o?) first! * The custom crt0.o *must not* be loaded! */ #ifndef emacs static int data_start = 0; static int initialized = 0; #else extern int initialized; extern unsigned data_start; extern int pureptr; #endif extern char *getenv (); static unsigned brk_value; static struct exec nhdr; static int rd_only_len; static long cookie; unexec (new_name, a_name, bndry, bss_start, entry) char *new_name, *a_name; unsigned bndry, bss_start, entry; { int fd, new; char *old; struct exec ohdr; /* Allocate on the stack, not needed in the next life */ struct stat stat; if ((fd = open (a_name, O_RDONLY)) < 0) { fprintf (stderr, "%s: open: ", a_name); perror (a_name); exit (1); } if ((new = open (new_name, O_WRONLY | O_CREAT, 0666)) == -1) { fprintf (stderr, "%s: open: ", a_name); perror (new_name); exit (1); } if ((fstat (fd, &stat) == -1)) { fprintf (stderr, "%s: ", a_name); perror ("fstat"); exit (1); } old = (char *)mmap (0, stat.st_size, PROT_READ, MAP_FILE|MAP_SHARED, fd, 0); if (old == (char *)-1) { fprintf (stderr, "%s: ", a_name); perror ("mmap"); exit (1); } close (fd); nhdr = ohdr = (*(struct exec *)old); /* * Remember a magic cookie so we know we've got the right binary * when remapping. */ cookie = time (0); /* Save the break, it is reset to &_end (by ld.so?). */ brk_value = (unsigned) sbrk (0); /* * Round up data start to a page boundary (Lose if not a 2 power!) */ data_start = ((((int)&data_start) - 1) & ~(N_PAGSIZ (nhdr) - 1)) + N_PAGSIZ (nhdr); /* * Round down read only pages to a multiple of the page size */ if (bndry) rd_only_len = ((int)bndry & ~(N_PAGSIZ (nhdr) - 1)) - data_start; #ifndef emacs /* Have to do this some time before dumping the data */ initialized = 1; #endif /* Handle new data and bss sizes and optional new entry point. No one actually uses bss_start and entry, but tradition compels one to support them. Could complain if bss_start > brk_value, but the caller is *supposed* to know what she is doing. */ nhdr.a_data = (bss_start ? bss_start : brk_value) - N_DATADDR (nhdr); nhdr.a_bss = bss_start ? brk_value - bss_start : 0; if (entry) nhdr.a_entry = entry; /* * Write out the text segment with new header * Dynamic executables are ZMAGIC with N_TXTOFF==0 and the header * part of the text segment, but no need to rely on this. * So write the TEXT first, then go back replace the header. * Doing it in the other order is less general! */ lseek (new, N_TXTOFF (nhdr), L_SET); write (new, old + N_TXTOFF (ohdr), N_TXTOFF (ohdr) + ohdr.a_text); lseek (new, 0L, L_SET); write (new, &nhdr, sizeof (nhdr)); /* * Write out the head of the old data segment from the file not * from core, this has the unresolved __DYNAMIC relocation data * we need to reload */ lseek (new, N_DATOFF (nhdr), L_SET); write (new, old + N_DATOFF (ohdr), (int)&data_start - N_DATADDR (ohdr)); /* * Copy the rest of the data from core */ write (new, &data_start, N_BSSADDR (nhdr) - (int)&data_start); /* * Copy the symbol table and line numbers */ lseek (new, N_TRELOFF (nhdr), L_SET); write (new, old + N_TRELOFF (ohdr), stat.st_size - N_TRELOFF (ohdr)); /* Some other BSD systems use this file. We don't know whether this change is right for them. */ #ifdef UNDO_RELOCATION /* Undo the relocations done at startup by ld.so. It will do these relocations again when we start the dumped Emacs. Doing them twice gives incorrect results. */ { unsigned long daddr = N_DATADDR (ohdr); unsigned long rel, erel; #ifdef SUNOS4 #ifdef SUNOS4_SHARED_LIBRARIES extern struct link_dynamic _DYNAMIC; /* SunOS4.x's ld_rel is relative to N_TXTADDR. */ if (!ohdr.a_dynamic) /* This was statically linked. */ rel = erel = 0; else if (_DYNAMIC.ld_version < 2) { rel = _DYNAMIC.ld_un.ld_1->ld_rel + N_TXTADDR (ohdr); erel = _DYNAMIC.ld_un.ld_1->ld_hash + N_TXTADDR (ohdr); } else { rel = _DYNAMIC.ld_un.ld_2->ld_rel + N_TXTADDR (ohdr); erel = _DYNAMIC.ld_un.ld_2->ld_hash + N_TXTADDR (ohdr); } #else /* not SUNOS4_SHARED_LIBRARIES */ rel = erel = 0; #endif /* not SUNOS4_SHARED_LIBRARIES */ #ifdef sparc #define REL_INFO_TYPE struct reloc_info_sparc #else #define REL_INFO_TYPE struct relocation_info #endif /* sparc */ #define REL_TARGET_ADDRESS(r) (((REL_INFO_TYPE *)(r))->r_address) #endif /* SUNOS4 */ #if defined (__FreeBSD__) || defined (__NetBSD__) extern struct _dynamic _DYNAMIC; /* FreeBSD's LD_REL is a virtual address itself. */ rel = LD_REL (&_DYNAMIC); erel = rel + LD_RELSZ (&_DYNAMIC); #define REL_INFO_TYPE struct relocation_info #define REL_TARGET_ADDRESS(r) (((REL_INFO_TYPE *)(r))->r_address) #endif for (; rel < erel; rel += sizeof (REL_INFO_TYPE)) { /* This is the virtual address where ld.so will do relocation. */ unsigned long target = REL_TARGET_ADDRESS (rel); /* This is the offset in the data segment. */ unsigned long segoffset = target - daddr; /* If it is located below data_start, we have to do nothing here, because the old data has been already written to the location. */ if (target < (unsigned long)&data_start) continue; lseek (new, N_DATOFF (nhdr) + segoffset, L_SET); write (new, old + N_DATOFF (ohdr) + segoffset, sizeof (unsigned long)); } } #endif /* UNDO_RELOCATION */ fchmod (new, 0755); } void run_time_remap (progname) char *progname; { char aout[MAXPATHLEN]; register char *path, *p; /* Just in case */ if (!initialized) return; /* Restore the break */ brk ((char *) brk_value); /* If nothing to remap: we are done! */ if (rd_only_len == 0) return; /* * Attempt to find the executable * First try argv[0], will almost always succeed as shells tend to give * the full path from the hash list rather than using execvp () */ if (is_it (progname)) return; /* * If argv[0] is a full path and does not exist, not much sense in * searching further */ if (strchr (progname, '/')) return; /* * Try to search for argv[0] on the PATH */ path = getenv ("PATH"); if (path == NULL) return; while (*path) { /* copy through ':' or end */ for (p = aout; *p = *path; ++p, ++path) if (*p == ':') { ++path; /* move past ':' */ break; } *p++ = '/'; strcpy (p, progname); /* * aout is a candidate full path name */ if (is_it (aout)) return; } } is_it (filename) char *filename; { int fd; long filenames_cookie; struct exec hdr; /* * Open an executable and check for a valid header! * Can't bcmp the header with what we had, it may have been stripped! * so we may save looking at non executables with the same name, mostly * directories. */ fd = open (filename, O_RDONLY); if (fd != -1) { if (read (fd, &hdr, sizeof (hdr)) == sizeof (hdr) && !N_BADMAG (hdr) && N_DATOFF (hdr) == N_DATOFF (nhdr) && N_TRELOFF (hdr) == N_TRELOFF (nhdr)) { /* compare cookies */ lseek (fd, N_DATOFF (hdr) + (int)&cookie - N_DATADDR (hdr), L_SET); read (fd, &filenames_cookie, sizeof (filenames_cookie)); if (filenames_cookie == cookie) { /* Eureka */ /* * Do the mapping * The PROT_EXEC may not be needed, but it is safer this way. * should the shared library decide to indirect through * addresses in the data segment not part of __DYNAMIC */ mmap ((char *) data_start, rd_only_len, PROT_READ | PROT_EXEC, MAP_FILE | MAP_SHARED | MAP_FIXED, fd, N_DATOFF (hdr) + data_start - N_DATADDR (hdr)); close (fd); return 1; } } close (fd); } return 0; } scm-5e5/eval.c0000644001705200017500000027570210750224437011146 0ustar tbtb/* "eval.c" eval and apply. * Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2002, 2006 Free Software Foundation, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see * . */ /* Authors: Radey Shouman, Aubrey Jaffer, & Hugh E. Secker-Walker. */ #include "scm.h" #include "setjump.h" #ifdef _M_ARM /* The Microsoft CLARM compiler has a bug in pointer arithmetic. It doesn't always take into account that data acceses have to be DWORD aligned. The MS_CLARM_dumy assignment resolves this problem. */ # define I_SYM(x) (CAR((SCM)(MS_CLARM_dumy = (x)-1L))) # define I_VAL(x) (CDR((SCM)(MS_CLARM_dumy = (x)-1L))) #else # define I_SYM(x) (CAR((x)-1L)) # define I_VAL(x) (CDR((x)-1L)) #endif #define ATOMP(x) (5==(5 & (int)CAR(x))) #define EVALCELLCAR(x) (ATOMP(CAR(x))?evalatomcar(x, 0):ceval_1(CAR(x))) #define EVALIMP(x) (ILOCP(x)?*ilookup(x):x) #define EVALCAR(x) (NCELLP(CAR(x))?(IMP(CAR(x))?EVALIMP(CAR(x)):\ I_VAL(CAR(x))):EVALCELLCAR(x)) /* Environment frames are initially allocated in a small cache ("ecache"). This cache is subject to copying gc, cells in it may be moved to the general purpose Scheme heap by a call to any routine that allocates cells in the cache. Global variables scm_env and scm_env_tmp are used as software registers: scm_env is the current lexical environment, scm_env_tmp is used for protecting environment frames under construction and not yet linked into the environment. In order to protect environments from garbage collection, a stack of environments (scm_estk) is maintained. scm_env and scm_env_tmp may be pushed on or popped off the stack using the macros ENV_PUSH and ENV_POP. It is not safe to pass objects that may allocated in the ecache as arguments to C functions, or to return them from C functions, since such objects may be moved by the ecache gc. Ecache gc may happen anywhere interrupts are not deferred, because some interrupt handlers may evaluate Scheme code and then return. Interrupts may be deferred with DEFER_INTS_EGC: This will prevent interrupts until an ALLOW_INTS or ALLOW_INTS_EGC, which may happen any time Scheme code is evaluated. It is not necessary to strictly nest DEFER_INTS_EGC and ALLOW_INTS_EGC since ALLOW_INTS_EGC is called in ceval_1 before any subrs are called. Instead of using the C stack and deferring interrupts, objects which might have been allocated in the ecache may be passed using the global variables scm_env_tmp and scm_env. If the CAR of a cell that might be allocated in the regular heap is made to point to a cell allocated in the cache, then the first cell must be recorded as a gc root, using the macro EGC_ROOT. There is no provision for allowing the CDR of a regular cell to point to a cache cell. */ #ifdef NO_ENV_CACHE # define scm_env_cons(a, b) {scm_env_tmp=cons((a), (b));} # define scm_env_cons2(a, b, c) {scm_env_tmp=cons2((a), (b), (c));} # define scm_env_cons3(a, b, c, d) {scm_env_tmp=cons2((a), (b), cons((c), (d)));} # define EXTEND_VALENV {scm_env=cons(scm_env_tmp, scm_env);} # define ENV_V2LST(argc, argv) \ {scm_env_tmp=scm_v2lst((argc), (argv), scm_env_tmp);} #else # define EXTEND_VALENV {scm_extend_env();} # define ENV_V2LST scm_env_v2lst #endif #define EXTEND_ENV cons SCM scm_env, scm_env_tmp; long tc16_env; /* Type code for environments passed to macro transformers. */ SCM nconc2copy P((SCM x)); SCM scm_cp_list P((SCM x, int minlen)); SCM scm_v2lst P((long argc, SCM *argv, SCM end)); SCM renamed_ident P((SCM id, SCM env)); SCM eqv P((SCM x, SCM y)); SCM scm_multi_set P((SCM syms, SCM vals)); SCM eval_args P((SCM x)); SCM m_quote P((SCM xorig, SCM env, SCM ctxt)); SCM m_begin P((SCM xorig, SCM env, SCM ctxt)); SCM m_if P((SCM xorig, SCM env, SCM ctxt)); SCM m_set P((SCM xorig, SCM env, SCM ctxt)); SCM m_and P((SCM xorig, SCM env, SCM ctxt)); SCM m_or P((SCM xorig, SCM env, SCM ctxt)); SCM m_cond P((SCM xorig, SCM env, SCM ctxt)); SCM m_case P((SCM xorig, SCM env, SCM ctxt)); SCM m_lambda P((SCM xorig, SCM env, SCM ctxt)); SCM m_letstar P((SCM xorig, SCM env, SCM ctxt)); SCM m_do P((SCM xorig, SCM env, SCM ctxt)); SCM m_quasiquote P((SCM xorig, SCM env, SCM ctxt)); SCM m_delay P((SCM xorig, SCM env, SCM ctxt)); SCM m_define P((SCM xorig, SCM env, SCM ctxt)); SCM m_letrec P((SCM xorig, SCM env, SCM ctxt)); SCM m_let P((SCM xorig, SCM env, SCM ctxt)); SCM m_apply P((SCM xorig, SCM env, SCM ctxt)); SCM m_syn_quote P((SCM xorig, SCM env, SCM ctxt)); SCM m_define_syntax P((SCM xorig, SCM env, SCM ctxt)); SCM m_let_syntax P((SCM xorig, SCM env, SCM ctxt)); SCM m_letrec_syntax P((SCM xorig, SCM env, SCM ctxt)); SCM m_the_macro P((SCM xorig, SCM env, SCM ctxt)); void scm_dynthrow P((SCM cont, SCM arg1, SCM arg2, SCM rest)); void scm_egc P((void)); void scm_estk_grow P((void)); void scm_estk_shrink P((void)); int badargsp P((SCM formals, SCM args)); static SCM *lookupcar P((SCM vloc)); static SCM scm_lookupval P((SCM vloc, int memo)); static SCM asubr_apply P((SCM proc, SCM arg1, SCM arg2, SCM arg3, SCM args)); static SCM ceval_1 P((SCM x)); static SCM evalatomcar P((SCM x, int toplevelp)); static SCM evalcar P((SCM x)); static SCM id2sym P((SCM id)); static SCM iqq P((SCM form)); static SCM m_body P((SCM xorig, SCM env, SCM ctxt)); static SCM m_iqq P((SCM form, int depth, SCM env, SCM ctxt)); static SCM m_parse_let P((SCM imm, SCM xorig, SCM x, SCM *vars, SCM *inits)); static SCM m_let_null P((SCM body, SCM env, SCM ctxt)); static SCM m_letrec1 P((SCM imm, SCM xorig, SCM env, SCM ctxt)); static SCM m_letstar1 P((SCM imm, SCM vars, SCM inits, SCM body, SCM env, SCM ctxt)); static SCM macroexp1 P((SCM x, SCM env, SCM ctxt, int mode)); /* static int checking_defines_p P((SCM ctxt)); */ /* static SCM wrapenv P((void)); */ static SCM scm_case_selector P((SCM x)); static SCM acro_call P((SCM x, SCM env)); static SCM m_binding P((SCM name, SCM value, SCM env, SCM ctxt)); static SCM m_bindings P((SCM name, SCM value, SCM env, SCM ctxt)); static SCM m_seq P((SCM x, SCM env, SCM ctxt)); static SCM m_expr P((SCM x, SCM env, SCM ctxt)); static void checked_define P((SCM name, SCM val, const char *what)); static int topdenote_eq P((SCM sym, SCM id, SCM env)); static int constant_p P((SCM x)); static int prinenv P((SCM exp, SCM port, int writing)); static int prinid P((SCM exp, SCM port, int writing)); static int prinmacro P((SCM exp, SCM port, int writing)); static int prinprom P((SCM exp, SCM port, int writing)); #ifdef MAC_INLINE static int env_depth P((void)); static void env_tail P((int depth)); #endif static void unpaint P((SCM *p)); static void ecache_evalx P((SCM x)); static int ecache_eval_args P((SCM proc, SCM arg1, SCM arg2, SCM arg3, SCM x)); static int varcheck P((SCM vars, SCM op, const char *what)); #ifdef CAREFUL_INTS static void debug_env_warn P((char *fnam, int line, const char *what)); static void debug_env_save P((char *fnam, int line)); #endif /* Flush global variable state to estk. */ #ifdef CAREFUL_INTS # define ENV_SAVE debug_env_save(__FILE__, __LINE__) #else # define ENV_SAVE {scm_estk_ptr[0]=scm_env; scm_estk_ptr[1]=scm_env_tmp;} #endif /* Make global variable state consistent with estk. */ #define ENV_RESTORE {scm_env=scm_estk_ptr[0]; scm_env_tmp=scm_estk_ptr[1];} #define ENV_PUSH \ {DEFER_INTS_EGC; ENV_SAVE;\ if (UNDEFINED==scm_estk_ptr[SCM_ESTK_FRLEN]) scm_estk_grow();\ else scm_estk_ptr += SCM_ESTK_FRLEN;\ STATIC_ENV=scm_estk_ptr[2 - SCM_ESTK_FRLEN];} #define ENV_POP {DEFER_INTS_EGC;\ if (UNDEFINED==scm_estk_ptr[-1]) scm_estk_shrink();\ else scm_estk_ptr -= SCM_ESTK_FRLEN; ENV_RESTORE;} #ifdef NO_ENV_CACHE # define EGC_ROOT(x) /**/ #else # ifdef CAREFUL_INTS # define EGC_ROOT(x) {if (!ints_disabled) \ debug_env_warn(__FILE__, __LINE__, "EGC_ROOT"); \ scm_egc_roots[--scm_egc_root_index] = (x); \ if (0==scm_egc_root_index) scm_egc();} # else # define EGC_ROOT(x) {scm_egc_roots[--scm_egc_root_index] = (x);\ if (0==scm_egc_root_index) scm_egc();} # endif #endif #ifndef RECKLESS SCM scm_trace, scm_trace_env; #endif #define ENV_MAY_POP(p, guard) if (p>0 && !(guard)) {ENV_POP; p=-1;} #define ENV_MAY_PUSH(p) if (p<=0) {ENV_PUSH; p=1;} #define SIDEVAL_1(x) if (NIMP(x)) ceval_1(x) #define STATIC_ENV (scm_estk_ptr[2]) #ifdef CAUTIOUS # define TRACE(x) {scm_estk_ptr[3]=(x);} # define TOP_TRACE(x, env) {scm_trace=(x); scm_trace_env=(env);} #else # define TRACE(x) /**/ # define TOP_TRACE(x, env) /**/ #endif #ifndef RECKLESS # define MACROEXP_TRACE(x, env) {scm_trace=(x); scm_trace_env=(env);} #else # define MACROEXP_TRACE(x, env) /**/ #endif long tc16_macro; /* Type code for macros */ #define MACROP(x) (tc16_macro==TYP16(x)) #define MAC_TYPE NUMDIGS #define MAC_PRIMITIVE 0x1L #define MAC_MEMOIZING 0x2L #define MAC_ACRO 0x4L #define MAC_MACRO 0x8L #define MAC_MMACRO 0x2L #define MAC_IDMACRO 0x6L /* Uncomment this to experiment with inline procedures: */ /* #define MAC_INLINE 0x10L */ #ifdef MACRO long tc16_ident; /* synthetic macro identifier */ static char s_escaped[] = "escaped synthetic identifier"; # define KEYWORDP(x) (NIMP(x) && IM_KEYWORD==CAR(x)) # define KEYWORD_MACRO CDR #else # define KEYWORDP(x) (NIMP(x) && MACROP(x)) # define KEYWORD_MACRO(x) (x) #endif /* #define SCM_PROFILE */ #ifdef SCM_PROFILE long eval_cases[128]; long eval_cases_other[NUM_ISYMS]; long ilookup_cases[10][10][2]; /* frame, dist, icdrp */ long eval_clo_cases[5][4]; /* actual args, required args */ SCM scm_profile(resetp) SCM resetp; { SCM ev = make_uve(sizeof(eval_cases)/sizeof(long), MAKINUM(-8L*sizeof(long))); SCM evo = make_uve(sizeof(eval_cases_other)/sizeof(long), MAKINUM(-8L*sizeof(long))); SCM il = dims2ura(cons2(MAKINUM(10), MAKINUM(10), cons(MAKINUM(2), EOL)), MAKINUM(-8L*sizeof(long)), EOL); SCM evc = dims2ura(cons2(MAKINUM(5), MAKINUM(4), EOL), MAKINUM(-8L*sizeof(long)), EOL); long *v = (long *)VELTS(ev); int i; for (i = 0; i < sizeof(eval_cases)/sizeof(long); i++) v[i] = eval_cases[i]; v = (long *)VELTS(evo); for (i = 0; i < sizeof(eval_cases_other)/sizeof(long); i++) v[i] = eval_cases_other[i]; v = (long *)VELTS(ARRAY_V(il)); for (i = 0; i < sizeof(ilookup_cases)/sizeof(long); i++) v[i] = ((long *)ilookup_cases)[i]; v = (long *)VELTS(ARRAY_V(evc)); for (i = 0; i < sizeof(eval_clo_cases)/sizeof(long); i++) v[i] = ((long *)eval_clo_cases)[i]; if (! UNBNDP(resetp)) { for (i = 0; i < sizeof(eval_cases)/sizeof(long); i++) eval_cases[i] = 0; for (i = 0; i < sizeof(eval_cases_other)/sizeof(long); i++) eval_cases_other[i] = 0; for (i = 0; i < sizeof(ilookup_cases)/sizeof(long); i++) ((long *)ilookup_cases)[i] = 0; for (i = 0; i < sizeof(eval_clo_cases)/sizeof(long); i++) ((long *)eval_clo_cases)[i] = 0; } return cons2(ev, evo, cons2(il, evc, EOL)); } #endif #ifdef CAREFUL_INTS # undef CAR # define CAR(x) (*debug_env_car((x), __FILE__, __LINE__)) # undef CDR # define CDR(x) (*debug_env_cdr((x), __FILE__, __LINE__)) /* Inhibit warnings for ARGC, is not changed by egc. */ # undef ARGC # define ARGC(x) ((6L & (((cell *)(SCM2PTR(x)))->cdr))>>1) # include SCM test_ints(x) SCM x; { static int cnt = 100; if (0==--cnt) { cnt = 100; DEFER_INTS; scm_egc(); ALLOW_INTS; /* l_raise(MAKINUM(SIGALRM)); */ } return x; } int ecache_p(x) SCM x; { register CELLPTR ptr; if (NCELLP(x)) return 0; ptr = (CELLPTR)SCM2PTR(x); if (PTR_LE(scm_ecache, ptr) && PTR_GT(scm_ecache+scm_ecache_len, ptr)) return !0; return 0; } static void debug_env_warn(fnam, line, what) char *fnam; int line; const char *what; { lputs(fnam, cur_errp); lputc(':', cur_errp); scm_intprint(line+0L, 10, cur_errp); lputs(": unprotected ", cur_errp); lputs(what, cur_errp); lputs(" of ecache value\n", cur_errp); } SCM *debug_env_car(x, fnam, line) SCM x; char *fnam; int line; { SCM *ret; if (!ints_disabled && ecache_p(x)) debug_env_warn(fnam, line, "CAR"); ret = &(((cell *)(SCM2PTR(x)))->car); if (!ints_disabled && NIMP(*ret) && ecache_p(*ret)) debug_env_warn(fnam, line, "CAR"); return ret; } SCM *debug_env_cdr(x, fnam, line) SCM x; char *fnam; int line; { SCM *ret; if (!ints_disabled && ecache_p(x)) debug_env_warn(fnam, line, "CDR"); ret = &(((cell *)(SCM2PTR(x)))->cdr); if (!ints_disabled && NIMP(*ret) && ecache_p(*ret)) debug_env_warn(fnam, line, "CAR"); return ret; } static void debug_env_save(fnam, line) char *fnam; int line; { if (NIMP(scm_env) && (!scm_cell_p(scm_env))) debug_env_warn(fnam, line, "ENV_SAVE (env)"); if (NIMP(scm_env_tmp) && (!scm_cell_p(scm_env_tmp))) debug_env_warn(fnam, line, "ENV_SAVE (tmp)"); scm_estk_ptr[0]=scm_env; scm_estk_ptr[1]=scm_env_tmp; } #endif /* CAREFUL_INTS */ SCM *ilookup(iloc) SCM iloc; { register int ir = IFRAME(iloc); register SCM er, *eloc; #ifdef SCM_PROFILE ilookup_cases[ir<10 ? ir : 9] [IDIST(iloc)<10 ? IDIST(iloc) : 9][ICDRP(iloc)?1:0]++; #endif DEFER_INTS_EGC; er = scm_env; /* shortcut the two most common cases. */ if (iloc==MAKILOC(0, 0)) return &CAR(CAR(er)); if (iloc==MAKILOC(0, 1)) return &CAR(CDR(CAR(er))); for (;0 != ir;--ir) er = CDR(er); eloc = &CAR(er); for (ir = IDIST(iloc); 0 != ir; --ir) eloc = &CDR(*eloc); if (ICDRP(iloc)) return eloc; return &CAR(*eloc); } SCM *farlookup(farloc) SCM farloc; { register int ir; register SCM er; SCM x = CDR(farloc); DEFER_INTS_EGC; er = scm_env; for (ir = INUM(CAR(x)); 0 != ir; --ir) er = CDR(er); if (0==(ir = INUM(CDR(x)))) { if (IM_FARLOC_CDR==CAR(farloc)) return &CAR(er); return &CAR(CAR(er)); } er = CAR(er); for (--ir;0 != ir;--ir) er = CDR(er); if (IM_FARLOC_CDR==CAR(farloc)) return &CDR(er); return &CAR(CDR(er)); } char s_badenv[] = "damaged environment"; static char s_lookup[] = "scm_env_lookup", s_badkey[] = "Use of keyword as variable", s_unbnd[] = "unbound variable: ", s_wtap[] = "Wrong type to apply: ", s_placement[] = "bad placement"; /* Returns: a symbol if VAR is not found in STENV, an ILOC if VAR is bound in STENV, a list (IM_FARLOC iframe idist) if VAR is bound very deeply in STENV, a pair (IM_KEYWORD . ) if VAR is a syntax keyword bound in STENV. */ SCM scm_env_lookup(var, stenv) SCM var, stenv; { SCM frame, env = stenv; long icdr = 0L; unsigned int idist, iframe = 0; #ifdef MACRO SCM mark = IDENT_ENV(var); if (NIMP(mark)) mark = CAR(mark); #endif for (; NIMP(env); env = CDR(env)) { idist = 0; frame = CAR(env); #ifdef MACRO if (frame==mark) { var = IDENT_PARENT(var); mark = IDENT_ENV(var); if (NIMP(mark)) mark = CAR(mark); } #endif if (IMP(frame)) { if (NULLP(frame)) iframe++; else if (INUMP(frame)) { #ifndef RECKLESS if (!(NIMP(env) && CONSP(env))) { badenv: wta(stenv, s_badenv, s_lookup); } #endif env = CDR(env); } else { ASRTGO(SCM_LINUMP(frame), badenv); } continue; } #ifdef MACRO if (NIMP(frame) && CONSP(frame) && SCM_ENV_SYNTAX==CAR(frame)) { /* syntax binding */ SCM s = assq(var, CDR(frame)); if (NIMP(s)) return cons(IM_KEYWORD, CDR(s)); continue; } #endif for (; NIMP(frame); frame = CDR(frame)) { if (NCONSP(frame)) { if (var==frame) { icdr = ICDR; goto local_out; } break; } if (CAR(frame)==var) { local_out: #ifndef TEST_FARLOC var = MAKILOC(iframe, idist) + icdr; if (iframe==IFRAME(var) && idist==IDIST(var)) return var; else #endif return cons2(icdr ? IM_FARLOC_CDR : IM_FARLOC_CAR, MAKINUM(iframe), MAKINUM(idist)); } ASRTGO(CONSP(frame), badenv); idist++; } iframe++; } ASRTGO(NULLP(env), badenv); #ifdef MACRO while (M_IDENTP(var)) { if (IMP(IDENT_ENV(var))) var = IDENT_PARENT(var); else break; } #endif return var; } /* Throws error for macro keywords and undefined variables, always memoizes. */ static SCM *lookupcar(vloc) SCM vloc; { SCM *pv, val, var = CAR(vloc), env = STATIC_ENV; SCM addr = scm_env_lookup(var, env); if (IMP(addr) || ISYMP(CAR(addr))) { /* local ref */ DEFER_INTS_EGC; pv = IMP(addr) ? ilookup(addr) : farlookup(addr); } #ifdef MACRO # ifndef RECKLESS else if (NIMP(addr) && IM_KEYWORD==CAR(addr)) { /* local macro binding */ badkey: wta(var, s_badkey, ""); } # endif #endif else { /* global ref */ #ifdef MACRO ASRTER(SYMBOLP(addr), var, s_escaped, ""); #endif val = sym2vcell(addr); addr = val + tc3_cons_gloc; pv = &CDR(val); #ifdef MACRO ASRTGO(!KEYWORDP(*pv), badkey); #endif } ASRTER(!UNBNDP(*pv) && undefineds != *pv, var, s_unbnd, ""); CAR(vloc) = addr; return pv; } /* Throws error for undefined variables, memoizes if memo is non-zero. For local macros, conses new result. */ static SCM scm_lookupval(vloc, memo) SCM vloc; int memo; { SCM val, env = STATIC_ENV, var = CAR(vloc); SCM addr = scm_env_lookup(var, env); if (IMP(addr)) { /* local ref */ DEFER_INTS_EGC; val = *ilookup(addr); } #ifdef MACRO else if (NIMP(addr) && IM_KEYWORD==CAR(addr)) /* local macro binding */ val = addr; #endif else if (ISYMP(CAR(addr))) { /* local ref (farloc) */ DEFER_INTS_EGC; val = *farlookup(addr); } else { /* global ref */ #ifdef MACRO ASRTER(SYMBOLP(addr), var, s_escaped, ""); #endif addr = sym2vcell(addr); val = CDR(addr); addr += tc3_cons_gloc; } ASRTER(!UNBNDP(val) && val != undefineds, var, s_unbnd, ""); if (memo && !KEYWORDP(val)) /* Don't memoize forms to be macroexpanded. */ CAR(vloc) = addr; return val; } /* CAR(x) is known to be a cell but not a cons */ static SCM evalatomcar(x, toplevelp) SCM x; int toplevelp; { SCM ret; switch TYP7(CAR(x)) { default: everr(x, STATIC_ENV, CAR(x), "Cannot evaluate: ", "", 0); lookup: case tcs_symbols: ret = scm_lookupval(x, !0); if (KEYWORDP(ret)) { SCM argv[3]; SCM mac = KEYWORD_MACRO(ret); argv[0] = CAR(x); argv[1] = STATIC_ENV; argv[2] = EOL; switch (MAC_TYPE(mac) & ~MAC_PRIMITIVE) { default: #ifdef MACRO if (!toplevelp) everr(x, argv[1], argv[0], s_badkey, "", 0); #endif return ret; case MAC_IDMACRO: ret = scm_cvapply(CDR(mac), 3L, argv); CAR(x) = ret; return evalcar(x); } } return ret; case tc7_vector: #ifndef RECKLESS if (2 <= verbose) scm_warn("unquoted ", s_vector, CAR(x)); #endif ret = cons2(IM_QUOTE, CAR(x), EOL); CAR(x) = ret; return CAR(CDR(ret)); case tc7_smob: #ifdef MACRO if (M_IDENTP(CAR(x))) goto lookup; #endif /* fall through */ case tcs_uves: return CAR(x); } } SCM scm_multi_set(syms, vals) SCM syms, vals; { SCM res = EOL, *pres = &res; SCM *loc; do { ASRTER(NIMP(vals) && CONSP(vals), vals, WNA, s_set); switch (7 & (int)(CAR(syms))) { case 0: loc = lookupcar(syms); break; case 1: loc = &(I_VAL(CAR(syms))); break; case 4: loc = ilookup(CAR(syms)); break; } *pres = cons(*loc, EOL); pres = &CDR(*pres); *loc = CAR(vals); syms = CDR(syms); vals = CDR(vals); } while (NIMP(syms)); ASRTER(NULLP(vals) && NULLP(syms), vals, WNA, s_set); return res; } static SCM scm_case_selector(x) SCM x; { SCM key, keys, *kv, *av; SCM actions, offset; long i, n; int op = ISYMVAL(CAR(x)); x = CDR(x); key = EVALCAR(x); x = CDR(x); switch (op) { default: wta(MAKINUM(op), "internal error", s_case); case 0: /* linear search */ keys = CAR(x); kv = VELTS(keys); av = VELTS(CAR(CDR(x))); n = LENGTH(keys); for (i = n - 1; i > 0; i--) if (key == kv[i]) return av[i]; #ifndef INUMS_ONLY /* Bignum and flonum keys are pessimized. */ if (NIMP(key) && NUMP(key)) for (i = n - 1; i > 0; i--) if (NFALSEP(eqv(kv[i], key))) return av[i]; #endif return av[0]; case 1: /* integer jump table */ offset = CAR(x); if (INUMP(key)) i = INUM(key) - INUM(offset) + 1; else i = 0; jump: actions = CAR(CDR(x)); if (i >= 1 && i < LENGTH(actions)) return VELTS(actions)[i]; else return VELTS(actions)[0]; case 2: /* character jump table */ offset = CAR(x); if (ICHRP(key)) i = ICHR(key) - ICHR(offset) + 1; else i = 0; goto jump; } } static SCM acro_call(x, env) SCM x, env; { SCM proc, argv[3]; x = CDR(x); proc = scm_lookupval(x, 0); ASRTGO(KEYWORDP(proc), errout); proc = KEYWORD_MACRO(proc); argv[0] = x; argv[1] = env; argv[2] = EOL; switch (MAC_TYPE(proc) & ~MAC_PRIMITIVE) { default: errout: wta(proc, CHARS(CAR(x)), "macro expected"); case MAC_MACRO: x = scm_cvapply(CDR(proc), 3L, argv); if (ilength(x) <= 0) x = cons2(IM_BEGIN, x, EOL); return x; case MAC_ACRO: x = scm_cvapply(CDR(proc), 3L, argv); return cons2(IM_QUOTE, x, EOL); } } static SCM toplevel_define(xorig, env) SCM xorig, env; { SCM x = CDR(xorig); SCM name = CAR(x); ASRTER(scm_nullenv_p(env), xorig, s_placement, s_define); ENV_PUSH; scm_env_tmp = EOL; /* Make sure multiple values -> error */ x = cons(m_binding(name, CAR(CDR(x)), env, EOL), EOL); x = evalcar(x); ENV_POP; checked_define(name, x, s_define); #ifdef SICP return name; #else return UNSPECIFIED; #endif } SCM eval_args(l) SCM l; { SCM res = EOL, *lloc = &res; while NIMP(l) { *lloc = cons(EVALCAR(l), EOL); lloc = &CDR(*lloc); l = CDR(l); } return res; } /* Evaluate each expression in argument list x, and return a list allocated in the ecache of the results. The result is left in scm_env_tmp. */ static void ecache_evalx(x) SCM x; { SCM argv[10]; int i = 0, imax = sizeof(argv)/sizeof(SCM); scm_env_tmp = EOL; while NIMP(x) { if (imax==i) { ecache_evalx(x); break; } argv[i++] = EVALCAR(x); x = CDR(x); } ENV_V2LST((long)i, argv); } /* Allocate a list of UNDEFINED in the ecache, one for each element of the argument list x. The result is left in scm_env_tmp. */ static void ecache_undefs(x) SCM x; { static SCM argv[10] = {UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED}; int imax = sizeof(argv)/sizeof(SCM); int i = 0; scm_env_tmp = EOL; while NIMP(x) { if (imax==i) { ecache_undefs(x); break; } i++; x = CDR(x); } ENV_V2LST((long)i, argv); } /* result is 1 if right number of arguments, 0 otherwise, environment frame is put in scm_env_tmp */ static int ecache_eval_args(proc, arg1, arg2, arg3, x) SCM proc, arg1, arg2, arg3, x; { SCM argv[3]; argv[0] = arg1; argv[1] = arg2; argv[2] = arg3; if (NIMP(x)) ecache_evalx(x); else scm_env_tmp = EOL; ENV_V2LST(3L, argv); #ifndef RECKLESS proc = SCM_ENV_FORMALS(CAR(CODE(proc))); proc = CDR(proc); proc = CDR(proc); proc = CDR(proc); for (; NIMP(proc); proc=CDR(proc)) { if (IMP(x)) return 0; x = CDR(x); } if (NIMP(x)) return 0; #endif return 1; } static SCM asubr_apply(proc, arg1, arg2, arg3, args) SCM proc, arg1, arg2, arg3, args; { switch TYP7(proc) { case tc7_asubr: arg1 = SUBRF(proc)(arg1, arg2); arg1 = SUBRF(proc)(arg1, arg3); while NIMP(args) { arg1 = SUBRF(proc)(arg1, CAR(args)); args = CDR(args); } return arg1; case tc7_rpsubr: if (FALSEP(SUBRF(proc)(arg1, arg2))) return BOOL_F; while (!0) { if (FALSEP(SUBRF(proc)(arg2, arg3))) return BOOL_F; if (IMP(args)) return BOOL_T; arg2 = arg3; arg3 = CAR(args); args = CDR(args); } default: return UNDEFINED; } } static char s_values[] = "values"; static char s_call_wv[] = "call-with-values"; SCM scm_values(arg1, arg2, rest, what) SCM arg1, arg2, rest; const char *what; { DEFER_INTS_EGC; ASRTER(IM_VALUES_TOKEN==scm_env_tmp, UNDEFINED, "one value expected", what); if (! UNBNDP(arg2)) scm_env_cons(arg2, rest); return arg1; } /* the following rewrite expressions and * some memoized forms have different syntax */ static char s_expression[] = "missing or extra expression"; static char s_test[] = "bad test"; static char s_body[] = "bad body"; static char s_bindings[] = "bad bindings"; static char s_variable[] = "bad variable"; static char s_bad_else_clause[] = "bad ELSE clause"; static char s_clauses[] = "bad or missing clauses"; static char s_formals[] = "bad formals"; static char s_expr[] = "bad expression"; #define ASSYNT(_cond, _arg, _pos, _subr)\ if (!(_cond))scm_experr(_arg, (char *)_pos, _subr); /* These symbols are needed by the reader, in repl.c */ SCM i_dot, i_quote, i_quasiquote, i_unquote, i_uq_splicing; static SCM i_lambda, i_define, i_let, i_begin, i_arrow, i_else; /* , i_atbind */ /* These symbols are passed in the context argument to macro expanders. */ static SCM i_bind, i_anon, i_side_effect, i_test, i_procedure, i_argument, i_check_defines; static SCM f_begin, f_define; #define ASRTSYNTAX(cond_, msg_) if (!(cond_))wta(xorig, (msg_), what); #ifdef MACRO # define TOPLEVELP(x, env) (topdenote_eq(UNDEFINED, (x), (env))) # define TOPDENOTE_EQ topdenote_eq # define TOPRENAME(v) (renamed_ident(v, BOOL_F)) static int topdenote_eq(sym, id, env) SCM sym, id, env; { if (UNBNDP(sym)) { sym = scm_env_lookup(id, env); return NIMP(sym) && SYMBOLP(sym); } return sym==id2sym(id) && sym==scm_env_lookup(id, env); } static SCM id2sym(id) SCM id; { if (NIMP(id)) while M_IDENTP(id) id = IDENT_PARENT(id); return id; } #else /* def MACRO */ # define TOPDENOTE_EQ(sym, x, env) ((sym)==(x)) # define TOPLEVELP(x, env) (!0) # define TOPRENAME(v) (v) #endif static void unpaint(p) SCM *p; { SCM x; while NIMP((x = *p)) { if (CONSP(x)) { if (NIMP(CAR(x))) unpaint(&CAR(x)); else if (SCM_LINUMP(CAR(x))) { *p = CDR(x); continue; } p = &CDR(*p); } else if (VECTORP(x)) { sizet i = LENGTH(x); if (0==i) return; while (i-- > 1) unpaint(&(VELTS(x)[i])); p = VELTS(x); } else { #ifdef MACRO while M_IDENTP(x) *p = x = IDENT_PARENT(x); #endif return; } } } SCM m_quote(xorig, env, ctxt) SCM xorig, env, ctxt; { SCM x = copytree(CDR(xorig)); ASSYNT(ilength(CDR(xorig))==1, xorig, s_expression, s_quote); DEFER_INTS; unpaint(&CAR(x)); ALLOW_INTS; return cons(IM_QUOTE, x); } SCM m_begin(xorig, env, ctxt) SCM xorig, env, ctxt; { int len = ilength(CDR(xorig)); if (0==len) return cons2(IM_BEGIN, UNSPECIFIED, EOL); if (1==len) return CAR(CDR(xorig)); ASSYNT(len >= 1, xorig, s_expression, s_begin); return cons(IM_BEGIN, CDR(xorig)); } static int constant_p(x) SCM x; { return IMP(x) ? !0 : (CONSP(x) ? 0 : !IDENTP(x)); } SCM m_if(xorig, env, ctxt) SCM xorig, env, ctxt; { SCM test, x = CDR(xorig); int len = ilength(x); ASSYNT(len >= 2 && len <= 3, xorig, s_expression, s_if); test = CAR(x); x = CDR(x); if (FALSEP(test)) return 3==len ? CAR(CDR(x)) : UNSPECIFIED; if (constant_p(test)) return CAR(x); return cons2(IM_IF, m_expr(test, env, i_test), cons(m_expr(CAR(x), env, ctxt), NULLP(CDR(x)) ? EOL : cons(m_expr(CAR(CDR(x)), env, ctxt), EOL))); } SCM m_set(xorig, env, ctxt) SCM xorig, env, ctxt; { SCM var, x = CDR(xorig); ASSYNT(2==ilength(x), xorig, s_expression, s_set); varcheck((NIMP(CAR(x)) && IDENTP(CAR(x))) ? CAR(x) : (ilength(CAR(x)) > 0) ? CAR(x) : UNDEFINED, IM_SET, s_variable); var = CAR(x); x = CDR(x); return cons(IM_SET, cons2(var, m_expr(CAR(x), env, ctxt), EOL)); } SCM m_and(xorig, env, ctxt) SCM xorig, env, ctxt; { SCM x = CDR(xorig); int len = ilength(x); ASSYNT(len >= 0, xorig, s_test, s_and); tail: switch (len) { default: if (FALSEP(CAR(x))) return BOOL_F; if (constant_p(CAR(x))) { x = CDR(x); len--; goto tail; } return cons(IM_AND, x); case 1: return CAR(x); case 0: return BOOL_T; } } SCM m_or(xorig, env, ctxt) SCM xorig, env, ctxt; { SCM x = CDR(xorig); int len = ilength(x); ASSYNT(len >= 0, xorig, s_test, s_or); tail: switch (len) { default: if (FALSEP(CAR(x))) { x = CDR(x); len--; goto tail; } if (constant_p(CAR(x))) return CAR(x); return cons(IM_OR, x); case 1: return CAR(x); case 0: return BOOL_F; } } #ifdef INUMS_ONLY # define memv memq #endif static SCM *loc_atcase_aux = 0; static int in_atcase_aux = 0; SCM m_case(xorig, env, ctxt) SCM xorig, env, ctxt; { SCM clause, key_expr, x = CDR(xorig); SCM s, keys = EOL, action, actions = EOL, else_action = list_unspecified; int opt = !scm_nullenv_p(env); ASSYNT(ilength(x) >= 2, xorig, s_clauses, s_case); key_expr = CAR(x); while(NIMP(x = CDR(x))) { clause = CAR(x); s = scm_check_linum(clause, 0L); ASSYNT(ilength(s) >= 2, clause /* xorig */, s_clauses, s_case); clause = s; if (TOPDENOTE_EQ(i_else, CAR(clause), env)) { ASSYNT(NULLP(CDR(x)), xorig, s_bad_else_clause, s_case); else_action = m_seq(CDR(clause), env, ctxt); } else { s = scm_check_linum(CAR(clause), 0L); #ifdef MACRO s = scm_cp_list(s, 0); ASSYNT(!UNBNDP(s), CAR(clause) /* xorig */, s_clauses, s_case); DEFER_INTS; unpaint(&s); ALLOW_INTS; #else ASSYNT(ilength(s) >= 0, CAR(clause) /* xorig */, s_clauses, s_case); #endif action = m_seq(CDR(clause), env, ctxt); for (; NIMP(s); s = CDR(s)) { ASSYNT(FALSEP(memv(CAR(s), keys)), xorig, "duplicate key value", s_case); if (NIMP(CAR(s)) && NUMP(CAR(s))) opt = 0; keys = cons(CAR(s), keys); actions = cons(action, actions); } } } key_expr = m_expr(key_expr, env, i_test); if (opt && NIMP(*loc_atcase_aux) && !in_atcase_aux) { SCM argv[3]; argv[0] = keys; argv[1] = actions; argv[2] = else_action; in_atcase_aux = !0; x = scm_cvapply(*loc_atcase_aux, 3L, argv); in_atcase_aux = 0; /* disabled after one error. C'est la vie. */ if (NIMP(x) && CONSP(x)) { s = CAR(x); if (INUMP(s) && INUM(s) >= 0 && INUM(s) <= 2) return cons2(MAKISYMVAL(IM_CASE, INUM(s)), key_expr, CDR(x)); } } keys = cons(UNSPECIFIED, keys); actions = cons(else_action, actions); return cons2(IM_CASE, key_expr, cons2(vector(keys), vector(actions), EOL)); } SCM m_cond(xorig, env, ctxt) SCM xorig, env, ctxt; { SCM s, clause, cdrx = scm_cp_list(CDR(xorig), 1), x = cdrx; int len = ilength(x); ASSYNT(!UNBNDP(cdrx), xorig, s_clauses, s_cond); while(NIMP(x)) { clause = scm_check_linum(CAR(x), 0L); len = ilength(clause); ASSYNT(len >= 1, CAR(x), s_clauses, s_cond); if (TOPDENOTE_EQ(i_else, CAR(clause), env)) { ASSYNT(NULLP(CDR(x)) && len >= 2, xorig, s_bad_else_clause, s_cond); clause = cons(BOOL_T, m_seq(CDR(clause), env, ctxt)); } else { s = CDR(clause); if (len >= 2 && TOPDENOTE_EQ(i_arrow, CAR(s), env)) { ASSYNT(3==len && NIMP(CAR(CDR(s))), clause, "bad recipient", s_cond); clause = cons2(CAR(clause), IM_ARROW, CDR(s)); } else clause = cons(CAR(clause), m_seq(s, env, ctxt)); } CAR(x) = clause; x = CDR(x); } return cons(IM_COND, cdrx); } static int varcheck(vars, op, what) SCM vars, op; const char *what; { SCM v1, vs; char *opstr = ISYMCHARS(op) + 2; int argc = 0; vars = scm_check_linum(vars, 0L); for (; NIMP(vars) && CONSP(vars); vars = CDR(vars)) { argc++; #ifndef RECKLESS v1 = CAR(vars); if (IMP(v1) || !IDENTP(v1)) badvar: scm_experr(v1, what, opstr); for (vs = CDR(vars); NIMP(vs) && CONSP(vs); vs = CDR(vs)) { if (v1==CAR(vs)) { nonuniq: what = "non-unique bindings"; goto badvar; } } if (v1==vs) goto nonuniq; #endif } /* argc of 3 means no rest argument, 3+ required arguments */ if (NULLP(vars) || ISYMP(vars)) return argc > 3 ? 3 : argc; ASRTGO(NIMP(vars) && IDENTP(vars), badvar); return argc > 2 ? 2 : argc; } SCM m_lambda(xorig, env, ctxt) SCM xorig, env, ctxt; { SCM x = CDR(xorig), formals; #ifdef CAUTIOUS SCM name, linum; #endif int argc; ASRTER(ilength(x) > 1, x, s_body, s_lambda); formals = CAR(x); argc = varcheck(formals, IM_LAMBDA, s_formals); formals = scm_check_linum(formals, 0L); if (argc > 3) argc = 3; x = CDR(x); if (NIMP(CDR(x)) && NIMP(CAR(x)) && STRINGP(CAR(x))) { env = scm_env_addprop(SCM_ENV_DOC, CAR(x), env); x = CDR(x); } #ifdef CAUTIOUS if (NIMP(ctxt) && i_bind==CAR(ctxt)) { ctxt = CDR(ctxt); name = CAR(ctxt); } else name = i_anon; if (NIMP(scm_trace) && xorig==scm_check_linum(scm_trace, &linum)) if (!UNBNDP(linum)) env = EXTEND_ENV(linum, env); env = scm_env_addprop(SCM_ENV_PROCNAME, name, env); #endif env = EXTEND_ENV(formals, env); return cons2(MAKISYMVAL(IM_LAMBDA, argc), env, m_body(x, env, EOL)); } #ifdef MAC_INLINE static int env_depth() { register int depth = 0; register SCM env; DEFER_INTS_EGC; env = scm_env; while(NIMP(env)) { env = CDR(env); depth++; } return depth; } static void env_tail(depth) int depth; { register SCM env; DEFER_INTS_EGC; env = scm_env; while(depth--) env = CDR(env); scm_env = env; } /* FIXME update for split-env */ SCM m_inline_lambda(xorig, env) SCM xorig, env; { SCM x = CDR(xorig); SCM typ = (SCM)(tc16_macro | (MAC_INLINE << 16)); int depth = env_depth(); ASRTER(ilength(x) > 1, xorig, s_formals, s_lambda); ASRTER(ilength(CAR(x)) >= 0, xorig, s_formals, s_lambda); varcheck(CAR(x), IM_LAMBDA, s_formals); x = cons2(typ, MAKINUM((long)depth), cons(CAR(x), m_body(CDR(x), env))); return cons2(IM_QUOTE, x, EOL); } #endif static char s_nullenv_p[] = "scm_nullenv_p"; int scm_nullenv_p(env) SCM env; { SCM fr, e; if (IMP(env)) return !0; for (e = env; NIMP(e); e = CDR(e)) { ASRTER(CONSP(e), e, s_badenv, s_nullenv_p); fr = CAR(e); if (IMP(fr)) { if (NULLP(fr)) return 0; if (INUMP(fr)) { /* These frames are for meta-data, not bindings. */ e = CDR(e); ASRTER(NIMP(e), env, s_badenv, s_nullenv_p); } } else return 0; } return !0; } static SCM m_letstar1(imm, vars, inits, body, env, ctxt) SCM imm, vars, inits, body, env, ctxt; { SCM init, bdgs = cons(env, EOL); /* initial env is for debug printing. */ SCM *loc = &CDR(bdgs); while (NIMP(vars)) { init = m_binding(CAR(vars), CAR(inits), env, ctxt); env = EXTEND_ENV(CAR(vars), env); *loc = cons2(init, env, EOL); loc = &CDR(CDR(*loc)); vars = CDR(vars); inits = CDR(inits); } return cons2(IM_LETSTAR, bdgs, m_body(body, env, ctxt)); } SCM m_letstar(xorig, env, ctxt) SCM xorig, env, ctxt; { SCM vars, inits; SCM body = m_parse_let(EOL, xorig, CDR(xorig), &vars, &inits); /* IM_LETSTAR must bind at least one variable. */ if (IMP(vars)) return m_let_null(body, env, ctxt); return m_letstar1(IM_LETSTAR, vars, inits, body, env, ctxt); } /* DO gets the most radically altered syntax (do (( ) ( ) ... ) ( ) ) ;; becomes (do_mem (varn ... var2 var1) ( ... ) ( ) () ... ) ;; missing steps replaced by var */ SCM m_do(xorig, env, ctxt) SCM xorig, env, ctxt; { SCM x = CDR(xorig), bdg, bdgs, test, body; SCM vars = IM_DO, inits = EOL, steps = EOL; int len = ilength(x); ASSYNT(len >= 2, xorig, s_test, s_do); bdgs = scm_check_linum(CAR(x), 0L); ASSYNT(ilength(bdgs) >= 0, CAR(x), s_bindings, s_do); while NIMP(bdgs) { bdg = scm_check_linum(CAR(bdgs), 0L); len = ilength(bdg); ASSYNT(2==len || 3==len, CAR(bdgs), s_bindings, s_do); vars = cons(CAR(bdg), vars); /* variable */ bdg = CDR(bdg); inits = cons(CAR(bdg), inits); bdg = CDR(bdg); steps = cons(IMP(bdg) ? CAR(vars) : CAR(bdg), steps); bdgs = CDR(bdgs); } if (IMP(vars)) vars = EOL; inits = m_bindings(vars, inits, env, ctxt); env = EXTEND_ENV(vars, env); steps = m_bindings(vars, steps, env, ctxt); x = CDR(x); test = scm_check_linum(CAR(x), 0L); ASSYNT(ilength(test) >= 1, CAR(x), s_test, s_do); if (IMP(CDR(test))) test = cons(CAR(test), list_unspecified); ASSYNT(ilength(CDR(x))>=0, xorig, s_expression, s_do); varcheck(vars, IM_DO, s_variable); body = scm_check_linum(CDR(x), 0L); x = cons2(test, m_seq(body, env, i_side_effect), steps); x = cons2(env, inits, x); return cons(IM_DO, x); } /* evalcar is small version of inline EVALCAR when we don't care about speed */ static SCM evalcar(x) SCM x; { return EVALCAR(x); } /* Here are acros which return values rather than code. */ static SCM iqq(form) SCM form; { SCM tmp; if (IMP(form)) return form; if (VECTORP(form)) { long i = LENGTH(form); SCM *data = VELTS(form); tmp = EOL; for (;--i >= 0;) tmp = cons(data[i], tmp); return vector(iqq(tmp)); } if (NCONSP(form)) return form; tmp = CAR(form); if (IM_UNQUOTE==tmp) return evalcar(CDR(form)); if (NIMP(tmp) && IM_UQ_SPLICING==CAR(tmp)) return append(cons2(evalcar(CDR(tmp)), iqq(CDR(form)), EOL)); return cons(iqq(CAR(form)), iqq(CDR(form))); } static SCM m_iqq(form, depth, env, ctxt) SCM form, env, ctxt; int depth; { SCM tmp; int edepth = depth; if (IMP(form)) return form; if (VECTORP(form)) { long i = LENGTH(form); SCM *data = VELTS(form); tmp = EOL; for (;--i >= 0;) tmp = cons(data[i], tmp); tmp = m_iqq(tmp, depth, env, ctxt); for (i = 0; i < LENGTH(form); i++) { data[i] = CAR(tmp); tmp = CDR(tmp); } return form; } if (NCONSP(form)) { #ifdef MACRO while M_IDENTP(form) form = IDENT_PARENT(form); #endif return form; } form = scm_check_linum(form, 0L); /* needed? */ tmp = scm_check_linum(CAR(form), 0L); if (NIMP(tmp)) { if (IDENTP(tmp)) { #ifdef MACRO while M_IDENTP(tmp) tmp = IDENT_PARENT(tmp); #endif if (i_quasiquote==tmp && TOPLEVELP(CAR(form), env)) { depth++; if (0==depth) tmp = IM_QUASIQUOTE; goto label; } else if (i_unquote==tmp && TOPLEVELP(CAR(form), env)) { --depth; if (0==depth) tmp = IM_UNQUOTE; label: form = CDR(form); ASRTER(NIMP(form) && ECONSP(form) && NULLP(CDR(form)), form, ARG1, s_quasiquote); if (0!=depth) form = cons(m_iqq(CAR(form), depth, env, ctxt), EOL); return cons(tmp, form); } } else { if (TOPDENOTE_EQ(i_uq_splicing, CAR(tmp), env)) { if (0==--edepth) return cons(cons(IM_UQ_SPLICING, CDR(tmp)), m_iqq(CDR(form), depth, env, ctxt)); } tmp = m_iqq(tmp, edepth, env, ctxt); } } return cons(tmp, m_iqq(CDR(form), depth, env, ctxt)); } SCM m_quasiquote(xorig, env, ctxt) SCM xorig, env, ctxt; { SCM x = CDR(xorig); ASSYNT(ilength(x)==1, xorig, s_expression, s_quasiquote); x = m_iqq(x, 1, env, ctxt); return cons(IM_QUASIQUOTE, x); } SCM m_delay(xorig, env, ctxt) SCM xorig, env, ctxt; { ASSYNT(ilength(xorig)==2, xorig, s_expression, s_delay); return cons2(IM_DELAY, EXTEND_ENV(EOL, env), CDR(xorig)); } static int built_inp(name, x) SCM name, x; { if (NIMP(x)) { tail: switch TYP7(x) { case tcs_subrs: return CHARS(name)==SNAME(x); case tc7_smob: if (MACROP(x)) {x = CDR(x); goto tail;} /* else fall through */ } } return 0; } extern char s_redefining[]; #ifndef RECKLESS char s_built_in_syntax[] = "built-in syntax "; # define s_syntax (&s_built_in_syntax[9]) #endif static void checked_define(name, val, what) SCM name, val; const char *what; { SCM old, vcell; #ifdef MACRO while (M_IDENTP(name)) { ASRTER(IMP(IDENT_ENV(name)), name, s_escaped, what); name = IDENT_PARENT(name); } #endif vcell = sym2vcell(name); old = CDR(vcell); #ifndef RECKLESS if ('@'==CHARS(name)[0] && UNDEFINED != old) scm_warn(s_redefining, "internal name ", name); if (KEYWORDP(old)) { if (1 <= verbose && built_inp(name, KEYWORD_MACRO(old))) scm_warn(s_redefining, s_built_in_syntax, name); else if (3 <= verbose) scm_warn(s_redefining, s_syntax, name); } else if (2 <= verbose && built_inp(name, old) && (old != val)) scm_warn(s_redefining, "built-in ", name); else if (5 <= verbose && UNDEFINED != old) scm_warn(s_redefining, "", name); #endif CDR(vcell) = val; } SCM m_define(xorig, env, ctxt) SCM xorig, env, ctxt; { SCM name, linum, x = CDR(xorig); ASSYNT(ilength(x) >= 2, xorig, s_expression, s_define); name = CAR(x); x = CDR(x); while (NIMP(name) && CONSP(name)) { /* nested define syntax */ name = scm_check_linum(name, &linum); x = scm_add_linum(linum, cons2(TOPRENAME(i_lambda), CDR(name), x)); x = cons(x, EOL); name = CAR(name); } ASSYNT(NIMP(name) && IDENTP(name), xorig, s_variable, s_define); ASSYNT(1==ilength(x), xorig, s_expression, s_define); return cons2(IM_DEFINE, name, x); } /* end of acros */ /* returns body, x should be cdr of a LET, LET*, or LETREC form. vars and inits are returned in the original order. */ static SCM m_parse_let(imm, xorig, x, vars, inits) SCM imm, xorig, x, *vars, *inits; { SCM clause, bdgs, *varloc = vars, *initloc = inits; int len = ilength(x); #ifdef MACRO const char *what = CHARS(ident2sym(CAR(xorig))); #else const char *what = CHARS(CAR(xorig)); #endif *varloc = imm; *initloc = EOL; ASSYNT(len >= 2, UNDEFINED, s_body, what); bdgs = scm_check_linum(CAR(x), 0L); ASSYNT(ilength(bdgs) >= 0, bdgs, s_bindings, what); while NIMP(bdgs) { clause = scm_check_linum(CAR(bdgs), 0L); ASSYNT(2==ilength(clause), clause, s_bindings, what); ASSYNT(NIMP(CAR(clause)) && IDENTP(CAR(clause)), CAR(clause), s_variable, what); *varloc = cons(CAR(clause), imm); varloc = &CDR(*varloc); *initloc = cons(CAR(CDR(clause)), EOL); initloc = &CDR(*initloc); bdgs = CDR(bdgs); } x = CDR(x); ASSYNT(ilength(x)>0, scm_wrapcode(x, EOL) /* xorig */, s_body, what); if (IMP(*vars)) *vars = EOL; return x; } static SCM m_let_null(body, env, ctxt) SCM body, env, ctxt; { SCM x; if (scm_nullenv_p(env)) { env = EXTEND_ENV(EOL, env); return cons2(IM_LET, env, cons(EOL, m_body(body, env, ctxt))); } x = m_body(body, env, ctxt); return NULLP(CDR(x)) ? CAR(x) : cons(IM_BEGIN, x); } static SCM m_letrec1(imm, xorig, env, ctxt) SCM imm, xorig, env, ctxt; { SCM vars, inits, op = MAKSPCSYM2(IM_LETREC, imm); SCM body = m_parse_let(imm, xorig, CDR(xorig), &vars, &inits); if (IMP(vars)) return m_let_null(body, env, ctxt); varcheck(vars, imm, s_variable); env = EXTEND_ENV(vars, env); inits = m_bindings(vars, inits, env, ctxt); return cons2(op, env, cons(inits, m_body(body, env, ctxt))); } SCM m_letrec(xorig, env, ctxt) SCM xorig, env, ctxt; { return m_letrec1(IM_LETREC, xorig, env, ctxt); } SCM m_let(xorig, env, ctxt) SCM xorig, env, ctxt; { SCM proc, body, vars, inits, x = CDR(xorig); ASSYNT(ilength(x) >= 2, xorig, s_body, s_let); proc = CAR(x); if (NIMP(proc) && IDENTP(proc)) { /* named let, build equiv letrec */ x = CDR(x); body = m_parse_let(IM_LET, xorig, x, &vars, &inits); x = cons2(TOPRENAME(i_lambda), vars, body); x = cons2(i_let, cons(cons2(proc, x, EOL), EOL), cons(proc, EOL)); return cons(m_letrec1(IM_LET, x, env, ctxt), inits); } /* vanilla let */ body = m_parse_let(IM_LET, xorig, x, &vars, &inits); varcheck(vars, IM_LET, s_variable); if (IMP(vars)) return m_let_null(body, env, ctxt); if (IMP(CDR(vars))) /* single binding, let* is faster */ return m_letstar1(IM_LET, vars, inits, body, env, ctxt); inits = m_bindings(vars, inits, env, ctxt); env = EXTEND_ENV(vars, env); return cons2(IM_LET, env, cons(inits, m_body(body, env, ctxt))); } #define s_atapply (ISYMCHARS(IM_APPLY)+1) SCM m_apply(xorig, env, ctxt) SCM xorig, env, ctxt; { ASSYNT(ilength(CDR(xorig))==2, xorig, s_expression, s_atapply); return cons(IM_APPLY, CDR(xorig)); } static SCM m_body(xorig, env, ctxt) SCM xorig, env, ctxt; { SCM form, denv = env, x = xorig, defs = EOL; const char *what = 0; /* Should this be passed in? */ ASRTSYNTAX(ilength(xorig) >= 1, s_expression); while NIMP(x) { form = scm_check_linum(CAR(x), 0L); if (IMP(form) || NCONSP(form)) break; if (IMP(CAR(form))) break; if (! IDENTP(CAR(form))) break; form = macroexp1(CAR(x), denv, i_check_defines, 1); if (IM_DEFINE==CAR(form)) { defs = cons(CDR(form), defs); x = CDR(x); } else if (IM_BEGIN==CAR(form)) { form = CDR(form); x = CDR(x); if (IMP(x)) x = form; else if (UNSPECIFIED==CAR(form) && IMP(CDR(form))) ; else x = append(cons2(form, x, EOL)); } else if (NIMP(defs)) { break; } else { /* Doesn't work when m_body recursively called x = cons(form, m_seq(CDR(x), env, ctxt)); */ x = cons(form, CDR(x)); break; } } ASSYNT(ilength(x) > 0, xorig, s_body, what); if (IMP(defs)) return x; return cons(m_letrec1(IM_DEFINE, cons2(i_define, defs, x), env, ctxt), EOL); } static SCM m_binding(name, value, env, ctxt) SCM name, value, env, ctxt; { if (IMP(value) || NCONSP(value)) return value; ctxt = cons2(i_bind, name, EOL); return macroexp1(value, env, ctxt, 2); } static SCM m_bindings(names, values, env, ctxt) SCM names, values, env, ctxt; { SCM x; for (x = values; NIMP(x); x = CDR(x)) { CAR(x) = m_binding(CAR(names), CAR(x), env, ctxt); names = CDR(names); } return values; } static SCM m_seq(x, env, ctxt) SCM x, env, ctxt; { SCM form, ret = EOL, *loc = &ret; for (; NIMP(x); x = CDR(x)) { form = CAR(x); if (NIMP(form) && CONSP(form)) { form = macroexp1(form, env, IMP(CDR(x)) ? ctxt : i_side_effect, 2); if (NIMP(form) && IM_BEGIN==CAR(form)) { x = append(cons2(form, CDR(x), EOL)); continue; } } *loc = cons(form, EOL); loc = &CDR(*loc); } return ret; } static SCM m_expr(x, env, ctxt) SCM x, env, ctxt; { if (NIMP(x) && CONSP(x)) { x = macroexp1(x, env, ctxt, 2); if (NIMP(x) && IM_BEGIN==CAR(x)) x = cons(IM_BEGIN, m_seq(CDR(x), env, ctxt)); } return x; } SCM scm_check_linum(x, linum) SCM x, *linum; { SCM lin = UNDEFINED; if (NIMP(x) && CONSP(x) && SCM_LINUMP(CAR(x))) { lin = CAR(x); x = CDR(x); } if (linum) *linum = lin; return x; } SCM scm_add_linum(linum, x) SCM x, linum; { if (UNBNDP(linum)) return x; if (NIMP(x) && CONSP(x) && SCM_LINUMP(CAR(x))) return x; return cons(linum, x); } /* mode values: 0 expand non-primitive macros only 1 check for defines, expand non-primitive macros and DEFINE and BEGIN 2 expand all macros 3 executing: all macros must be expanded, all values must be defined and will be memoized, the form may be destructively altered. */ static SCM macroexp1(xorig, env, ctxt, mode) SCM xorig, env, ctxt; int mode; { SCM x = xorig, linum, proc = UNDEFINED, res = UNDEFINED; #ifndef RECKLESS SCM trace = scm_trace, trace_env = scm_trace_env; long argc; const char *what = s_wtap; MACROEXP_TRACE(xorig, env); #endif x = scm_check_linum(xorig, &linum); if (IMP(x) || NCONSP(x)) { /* Happens for unquoted vectors. */ if (NIMP(x)) x = evalatomcar(cons(x, EOL), 0); x = cons2(IM_QUOTE, x, EOL); goto retx; } else if (IDENTP(x)) { /* Happens for @macroexpand1 */ proc = x; x = cons(proc, EOL); } else proc = CAR(x); ASRTGO(NIMP(proc), errout); if (CONSP(proc)) { if (mode < 3) { x = xorig; goto retx; } if (NIMP(CAR(proc))) proc = macroexp1(cons(CAR(proc), CDR(proc)), env, i_procedure, mode); if ((127L & IM_LAMBDA)==(127L & CAR(proc))) { SCM nenv = CAR(CDR(proc)); SCM formals = SCM_ENV_FORMALS(nenv); #ifndef RECKLESS if (badargsp(formals, CDR(x))) { what = (char *)WNA; proc = CAR(x); goto errout; } #endif res = CDR(x); if (ilength(formals) >= 0) { x = cons2(IM_LET, nenv, cons(res, CDR(CDR(proc)))); goto retx; } } #ifndef RECKLESS if (ilength(x) < 0) { what = s_expr; goto errout; } #endif x = cons2(IM_FUNCALL, proc, CDR(x)); goto retx; } ASRTGO(IDENTP(proc), errout); macro_tail: res = proc; /* For nicer error message. */ if (mode >= 3) { x = cons(CAR(x), CDR(x)); proc = scm_lookupval(x, !0); } else { proc = scm_env_lookup(proc, env); if (IMP(proc)) { /* local binding */ x = scm_add_linum(linum, x); goto retx; } if (CONSP(proc)) /* local syntax binding. */ proc = CDR(proc); else if (SYMBOLP(proc)) /* global variable */ proc = CDR(sym2vcell(proc)); } if (KEYWORDP(proc)) { SCM argv[3]; long argc = 2; proc = KEYWORD_MACRO(proc); argv[0] = x; argv[1] = env; argv[2] = ctxt; switch (MAC_TYPE(proc)) { case MAC_MACRO: case MAC_MACRO | MAC_PRIMITIVE: case MAC_ACRO: case MAC_ACRO | MAC_PRIMITIVE: /* This means non-memoizing macros can't expand into internal defines. That's ok with me. */ if (mode > 1) x = cons2(IM_ACRO_CALL, CAR(x), CDR(x)); goto retx; case MAC_MMACRO | MAC_PRIMITIVE: case MAC_IDMACRO | MAC_PRIMITIVE: if (0==mode || (1==mode && f_define != CDR(proc) && f_begin != CDR(proc))) { x = scm_add_linum(linum, x); goto retx; } argv[2] = ctxt; argc = 3; /* fall through */ case MAC_MMACRO: case MAC_IDMACRO: argv[0] = x; argv[1] = env; x = scm_cvapply(CDR(proc), argc, argv); if (ilength(x) <= 0) x = cons2((0==mode ? TOPRENAME(i_begin): IM_BEGIN), x, EOL); break; #ifdef MAC_INLINE /* FIXME this is broken */ case MAC_INLINE: { int depth = env_depth(); res = CDR(proc); depth -= INUM(CAR(res)); res = CDR(res); x = cons2(MAKISYMVAL(IM_LET, depth), CAR(res), cons(CDR(x), CDR(res))); break; } #endif } MACROEXP_TRACE(xorig, env); x = scm_check_linum(x, 0L); if (NIMP(CAR(x)) && IDENTP(CAR(x))) { proc = CAR(x); goto macro_tail; } #ifndef RECKLESS if (IM_DEFINE==CAR(x) && (mode != 1) && !scm_nullenv_p(env)) { what = s_placement; proc = res = i_define; errout: if (!UNBNDP(res)) CAR(x) = res; /* FIXME may not be right for @macroexpand1 */ if (UNBNDP(proc) && NIMP(x) && CONSP(x)) proc = CAR(x); scm_experr(proc, what, ""); } #endif } else { /* not a macro expression, car is identifier */ if (0 == mode) x = BOOL_F; else if (mode <=2 ) x = scm_add_linum(linum, x); #ifndef RECKLESS else if (mode >= 3) { argc = ilength(CDR(x)); if (! scm_arity_check(proc, argc, (char *)0)) { if (argc < 0) { what = s_expr; proc = x; } else what = FALSEP(procedurep(proc)) ? s_wtap : (char *)WNA; goto errout; } for (proc = CDR(x); NIMP(proc); proc = CDR(proc)) { res = CAR(proc); if (NIMP(res)) { if (IDENTP(res)) scm_lookupval(proc, !0); else if (CONSP(res)) macroexp1(res, env, i_argument, mode); } } } #endif } retx: if (mode >= 3 && x != xorig) { DEFER_INTS; CAR(xorig) = CAR(x); CDR(xorig) = CDR(x); x = xorig; ALLOW_INTS; } MACROEXP_TRACE(trace, trace_env); /* restore */ return x; } #ifndef RECKLESS int badargsp(formals, args) SCM formals, args; { while NIMP(formals) { if (NCONSP(formals)) return 0; if (IMP(args)) return 1; formals = CDR(formals); args = CDR(args); } return NNULLP(args) ? 1 : 0; } /* If what is non-null, signals error instead of returning false. */ int scm_arity_check(proc, argc, what) SCM proc; long argc; const char *what; { SCM p = proc; if (IMP(p) || argc < 0) goto badproc; cclo_tail: switch TYP7(p) { default: badproc: if (what) wta(proc, s_wtap, what); return 0; wrongnumargs: if (what) wta(proc, (char *)WNA, what); return 0; case tc7_subr_0: ASRTGO(0==argc, wrongnumargs) return !0; case tc7_contin: if (IM_VALUES_TOKEN == CONT(proc)->other.stkframe[1]) return !0; /* else fall through */ case tc7_cxr: case tc7_subr_1: ASRTGO(1==argc, wrongnumargs) return !0; case tc7_subr_1o: ASRTGO(0==argc || 1==argc, wrongnumargs) return !0; case tc7_subr_2: ASRTGO(2==argc, wrongnumargs) return !0; case tc7_subr_2o: ASRTGO( 1==argc || 2==argc, wrongnumargs) return !0; case tc7_subr_3: ASRTGO(3==argc, wrongnumargs) return !0; case tc7_rpsubr: case tc7_asubr: case tc7_lsubr: return !0; case tc7_lsubr_2: ASRTGO(2<=argc, wrongnumargs) return !0; case tc7_specfun: switch TYP16(proc) { default: wta(proc, "internal error", "scm_arity_check"); case tc16_apply: ASRTGO(2<=argc, wrongnumargs); return !0; case tc16_call_cc: case tc16_eval: ASRTGO(1==argc, wrongnumargs); /* fall through */ case tc16_values: return !0; case tc16_call_wv: ASRTGO(2==argc, wrongnumargs); return !0; # ifdef CCLO case tc16_cclo: p = CCLO_SUBR(p); argc++; goto cclo_tail; # endif } case tcs_closures: { SCM formals = SCM_ENV_FORMALS(CAR(CODE(p))); while (argc--) { ASRTGO(NIMP(formals), wrongnumargs); if (CONSP(formals)) formals = CDR(formals); else return !0; } ASRTGO(IMP(formals) || NCONSP(formals), wrongnumargs); return !0; } } } #endif char s_map[] = "map", s_for_each[] = "for-each", s_eval[] = "@eval"; char s_call_cc[] = "call-with-current-continuation"; /* s_apply[] = "apply"; */ /* static int checking_defines_p(ctxt) SCM ctxt; */ /* {return (NIMP(ctxt) && i_check_defines==CAR(ctxt));} */ /* static SCM wrapenv() */ /* {register SCM z; */ /* DEFER_INTS_EGC; if (NULLP(scm_env)) return EOL; */ /* NEWCELL(z); DEFER_INTS_EGC; */ /* if (NIMP(scm_env) && ENVP(scm_env)) return scm_env; */ /* CDR(z) = scm_env; CAR(z) = tc16_env; */ /* EGC_ROOT(z); return z;} */ SCM scm_current_env() { if (NFALSEP(scm_estk)) return STATIC_ENV; return EOL; } SCM ceval(x, static_env, env) SCM x, static_env, env; { ENV_PUSH; #ifdef CAUTIOUS scm_trace = BOOL_F; #endif TRACE(x); STATIC_ENV = static_env; scm_env = env; x = ceval_1(x); ENV_POP; ALLOW_INTS_EGC; return x; } SCM scm_eval_values(x, env, valenv) SCM x, env, valenv; { SCM res; ENV_PUSH; #ifdef CAUTIOUS scm_trace = BOOL_F; #endif TRACE(x); STATIC_ENV = env; scm_env = valenv; scm_env_tmp = IM_VALUES_TOKEN; if (NIMP(x)) x = ceval_1(cons2(IM_EVAL_VALUES, x, EOL)); DEFER_INTS_EGC; if (IM_VALUES_TOKEN==scm_env_tmp) { if (UNBNDP(x)) res = EOL; else res = cons(x, EOL); } else res = cons2(x, CAR(scm_env_tmp), CDR(scm_env_tmp)); ENV_POP; ALLOW_INTS_EGC; return res; } SCM scm_apply_cxr(proc, arg1) SCM proc, arg1; { double y; #ifdef FLOATS if (SUBRF(proc)) { if (INUMP(arg1)) { y = DSUBRF(proc)((double) INUM(arg1)); goto ret; } ASRTGO(NIMP(arg1), floerr); if (REALP(arg1)) { y = DSUBRF(proc)(REALPART(arg1)); ret: if (y==y) return makdbl(y, 0.0); goto floerr; } # ifdef BIGDIG if (BIGP(arg1)) { y = DSUBRF(proc)(big2dbl(arg1)); goto ret; } # endif floerr: wta(arg1, (char *)ARG1, SNAME(proc)); } #endif { int op = CXR_OP(proc); #ifndef RECKLESS SCM x = arg1; #endif while (op) { ASRTER(NIMP(arg1) && CONSP(arg1), x, ARG1, SNAME(proc)); arg1 = (1 & op ? CAR(arg1) : CDR(arg1)); op >>= 2; } return arg1; } } #ifdef __GNUC__ # define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) /* __GNUC_PATCHLEVEL__ */ # if 302 == GCC_VERSION # ifdef sparc # define GCC_SPARC_BUG # endif # endif #endif static SCM ceval_1(x) SCM x; { #ifdef GCC_SPARC_BUG SCM arg1; #else struct {SCM arg_1;} t; # define arg1 t.arg_1 #endif SCM arg2, arg3, proc; int envpp = 0; /* 1 means an environment has been pushed in this invocation of ceval_1, -1 means pushed and then popped. */ #ifdef CAUTIOUS SCM xorig; #endif CHECK_STACK; loop: POLL; #ifdef CAUTIOUS xorig = x; #endif #ifdef SCM_PROFILE eval_cases[TYP7(x)]++; #endif switch TYP7(x) { case tcs_symbols: /* only happens when called at top level */ x = evalatomcar(cons(x, UNDEFINED), !0); goto retx; case (127 & IM_AND): x = CDR(x); arg1 = x; while(NNULLP(arg1 = CDR(arg1))) if (FALSEP(EVALCAR(x))) {x = BOOL_F; goto retx;} else x = arg1; goto carloop; cdrxbegin: case (127 & IM_BEGIN): x = CDR(x); begin: arg1 = x; while(NNULLP(arg1 = CDR(arg1))) { if (NIMP(CAR(x))) ceval_1(CAR(x)); x = arg1; } carloop: /* eval car of last form in list */ if (NCELLP(CAR(x))) { x = CAR(x); x = IMP(x) ? EVALIMP(x) : I_VAL(x); } else if (ATOMP(CAR(x))) x = evalatomcar(x, 0); else { x = CAR(x); goto loop; /* tail recurse */ } retx: ENV_MAY_POP(envpp, 0); ALLOW_INTS_EGC; return x; case (127 & IM_CASE): x = scm_case_selector(x); goto begin; case (127 & IM_COND): while(NIMP(x = CDR(x))) { proc = CAR(x); arg1 = EVALCAR(proc); if (NFALSEP(arg1)) { x = CDR(proc); if (NULLP(x)) { x = arg1; goto retx; } if (IM_ARROW != CAR(x)) goto begin; proc = CDR(x); proc = EVALCAR(proc); ASRTGO(NIMP(proc), badfun); goto evap1; } } x = UNSPECIFIED; goto retx; case (127 & IM_DO): ENV_MAY_PUSH(envpp); TRACE(x); x = CDR(x); ecache_evalx(CAR(CDR(x))); /* inits */ STATIC_ENV = CAR(x); EXTEND_VALENV; x = CDR(CDR(x)); while (proc = CAR(x), FALSEP(EVALCAR(proc))) { for (proc = CAR(CDR(x));NIMP(proc);proc = CDR(proc)) { arg1 = CAR(proc); /* body */ SIDEVAL_1(arg1); } ecache_evalx(CDR(CDR(x))); /* steps */ scm_env = CDR(scm_env); EXTEND_VALENV; } x = CDR(proc); if (NULLP(x)) {x = UNSPECIFIED; goto retx;} goto begin; case (127 & IM_IF): x = CDR(x); if (NFALSEP(EVALCAR(x))) x = CDR(x); else if (IMP(x = CDR(CDR(x)))) {x = UNSPECIFIED; goto retx;} goto carloop; case (127 & IM_LET): ENV_MAY_PUSH(envpp); TRACE(x); #ifdef MAC_INLINE arg1 = CAR(x); #endif x = CDR(x); ecache_evalx(CAR(CDR(x))); #ifdef MAC_INLINE if (arg1 != IM_LET) /* inline call */ env_tail(ISYMVAL(arg1)); #endif STATIC_ENV = CAR(x); EXTEND_VALENV; x = CDR(x); goto cdrxbegin; case (127 & IM_LETREC): ENV_MAY_PUSH(envpp); TRACE(x); x = CDR(x); STATIC_ENV = CAR(x); #if 0 /* The block below signals an error if any variable bound in a LETREC is referenced in any init. */ scm_env_tmp = undefineds; EXTEND_VALENV; x = CDR(x); ecache_evalx(CAR(x)); EGC_ROOT(scm_env); CAR(scm_env) = scm_env_tmp; #else /* The block below implements LETREC* */ ecache_undefs(CAR(CAR(x))); EXTEND_VALENV; x = CDR(x); proc = CAR(x); while (NIMP(proc)) { arg1 = EVALCAR(proc); proc = CDR(proc); DEFER_INTS_EGC; CAR(scm_env_tmp) = arg1; scm_env_tmp = CDR(scm_env_tmp); } #endif scm_env_tmp = EOL; goto cdrxbegin; case (127 & IM_LETSTAR): ENV_MAY_PUSH(envpp); TRACE(x); x = CDR(x); proc = CDR(CAR(x)); /* No longer happens. if (IMP(proc)) { scm_env_tmp = EOL; EXTEND_VALENV; goto cdrxbegin; } */ scm_env_tmp = EOL; /* needed so multiple values cause an error to be signaled when this is a top-level form. */ do { scm_env_tmp = EVALCAR(proc); proc = CDR(proc); STATIC_ENV = CAR(proc); EXTEND_VALENV; } while NIMP(proc = CDR(proc)); goto cdrxbegin; case (127 & IM_OR): x = CDR(x); arg1 = x; while(NNULLP(arg1 = CDR(arg1))) { x = EVALCAR(x); if (NFALSEP(x)) goto retx; x = arg1; } goto carloop; case (127 & IM_LAMBDA): x = closure(CDR(x), ISYMVAL(CAR(x))); goto retx; case (127 & IM_QUOTE): x = CAR(CDR(x)); goto retx; case (127 & IM_SET): x = CDR(x); arg2 = EVALCAR(CDR(x)); proc = CAR(x); switch (7 & (int)proc) { case 0: if (ECONSP(proc)) if (ISYMP(CAR(proc))) *farlookup(proc) = arg2; else { x = scm_multi_set(proc, arg2); goto retx; } else *lookupcar(x) = arg2; break; case 1: I_VAL(proc) = arg2; break; case 4: *ilookup(proc) = arg2; break; } #ifdef SICP x = arg2; #else x = UNSPECIFIED; #endif goto retx; case (127 & IM_FUNCALL): x = CDR(x); proc = ceval_1(CAR(x)); break; case (127 & MAKISYM(0)): proc = CAR(x); ASRTGO(ISYMP(proc), badfun); #ifdef SCM_PROFILE eval_cases_other[ISYMNUM(proc)]++; #endif switch ISYMNUM(proc) { case (ISYMNUM(IM_APPLY)): x = CDR(x); proc = evalcar(x); ASRTGO(NIMP(proc), badfun); arg1 = evalcar(CDR(x)); if (CLOSUREP(proc)) { ENV_MAY_PUSH(envpp); TRACE(x); scm_env_tmp = arg1; #ifndef RECKLESS goto clo_checked; #else goto clo_unchecked; #endif } x = apply(proc, arg1, EOL); goto retx; case (ISYMNUM(IM_DELAY)): x = makprom(closure(CDR(x), 0)); goto retx; case (ISYMNUM(IM_QUASIQUOTE)): ALLOW_INTS_EGC; x = iqq(CAR(CDR(x))); goto retx; case (ISYMNUM(IM_FARLOC_CAR)): case (ISYMNUM(IM_FARLOC_CDR)): x = *farlookup(x); goto retx; case (ISYMNUM(IM_EVAL_FOR_APPLY)): /* only happens when called from C-level apply or cvapply */ envpp = 1; proc = CAR(scm_env_tmp); scm_env_tmp = CDR(scm_env_tmp); goto clo_unchecked; case (ISYMNUM(IM_LET_SYNTAX)): x = CDR(x); STATIC_ENV = CAR(x); goto cdrxbegin; case (ISYMNUM(IM_ACRO_CALL)): x = acro_call(x, STATIC_ENV); goto loop; case (ISYMNUM(IM_LINUM)): #ifndef MEMOIZE_LOCALS x = CDR(x); /* For non-memoizing case, just throw away line number. */ goto loop; #else goto expand; #endif case (ISYMNUM(IM_DEFINE)): x = toplevel_define(x, STATIC_ENV); goto retx; case (ISYMNUM(IM_EVAL_VALUES)): /* Push magic VALUES token on estk until tail call occurs. Only happens when called from scm_eval_values. */ ENV_MAY_PUSH(envpp); scm_env_tmp = EOL; goto cdrxbegin; /* new syntactic forms go here. */ default: goto badfun; } default: proc = x; badfun: #ifdef CAUTIOUS scm_trace = BOOL_F; everr(xorig, STATIC_ENV, proc, s_wtap, "", 0); #else everr(x, STATIC_ENV, proc, s_wtap, "", 0); #endif case tc7_vector: case tcs_uves: case tc7_smob: goto retx; case (127 & ILOC00): proc = *ilookup(CAR(x)); break; case tcs_cons_gloc: proc = I_VAL(CAR(x)); break; case tcs_cons_nimcar: expand: TOP_TRACE(x, STATIC_ENV); #ifdef MEMOIZE_LOCALS x = macroexp1(x, STATIC_ENV, EOL, 3); goto loop; #else if (ATOMP(CAR(x))) { proc = scm_lookupval(x, 0); if (KEYWORDP(proc)) { x = macroexp1(x, STATIC_ENV, EOL, 3); goto loop; } } else proc = ceval_1(CAR(x)); #endif } /* At this point proc is the evaluated procedure from the function position and x has the form which is being evaluated. */ ASRTGO(NIMP(proc), badfun); scm_estk_ptr[0] = scm_env; /* For error reporting at wrongnumargs. */ if (NULLP(CDR(x))) { evap0: TOP_TRACE(xorig, STATIC_ENV); ENV_MAY_POP(envpp, CLOSUREP(proc)); ALLOW_INTS_EGC; switch TYP7(proc) { /* no arguments given */ case tc7_subr_0: return SUBRF(proc)(); case tc7_subr_1o: return SUBRF(proc) (UNDEFINED); case tc7_lsubr: return SUBRF(proc)(EOL); case tc7_rpsubr: return BOOL_T; case tc7_asubr: return SUBRF(proc)(UNDEFINED, UNDEFINED); case tcs_closures: DEFER_INTS_EGC; ENV_MAY_PUSH(envpp); scm_env_tmp = EOL; #ifdef SCM_PROFILE eval_clo_cases[0][0]++; #endif #ifdef CAUTIOUS if (0!=ARGC(proc)) { clo_checked: arg1 = SCM_ENV_FORMALS(CAR(CODE(proc))); DEFER_INTS_EGC; arg2 = scm_env_tmp; while NIMP(arg1) { if (NCONSP(arg1)) goto clo_unchecked; if (IMP(arg2)) goto umwrongnumargs; arg1 = CDR(arg1); arg2 = CDR(arg2); } if (NNULLP(arg2)) goto umwrongnumargs; } #else /* def CAUTIOUS */ clo_checked: #endif clo_unchecked: x = CODE(proc); scm_env = ENV(proc); STATIC_ENV = CAR(x); EXTEND_VALENV; TRACE(CDR(x)); goto cdrxbegin; case tc7_specfun: switch TYP16(proc) { /* default: break; */ #ifdef CCLO case tc16_cclo: arg1 = proc; proc = CCLO_SUBR(proc); goto evap1; #endif case tc16_values: return scm_values(UNDEFINED, UNDEFINED, EOL, s_values); } case tc7_contin: scm_dynthrow(proc, UNDEFINED, UNDEFINED, EOL); case tc7_subr_1: case tc7_subr_2: case tc7_subr_2o: case tc7_cxr: case tc7_subr_3: case tc7_lsubr_2: umwrongnumargs: wrongnumargs: if (envpp < 0) { scm_estk_ptr += SCM_ESTK_FRLEN; scm_env = scm_estk_ptr[0]; } #ifdef CAUTIOUS if (xorig==scm_trace) STATIC_ENV = scm_trace_env; TOP_TRACE(BOOL_F, BOOL_F); everr(xorig, STATIC_ENV, proc, (char *)WNA, "", 0); #else everr(x, STATIC_ENV, proc, (char *)WNA, "", 0); #endif default: goto badfun; } } x = CDR(x); #ifdef CAUTIOUS if (IMP(x)) goto wrongnumargs; #endif arg1 = EVALCAR(x); x = CDR(x); if (NULLP(x)) { TOP_TRACE(xorig, STATIC_ENV); evap1: ENV_MAY_POP(envpp, CLOSUREP(proc)); ALLOW_INTS_EGC; switch TYP7(proc) { /* have one argument in arg1 */ case tc7_subr_2o: return SUBRF(proc)(arg1, UNDEFINED); case tc7_subr_1: case tc7_subr_1o: return SUBRF(proc)(arg1); case tc7_cxr: return scm_apply_cxr(proc, arg1); case tc7_rpsubr: return BOOL_T; case tc7_asubr: return SUBRF(proc)(arg1, UNDEFINED); case tc7_lsubr: return SUBRF(proc)(cons(arg1, EOL)); case tcs_closures: ENV_MAY_PUSH(envpp); #ifdef SCM_PROFILE eval_clo_cases[1][ARGC(proc)]++; #endif if (1==ARGC(proc)) { scm_env_cons(arg1, EOL); goto clo_unchecked; } else { scm_env_tmp = cons(arg1, EOL); goto clo_checked; } case tc7_contin: scm_dynthrow(proc, arg1, UNDEFINED, EOL); case tc7_specfun: switch TYP16(proc) { case tc16_call_cc: proc = arg1; DEFER_INTS_EGC; arg1 = scm_make_cont(); EGC_ROOT(arg1); x = setjump(CONT(arg1)->jmpbuf); if (x) { #ifdef SHORT_INT x = (SCM)thrown_value; #endif #ifdef CHEAP_CONTINUATIONS envpp = 0; #endif goto retx; } ASRTGO(NIMP(proc), badfun); goto evap1; case tc16_eval: ENV_MAY_PUSH(envpp); TRACE(arg1); STATIC_ENV = eval_env; scm_env = EOL; x = arg1; if (IMP(x)) goto retx; goto loop; #ifdef CCLO case tc16_cclo: arg2 = UNDEFINED; goto cclon; /* arg2 = arg1; arg1 = proc; proc = CCLO_SUBR(proc); goto evap2; */ #endif case tc16_values: return arg1; } case tc7_subr_2: case tc7_subr_0: case tc7_subr_3: case tc7_lsubr_2: goto wrongnumargs; default: goto badfun; } } #ifdef CAUTIOUS if (IMP(x)) goto wrongnumargs; #endif { /* have two or more arguments */ arg2 = EVALCAR(x); x = CDR(x); if (NULLP(x)) { /* have two arguments */ TOP_TRACE(xorig, STATIC_ENV); evap2: ENV_MAY_POP(envpp, CLOSUREP(proc)); ALLOW_INTS_EGC; switch TYP7(proc) { case tc7_subr_2: case tc7_subr_2o: return SUBRF(proc)(arg1, arg2); case tc7_lsubr: return SUBRF(proc)(cons2(arg1, arg2, EOL)); case tc7_lsubr_2: return SUBRF(proc)(arg1, arg2, EOL); case tc7_rpsubr: case tc7_asubr: return SUBRF(proc)(arg1, arg2); case tc7_specfun: switch TYP16(proc) { case tc16_apply: proc = arg1; ASRTGO(NIMP(proc), badfun); if (NULLP(arg2)) goto evap0; if (IMP(arg2) || NCONSP(arg2)) { x = arg2; badlst: wta(x, (char *)ARGn, s_apply); } arg1 = CAR(arg2); x = CDR(arg2); apply3: if (NULLP(x)) goto evap1; ASRTGO(NIMP(x) && CONSP(x), badlst); arg2 = CAR(x); x = CDR(x); apply4: if (NULLP(x)) goto evap2; ASRTGO(NIMP(x) && CONSP(x), badlst); arg3 = x; x = scm_cp_list(CDR(x), 0); #ifndef RECKLESS if (UNBNDP(x)) {x = arg3; goto badlst;} #endif arg3 = CAR(arg3); goto evap3; #ifdef CCLO case tc16_cclo: cclon: arg3 = arg2; arg2 = arg1; arg1 = proc; proc = CCLO_SUBR(proc); if (UNBNDP(arg3)) goto evap2; goto evap3; /* return apply(CCLO_SUBR(proc), cons2(proc, arg1, cons(arg2, x)), EOL); */ #endif case tc16_values: return scm_values(arg1, arg2, EOL, s_values); case tc16_call_wv: ENV_MAY_PUSH(envpp); scm_env_tmp = IM_VALUES_TOKEN; /* Magic value recognized by VALUES */ arg1 = apply(arg1, EOL, EOL); proc = arg2; DEFER_INTS_EGC; if (IM_VALUES_TOKEN==scm_env_tmp) { scm_env_tmp = EOL; if (UNBNDP(arg1)) goto evap0; goto evap1; } arg2 = CAR(scm_env_tmp); x = CDR(scm_env_tmp); goto apply4; /* Jumping to apply code results in extra list copy for >=3 args, but we want to minimize bloat. */ } case tc7_subr_0: case tc7_cxr: case tc7_subr_1o: case tc7_subr_1: case tc7_subr_3: case tc7_contin: scm_dynthrow(proc, arg1, arg2, EOL); goto wrongnumargs; default: goto badfun; case tcs_closures: ENV_MAY_PUSH(envpp); #ifdef SCM_PROFILE eval_clo_cases[2][ARGC(proc)]++; #endif switch ARGC(proc) { case 2: scm_env_cons2(arg1, arg2, EOL); goto clo_unchecked; case 1: scm_env_cons(arg1, cons(arg2, EOL)); goto clo_checked; case 0: case 3: /* Error, will be caught at clo_checked: */ scm_env_tmp = cons2(arg1, arg2, EOL); goto clo_checked; } } } { /* have 3 or more arguments */ arg3 = EVALCAR(x); x = CDR(x); if (NIMP(x)) { if (CLOSUREP(proc) && 3==ARGC(proc)) { ALLOW_INTS_EGC; ENV_MAY_PUSH(envpp); if (ecache_eval_args(proc, arg1, arg2, arg3, x)) goto clo_unchecked; goto umwrongnumargs; } x = eval_args(x); } TOP_TRACE(xorig, STATIC_ENV); evap3: ENV_MAY_POP(envpp, CLOSUREP(proc)); ALLOW_INTS_EGC; switch TYP7(proc) { case tc7_subr_3: ASRTGO(NULLP(x), wrongnumargs); return SUBRF(proc)(arg1, arg2, arg3); case tc7_asubr: case tc7_rpsubr: return asubr_apply(proc, arg1, arg2, arg3, x); /* return apply(proc, cons2(arg1, arg2, cons(arg3, x)), EOL); */ case tc7_lsubr_2: return SUBRF(proc)(arg1, arg2, cons(arg3, x)); case tc7_lsubr: return SUBRF(proc)(cons2(arg1, arg2, cons(arg3, x))); case tcs_closures: ENV_MAY_PUSH(envpp); #ifdef SCM_PROFILE eval_clo_cases[IMP(x)?3:4][ARGC(proc)]++; #endif switch ARGC(proc) { case 3: scm_env_cons3(arg1, arg2, arg3, x); goto clo_checked; case 2: scm_env_cons2(arg1, arg2, cons(arg3, x)); goto clo_checked; case 1: scm_env_cons(arg1, cons2(arg2, arg3, x)); goto clo_checked; case 0: scm_env_tmp = cons2(arg1, arg2, cons(arg3, x)); goto clo_checked; } case tc7_specfun: switch TYP16(proc) { case tc16_apply: proc = arg1; ASRTGO(NIMP(proc), badfun); arg1 = arg2; if (IMP(x)) { x = arg3; goto apply3; } arg2 = arg3; if (IMP(CDR(x))) { x = CAR(x); goto apply4; } arg3 = CAR(x); x = nconc2copy(CDR(x)); goto evap3; #ifdef CCLO case tc16_cclo: x = cons(arg3, x); goto cclon; #endif case tc16_values: return scm_values(arg1, arg2, cons(arg3, x), s_values); } case tc7_contin: scm_dynthrow(proc, arg1, arg2, cons(arg3, x)); case tc7_subr_2: case tc7_subr_1o: case tc7_subr_2o: case tc7_subr_0: case tc7_cxr: case tc7_subr_1: goto wrongnumargs; default: goto badfun; } } } #undef arg1 } SCM procedurep(obj) SCM obj; { if (NIMP(obj)) switch TYP7(obj) { case tcs_closures: case tc7_contin: case tcs_subrs: case tc7_specfun: return BOOL_T; } return BOOL_F; } static char s_proc_doc[] = "procedure-documentation"; SCM l_proc_doc(proc) SCM proc; { SCM env; ASRTER(BOOL_T==procedurep(proc) && NIMP(proc) && TYP7(proc) != tc7_contin, proc, ARG1, s_proc_doc); switch TYP7(proc) { case tcs_closures: env = CAR(CODE(proc)); env = scm_env_getprop(SCM_ENV_DOC, CAR(CODE(proc))); return IMP(env) ? BOOL_F : CAR(env); default: return BOOL_F; /* case tcs_subrs: case tc7_specfun: */ } } /* This code is for apply. it is destructive on multiple args. This will only screw you if you do (apply apply '( ... )) */ /* Copy last (list) argument, so SET! in a closure can't mutate it. */ SCM nconc2copy(lst) SCM lst; { SCM last, *lloc = &lst; #ifdef CAUTIOUS ASRTER(ilength(lst) >= 1, lst, WNA, s_apply); #endif while NNULLP(CDR(*lloc)) lloc = &CDR(*lloc); #ifdef CAUTIOUS ASRTER(ilength(CAR(*lloc)) >= 0, lst, ARGn, s_apply); #endif last = CAR(*lloc); *lloc = EOL; for (; NIMP(last); last=CDR(last)) { *lloc = cons(CAR(last), EOL); lloc = &CDR(*lloc); } return lst; } /* Shallow copy. If LST is not a proper list of length at least MINLEN, returns UNDEFINED */ SCM scm_cp_list(lst, minlen) SCM lst; int minlen; { SCM res, *lloc = &res; res = EOL; for (; NIMP(lst) && CONSP(lst); lst = CDR(lst)) { *lloc = cons(CAR(lst), EOL); lloc = &CDR(*lloc); minlen--; } if (NULLP(lst) && minlen <= 0) return res; return UNDEFINED; } SCM scm_v2lst(n, v, end) long n; SCM *v, end; { SCM res = end; for (n--; n >= 0; n--) res = cons(v[n], res); return res; } SCM apply(proc, arg1, args) SCM proc, arg1, args; { ASRTGO(NIMP(proc), badproc); if (NULLP(args)) if (NULLP(arg1)) arg1 = UNDEFINED; else { args = CDR(arg1); arg1 = CAR(arg1); } else args = nconc2copy(args); cc_tail: ALLOW_INTS_EGC; switch TYP7(proc) { default: badproc: wta(proc, (char *)ARG1, s_apply); wrongnumargs: wta(proc, (char *)WNA, s_apply); case tc7_subr_2o: if (NULLP(args)) { args = UNDEFINED; return SUBRF(proc)(arg1, args); } /* Fall through */ case tc7_subr_2: ASRTGO(NIMP(args) && NULLP(CDR(args)), wrongnumargs); args = CAR(args); return SUBRF(proc)(arg1, args); case tc7_subr_0: ASRTGO(UNBNDP(arg1), wrongnumargs); return SUBRF(proc)(); case tc7_subr_1: case tc7_subr_1o: ASRTGO(NULLP(args), wrongnumargs); return SUBRF(proc)(arg1); case tc7_cxr: ASRTGO(NULLP(args), wrongnumargs); return scm_apply_cxr(proc, arg1); case tc7_subr_3: ASRTGO(NIMP(args) && NIMP(CDR(args)) && NULLP(CDR(CDR(args))), wrongnumargs); return SUBRF(proc)(arg1, CAR(args), CAR(CDR(args))); case tc7_lsubr: return SUBRF(proc)(UNBNDP(arg1) ? EOL : cons(arg1, args)); case tc7_lsubr_2: ASRTGO(NIMP(args) && CONSP(args), wrongnumargs); return SUBRF(proc)(arg1, CAR(args), CDR(args)); case tc7_asubr: if (NULLP(args)) return SUBRF(proc)(arg1, UNDEFINED); while NIMP(args) { ASRTER(CONSP(args), args, ARG2, s_apply); arg1 = SUBRF(proc)(arg1, CAR(args)); args = CDR(args); } return arg1; case tc7_rpsubr: if (NULLP(args)) return BOOL_T; while NIMP(args) { ASRTER(CONSP(args), args, ARG2, s_apply); if (FALSEP(SUBRF(proc)(arg1, CAR(args)))) return BOOL_F; arg1 = CAR(args); args = CDR(args); } return BOOL_T; case tcs_closures: { arg1 = (UNBNDP(arg1) ? EOL : cons(arg1, args)); #ifndef RECKLESS if (badargsp(SCM_ENV_FORMALS(CAR(CODE(proc))), arg1)) goto wrongnumargs; #endif ENV_PUSH; scm_env_cons(proc, arg1); arg1 = ceval_1(f_evapply); return arg1; } case tc7_contin: if (NULLP(args)) scm_dynthrow(proc, arg1, UNDEFINED, EOL); /* else fall through */ case tc7_specfun: args = UNBNDP(arg1) ? EOL : cons(arg1, args); arg1 = proc; #ifdef CCLO proc = (TYP16(proc)==tc16_cclo ? CCLO_SUBR(proc) : f_apply_closure); #else proc = f_apply_closure; #endif goto cc_tail; } } /* This function does not check that proc is a procedure, nor that it accepts n arguments. Call scm_arity_check to do that. */ SCM scm_cvapply(proc, n, argv) SCM proc, *argv; long n; { SCM res; long i; tail: ALLOW_INTS_EGC; switch TYP7(proc) { default: return UNSPECIFIED; case tc7_subr_2o: if (1==n) return SUBRF(proc)(argv[0], UNDEFINED); /* Fall through */ case tc7_subr_2: return SUBRF(proc)(argv[0], argv[1]); case tc7_subr_0: return SUBRF(proc)(); case tc7_subr_1o: if (0==n) return SUBRF(proc)(UNDEFINED); /* Fall through */ case tc7_subr_1: return SUBRF(proc)(argv[0]); case tc7_cxr: return scm_apply_cxr(proc, argv[0]); case tc7_subr_3: return SUBRF(proc)(argv[0], argv[1], argv[2]); case tc7_lsubr: return SUBRF(proc)(0==n ? EOL : scm_v2lst(n, argv, EOL)); case tc7_lsubr_2: return SUBRF(proc)(argv[0], argv[1], 2==n ? EOL : scm_v2lst(n-2, &argv[2], EOL)); case tc7_asubr: if (1 >= n) return SUBRF(proc)(0==n ? UNDEFINED: argv[0], UNDEFINED); res = argv[0]; for (i = 1; i < n; i++) res = SUBRF(proc)(res, argv[i]); return res; case tc7_rpsubr: if (1 >= n) return BOOL_T; for (i = 0; i < n-1; i++) if (FALSEP(SUBRF(proc)(argv[i], argv[i+1]))) return BOOL_F; return BOOL_T; case tcs_closures: { SCM p = proc; ENV_PUSH; i = ARGC(proc); if (3==i) { scm_env_tmp = EOL; ENV_V2LST(n, argv); } else { scm_env_tmp = (i < n) ? scm_v2lst(n-i, &argv[i], EOL) : EOL; if (i>0) ENV_V2LST(i, argv); } ENV_V2LST(1L, &p); res = ceval_1(f_evapply); return res; } case tc7_contin: if (1 == n) scm_dynthrow(proc, argv[0], UNDEFINED, EOL); goto call_apply; case tc7_specfun: if (tc16_apply==TYP16(proc)) { proc = argv[0]; argv++; n--; #ifndef RECKLESS scm_arity_check(proc, n, s_apply); #endif goto tail; } call_apply: res = cons(proc, 0==n ? EOL : scm_v2lst(n, argv, EOL)); #ifdef CCLO proc = (TYP16(proc)==tc16_cclo ? CCLO_SUBR(proc) : f_apply_closure); #else proc = f_apply_closure; #endif return apply(proc, res, EOL); } } SCM map(proc, arg1, args) SCM proc, arg1, args; { SCM res = EOL, *pres = &res; SCM heap_ve, auto_ve[5], auto_ave[5]; SCM *ve = auto_ve, *ave = auto_ave; long i, n = ilength(args) + 1; scm_protect_temp(&heap_ve); /* Keep heap_ve from being optimized away. */ if (NULLP(arg1)) return res; #ifndef RECKLESS scm_arity_check(proc, n, s_map); #endif ASRTER(NIMP(arg1), arg1, ARG2, s_map); #ifdef CCLO if (tc16_cclo==TYP16(proc)) { args = cons(arg1, args); arg1 = cons(proc, EOL); SETCDR(arg1, arg1); /* circular list */ proc = CCLO_SUBR(proc); n++; } #endif if (n > 5) { heap_ve = make_vector(MAKINUM(2*n), BOOL_F); ve = VELTS(heap_ve); ave = &(ve[n]); } ve[0] = arg1; ASRTER(NIMP(ve[0]), arg1, ARG2, s_map); for (i = 1; i < n; i++) { ve[i] = CAR(args); ASRTER(NIMP(ve[i]), ve[i], ARGn, s_map); args = CDR(args); } while (1) { arg1 = EOL; for (i = n-1;i >= 0;i--) { if (IMP(ve[i])) { /* We could check for lists the same length here. */ return res; } ASRTER(CONSP(ve[i]), ve[i], 0==i ? ARG2 : ARGn, s_map); ave[i] = CAR(ve[i]); ve[i] = CDR(ve[i]); } *pres = cons(scm_cvapply(proc, n, ave), EOL); pres = &CDR(*pres); } } SCM for_each(proc, arg1, args) SCM proc, arg1, args; { SCM heap_ve, auto_ve[5], auto_ave[5]; SCM *ve = auto_ve, *ave = auto_ave; long i, n = ilength(args) + 1; scm_protect_temp(&heap_ve); /* Keep heap_ve from being optimized away. */ if (NULLP(arg1)) return UNSPECIFIED; #ifndef RECKLESS scm_arity_check(proc, n, s_for_each); #endif ASRTER(NIMP(arg1), arg1, ARG2, s_for_each); #ifdef CCLO if (tc16_cclo==TYP16(proc)) { args = cons(arg1, args); arg1 = cons(proc, EOL); SETCDR(arg1, arg1); /* circular list */ proc = CCLO_SUBR(proc); n++; } #endif if (n > 5) { heap_ve = make_vector(MAKINUM(2*n), BOOL_F); ve = VELTS(heap_ve); ave = &(ve[n]); } ve[0] = arg1; ASRTER(NIMP(ve[0]), arg1, ARG2, s_for_each); for (i = 1; i < n; i++) { ve[i] = CAR(args); ASRTER(NIMP(ve[i]), args, ARGn, s_for_each); args = CDR(args); } while (1) { arg1 = EOL; for (i = n-1;i >= 0;i--) { if (IMP(ve[i])) { return UNSPECIFIED; } ASRTER(CONSP(ve[i]), ve[i], 0==i ? ARG2 : ARGn, s_for_each); ave[i] = CAR(ve[i]); ve[i] = CDR(ve[i]); } scm_cvapply(proc, n, ave); } } /* The number of required arguments up to 3 is encoded in the cdr of the closure. A value 3 means no rest argument, 3 or more required arguments. This information is used to make sure that rest args are not allocated in the environment cache. */ SCM closure(code, argc) SCM code; int argc; { register SCM z; NEWCELL(z); SETCODE(z, code); DEFER_INTS_EGC; if (IMP(scm_env)) CDR(z) = argc<<1; else { CDR(z) = scm_env | (argc<<1); EGC_ROOT(z); } return z; } long tc16_promise; SCM makprom(code) SCM code; { register SCM z; NEWCELL(z); CDR(z) = code; CAR(z) = tc16_promise; return z; } static int prinprom(exp, port, writing) SCM exp; SCM port; int writing; { lputs("#', port); return !0; } static SCM makro(code, flags, what) SCM code; long flags; const char *what; { register SCM z; ASRTER(scm_arity_check(code, (MAC_PRIMITIVE & flags ? 3L : 2L), (char *)0), code, ARG1, what); NEWCELL(z); CDR(z) = code; CAR(z) = tc16_macro | (flags << 16); return z; } static char s_makacro[] = "procedure->syntax"; SCM makacro(code) SCM code; { return makro(code, MAC_ACRO, s_makacro); } static char s_makmacro[] = "procedure->macro"; SCM makmacro(code) SCM code; { return makro(code, MAC_MACRO, s_makmacro); } static char s_makmmacro[] = "procedure->memoizing-macro"; SCM makmmacro(code) SCM code; { return makro(code, MAC_MMACRO, s_makmmacro); } static char s_makidmacro[] = "procedure->identifier-macro"; SCM makidmacro(code) SCM code; { return makro(code, MAC_IDMACRO, s_makidmacro); } #ifdef MACRO /* Functions for smart expansion */ /* @MACROEXPAND1 returns: '#F' if its argument is not a macro invocation, the argument if the argument is a primitive syntax invocation, the result of expansion if the argument is a macro invocation (BEGIN #F) will be returned instead of #F if #F is the result. */ static char s_macroexpand1[] = "@macroexpand1"; SCM scm_macroexpand1(x, env) SCM x, env; { SCM name; if (IMP(x)) return BOOL_F; if (CONSP(x)) { name = CAR(x); if (IMP(name) || !IDENTP(name)) return BOOL_F; /* probably an error */ } else if (IDENTP(x)) { name = x; } else return BOOL_F; return macroexp1(x, env, BOOL_F, 0); } static char s_eval_syntax[] = "eval-syntax"; SCM scm_eval_syntax(x, env) SCM x, env; { SCM venv = cons(undefineds, undefineds); CDR(venv) = venv; return EVAL(x, env, venv); } #endif /* MACRO */ static int prinmacro(exp, port, writing) SCM exp; SCM port; int writing; { lputs("#<", port); if (MAC_TYPE(exp) & MAC_PRIMITIVE) lputs("primitive-", port); switch (MAC_TYPE(exp) & ~MAC_PRIMITIVE) { default: lputs("macro", port); break; case MAC_ACRO: lputs("syntax", port); break; #ifdef MAC_INLINE case MAC_INLINE: lputs("inline function", port); break; #endif } if (MAC_TYPE(exp) & MAC_MEMOIZING) lputc('!', port); lputc(' ', port); scm_iprin1(CDR(exp), port, writing); lputc('>', port); return !0; } static int prinenv(exp, port, writing) SCM exp; SCM port; int writing; { lputs("#', port); return !0; } #ifdef MACRO static int prinid(exp, port, writing) SCM exp; SCM port; int writing; { SCM s = IDENT_PARENT(exp); while (M_IDENTP(s)) s = IDENT_PARENT(s); lputs("#', port); return !0; } #endif char s_force[] = "force"; SCM force(x) SCM x; { tail: ASRTGO(NIMP(x) && (TYP16(x)==tc16_promise), badx); switch (CAR(x)>>16) { default: badx: wta(x, (char *)ARG1, s_force); case 0: { SCM ans; int mv = (IM_VALUES_TOKEN==scm_env_tmp); ans = scm_cvapply(CDR(x), 0L, (SCM *)0); if (mv) { DEFER_INTS_EGC; if (IM_VALUES_TOKEN==scm_env_tmp) { if (!UNBNDP(ans)) mv = 0; } else { ans = cons2(ans, CAR(scm_env_tmp), CDR(scm_env_tmp)); scm_env_tmp = IM_VALUES_TOKEN; } ALLOW_INTS_EGC; } if (!((1L<<16) & CAR(x))) { DEFER_INTS; CDR(x) = ans; CAR(x) |= mv ? (3L<<16) : (1L<<16); ALLOW_INTS; } goto tail; } case 1: return CDR(x); case 3: x = CDR(x); if (UNBNDP(x)) return scm_values(UNDEFINED, UNDEFINED, EOL, s_force); return scm_values(CAR(x), CAR(CDR(x)), CDR(CDR(x)), s_force); } } SCM copytree(obj) SCM obj; { SCM ans, tl; if (IMP(obj)) return obj; if (VECTORP(obj)) { sizet i = LENGTH(obj); ans = make_vector(MAKINUM(i), UNSPECIFIED); while(i--) VELTS(ans)[i] = copytree(VELTS(obj)[i]); return ans; } if (NCONSP(obj)) return obj; /* return cons(copytree(CAR(obj)), copytree(CDR(obj))); */ ans = tl = cons(copytree(CAR(obj)), UNSPECIFIED); while(NIMP(obj = CDR(obj)) && CONSP(obj)) tl = (CDR(tl) = cons(copytree(CAR(obj)), UNSPECIFIED)); CDR(tl) = obj; return ans; } SCM eval(obj) SCM obj; { obj = copytree(obj); return EVAL(obj, EOL, EOL); } static char s_definedp[] = "defined?"; SCM definedp(xorig, env, ctxt) SCM xorig, env, ctxt; { SCM x = CDR(xorig); SCM proc; ASSYNT(1 == ilength(x), xorig, s_body, s_definedp); proc = CAR(x); #ifdef MACRO proc = id2sym(proc); #endif return (ISYMP(proc) || (NIMP(proc) && IDENTP(proc) && !UNBNDP(CDR(sym2vcell(proc)))))? (SCM)BOOL_T : (SCM)BOOL_F; } #ifdef MACRO static char s_identp[] = "identifier?"; SCM identp(obj) SCM obj; { return (NIMP(obj) && IDENTP(obj)) ? BOOL_T : BOOL_F; } static char s_ident_eqp[] = "identifier-equal?"; SCM ident_eqp(id1, id2, env) SCM id1, id2, env; { SCM s1 = id1, s2 = id2; # ifndef RECKLESS if (IMP(id1)) badarg1: wta(id1, (char *)ARG1, s_ident_eqp); if (IMP(id1)) badarg2: wta(id2, (char *)ARG2, s_ident_eqp); # endif if (id1==id2) return BOOL_T; while M_IDENTP(s1) s1 = IDENT_PARENT(s1); while M_IDENTP(s2) s2 = IDENT_PARENT(s2); ASRTGO(SYMBOLP(s1), badarg1); ASRTGO(SYMBOLP(s2), badarg2); if (s1 != s2) return BOOL_F; s1 = scm_env_lookup(id1, env); s2 = scm_env_lookup(id2, env); if (s1==s2) return BOOL_T; if (NIMP(s1) && ISYMP(CAR(s1))) /* FARLOC case */ return equal(s1, s2); return BOOL_F; } static char s_ident2sym[] = "identifier->symbol"; SCM ident2sym(id) SCM id; { id = id2sym(id); ASRTER(NIMP(id) && SYMBOLP(id), id, ARG1, s_ident2sym); return id; } static char s_renamed_ident[] = "renamed-identifier"; SCM renamed_ident(id, env) SCM id, env; { SCM z; ASRTER(NIMP(id) && IDENTP(id), id, ARG1, s_renamed_ident); NEWCELL(z); while (NIMP(env)) { if (INUMP(CAR(env))) { ASRTER(NIMP(CDR(env)), env, s_badenv, s_renamed_ident); env = CDR(CDR(env)); } else if (SCM_LINUMP(CAR(env))) { env = CDR(env); } else { ASRTER(NULLP(env) || (NIMP(env) && CONSP(env)), env, s_badenv, s_renamed_ident); break; } } if (scm_nullenv_p(env)) { CAR(z) = tc16_ident; CDR(z) = id; return z; } else { SCM y; CAR(z) = id; CDR(z) = env; NEWCELL(y); CAR(y) = tc16_ident | 1L<<16; CDR(y) = z; return y; } } static char s_syn_quote[] = "syntax-quote"; SCM m_syn_quote(xorig, env, ctxt) SCM xorig, env, ctxt; { ASSYNT(ilength(CDR(xorig))==1, xorig, s_expression, s_syn_quote); return cons(IM_QUOTE, CDR(xorig)); } static char s_defsyntax[] = "defsyntax"; SCM m_defsyntax(xorig, env, ctxt) SCM xorig, env, ctxt; { SCM x = CDR(xorig), name, val; ASSYNT(ilength(x)==2, xorig, s_expression, s_defsyntax); ASSYNT(scm_nullenv_p(env), xorig, s_placement, s_defsyntax); name = CAR(x); ASSYNT(NIMP(name) && IDENTP(name), name, s_variable, s_defsyntax); val = evalcar(CDR(x)); ASSYNT(NIMP(val) && MACROP(val), CAR(CDR(x)), s_expr, s_defsyntax); checked_define(name, cons(IM_KEYWORD, val), s_defsyntax); return UNSPECIFIED; } SCM m_let_syntax(xorig, env, ctxt) SCM xorig, env, ctxt; { SCM proc, vars, inits, fr; SCM body = m_parse_let(EOL, xorig, CDR(xorig), &vars, &inits); /* if (IMP(vars)) return m_let_null(body, env, ctxt); */ /* Add a unique frame for an environment mark. */ env = EXTEND_ENV(cons(SCM_ENV_SYNTAX, EOL), env); for (fr = EOL; NIMP(inits); inits = CDR(inits)) { proc = scm_eval_syntax(CAR(inits), env); ASSYNT(NIMP(proc) && MACROP(proc), CAR(inits), s_expr, s_let_syntax); fr = acons(CAR(vars), proc, fr); vars = CDR(vars); } fr = cons(SCM_ENV_SYNTAX, fr); env = EXTEND_ENV(fr, env); return cons2(IM_LET_SYNTAX, env, m_body(body, env, ctxt)); } static char s_letrec_syntax[] = "letrec-syntax"; SCM m_letrec_syntax(xorig, env, ctxt) SCM xorig, env, ctxt; { SCM proc, vars, vals, inits, fr; SCM body = m_parse_let(EOL, xorig, CDR(xorig), &vars, &inits); /* if (IMP(vars)) return m_let_null(body, env, ctxt); */ for (fr = EOL; NIMP(vars); vars = CDR(vars)) fr = acons(CAR(vars), UNDEFINED, fr); fr = cons(SCM_ENV_SYNTAX, fr); env = EXTEND_ENV(fr, env); for (vals = EOL; NIMP(inits); inits = CDR(inits)) { proc = scm_eval_syntax(CAR(inits), env); ASSYNT(NIMP(proc) && MACROP(proc), CAR(inits), s_expr, s_letrec_syntax); vals = cons(proc, vals); } for (fr = CDR(fr); NIMP(fr); fr = CDR(fr)) { CDR(CAR(fr)) = CAR(vals); vals = CDR(vals); } return cons2(IM_LET_SYNTAX, env, m_body(body, env, ctxt)); } static char s_the_macro[] = "the-macro"; SCM m_the_macro(xorig, env, ctxt) SCM xorig, env, ctxt; { SCM addr, x = CDR(xorig); ASSYNT(1==ilength(x), xorig, s_expression, s_the_macro); x = CAR(x); ASSYNT(NIMP(x) && IDENTP(x), x, s_expression, s_the_macro); addr = scm_env_lookup(x, env); /* Require global ref for now. */ ASSYNT(NIMP(addr) && SYMBOLP(addr), x, s_expression, s_the_macro); x = CDR(sym2vcell(addr)); ASSYNT(KEYWORDP(x), xorig, ARG1, s_the_macro); return KEYWORD_MACRO(x); } #endif static iproc subr1s[] = { {"@copy-tree", copytree}, /* {s_eval, eval}, now a (tail recursive) specfun */ {s_force, force}, {s_proc_doc, l_proc_doc}, {s_makacro, makacro}, {s_makmacro, makmacro}, {s_makmmacro, makmmacro}, {s_makidmacro, makidmacro}, {"apply:nconc-to-last", nconc2copy}, /* {s_env2tree, env2tree}, */ #ifdef MACRO {s_identp, identp}, {s_ident2sym, ident2sym}, #endif {0, 0}}; static iproc subr2s[] = { #ifdef MACRO {s_macroexpand1, scm_macroexpand1}, {s_eval_syntax, scm_eval_syntax}, #endif {0, 0}}; static iproc lsubr2s[] = { /* {s_apply, apply}, now explicity initted */ {s_map, map}, {s_for_each, for_each}, {0, 0}}; static iproc subr3s[] = { #ifdef MACRO {s_ident_eqp, ident_eqp}, #endif {0, 0}}; static smobfuns promsmob = {markcdr, free0, prinprom}; static smobfuns macrosmob = {markcdr, free0, prinmacro}; static smobfuns envsmob = {markcdr, free0, prinenv}; #ifdef MACRO static smobfuns idsmob = {markcdr, free0, prinid}; #endif SCM make_synt(name, flags, fcn) const char *name; long flags; SCM (*fcn)(); { SCM symcell = sysintern(name, UNDEFINED); SCM z = makro(scm_maksubr(name, tc7_subr_3, fcn), flags | MAC_PRIMITIVE, "make_synt"); #ifdef MACRO z = cons(IM_KEYWORD, z); #endif CDR(symcell) = z; return CAR(symcell); } SCM make_specfun(name, typ, flags) char *name; int typ, flags; { SCM symcell = sysintern(name, UNDEFINED); register SCM z; NEWCELL(z); CAR(z) = (long)typ | ((long)flags)<<16; CDR(z) = CAR(symcell); CDR(symcell) = z; return z; } void init_eval() { scm_env = EOL; scm_env_tmp = UNSPECIFIED; #ifndef RECKLESS scm_trace = BOOL_F; scm_trace_env = EOL; #endif tc16_promise = newsmob(&promsmob); tc16_macro = newsmob(¯osmob); tc16_env = newsmob(&envsmob); init_iprocs(subr1s, tc7_subr_1); init_iprocs(subr2s, tc7_subr_2); init_iprocs(lsubr2s, tc7_lsubr_2); init_iprocs(subr3s, tc7_subr_3); #ifdef SCM_PROFILE make_subr("scm:profile", tc7_subr_1o, scm_profile); #endif make_specfun(s_apply, tc16_apply, 0); make_specfun(s_call_cc, tc16_call_cc, 0); make_specfun(s_eval, tc16_eval, 0); make_specfun(s_values, tc16_values, 0); make_specfun(s_call_wv, tc16_call_wv, 0); add_feature(s_values); i_dot = CAR(sysintern(".", UNDEFINED)); i_arrow = CAR(sysintern("=>", UNDEFINED)); i_else = CAR(sysintern("else", UNDEFINED)); i_unquote = CAR(sysintern("unquote", UNDEFINED)); i_uq_splicing = CAR(sysintern("unquote-splicing", UNDEFINED)); i_quasiquote = make_synt(s_quasiquote, MAC_MMACRO, m_quasiquote); i_define = make_synt(s_define, MAC_MMACRO, m_define); make_synt(s_delay, MAC_MMACRO, m_delay); i_bind = CAR(sysintern("bind", UNDEFINED)); i_anon = CAR(sysintern("", UNDEFINED)); i_side_effect = CAR(sysintern("side-effect", UNDEFINED)); i_test = CAR(sysintern("test", UNDEFINED)); i_procedure = CAR(sysintern("procedure", UNDEFINED)); i_argument = CAR(sysintern("argument", UNDEFINED)); i_check_defines = CAR(sysintern("check-defines", UNDEFINED)); loc_atcase_aux = &CDR(sysintern("@case-aux", UNDEFINED)); /* acros */ make_synt(s_definedp, MAC_ACRO, definedp); /* end of acros */ make_synt(s_and, MAC_MMACRO, m_and); i_begin = make_synt(s_begin, MAC_MMACRO, m_begin); make_synt(s_case, MAC_MMACRO, m_case); make_synt(s_cond, MAC_MMACRO, m_cond); make_synt(s_do, MAC_MMACRO, m_do); make_synt(s_if, MAC_MMACRO, m_if); i_lambda = make_synt(s_lambda, MAC_MMACRO, m_lambda); i_let = make_synt(s_let, MAC_MMACRO, m_let); make_synt(s_letrec, MAC_MMACRO, m_letrec); make_synt(s_letstar, MAC_MMACRO, m_letstar); make_synt(s_or, MAC_MMACRO, m_or); i_quote = make_synt(s_quote, MAC_MMACRO, m_quote); make_synt(s_set, MAC_MMACRO, m_set); make_synt(s_atapply, MAC_MMACRO, m_apply); /* make_synt(s_atcall_cc, MAC_MMACRO, m_cont); */ #ifdef MAC_INLINE make_synt("@inline-lambda", MAC_MMACRO, m_inline_lambda); #endif #ifdef MACRO tc16_ident = newsmob(&idsmob); make_subr(s_renamed_ident, tc7_subr_2, renamed_ident); make_synt(s_syn_quote, MAC_MMACRO, m_syn_quote); make_synt(s_defsyntax, MAC_MMACRO, m_defsyntax); make_synt(s_let_syntax, MAC_MMACRO, m_let_syntax); make_synt(s_letrec_syntax, MAC_MMACRO, m_letrec_syntax); make_synt(s_the_macro, MAC_ACRO, m_the_macro); add_feature("primitive-hygiene"); #endif f_begin = CDR(CDR(KEYWORD_MACRO(sym2vcell(i_begin)))); f_define = CDR(CDR(KEYWORD_MACRO(sym2vcell(i_define)))); list_unspecified = cons(UNSPECIFIED, EOL); f_evapply = cons(IM_EVAL_FOR_APPLY, EOL); #ifdef SCM_ENV_FILENAME eval_env = scm_env_addprop(SCM_ENV_FILENAME, CAR(sysintern("eval", UNDEFINED)), EOL); #else eval_env = EOL; #endif f_apply_closure = scm_evstr("(let ((ap apply)) (lambda (p . a) (ap p a)))"); } scm-5e5/scm.doc0000644001705200017500000002346310647033027011315 0ustar tbtbSCM(April 2006) SCM(April 2006) NAME scm - a Scheme Language Interpreter SYNOPSIS scm [-a kbytes ] [-muvqib] [--version] [--help] [[-]-no-init-file] [--no-symbol-case-fold] [-p int ] [-r feature ] [-h feature ] [-d filename ] [-f filename ] [-l filename ] [-c expression ] [-e expression ] [-o dumpname ] [-- | - | -s] [ filename ] [ arguments ... ] DESCRIPTION Scm is a Scheme interpreter. Upon startup scm loads the file specified by by the environment vari- able SCM_INIT_PATH or by the parameter IMPLINIT in the makefile (or scmfig.h) if SCM_INIT_PATH is not defined. The makefiles attempt to set IMPLINIT to "Init.scm" in the source directory. Unless the option -no-init-file or --no-init-file occurs in the command line or if scm is being invoked as a script, "Init.scm" checks to see if there is file "ScmInit.scm" in the path specified by the environment variable HOME (or in the current directory if HOME is undefined). If it finds such a file, then it is loaded. "Init.scm" then looks for command input from one of three sources: From an option on the command line, from a file named on the command line, or from standard input. OPTIONS The options are processed in the order specified on the command line. -akbytes specifies that scm should allocate an initial heapsize of kbytes. This option, if present, must be the first on the command line. --no-init-file Inhibits the loading of "ScmInit.scm" as described above. --no-symbol-case-fold Symbol (and identifier) names are case-sensitive. -eexpression -cexpression specifies that the scheme expression expression is to be evalu- ated. These options are inspired by perl and sh respectively. On Amiga systems the entire option and argument need to be enclosed in quotes. For instance "-e(newline)". -rfeature requires feature. This will load a file from SLIB if that feature is not already supported. If feature is 2, 3, 4, or 5 scm will require the features necessary to support R2RS, R3RS, R4RS, or R5RS, respectively. -hfeature provides feature. -lfilename -ffilename loads filename. Scm will load the first (unoptioned) file named on the command line if no -c, -e, -f, -l, or -s option precedes it. -dfilename opens (read-only) the extended relational database filename. If filename contains initialization code, it will be run when the database is opened. -odumpname saves the current SCM session as the executable program dumpname. This option works only in SCM builds supporting dump. If options appear on the command line after -o dumpname, then the saved session will continue with processing those options when it is invoked. Otherwise the (new) command line is processed as usual when the saved image is invoked. -plevel sets the prolixity (verboseness) to level. This is the same as the scm command (verbose level ). -v (verbose mode) specifies that scm will print prompts, evaluation times, notice of loading files, and garbage collection statistics. This is the same as -p3. -q (quiet mode) specifies that scm will print no extra information. This is the same as -p0. -m specifies that subsequent loads, evaluations, and user interac- tions will be with R4RS macro capability. To use a specific R4RS macro implementation from SLIB (instead of SLIB’s default) put -r macropackage before -m on the command line. -u specifies that subsequent loads, evaluations, and user interac- tions will be without R4RS macro capability. R4RS macro capabil- ity can be restored by a subsequent -m on the command line or from Scheme code. -i specifies that scm should run interactively. That means that scm will not terminate until the (quit) or (exit) command is given, even if there are errors. It also sets the prolixity level to 2 if it is less than 2. This will print prompts, evaluation times, and notice of loading files. The prolixity level can be set by subsequent options. If scm is started from a tty, it will assume that it should be interactive unless given a subsequent -b option. -b specifies that scm should run non-interactively. That means that scm will terminate after processing the command line or if there are errors. -s specifies, by analogy with sh, that further options are to be treated as program arguments. - -- specifies that there are no more options on the command line. ENVIRONMENT VARIABLES SCM_INIT_PATH is the pathname where scm will look for its initialization code. The default is the file "Init.scm" in the source directory. SCHEME_LIBRARY_PATH is the SLIB Scheme library directory. HOME is the directory where "Init.scm" will look for the user initial- ization file "ScmInit.scm". SCHEME VARIABLES *argv* contains the list of arguments to the program. *argv* can change during argument processing. This list is suitable for use as an argument to SLIB getopt. *R4RS-macro* controls whether loading and interaction support R4RS macros. Define this in "ScmInit.scm" or files specified on the command line. This can be overridden by subsequent -m and -u options. *interactive* controls interactivity as explained for the -i and -b options. Define this in "ScmInit.scm" or files specified on the command line. This can be overridden by subsequent -i and -b options. EXAMPLES % scm foo.scm arg1 arg2 arg3 Load and execute the contents of foo.scm. Parameters arg1 arg2 and arg3 are stored in the global list *argv*. % scm -f foo.scm arg1 arg2 arg3 The same. % scm -s foo.scm arg1 arg2 Set *argv* to ("foo.scm" "arg1" "arg2") and enter interactive ses- sion. % scm -e ’(display (list-ref *argv* *optind*))’ bar Print ‘‘bar’’ % scm -rpretty-print -r format -i Load pretty-print and format and enter interactive mode. % scm -r5 Load dynamic-wind, values, and R4RS macros and enter interactive (with macros) mode. % scm -r5 -r4 Like above but rev4-optional-procedures are also loaded. FEATURES Runs under Amiga, Atari-ST, MacOS, MS-DOS, OS/2, NOS/VE, Unicos, VMS, Unix and similar systems. Support for ASCII and EBCDIC character sets. Conforms to Revised^5 Report on the Algorithmic Language Scheme and the IEEE P1178 specification. Support for SICP, R2RS, R3RS, and R4RS scheme code. Many Common Lisp functions: logand, logor, logxor, lognot, ash, log- count, integer-length, bit-extract, defmacro, macroexpand, macroex- pand1, gentemp, defvar, force-output, software-type, get-decoded-time, get-internal-run-time, get-internal-real-time, delete-file, rename- file, copy-tree, acons, and eval. Char-code-limit, most-positive-fixnum, most-negative-fixnum, and inter- nal-time-units-per-second constants. *Features* and *load-pathname* variables. Arrays and bit-vectors. String ports and software emulation ports. I/O extensions providing most of ANSI C and POSIX.1 facilities. User definable responses to interrupts and errors, Process-synchroniza- tion primitives, String regular expression matching, and the CURSES screen management package. Available add-on packages including an interactive debugger, database, X-window graphics, BGI graphics, Motif, and Open-Windows packages. A compiler (HOBBIT, available separately) and dynamic linking of com- piled modules. Setable levels of monitoring and timing information printed interac- tively (the ‘verbose’ function). Restart, quit, and exec. FILES scm.texi Texinfo documentation of scm enhancements, internal representa- tions, and how to extend or include scm in other programs. AUTHORS Aubrey Jaffer (jaffer @ alum.mit.edu) Radey Shouman (shouman @ ne.mediaone.net) BUGS SEE ALSO The SCM home-page: http://swissnet.ai.mit.edu/~jaffer/SCM.html The Scheme specifications for details on specific procedures (http://swissnet.ai.mit.edu/ftpdir/scheme-reports/) or IEEE Std 1178-1990, IEEE Standard for the Scheme Programming Language, Institute of Electrical and Electronic Engineers, Inc., New York, NY, 1991 Brian Harvey and Matthew Wright Simply Scheme: Introducing Computer Science_ MIT Press, 1994 ISBN 0-262-08226-8 R. Kent Dybvig, The Scheme Programming Language, Prentice-Hall Inc, Englewood Cliffs, New Jersey 07632, USA H. Abelson, G. J. Sussman, and J. Sussman, Structure and Interpretation of Computer Programs, The MIT Press, Cambridge, Massachusetts, USA 4th Berkeley Distribution SCM(April 2006) scm-5e5/x.c0000644001705200017500000022261410750223123010447 0ustar tbtb/* "x.c" SCM interface to Xlib. * Copyright (C) 1999 Free Software Foundation, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see * . */ /* Authors: Aubrey Jaffer (I have rewritten nearly all of it) and: * * Modified by Shigenobu Kimura (skimu@izanagi.phys.s.u-tokyo.ac.jp) * Author: Larry Campbell (campbell@world.std.com) * * Copyright 1992 by The Boston Software Works, Inc. * Permission to use for any purpose whatsoever granted, as long * as this copyright notice remains intact. Please send bug fixes * or enhancements to the above email address. * * Generic X and Xlib functions for scm. * These functions do not depend on any toolkit. */ #include #include #include #include /*#include */ /* For IntensityTbl */ #include #include #include #include "scm.h" /* These structs are mallocated for use in SMOBS. */ struct xs_Display { SCM after; int screen_count; Display *dpy; }; /* An array of struct xs_screen (following xs_Display) holds the root-windows and default colormaps. */ struct xs_screen { SCM root_window; SCM default_gcontext; SCM default_visual; SCM default_colormap; }; struct xs_Window { SCM display; int screen_number; Display *dpy; union { Window win; Pixmap pm; Drawable drbl; } p; }; struct xs_GContext { SCM display; int screen_number; Display *dpy; GC gc; SCM font; SCM tile; SCM stipple; SCM clipmask; }; struct xs_Cursor { SCM display; Cursor cursor; }; struct xs_Font { SCM display; Font font; SCM name; }; struct xs_Colormap { SCM display; Display *dpy; Colormap cm; }; /* These structs are for returning multiple values when processing procedure arguments. */ struct display_screen{ SCM display; Display *dpy; int screen_number; }; /* The cproto program fills x.h with ANSI-C prototypes of the functions in x.c. */ #include "x.h" /* Macros for accessing these structs */ #define DISPLAY(x) ((struct xs_Display *) CDR(x)) #define WINDOW(x) ((struct xs_Window *) CDR(x)) #define CURSOR(x) ((struct xs_Cursor *) CDR(x)) #define FONT(x) ((struct xs_Font *) CDR(x)) #define COLORMAP(x) ((struct xs_Colormap *) CDR(x)) #define GCONTEXT(x) ((struct xs_GContext *) CDR(x)) #define XDISPLAY(x) (DISPLAY(x)->dpy) #define XWINDOW(x) (WINDOW(x)->p.win) #define XWINDISPLAY(x) (WINDOW(x)->dpy) #define XCURSOR(x) (CURSOR(x)->cursor) #define XFONT(x) (FONT(x)->font) #define XGCONTEXT(x) (GCONTEXT(x)->gc) #define XCOLORMAP(x) (COLORMAP(x)->cm) #define XGCONDISPLAY(x) (GCONTEXT(x)->dpy) /* Notice that types XVisualInfo, XcmsCCC, and XEvent don't have struct wrappers. */ #define XVISUALINFO(x) ((XVisualInfo *) CDR(x)) #define XVISUAL(x) (XVISUALINFO(x)->visual) #define XCCC(x) ((XcmsCCC) CDR(x)) #define XEVENT(x) ((XEvent *) CDR(x)) /* Type predicates */ #define DISPLAYP(x) (TYP16(x)==tc16_xdisplay) #define OPDISPLAYP(x) (((0xffff | OPN) & (int)CAR(x))==(tc16_xdisplay | OPN)) #define WINDOWP(x) (TYP16(x)==tc16_xwindow) #define OPWINDOWP(x) (((0xffff | OPN) & (int)CAR(x))==(tc16_xwindow | OPN)) #define COLORMAPP(x) (TYP16(x)==tc16_xcolormap) #define GCONTEXTP(x) (TYP16(x)==tc16_xgcontext) #define CCCP(x) (TYP16(x)==tc16_xccc) #define CURSORP(x) (TYP16(x)==tc16_xcursor) #define FONTP(x) (TYP16(x)==tc16_xfont) #define VISUALP(x) (TYP16(x)==tc16_xvisual) #define XEVENTP(x) (TYP16(x)==tc16_xevent) /* Scheme Procedure Names */ static char s_x_open_display[] = "x:open-display"; static char s_x_close[] = "x:close"; static char s_x_display_debug[] = "x:display-debug"; static char s_x_default_screen[] = "x:default-screen"; static char s_x_root_window[] = "x:root-window"; static char s_x_default_gcontext[] = "x:default-gc"; static char s_x_default_visual[] = "x:default-visual"; static char s_x_default_colormap[] = "x:default-colormap"; static char s_x_default_ccc[] = "x:default-ccc"; /* static char s_x_ccc_screen_info[] = "x:ccc-screen-info"; */ static char s_x_create_window[] = "x:create-window"; static char s_x_window_set[] = "x:window-set!"; static char s_x_window_ref[] = "x:window-ref"; static char s_x_create_pixmap[] = "x:create-pixmap"; static char s_x_get_window_property[] = "x:get-window-property"; static char s_x_list_properties[] = "x:list-properties"; static char s_x_map_window[] = "x:map-window"; static char s_x_map_subwindows[] = "x:map-subwindows"; static char s_x_unmap_window[] = "x:unmap-window"; static char s_x_unmap_subwindows[] = "x:unmap-subwindows"; static char s_x_create_gc[] = "x:create-gc"; static char s_x_gc_set[] = "x:gc-set!"; static char s_x_gc_ref[] = "x:gc-ref"; static char s_x_copy_gc[] = "x:copy-gc-fields!"; static char s_x_create_cursor[] = "x:create-cursor"; static char s_x_load_font[] = "x:load-font"; static char s_x_protocol_version[] = "x:protocol-version"; static char s_x_vendor_release[] = "x:vendor-release"; static char s_x_server_vendor[] = "x:server-vendor"; static char s_x_next_event[] = "x:next-event"; static char s_x_peek_event[] = "x:peek-event"; static char s_x_events_queued[] = "x:events-queued"; static char s_x_q_length[] = "x:q-length"; static char s_x_pending[] = "x:pending"; static char s_x_screen_count[] = "x:screen-count"; static char s_x_screen_cells[] = "x:screen-cells"; static char s_x_screen_depths[] = "x:screen-depths"; static char s_x_screen_depth[] = "x:screen-depth"; static char s_x_screen_size[] = "x:screen-size"; static char s_x_screen_dimm[] = "x:screen-dimensions"; static char s_x_screen_white[] = "x:screen-white"; static char s_x_screen_black[] = "x:screen-black"; static char s_x_make_visual[] = "x:make-visual"; static char s_x_visual_class[] = "x:visual-class"; static char s_x_visual_geometry[] = "x:visual-geometry"; static char s_x_window_geometry[] = "x:window-geometry"; static char s_x_window_geometry_set[] = "x:window-geometry-set!"; static char s_x_create_colormap[] = "x:create-colormap"; static char s_x_recreate_colormap[] = "x:copy-colormap-and-free"; static char s_x_alloc_color_cells[] = "x:alloc-colormap-cells"; static char s_x_free_color_cells[] = "x:free-colormap-cells"; static char s_x_find_color[] = "x:colormap-find-color"; static char s_x_color_set[] = "x:colormap-set!"; static char s_x_color_ref[] = "x:colormap-ref"; static char s_x_install_colormap[] = "x:install-colormap"; /* static char s_x_colormap_basis[] = "x:colormap-basis"; */ /* static char s_x_colormap_limits[] = "x:colormap-limits"; */ static char s_x_clear_area[] = "x:clear-area"; static char s_x_fill_rectangle[] = "x:fill-rectangle"; /* static char s_x_copy_area[] = "x:copy-area"; */ static char s_x_draw_points[] = "x:draw-points"; static char s_x_draw_segments[] = "x:draw-segments"; static char s_x_draw_lines[] = "x:draw-lines"; static char s_x_fill_poly[] = "x:fill-polygon"; static char s_x_draw_string[] = "x:draw-string"; static char s_x_image_string[] = "x:image-string"; static char s_x_flush[] = "x:flush"; static char s_x_event_ref[] = "x:event-ref"; static char s_x_event_keysym[] = "x:event->keysym"; /* Type-name strings */ static char s_gc[] = "graphics-context"; #define s_display (&s_x_open_display[7]) #define s_window (&s_x_root_window[7]) #define s_cursor (&s_x_create_cursor[9]) #define s_font (&s_x_load_font[7]) #define s_colormap (&s_x_create_colormap[9]) #define s_visual (&s_x_make_visual[7]) /* Scheme (SMOB) types defined in this module */ long tc16_xdisplay; long tc16_xgcontext; long tc16_xcolormap; long tc16_xwindow; long tc16_xcursor; long tc16_xfont; long tc16_xvisual; long tc16_xevent; long tc16_xccc; XContext xtc_ccc, xtc_cmp; /* We use OPN (which is already defined and used for PTOB ports) to keep track of whether objects of types Display and Window are open. The type xs_Window includes screen root-windows and pixmaps. The SMOB (CAR) header bits SCROOT and PXMP keep track of which type of window the SMOB is. */ /* #define OPN (1L<<16) */ /* #define RDNG (2L<<16) */ /* #define WRTNG (4L<<16) */ #define SCROOT (8L<<16) #define PXMP (16L<<16) /* Utility routines for creating SCM-wrapped X structs and the SMOB routines for collecting them. */ SCM make_xwindow(display, screen_number, win, pxmp, rootp) SCM display; int screen_number; Drawable win; char pxmp, rootp; { SCM z; struct xs_Window *xsw; DEFER_INTS; z = must_malloc_cell((long)sizeof(struct xs_Window), (SCM)(tc16_xwindow | OPN | (pxmp ? PXMP : 0L) | (rootp ? SCROOT : 0L)), s_window); xsw = WINDOW(z); xsw->display = display; xsw->dpy = XDISPLAY(display); xsw->screen_number = screen_number; if (pxmp) xsw->p.pm = (Pixmap)win; else xsw->p.win = (Window)win; ALLOW_INTS; return z; } static SCM mark_xwindow(ptr) SCM ptr; { if (CLOSEDP(ptr)) return BOOL_F; return WINDOW(ptr)->display; } static sizet free_xwindow(ptr) CELLPTR ptr; { SCM td = CAR((SCM)ptr); if (!(td & OPN)) return 0; if (!(td & SCROOT)) { struct xs_Window *xsw = WINDOW((SCM)ptr); SCM sd = xsw->display; if (NIMP(sd) && OPDISPLAYP(sd)) { if (td & PXMP) XFreePixmap(xsw->dpy, xsw->p.pm); else XDestroyWindow(xsw->dpy, xsw->p.win); } } must_free((char *)CDR((SCM)ptr), sizeof(struct xs_Window)); CAR((SCM)ptr) = td & ~OPN; return sizeof(struct xs_Window); } SCM make_xcolormap(sdpy, cmp) SCM sdpy; Colormap cmp; { SCM z; struct xs_Colormap *xcm; XPointer scmptr; if (!XFindContext(XDISPLAY(sdpy), (XID)cmp, xtc_cmp, &scmptr)) return (SCM)scmptr; DEFER_INTS; z = must_malloc_cell((long)sizeof(struct xs_Colormap), (SCM)tc16_xcolormap, s_colormap); xcm = COLORMAP(z); xcm->display = sdpy; xcm->dpy = DISPLAY(xcm->display)->dpy; xcm->cm = cmp; XSaveContext(XDISPLAY(sdpy), (XID)cmp, xtc_cmp, z); ALLOW_INTS; return z; } static SCM mark_xcolormap(ptr) SCM ptr; { struct xs_Colormap *xcm; if (CLOSEDP(ptr)) return BOOL_F; xcm = COLORMAP(ptr); gc_mark(CCC2SCM_P(XcmsCCCOfColormap(xcm->dpy, xcm->cm))); return xcm->display; } static sizet free_xcolormap(ptr) CELLPTR ptr; { struct xs_Colormap *xcmp = COLORMAP((SCM)ptr); SCM sdpy = xcmp->display; if (NIMP(sdpy) && OPDISPLAYP(sdpy)) XFreeColormap(xcmp->dpy, xcmp->cm); must_free((char *)CDR((SCM)ptr), sizeof(struct xs_Colormap)); return sizeof(struct xs_Colormap); } SCM make_xdisplay(d) Display *d; { SCM z; struct xs_screen *scrns; struct xs_Display *xsd; int idx = ScreenCount(d); DEFER_INTS; z = must_malloc_cell((long)sizeof(struct xs_Display) + idx * sizeof(struct xs_screen), (SCM)tc16_xdisplay | OPN, s_display); xsd = DISPLAY(z); xsd->after = BOOL_F; xsd->screen_count = idx; xsd->dpy = d; scrns = (struct xs_screen *)(xsd + 1); while (idx--) { scrns[idx].root_window = BOOL_F; scrns[idx].default_gcontext = BOOL_F; scrns[idx].default_visual = BOOL_F; scrns[idx].default_colormap = BOOL_F; } ALLOW_INTS; idx = xsd->screen_count; while (idx--) { scrns[idx].root_window = make_xwindow(z, idx, RootWindow(d, idx), (char) 0, (char) 1); scrns[idx].default_gcontext = make_xgcontext(z, idx, XDefaultGC(d, idx), !0); scrns[idx].default_visual = make_xvisual(visual2visualinfo(d, DefaultVisual(d, idx))); scrns[idx].default_colormap = make_xcolormap(z, DefaultColormap(d, idx)); } return z; } static SCM mark_xdisplay(ptr) SCM ptr; { if (CLOSEDP(ptr)) return BOOL_F; { struct xs_Display *xsd = DISPLAY((SCM)ptr); struct xs_screen *scrns = (struct xs_screen *)(xsd + 1); int idx = xsd->screen_count; while (--idx) { SCM scmp = scrns[idx].default_colormap; gc_mark(scrns[idx].root_window); gc_mark(scrns[idx].default_gcontext); gc_mark(scrns[idx].default_visual); gc_mark(scmp); gc_mark (CCC2SCM_P(XcmsCCCOfColormap(xsd->dpy, XCOLORMAP(scmp)))); } gc_mark(scrns[idx].root_window); gc_mark(scrns[idx].default_gcontext); gc_mark(scrns[idx].default_visual); return scrns[idx].default_colormap; } } static sizet free_xdisplay(ptr) CELLPTR ptr; { SCM td = CAR((SCM)ptr); if (!(td & OPN)) return 0; { struct xs_Display *xsd = DISPLAY((SCM)ptr); sizet len = sizeof(struct xs_Display) + xsd->screen_count * sizeof(struct xs_screen); XCloseDisplay(xsd->dpy); must_free((char *)xsd, len); CAR((SCM)ptr) = td & ~OPN; return len; } } SCM make_xgcontext(d, screen_number, gc, rootp) SCM d; int screen_number; GC gc; int rootp; { SCM z; struct xs_GContext *xgc; DEFER_INTS; z = must_malloc_cell((long)sizeof(struct xs_GContext), (SCM)tc16_xgcontext | (rootp ? SCROOT : 0L), s_gc); xgc = GCONTEXT(z); xgc->display = d; xgc->screen_number = screen_number; xgc->dpy = XDISPLAY(d); xgc->gc = gc; xgc->font = BOOL_F; xgc->tile = BOOL_F; xgc->stipple = BOOL_F; xgc->clipmask = BOOL_F; ALLOW_INTS; return z; } static SCM mark_xgcontext(ptr) SCM ptr; { struct xs_GContext *xgc = GCONTEXT(ptr); gc_mark(xgc->font); gc_mark(xgc->tile); gc_mark(xgc->stipple); gc_mark(xgc->clipmask); return xgc->display; } static sizet free_xgcontext(ptr) CELLPTR ptr; { SCM td = CAR((SCM)ptr); if (!(td & OPN)) return 0; if (!(td & SCROOT)) { struct xs_GContext *xgc = GCONTEXT((SCM)ptr); SCM sd = xgc->display; if (NIMP(sd) && OPDISPLAYP(sd)) XFreeGC(xgc->dpy, xgc->gc); } must_free((char *)CDR((SCM)ptr), sizeof(struct xs_GContext)); return sizeof(struct xs_GContext); } SCM make_xcursor(display, cursor) SCM display; Cursor cursor; { SCM z; struct xs_Cursor *xcsr; DEFER_INTS; z = must_malloc_cell((long)sizeof(struct xs_Cursor), (SCM)tc16_xcursor, s_cursor); xcsr = CURSOR(z); xcsr->display = display; xcsr->cursor = cursor; ALLOW_INTS; return z; } static SCM mark_xcursor(ptr) SCM ptr; { if (CLOSEDP(ptr)) return BOOL_F; return CURSOR(ptr)->display; } static sizet free_xcursor(ptr) CELLPTR ptr; { struct xs_Cursor *xcsr = CURSOR((SCM)ptr); SCM sdpy = xcsr->display; if (NIMP(sdpy) && OPDISPLAYP(sdpy)) { struct xs_Display *xdp = DISPLAY(sdpy); XFreeCursor(xdp->dpy, xcsr->cursor); } must_free((char *)CDR((SCM)ptr), sizeof(struct xs_Cursor)); return sizeof(struct xs_Cursor); } SCM make_xfont(display, font, name) SCM display; Font font; SCM name; { SCM z; struct xs_Font *xfnt; DEFER_INTS; z = must_malloc_cell((long)sizeof(struct xs_Font), (SCM)tc16_xfont, s_font); xfnt = FONT(z); xfnt->display = display; xfnt->font = font; xfnt->name = name; ALLOW_INTS; return z; } static SCM mark_xfont(ptr) SCM ptr; { struct xs_Font *xfn = FONT(ptr); gc_mark(xfn->name); return xfn->display; } static sizet free_xfont(ptr) CELLPTR ptr; { struct xs_Font *xfnt = FONT((SCM)ptr); SCM sdpy = xfnt->display; if (NIMP(sdpy) && OPDISPLAYP(sdpy)) { struct xs_Display *xdp = DISPLAY(sdpy); XUnloadFont(xdp->dpy, xfnt->font); } must_free((char *)CDR((SCM)ptr), sizeof(struct xs_Font)); return sizeof(struct xs_Font); } SCM make_xvisual(vsl) XVisualInfo *vsl; { SCM s_vsl; NEWCELL(s_vsl); DEFER_INTS; CAR(s_vsl) = tc16_xvisual; SETCDR(s_vsl, vsl); ALLOW_INTS; return s_vsl; } SCM CCC2SCM_P(ccc) XcmsCCC ccc; { XPointer scmptr; if (XFindContext(ccc->dpy, (XID)ccc, xtc_ccc, &scmptr)) return BOOL_F; return (SCM)scmptr; } SCM CCC2SCM(ccc) XcmsCCC ccc; { SCM s_ccc = CCC2SCM_P(ccc); if (FALSEP(s_ccc)) { NEWCELL(s_ccc); DEFER_INTS; CAR(s_ccc) = tc16_xccc; SETCDR(s_ccc, ccc); XSaveContext(ccc->dpy, (XID)ccc, xtc_ccc, s_ccc); ALLOW_INTS; } return s_ccc; } static sizet free_xccc(ptr) CELLPTR ptr; { XcmsCCC ccc = XCCC((SCM)ptr); XDeleteContext(ccc->dpy, (XID)ccc, xtc_ccc); XcmsFreeCCC(ccc); return 0; } SCM make_xevent(e) XEvent *e; { SCM w; XEvent *ec; ec = (XEvent *) must_malloc(sizeof(XEvent), "X event"); (void)memcpy(ec, e, sizeof(XEvent)); NEWCELL(w); DEFER_INTS; CAR(w) = tc16_xevent; SETCDR(w, ec); ALLOW_INTS; return w; } sizet x_free_xevent(ptr) CELLPTR ptr; { must_free(CHARS(ptr), sizeof(XEvent)); return sizeof(XEvent); } /* Utility macro and functions for checking and coercing SCM arguments. */ #define GET_NEXT_INT(result, args, err, rtn) \ ASRTER(NIMP(args) && CONSP(args) && INUMP(CAR(args)), args, err, rtn); \ result = INUM(CAR(args)); \ args = CDR(args); void scm2XPoint(signp, dat, ipr, pos, s_caller) int signp; SCM dat; XPoint *ipr; char *pos, *s_caller; { SCM x, y; if (IMP(dat)) badarg: wta(dat, pos, s_caller); if (CONSP(dat)) { if (INUMP(CDR(dat))) { x = CAR(dat); y = CDR(dat); } else { ASRTGO(2==ilength(dat), badarg); x = CAR(dat); y = CAR(CDR(dat)); } } else switch TYP7(dat) { default: goto badarg; case tc7_vector: ASRTGO(2==LENGTH(dat), badarg); x = VELTS(dat)[0]; y = VELTS(dat)[1]; break; case tc7_VfixN32: case tc7_VfixZ32: ASRTGO(2==LENGTH(dat), badarg); x = MAKINUM(((long *)VELTS(dat))[0]); y = MAKINUM(((long *)VELTS(dat))[1]); break; case tc7_VfixZ16: ASRTGO(2==LENGTH(dat), badarg); x = MAKINUM(((short *)VELTS(dat))[0]); y = MAKINUM(((short *)VELTS(dat))[1]); break; case tc7_smob: ASRTGO(ARRAYP(dat) && 1==ARRAY_NDIM(dat) && 0==ARRAY_DIMS(dat)[0].lbnd && 1==ARRAY_DIMS(dat)[0].ubnd, badarg); x = aref(dat, MAKINUM(0)); y = aref(dat, MAKINUM(1)); break; } ASRTGO(INUMP(x) && INUMP(y), badarg); ipr->x = INUM(x); ipr->y = INUM(y); ASRTGO((ipr->x==INUM(x)) && (ipr->y==INUM(y)) && (signp ? !0 : ((x >= 0) && (y >= 0))), badarg); } int scm2XColor(s_dat, xclr) SCM s_dat; XColor *xclr; { SCM dat = s_dat; unsigned int ura[3]; int idx; /* if (INUMP(dat)) { */ /* xclr->red = (dat>>16 & 0x00ff) * 0x0101; */ /* xclr->green = (dat>>8 & 0x00ff) * 0x0101; */ /* xclr->blue = (dat & 0x00ff) * 0x0101; */ /* } */ /* else */ if (IMP(dat)) return 0; else if (3==ilength(dat)) for (idx = 0; idx < 3; idx++) { SCM clr = CAR(dat); if (!INUMP(clr)) return 0; ura[idx] = INUM(clr); dat = CDR(dat); } else if (VECTORP(dat) && (3==LENGTH(dat))) for (idx = 0; idx < 3; idx++) { if (!INUMP(VELTS(dat)[idx])) return 0; ura[idx] = INUM(VELTS(dat)[idx]); } else return 0; xclr->red = ura[0]; xclr->green = ura[1]; xclr->blue = ura[2]; return !0; } int scm2xpointslen(sara, s_caller) SCM sara; char *s_caller; { array_dim *adm; int len; if (!(NIMP(sara) && ARRAYP(sara) && 2==ARRAY_NDIM(sara))) return -1; adm = ARRAY_DIMS(sara); if (!((1==(adm[1].ubnd - adm[1].lbnd)) && (1==adm[1].inc) && ARRAY_CONTP(sara) && (tc7_VfixZ16==TYP7(ARRAY_V(sara))))) return -1; len = 1 + adm[0].ubnd - adm[0].lbnd; if (len < 0) return 0; return len; } void scm2display_screen(dat, optidx, dspscn, s_caller) SCM dat; SCM optidx; struct display_screen *dspscn; char *s_caller; { ASRTGO(NIMP(dat), badarg); if (OPDISPLAYP(dat)) { dspscn->display = dat; dspscn->dpy = XDISPLAY(dat); if (UNBNDP(optidx)) dspscn->screen_number = DefaultScreen(dspscn->dpy); else if (INUMP(optidx) && (INUM(optidx) < DISPLAY(dat)->screen_count)) dspscn->screen_number = INUM(optidx); else wta(optidx, (char *)ARG2, s_caller); } else if (OPWINDOWP(dat)) { struct xs_Window *xsw = WINDOW(dat); dspscn->display = xsw->display; dspscn->dpy = xsw->dpy; dspscn->screen_number = xsw->screen_number; ASRTGO(UNBNDP(optidx), badarg); } else badarg: wta(dat, (char *)ARG1, s_caller); } #define OpPxmpMask (0xffff | OPN | PXMP) #define OpPxmp (tc16_xwindow | OPN | PXMP) SCM thevalue(obj) SCM obj; { if (NIMP(obj) && SYMBOLP(obj)) return ceval(obj, (SCM)EOL, (SCM)EOL); else return obj; } Pixmap thepxmap(obj, s_caller) SCM obj; char *s_caller; { if (FALSEP(obj) || (INUM0==obj)) return 0L; ASRTER(NIMP(obj) && ((OpPxmpMask & (int)CAR(obj))==OpPxmp), obj, ARGn, s_caller); return WINDOW(obj)->p.pm; } Font thefont(obj, s_caller) SCM obj; char *s_caller; { ASRTER(NIMP(obj) && FONTP(obj), obj, ARGn, s_caller); return FONT(obj)->font; } Colormap thecmap(obj, s_caller) SCM obj; char *s_caller; { if (FALSEP(obj) || (INUM0==obj)) return 0L; ASRTER(NIMP(obj) && COLORMAPP(obj), obj, ARGn, s_caller); return COLORMAP(obj)->cm; } Cursor thecsr(obj, s_caller) SCM obj; char *s_caller; { if (FALSEP(obj) || (INUM0==obj)) return 0L; ASRTER(NIMP(obj) && CURSORP(obj), obj, ARGn, s_caller); return CURSOR(obj)->cursor; } Bool thebool(obj, s_caller) SCM obj; char *s_caller; { SCM val = thevalue(obj); ASRTER(BOOL_F==val || BOOL_T==val, obj, ARGn, s_caller); return NFALSEP(val); } int theint(obj, s_caller) SCM obj; char *s_caller; { SCM val = thevalue(obj); ASRTER(INUMP(val), obj, ARGn, s_caller); return INUM(val); } int theuint(obj, s_caller) SCM obj; char *s_caller; { SCM val = thevalue(obj); ASRTER(INUMP(val) && (0 <= INUM(val)), obj, ARGn, s_caller); return INUM(val); } static int args2valmask(oargs, s_caller) SCM oargs; char *s_caller; { SCM args = oargs; int attr, len, attr_mask = 0; if (!(len = ilength(args))) return 0; while (len) { ASRTER(NIMP(args), oargs, WNA, s_caller); attr = theint(CAR(args), s_caller); args = CDR(args); attr_mask |= attr; len -= 1; } return attr_mask; } static int args2xgcvalues(sgc, vlu, oargs) SCM sgc; XGCValues *vlu; SCM oargs; { struct xs_GContext *xgc = GCONTEXT(sgc); SCM sval, args = oargs; int attr, len, attr_mask = 0; /* (void)memset((char *)vlu, 0, sizeof(XGCValues)); */ if (!(len = ilength(args))) return 0; ASRTER(len > 0 && (! (len & 1)), oargs, WNA, s_gc); while (len) { ASRTER(NIMP(args), oargs, WNA, s_gc); attr = theint(CAR(args), s_gc); args = CDR(args); ASRTER(NIMP(args), oargs, WNA, s_gc); sval = CAR(args); args = CDR(args); attr_mask |= attr; switch (attr) { case GCFunction: vlu->function = theint(sval, s_gc); break; case GCPlaneMask: vlu->plane_mask = theuint(sval, s_gc); break; case GCForeground: vlu->foreground = theuint(sval, s_gc); break; case GCBackground: vlu->background = theuint(sval, s_gc); break; case GCLineWidth: vlu->line_width = theint(sval, s_gc); break; case GCLineStyle: vlu->line_style = theint(sval, s_gc); break; case GCCapStyle: vlu->cap_style = theint(sval, s_gc); break; case GCJoinStyle: vlu->join_style = theint(sval, s_gc); break; case GCFillStyle: vlu->fill_style = theint(sval, s_gc); break; case GCFillRule: vlu->fill_rule = theint(sval, s_gc); break; case GCTile: vlu->tile = thepxmap(sval, s_gc); xgc->tile = sval; break; case GCStipple: vlu->stipple = thepxmap(sval, s_gc); xgc->stipple = sval; break; case GCTileStipXOrigin: vlu->ts_x_origin = theint(sval, s_gc); break; case GCTileStipYOrigin: vlu->ts_y_origin = theint(sval, s_gc); break; case (GCTileStipXOrigin | GCTileStipYOrigin): { XPoint position; scm2XPoint(!0, sval, &position, (char *)ARGn, s_gc); vlu->ts_x_origin = position.x; vlu->ts_y_origin = position.y; } break; case GCFont: vlu->font = thefont(sval, s_gc); xgc->font = sval; break; case GCSubwindowMode: vlu->subwindow_mode = theint(sval, s_gc); break; case GCGraphicsExposures: vlu->graphics_exposures = thebool(sval, s_gc); break; case GCClipXOrigin: vlu->clip_x_origin = theint(sval, s_gc); break; case GCClipYOrigin: vlu->clip_y_origin = theint(sval, s_gc); break; case (GCClipXOrigin | GCClipYOrigin): { XPoint position; scm2XPoint(!0, sval, &position, (char *)ARGn, s_gc); vlu->clip_x_origin = position.x; vlu->clip_y_origin = position.y; } break; case GCClipMask: vlu->clip_mask = thepxmap(sval, s_gc); xgc->clipmask = sval; break; case GCDashOffset: vlu->dash_offset = theint(sval, s_gc); break; case GCDashList: vlu->dashes = (char)theint(sval, s_gc); break; case GCArcMode: vlu->arc_mode = theint(sval, s_gc); break; default: ASRTER(0, MAKINUM(attr), ARGn, s_gc); } len -= 2; } return attr_mask; } static int args2winattribs(vlu, oargs) XSetWindowAttributes *vlu; SCM oargs; { SCM sval, args = oargs; int attr, len, attr_mask = 0; /* (void)memset((char *)vlu, 0, sizeof(XSetWindowAttributes)); */ if (!(len = ilength(args))) return 0; ASRTER(len > 0 && (! (len & 1)), oargs, WNA, s_window); while (len) { ASRTER(NIMP(args), oargs, WNA, s_window); attr = theint(CAR(args), s_window); args = CDR(args); ASRTER(NIMP(args), oargs, WNA, s_window); sval = CAR(args); args = CDR(args); attr_mask |= attr; switch (attr) { case CWBackPixmap: vlu->background_pixmap=thepxmap(sval, s_window); break; case CWBackPixel: vlu->background_pixel = theuint(sval, s_window); break; case CWBorderPixmap:vlu->border_pixmap =thepxmap(sval, s_window); break; case CWBorderPixel: vlu->border_pixel = theuint(sval, s_window); break; case CWBitGravity: vlu->bit_gravity = theint(sval, s_window); break; case CWWinGravity: vlu->win_gravity = theint(sval, s_window); break; case CWBackingStore:vlu->backing_store = theint(sval, s_window); break; case CWBackingPlanes:vlu->backing_planes = theuint(sval, s_window); break; case CWBackingPixel:vlu->backing_pixel = theuint(sval, s_window); break; case CWOverrideRedirect:vlu->override_redirect = thebool(sval, s_window); break; case CWSaveUnder: vlu->save_under = thebool(sval, s_window); break; case CWEventMask: vlu->event_mask = theint(sval, s_window); break; case CWDontPropagate:vlu->do_not_propagate_mask = thebool(sval, s_window); break; case CWColormap: vlu->colormap = thecmap(sval, s_window); break; case CWCursor: vlu->cursor = thecsr(sval, s_window); break; default: ASRTER(0, MAKINUM(attr), ARGn, s_window); } len -= 2; } return attr_mask; } static int args2wincfgs(vlu, oargs) XWindowChanges *vlu; SCM oargs; { SCM sval, args = oargs; int cfgs, len, cfgs_mask = 0; /* (void)memset((char *)vlu, 0, sizeof(XWindowChanges)); */ if (!(len = ilength(args))) return 0; ASRTER(len > 0 && (! (len & 1)), oargs, WNA, s_window); while (len) { ASRTER(NIMP(args), oargs, WNA, s_window); cfgs = theint(CAR(args), s_window); args = CDR(args); ASRTER(NIMP(args), oargs, WNA, s_window); sval = CAR(args); args = CDR(args); cfgs_mask |= cfgs; switch (cfgs) { case CWX: vlu->x = theuint(sval, s_window); break; case CWY: vlu->y = theuint(sval, s_window); break; case CWWidth: vlu->width = theuint(sval, s_window); break; case CWHeight: vlu->height = theuint(sval, s_window); break; case CWBorderWidth: vlu->border_width = theuint(sval, s_window); break; case CWSibling: vlu->sibling =thepxmap(sval, s_window); break; case CWStackMode: vlu->stack_mode = theint(sval, s_window); break; default: ASRTER(0, MAKINUM(cfgs), ARGn, s_window); } len -= 2; } return cfgs_mask; } /* Scheme-visible procedures */ SCM x_open_display(dpy_name) SCM dpy_name; { Display *display; if (FALSEP(dpy_name)) dpy_name = nullstr; ASRTER(NIMP(dpy_name) && STRINGP(dpy_name), dpy_name, ARG1, s_x_open_display); display = XOpenDisplay(CHARS(dpy_name)); return (display ? make_xdisplay(display) : BOOL_F); } SCM x_display_debug(sd, si) SCM sd, si; { int (*previous_after_function)(); struct display_screen dspscn; scm2display_screen(sd, UNDEFINED, &dspscn, s_x_display_debug); previous_after_function = XSynchronize(dspscn.dpy, thebool(si, s_x_display_debug)); return UNSPECIFIED; } SCM x_default_screen(sdpy) SCM sdpy; { ASRTER(NIMP(sdpy) && OPDISPLAYP(sdpy), sdpy, ARG1, s_x_default_screen); return MAKINUM(DefaultScreen(XDISPLAY(sdpy))); } SCM x_create_window(swin, spos, sargs) SCM swin, spos, sargs; { XPoint position, size; unsigned int border_width; Window window; int len = ilength(sargs); ASRTER(NIMP(swin) && OPWINDOWP(swin), swin, ARG1, s_x_create_window); scm2XPoint(!0, spos, &position, (char *)ARG2, s_x_create_window); scm2XPoint(0, CAR(sargs), &size, (char *)ARG3, s_x_create_window); sargs = CDR(sargs); GET_NEXT_INT(border_width, sargs, ARG4, s_x_create_window); if (4==len) { unsigned long border; unsigned long background; GET_NEXT_INT(border, sargs, ARG5, s_x_create_window); GET_NEXT_INT(background, sargs, ARGn, s_x_create_window); window = XCreateSimpleWindow(XWINDISPLAY(swin), XWINDOW(swin), position.x, position.y, /* initial placement */ size.x, size.y, border_width, border, background); /* pixel values */ } else { int depth; unsigned int class; SCM svis; unsigned long valuemask; XSetWindowAttributes attributes; ASRTER(5 <= len, sargs, WNA, s_x_create_window); GET_NEXT_INT(depth, sargs, ARG5, s_x_create_window); GET_NEXT_INT(class, sargs, ARGn, s_x_create_window); svis = CAR(sargs); sargs = CDR(sargs); ASRTER(NIMP(svis) && VISUALP(svis), svis, ARGn, s_x_create_window); valuemask = args2winattribs(&attributes, sargs); window = XCreateWindow(XWINDISPLAY(swin), XWINDOW(swin), position.x, position.y, /* initial placement */ size.x, size.y, border_width, depth, class, XVISUAL(svis), valuemask, &attributes); } return window ? make_xwindow(WINDOW(swin)->display, WINDOW(swin)->screen_number, window, (char) 0, (char) 0) : BOOL_F; } SCM x_create_pixmap(obj, s_size, s_depth) SCM obj, s_size, s_depth; { unsigned int depth = INUM(s_depth); SCM display; Display *dpy; int scn; Drawable drawable; Pixmap p; XPoint size; if (IMP(obj)) badarg1: wta(obj, (char *)ARG1, s_x_create_pixmap); if (OPDISPLAYP(obj)) { display = obj; dpy = XDISPLAY(display); scn = DefaultScreen(dpy); drawable = RootWindow(dpy, scn); } else if (OPWINDOWP(obj)) { display = WINDOW(obj)->display; dpy = XDISPLAY(display); scn = WINDOW(obj)->screen_number; drawable = WINDOW(obj)->p.drbl; } else goto badarg1; scm2XPoint(0, s_size, &size, (char *)ARG2, s_x_create_pixmap); ASRTER(INUMP(s_depth) && depth >= 0, s_depth, ARG3, s_x_create_pixmap); p = XCreatePixmap(dpy, drawable, size.x, size.y, depth); return make_xwindow(display, scn, p, (char) 1, (char) 0); } SCM x_window_ref(oargs) SCM oargs; { SCM swn, args = oargs, sval = BOOL_F; SCM vals = cons(BOOL_T, EOL), valend = vals; struct xs_Window *xwn; XWindowAttributes vlu; int attr, len = ilength(args); /* (void)memset((char *)&vlu, 0, sizeof(XWindowAttributes)); */ ASRTER(len > 0, oargs, WNA, s_x_window_ref); if (1==len--) return EOL; swn = CAR(args); args = CDR(args); ASRTER(NIMP(swn) && WINDOWP(swn), swn, ARG1, s_x_window_ref); xwn = WINDOW(swn); if (!XGetWindowAttributes(xwn->dpy, xwn->p.win, &vlu)) return BOOL_F; while (len) { attr = theint(CAR(args), s_x_window_ref); args = CDR(args); switch (attr) { case CWBackPixel: sval = MAKINUM(vlu.backing_pixel); break; case CWBitGravity: sval = MAKINUM(vlu.bit_gravity); break; case CWWinGravity: sval = MAKINUM(vlu.win_gravity); break; case CWBackingStore: sval = MAKINUM(vlu.backing_store); break; case CWBackingPlanes:sval = MAKINUM(vlu.backing_planes); break; case CWBackingPixel: sval = MAKINUM(vlu.backing_pixel); break; case CWOverrideRedirect:sval = x_make_bool(vlu.override_redirect); break; case CWSaveUnder: sval = x_make_bool(vlu.save_under); break; case CWEventMask: sval = MAKINUM(vlu.your_event_mask); break; case CWDontPropagate:sval = MAKINUM(vlu.do_not_propagate_mask); break; case CWColormap: sval = make_xcolormap(xwn->display, vlu.colormap); break; default: ASRTER(0, MAKINUM(attr), ARGn, s_x_window_ref); } CAR(valend) = sval; CDR(valend) = cons(BOOL_T, EOL); len -= 1; if (len) valend = CDR(valend); else CDR(valend) = EOL; } return vals; } SCM x_window_set(args) SCM args; { SCM swn; struct xs_Window *xwn; XSetWindowAttributes vlu; unsigned long mask; ASRTER(NIMP(args), args, WNA, s_x_window_set); swn = CAR(args); args = CDR(args); ASRTER(NIMP(swn) && WINDOWP(swn), swn, ARG1, s_x_window_set); xwn = WINDOW(swn); mask = args2winattribs(&vlu, args); XChangeWindowAttributes(xwn->dpy, xwn->p.win, mask, &vlu); return UNSPECIFIED; } SCM x_window_geometry(swin) SCM swin; { struct xs_Window *sxw; Window root; Status sts; int x, y; unsigned int w, h, border_width, depth; ASRTER(NIMP(swin) && OPWINDOWP(swin), swin, ARG1, s_x_window_geometry); sxw = WINDOW(swin); sts = XGetGeometry(sxw->dpy, sxw->p.drbl, &root, &x, &y, &w, &h, &border_width, &depth); if (!sts) return BOOL_F; return cons2(cons2(MAKINUM(x), MAKINUM(y), EOL), cons2(MAKINUM(w), MAKINUM(h), EOL), cons2(MAKINUM(border_width), MAKINUM(depth), EOL)); } SCM x_window_geometry_set(args) SCM args; { SCM swn; struct xs_Window *xwn; XWindowChanges vlu; unsigned long mask; ASRTER(NIMP(args), args, WNA, s_x_window_geometry_set); swn = CAR(args); args = CDR(args); ASRTER(NIMP(swn) && WINDOWP(swn), swn, ARG1, s_x_window_geometry_set); xwn = WINDOW(swn); mask = args2wincfgs(&vlu, args); XConfigureWindow(xwn->dpy, xwn->p.win, mask, &vlu); return UNSPECIFIED; } SCM x_close(obj) SCM obj; { ASRTER(NIMP(obj), obj, ARG1, s_x_close); if (WINDOWP(obj)) { Display *dpy; ASRTER(!(CAR((SCM)obj) & SCROOT), obj, ARG1, s_x_close); if (CLOSEDP(obj)) return UNSPECIFIED; DEFER_INTS; dpy = XWINDISPLAY(obj); free_xwindow((CELLPTR)obj); XFlush(dpy); ALLOW_INTS; } else { ASRTER(DISPLAYP(obj), obj, ARG1, s_x_close); DEFER_INTS; free_xdisplay((CELLPTR)obj); ALLOW_INTS; } return UNSPECIFIED; } SCM x_flush(sd, si) SCM sd, si; { struct display_screen dspscn; if (NIMP(sd) && UNBNDP(si) && GCONTEXTP(sd)) { dspscn.dpy = XGCONDISPLAY(sd); XFlushGC(dspscn.dpy, XGCONTEXT(sd)); } else { scm2display_screen(sd, si, &dspscn, s_x_flush); XFlush(dspscn.dpy); } return UNSPECIFIED; } /* Colormaps */ SCM x_create_colormap(swin, s_vis, s_alloc) SCM swin, s_vis, s_alloc; { SCM alloc; int allo; struct xs_Window *sxw; ASRTER(NIMP(swin) && WINDOWP(swin), swin, ARG1, s_x_create_colormap); sxw = WINDOW(swin); ASRTER(NIMP(s_vis) && VISUALP(s_vis), s_vis, ARG2, s_x_create_colormap); alloc = thevalue(s_alloc); allo = INUM(alloc); ASRTER(INUMP(alloc) && (allo==AllocNone || allo==AllocAll), s_alloc, ARG3, s_x_create_colormap); return make_xcolormap(sxw->display, XCreateColormap(sxw->dpy, sxw->p.win, XVISUAL(s_vis), allo)); } SCM x_recreate_colormap(s_cm) SCM s_cm; { struct xs_Colormap *sxw; ASRTER(NIMP(s_cm) && COLORMAPP(s_cm), s_cm, ARG1, s_x_recreate_colormap); sxw = COLORMAP(s_cm); return make_xcolormap(sxw->display, XCopyColormapAndFree(XDISPLAY(sxw->display), sxw->cm)); } SCM x_install_colormap(s_cm, s_flg) SCM s_cm, s_flg; { struct xs_Colormap *xcm; ASRTER(NIMP(s_cm) && COLORMAPP(s_cm), s_cm, ARG1, s_x_install_colormap); if (UNBNDP(s_flg)) s_flg = BOOL_T; xcm = COLORMAP(s_cm); if (FALSEP(s_flg)) XUninstallColormap(XDISPLAY(xcm->display), xcm->cm); XInstallColormap(XDISPLAY(xcm->display), xcm->cm); return UNSPECIFIED; } /* SCM x_colormap_basis(svsl) */ /* SCM svsl; */ /* { */ /* XColormapInfo *vsl; */ /* ASRTER(NIMP(svsl) && COLORMAPP(svsl), svsl, ARG1, s_x_colormap_basis); */ /* vsl = XCOLORMAPINFO(svsl); */ /* return cons2(vsl->red_mult, vsl->green_mult, */ /* cons2(vsl->blue_mult, vsl->base_pixel, EOL)); */ /* } */ /* SCM x_colormap_limits(svsl) */ /* SCM svsl; */ /* { */ /* XColormapInfo *vsl; */ /* ASRTER(NIMP(svsl) && COLORMAPP(svsl), svsl, ARG1, s_x_colormap_limits); */ /* vsl = XCOLORMAPINFO(svsl); */ /* return cons2(vsl->red_mult, vsl->green_mult, */ /* cons2(vsl->blue_mult, vsl->base_pixel, EOL)); */ /* } */ /* Colors in Colormap */ SCM x_alloc_color_cells(scmap, spxls, sargs) SCM scmap, spxls, sargs; { XColor xclr; Status sts; struct xs_Colormap *xcm; Bool contig = 0; SCM pxra, plra; unsigned int npixels, nplanes; ASRTER(NIMP(scmap) && COLORMAPP(scmap), scmap, ARG1, s_x_alloc_color_cells); xcm = COLORMAP(scmap); npixels = INUM(spxls); ASRTER(INUMP(spxls) && npixels > 0, spxls, ARG2, s_x_alloc_color_cells); pxra = make_uve(npixels, MAKINUM(32L)); /* Uniform vector of long */ switch (ilength(sargs) + 2) { default: wta(sargs, (char *)WNA, s_x_alloc_color_cells); case 3: case 4: if (scm2XColor(CAR(sargs), &xclr)) { unsigned long rmask_return, gmask_return, bmask_return; sargs = CDR(sargs); if (NNULLP(sargs)) contig = thebool(CAR(sargs), s_x_alloc_color_cells); sts = XAllocColorPlanes(xcm->dpy, xcm->cm, contig, VELTS(pxra), npixels, xclr.red, xclr.green, xclr.blue, &rmask_return, &gmask_return, &bmask_return); if (!sts) return BOOL_F; return cons2(pxra, MAKINUM(rmask_return), cons2(MAKINUM(gmask_return), MAKINUM(bmask_return), EOL)); } nplanes = theuint(CAR(sargs), s_x_alloc_color_cells); sargs = CDR(sargs); if (NNULLP(sargs)) contig = thebool(CAR(sargs), s_x_alloc_color_cells); plra = make_uve(nplanes, MAKINUM(32L)); /* Uniform vector of long */ sts = XAllocColorCells(xcm->dpy, xcm->cm, contig, VELTS(plra), nplanes, VELTS(pxra), npixels); if (!sts) return BOOL_F; return cons2(pxra, plra, EOL); } } SCM x_free_color_cells(scmap, spxls, sargs) SCM scmap, spxls, sargs; { struct xs_Colormap *xcm; unsigned int planes = 0; ASRTER(NIMP(scmap) && COLORMAPP(scmap), scmap, ARG1, s_x_free_color_cells); xcm = COLORMAP(scmap); ASRTER(NIMP(spxls) && (TYP7(spxls)==tc7_VfixN32), spxls, ARG2, s_x_free_color_cells); switch (ilength(sargs) + 2) { default: wta(sargs, (char *)WNA, s_x_free_color_cells); case 4: planes = theuint(CAR(sargs), s_x_free_color_cells); case 3: XFreeColors(xcm->dpy, xcm->cm, VELTS(spxls), INUM(spxls), planes); return UNSPECIFIED; } } SCM x_find_color(scmap, dat) SCM scmap, dat; { XColor xclr; struct xs_Colormap *xcm; (void)memset((char *)&xclr, 0, sizeof(xclr)); ASRTER(NIMP(scmap) && COLORMAPP(scmap), scmap, ARG1, s_x_find_color); xcm = COLORMAP(scmap); if (!scm2XColor(dat, &xclr)) { ASRTER(NIMP(dat) && STRINGP(dat), dat, (char*)ARG2, s_x_find_color); if (XAllocNamedColor(xcm->dpy, xcm->cm, CHARS(dat), &xclr, &xclr)) return MAKINUM(xclr.pixel); else return BOOL_F; } if (XAllocColor(xcm->dpy, xcm->cm, &xclr)) return MAKINUM(xclr.pixel); else return BOOL_F; } SCM x_color_set(scmap, s_pix, dat) SCM scmap, s_pix, dat; { XColor xclr; struct xs_Colormap *xcm; (void)memset((char *)&xclr, 0, sizeof(xclr)); ASRTER(NIMP(scmap) && COLORMAPP(scmap), scmap, ARG1, s_x_color_set); ASRTER(INUMP(s_pix), s_pix, ARG2, s_x_color_set); xcm = COLORMAP(scmap); xclr.pixel = INUM(s_pix); xclr.flags = DoRed | DoGreen | DoBlue; if (!scm2XColor(dat, &xclr)) { ASRTER(NIMP(dat) && STRINGP(dat), dat, (char*)ARG3, s_x_color_set); XStoreNamedColor(xcm->dpy, xcm->cm, CHARS(dat), xclr.pixel, xclr.flags); } else XStoreColor(xcm->dpy, xcm->cm, &xclr); return UNSPECIFIED; } SCM x_color_ref(scmap, sidx) SCM scmap, sidx; { XColor xclr; struct xs_Colormap *xcm; (void)memset((char *)&xclr, 0, sizeof(xclr)); ASRTER(NIMP(scmap) && COLORMAPP(scmap), scmap, ARG1, s_x_color_ref); xcm = COLORMAP(scmap); ASRTER(INUMP(sidx), sidx, (char*)ARG2, s_x_color_ref); xclr.pixel = INUM(sidx); XQueryColor(xcm->dpy, xcm->cm, &xclr); if (xclr.flags==(DoRed | DoGreen | DoBlue)) return cons2(MAKINUM(xclr.red), MAKINUM(xclr.green), cons(MAKINUM(xclr.blue), EOL)); else return BOOL_F; } /* Window Mapping */ SCM x_map_window(swin) SCM swin; { struct xs_Window *w; ASRTER(NIMP(swin) && WINDOWP(swin), swin, ARG1, s_x_map_window); w = WINDOW(swin); XMapWindow(w->dpy, w->p.win); return UNSPECIFIED; } SCM x_map_subwindows(swin) SCM swin; { struct xs_Window *w; ASRTER(NIMP(swin) && WINDOWP(swin), swin, ARG1, s_x_map_subwindows); w = WINDOW(swin); XMapSubwindows(w->dpy, w->p.win); return UNSPECIFIED; } SCM x_unmap_window(swin) SCM swin; { struct xs_Window *w; ASRTER(NIMP(swin) && WINDOWP(swin), swin, ARG1, s_x_unmap_window); w = WINDOW(swin); XUnmapWindow(w->dpy, w->p.win); return UNSPECIFIED; } SCM x_unmap_subwindows(swin) SCM swin; { struct xs_Window *w; ASRTER(NIMP(swin) && WINDOWP(swin), swin, ARG1, s_x_unmap_subwindows); w = WINDOW(swin); XUnmapSubwindows(w->dpy, w->p.win); return UNSPECIFIED; } SCM x_create_gc(args) SCM args; { SCM swin; struct xs_Window *xsw; struct xs_GContext *xgc; XGCValues v; unsigned long mask; SCM ans; ASRTER(NIMP(args), args, WNA, s_x_create_gc); swin = CAR(args); args = CDR(args); ASRTER(NIMP(swin) && WINDOWP(swin), swin, ARG1, s_x_create_gc); xsw = WINDOW(swin); ans = make_xgcontext(xsw->display, xsw->screen_number, XCreateGC(xsw->dpy, xsw->p.drbl, 0L, &v), 0); xgc = GCONTEXT(ans); mask = args2xgcvalues(ans, &v, args); XChangeGC(xgc->dpy, xgc->gc, mask, &v); return ans; } SCM x_gc_set(args) SCM args; { SCM sgc; struct xs_GContext *xgc; XGCValues v; unsigned long mask; ASRTER(NIMP(args), args, WNA, s_x_gc_set); sgc = CAR(args); args = CDR(args); ASRTER(NIMP(sgc) && GCONTEXTP(sgc), sgc, ARG1, s_x_gc_set); xgc = GCONTEXT(sgc); mask = args2xgcvalues(sgc, &v, args); XChangeGC(xgc->dpy, xgc->gc, mask, &v); return UNSPECIFIED; } SCM x_copy_gc(dst, src, args) SCM dst; SCM src; SCM args; { struct xs_GContext *dgc, *sgc; unsigned long mask; ASRTER(NIMP(dst) && GCONTEXTP(dst), dst, ARG1, s_x_copy_gc); ASRTER(NIMP(src) && GCONTEXTP(src), src, ARG2, s_x_copy_gc); dgc = GCONTEXT(dst); sgc = GCONTEXT(src); mask = args2valmask(args, s_gc); XCopyGC(dgc->dpy, sgc->gc, mask, dgc->gc); return UNSPECIFIED; } SCM x_gc_ref(oargs) SCM oargs; { SCM sgc, args = oargs, sval = BOOL_F; SCM vals = cons(BOOL_T, EOL), valend = vals; struct xs_GContext *xgc; unsigned long valuemask; XGCValues vlu; int attr, len = ilength(args); /* (void)memset((char *)&vlu, 0, sizeof(XGCValues)); */ ASRTER(len > 0, oargs, WNA, s_x_gc_ref); if (1==len--) return EOL; sgc = CAR(args); args = CDR(args); ASRTER(NIMP(sgc) && GCONTEXTP(sgc), sgc, ARG1, s_x_gc_ref); xgc = GCONTEXT(sgc); valuemask = args2valmask(args, s_gc); /* printf("valuemask = %lx\n", valuemask); */ valuemask &= (GCFunction | GCPlaneMask | GCForeground | GCBackground | GCLineWidth | GCLineStyle | GCCapStyle | GCJoinStyle | GCFillStyle | GCFillRule | GCTileStipXOrigin | GCTileStipYOrigin | GCSubwindowMode | GCGraphicsExposures | GCClipXOrigin | GCClipYOrigin | GCDashOffset | GCArcMode); if (!XGetGCValues(xgc->dpy, xgc->gc, valuemask, &vlu)) return BOOL_F; while (len) { attr = theint(CAR(args), s_gc); args = CDR(args); switch (attr) { case GCFunction: sval = MAKINUM(vlu.function ); break; case GCPlaneMask: sval = MAKINUM(vlu.plane_mask); break; case GCForeground: sval = MAKINUM(vlu.foreground); break; case GCBackground: sval = MAKINUM(vlu.background); break; case GCLineWidth: sval = MAKINUM(vlu.line_width); break; case GCLineStyle: sval = MAKINUM(vlu.line_style); break; case GCCapStyle: sval = MAKINUM(vlu.cap_style ); break; case GCJoinStyle: sval = MAKINUM(vlu.join_style); break; case GCFillStyle: sval = MAKINUM(vlu.fill_style); break; case GCFillRule: sval = MAKINUM(vlu.fill_rule ); break; case GCTile: sval = xgc->tile; break; case GCStipple: sval = xgc->stipple; break; case GCTileStipXOrigin: sval = MAKINUM(vlu.ts_x_origin); break; case GCTileStipYOrigin: sval = MAKINUM(vlu.ts_y_origin); break; case (GCTileStipXOrigin | GCTileStipYOrigin): sval = cons2(MAKINUM(vlu.ts_x_origin), MAKINUM(vlu.ts_y_origin), EOL); break; case GCFont: sval = xgc->font; break; case GCSubwindowMode: sval = MAKINUM(vlu.subwindow_mode); break; case GCGraphicsExposures: sval = x_make_bool(vlu.graphics_exposures); break; case GCClipXOrigin: sval = MAKINUM(vlu.clip_x_origin); break; case GCClipYOrigin: sval = MAKINUM(vlu.clip_y_origin); break; case (GCClipXOrigin | GCClipYOrigin): sval = cons2(MAKINUM(vlu.clip_x_origin), MAKINUM(vlu.clip_y_origin), EOL); break; case GCClipMask: sval = xgc->clipmask; break; case GCDashOffset: sval = MAKINUM(vlu.dash_offset); break; case GCDashList: sval = MAKINUM(vlu.dashes); break; case GCArcMode: sval = MAKINUM(vlu.arc_mode); break; default: ASRTER(0, MAKINUM(attr), ARGn, s_x_gc_ref); } CAR(valend) = sval; CDR(valend) = cons(BOOL_T, EOL); len -= 1; if (len) valend = CDR(valend); else CDR(valend) = EOL; } return vals; } SCM x_create_cursor(sdpy, scsr, sargs) SCM sdpy, scsr, sargs; { Cursor cursor; switch (ilength(sargs)) { default: ASRTER(0, sargs, WNA, s_x_create_cursor); case 0: { SCM shape; ASRTER(NIMP(sdpy) && DISPLAYP(sdpy), sdpy, ARG1, s_x_create_cursor); shape = thevalue(scsr); ASRTER(INUMP(shape) && 0 <= INUM(shape), scsr, ARG2, s_x_create_cursor); cursor = XCreateFontCursor(XDISPLAY(sdpy), INUM(shape)); return make_xcursor(sdpy, cursor); } case 3: { XColor foreground_color, background_color; XPoint origin; int sts; ASRTER(NIMP(sdpy) && WINDOWP(sdpy), sdpy, ARG1, s_x_create_cursor); ASRTER(FALSEP(scsr) || (NIMP(scsr) && WINDOWP(scsr)), scsr, ARG2, s_x_create_cursor); sts = scm2XColor(CAR(sargs), &foreground_color); ASRTER(sts, CAR(sargs), ARG3, s_x_create_cursor); sargs = CDR(sargs); sts = scm2XColor(CAR(sargs), &background_color); ASRTER(sts, CAR(sargs), ARG4, s_x_create_cursor); sargs = CDR(sargs); scm2XPoint(0, CAR(sargs), &origin, (char*)ARG5, s_x_create_cursor); cursor = XCreatePixmapCursor(XWINDISPLAY(sdpy), XWINDOW(sdpy), FALSEP(scsr) ? 0L : XWINDOW(scsr), &foreground_color, &background_color, origin.x, origin.y); return make_xcursor(WINDOW(sdpy)->display, cursor); } case 4: { XColor foreground_color, background_color; Font source_font, mask_font = 0; unsigned int source_char, mask_char = 0; int sts; source_font = thefont(sdpy, s_x_create_cursor); GET_NEXT_INT(source_char, sargs, ARG2, s_x_create_cursor); if (FALSEP(CAR(sargs))) { sargs = CDR(sargs); ASRTER(FALSEP(CAR(sargs)), sargs, ARG4, s_x_create_cursor); sargs = CDR(sargs); } else { mask_font = thefont(CAR(sargs), s_x_create_cursor); sargs = CDR(sargs); GET_NEXT_INT(mask_char, sargs, ARG4, s_x_create_cursor); } sts = scm2XColor(CAR(sargs), &foreground_color); ASRTER(sts, CAR(sargs), ARG5, s_x_create_cursor); sargs = CDR(sargs); sts = scm2XColor(CAR(sargs), &background_color); ASRTER(sts, CAR(sargs), ARGn, s_x_create_cursor); cursor = XCreateGlyphCursor(XWINDISPLAY(sdpy), source_font, mask_font, source_char, mask_char, &foreground_color, &background_color); return make_xcursor(FONT(sdpy)->display, cursor); }} } SCM x_load_font(sdpy, fntnam) SCM sdpy, fntnam; { Font font; ASRTER(NIMP(sdpy) && DISPLAYP(sdpy), sdpy, ARG1, s_x_load_font); ASRTER(NIMP(fntnam) && STRINGP(fntnam), fntnam, ARG2, s_x_load_font); font = XLoadFont(XDISPLAY(sdpy), CHARS(fntnam)); return make_xfont(sdpy, font, fntnam); } /* Xlib information functions. */ SCM x_protocol_version(sd, si) SCM sd, si; { struct display_screen dspscn; scm2display_screen(sd, si, &dspscn, s_x_protocol_version); return cons(MAKINUM(ProtocolVersion(dspscn.dpy)), MAKINUM(ProtocolRevision(dspscn.dpy))); } SCM x_server_vendor(sd, si) SCM sd, si; { struct display_screen dspscn; scm2display_screen(sd, si, &dspscn, s_x_server_vendor); return makfrom0str(ServerVendor(dspscn.dpy)); } SCM x_vendor_release(sd, si) SCM sd, si; { struct display_screen dspscn; scm2display_screen(sd, si, &dspscn, s_x_vendor_release); return MAKINUM(VendorRelease(dspscn.dpy)); } int x_scm_error_handler(display, xee) Display *display; XErrorEvent *xee; { char buffer_return[1024]; fflush(stdout); XGetErrorText(display, xee->error_code, buffer_return, sizeof buffer_return); *loc_errobj = MAKINUM((xee->request_code<<8) + xee->minor_code); fputs(buffer_return, stderr); fputc('\n', stderr); fflush(stderr); return 0; } SCM x_q_length(sd, si) SCM sd, si; { struct display_screen dspscn; scm2display_screen(sd, si, &dspscn, s_x_q_length); return MAKINUM(QLength(dspscn.dpy)); } SCM x_pending(sd, si) SCM sd, si; { struct display_screen dspscn; scm2display_screen(sd, si, &dspscn, s_x_pending); return MAKINUM(XPending(dspscn.dpy)); } SCM x_events_queued(sd, si) SCM sd, si; { struct display_screen dspscn; scm2display_screen(sd, si, &dspscn, s_x_events_queued); return MAKINUM(XEventsQueued(dspscn.dpy, QueuedAfterReading)); } SCM x_next_event(sd, si) SCM sd, si; { struct display_screen dspscn; XEvent event_return; scm2display_screen(sd, si, &dspscn, s_x_next_event); XNextEvent(dspscn.dpy, &event_return); return make_xevent(&event_return); } SCM x_peek_event(sd, si) SCM sd, si; { struct display_screen dspscn; XEvent event_return; scm2display_screen(sd, si, &dspscn, s_x_peek_event); XPeekEvent(dspscn.dpy, &event_return); return make_xevent(&event_return); } /* Screen information functions */ SCM x_screen_count(sd, si) SCM sd, si; { struct display_screen dspscn; scm2display_screen(sd, si, &dspscn, s_x_screen_count); return MAKINUM(ScreenCount(dspscn.dpy)); } SCM x_screen_cells(sd, si) SCM sd, si; { struct display_screen dspscn; scm2display_screen(sd, si, &dspscn, s_x_screen_cells); return MAKINUM(DisplayCells(dspscn.dpy, dspscn.screen_number)); } SCM x_screen_depth(sd, si) SCM sd, si; { struct display_screen dspscn; if (UNBNDP(si) && NIMP(sd) && VISUALP(sd)) return MAKINUM(XVISUALINFO(sd)->depth); scm2display_screen(sd, si, &dspscn, s_x_screen_depth); return MAKINUM(DisplayPlanes(dspscn.dpy, dspscn.screen_number)); } SCM x_screen_depths(sd, si) SCM sd, si; { int count_return = 0; int *depths; SCM depra; struct display_screen dspscn; scm2display_screen(sd, si, &dspscn, s_x_screen_depths); depths = XListDepths(dspscn.dpy, dspscn.screen_number, &count_return); if (!depths) return BOOL_F; depra = make_uve(count_return, MAKINUM(32L)); /* Uniform vector of long */ for (;count_return--;) VELTS(depra)[count_return] = depths[count_return]; XFree(depths); return depra; } SCM x_screen_size(sd, si) SCM sd, si; { struct display_screen dspscn; scm2display_screen(sd, si, &dspscn, s_x_screen_size); return cons2(MAKINUM(DisplayWidth(dspscn.dpy, dspscn.screen_number)), MAKINUM(DisplayHeight(dspscn.dpy, dspscn.screen_number)), EOL); } SCM x_screen_dimm(sd, si) SCM sd, si; { struct display_screen dspscn; scm2display_screen(sd, si, &dspscn, s_x_screen_dimm); return cons2(MAKINUM(DisplayWidthMM(dspscn.dpy, dspscn.screen_number)), MAKINUM(DisplayHeightMM(dspscn.dpy, dspscn.screen_number)), EOL); } SCM x_screen_black(sd, si) SCM sd, si; { struct display_screen dspscn; Screen *scn; scm2display_screen(sd, si, &dspscn, s_x_screen_black); scn = ScreenOfDisplay(dspscn.dpy, dspscn.screen_number); return ulong2num(BlackPixelOfScreen(scn)); } SCM x_screen_white(sd, si) SCM sd, si; { struct display_screen dspscn; Screen *scn; scm2display_screen(sd, si, &dspscn, s_x_screen_white); scn = ScreenOfDisplay(dspscn.dpy, dspscn.screen_number); return ulong2num(WhitePixelOfScreen(scn)); } XVisualInfo *visual2visualinfo(dsp, vis) Display *dsp; Visual *vis; { int nitems_return; XVisualInfo vinfo_template; XVisualInfo *vislst; vinfo_template.visualid = XVisualIDFromVisual(vis); vislst = XGetVisualInfo(dsp, VisualIDMask, &vinfo_template, &nitems_return); if (1 != nitems_return) { if (vislst) XFree(vislst); wta(MAKINUM(nitems_return), (char *)WNA, s_visual); } return vislst; } SCM x_make_visual(sd, sdepth, sclass) SCM sd, sdepth, sclass; { int nitems_return; struct display_screen dspscn; XVisualInfo vinfo_template; XVisualInfo *vislst; scm2display_screen(sd, UNDEFINED, &dspscn, s_x_make_visual); vinfo_template.screen = dspscn.screen_number; vinfo_template.depth = theuint(sdepth, s_x_make_visual); vinfo_template.class = theuint(sclass, s_x_make_visual); vislst = XGetVisualInfo(dspscn.dpy, VisualScreenMask | VisualDepthMask | VisualClassMask, &vinfo_template, &nitems_return); if (0==nitems_return) return BOOL_F; return make_xvisual(vislst); } static sizet free_visual(ptr) CELLPTR ptr; { XFree(XVISUALINFO(ptr)); return 0; } SCM x_visual_geometry(svsl) SCM svsl; { XVisualInfo *vsl; ASRTER(NIMP(svsl) && VISUALP(svsl), svsl, ARG1, s_x_visual_geometry); vsl = XVISUALINFO(svsl); return cons2(MAKINUM(vsl->red_mask), MAKINUM(vsl->green_mask), cons2(MAKINUM(vsl->blue_mask), MAKINUM(vsl->colormap_size), EOL)); } SCM x_visual_class(svsl) SCM svsl; { XVisualInfo *vsl; ASRTER(NIMP(svsl) && VISUALP(svsl), svsl, ARG1, s_x_visual_class); vsl = XVISUALINFO(svsl); return MAKINUM(vsl->class); } SCM x_root_window(sdpy, sscr) SCM sdpy, sscr; { struct display_screen dspscn; struct xs_Display *xsd; struct xs_screen *scrns; scm2display_screen(sdpy, sscr, &dspscn, s_x_root_window); xsd = DISPLAY(dspscn.display); scrns = (struct xs_screen *)(xsd + 1); return scrns[dspscn.screen_number].root_window; } SCM x_default_colormap(sdpy, sscr) SCM sdpy, sscr; { struct display_screen dspscn; struct xs_Display *xsd; struct xs_screen *scrns; scm2display_screen(sdpy, sscr, &dspscn, s_x_default_colormap); xsd = DISPLAY(dspscn.display); scrns = (struct xs_screen *)(xsd + 1); return scrns[dspscn.screen_number].default_colormap; } SCM x_default_gcontext(sdpy, sscr) SCM sdpy, sscr; { struct display_screen dspscn; struct xs_Display *xsd; struct xs_screen *scrns; scm2display_screen(sdpy, sscr, &dspscn, s_x_default_gcontext); xsd = DISPLAY(dspscn.display); scrns = (struct xs_screen *)(xsd + 1); return scrns[dspscn.screen_number].default_gcontext; } SCM x_default_visual(sdpy, sscr) SCM sdpy, sscr; { struct display_screen dspscn; struct xs_Display *xsd; struct xs_screen *scrns; scm2display_screen(sdpy, sscr, &dspscn, s_x_default_visual); xsd = DISPLAY(dspscn.display); scrns = (struct xs_screen *)(xsd + 1); return scrns[dspscn.screen_number].default_visual; } SCM x_default_ccc(sdpy, sscr) SCM sdpy, sscr; { struct display_screen dspscn; XcmsCCC ccc; if (NIMP(sdpy) && COLORMAPP(sdpy) && UNBNDP(sscr)) { struct xs_Colormap *cmp = COLORMAP(sdpy); ccc = XcmsCCCOfColormap(cmp->dpy, cmp->cm); } else { scm2display_screen(sdpy, sscr, &dspscn, s_x_default_ccc); ccc = XcmsDefaultCCC(dspscn.dpy, dspscn.screen_number); } return CCC2SCM(ccc); } /* SCM x_ccc_screen_info(sccc, sfmt) SCM sccc; SCM sfmt; { XcmsCCC xccc; XcmsPerScrnInfo *pPerScrnInfo; ASRTER(NIMP(sccc) && CCCP(sccc), sccc, ARG1, s_x_ccc_screen_info); ASRTER(NIMP(sfmt) && STRINGP(sfmt), sfmt, ARG2, s_x_ccc_screen_info); xccc = XCCC(sccc); pPerScrnInfo = (XcmsFunctionSet *)xccc->pPerScrnInfo; return ; } */ /* Window Information */ SCM x_propdata2scm(type, format, nitems, data) Atom type; int format; unsigned long nitems; unsigned char* data; { SCM datum = EOL; SCM lst = EOL; int cnt; for (cnt = nitems; cnt--;) { switch (type) { case XA_ATOM: case XA_VISUALID: case XA_CARDINAL: switch (format) { case 8: datum = MAKINUM(((unsigned char *)data)[cnt]); break; case 16: datum = MAKINUM(((unsigned short *)data)[cnt]); break; case 32: datum = ulong2num(((unsigned long *)data)[cnt]); break; default: return MAKINUM(format); } break; case XA_INTEGER: switch (format) { case 8: datum = MAKINUM(((char *)data)[cnt]); break; case 16: datum = MAKINUM(((short *)data)[cnt]); break; case 32: datum = long2num(((long *)data)[cnt]); break; default: return MAKINUM(format); } break; case XA_STRING: switch (format) { case 8: return makfrom0str(data); default: return MAKINUM(format); } break; case XA_ARC: case XA_BITMAP: case XA_COLORMAP: case XA_CURSOR: case XA_DRAWABLE: case XA_FONT: case XA_PIXMAP: case XA_POINT: case XA_RECTANGLE: case XA_RGB_COLOR_MAP: case XA_WINDOW: case XA_WM_HINTS: case XA_WM_SIZE_HINTS: default: /* datum = BOOL_F; */ return MAKINUM(-type); } lst = cons(datum, lst); } return lst; } SCM x_get_window_property(swin, sprop, sargs) SCM swin, sprop, sargs; { struct xs_Window *xwn; Atom property; Atom actual_type_return; int actual_format_return; unsigned long nitems_return; unsigned long bytes_after_return; unsigned char *prop_return; int sarglen = ilength(sargs); ASRTER(IMP(sprop) ? INUMP(sprop) : STRINGP(sprop), sprop, ARG2, s_x_get_window_property); ASRTER(sarglen >= 0 && sarglen < 2, sargs, WNA, s_x_get_window_property); if (1 == sarglen) { ASRTER(NFALSEP(booleanp(CAR(sargs))), sargs, ARG3, s_x_get_window_property); } ASRTER(NIMP(swin) && WINDOWP(swin), swin, ARG1, s_x_map_window); xwn = WINDOW(swin); if (INUMP(sprop)) property = INUM(sprop); else property = XInternAtom(xwn->dpy, CHARS(sprop), !0); if (None == property) return BOOL_F; if (XGetWindowProperty(xwn->dpy, xwn->p.win, property, 0L, 65536L, (1 == sarglen) && NFALSEP(CAR(sargs)), AnyPropertyType, &actual_type_return, &actual_format_return, &nitems_return, &bytes_after_return, &prop_return) != Success) return BOOL_F; { SCM ans = x_propdata2scm(actual_type_return, actual_format_return, nitems_return, prop_return); XFree(prop_return); return ans; } } SCM x_list_properties(swin) SCM swin; { struct xs_Window *xwn; Atom *atoms; int num_prop_return; SCM lst; ASRTER(NIMP(swin) && WINDOWP(swin), swin, ARG1, s_x_map_window); xwn = WINDOW(swin); atoms = XListProperties(xwn->dpy, xwn->p.win, &num_prop_return); { int i = num_prop_return; lst = EOL; while (i--) { char *name = XGetAtomName(xwn->dpy, atoms[i]); lst = cons(makfrom0str(name), lst); XFree(name); } } XFree(atoms); return lst; } /* Rendering */ SCM x_clear_area(swin, spos, sargs) SCM swin, spos, sargs; { XPoint position, size; ASRTER(2==ilength(sargs), sargs, WNA, s_x_clear_area); ASRTER(NIMP(swin) && WINDOWP(swin), swin, ARG1, s_x_clear_area); scm2XPoint(!0, spos, &position, (char *)ARG2, s_x_clear_area); scm2XPoint(0, CAR(sargs), &size, (char *)ARG3, s_x_clear_area); sargs = CDR(sargs); XClearArea(XWINDISPLAY(swin), XWINDOW(swin), position.x, position.y, size.x, size.y, NFALSEP(CAR(sargs))); return UNSPECIFIED; } SCM x_fill_rectangle(swin, sgc, sargs) SCM swin, sgc, sargs; { XPoint position, size; ASRTER(2==ilength(sargs), sargs, WNA, s_x_fill_rectangle); ASRTER(NIMP(swin) && WINDOWP(swin), swin, ARG1, s_x_fill_rectangle); ASRTER(NIMP(sgc) && GCONTEXTP(sgc), sgc, ARG2, s_x_fill_rectangle); scm2XPoint(!0, CAR(sargs), &position, (char *)ARG3, s_x_fill_rectangle); sargs = CDR(sargs); scm2XPoint(0, CAR(sargs), &size, (char *)ARG4, s_x_fill_rectangle); XFillRectangle(XWINDISPLAY(swin), XWINDOW(swin), XGCONTEXT(sgc), position.x, position.y, size.x, size.y); return UNSPECIFIED; } void xldraw_string(sdbl, sgc, sargs, proc, s_caller) SCM sdbl, sgc, sargs; int (*proc)(); char *s_caller; { XPoint position; ASRTER(2==ilength(sargs), sargs, WNA, s_caller); ASRTER(NIMP(sdbl) && WINDOWP(sdbl), sdbl, ARG1, s_caller); ASRTER(NIMP(sgc) && GCONTEXTP(sgc), sgc, ARG2, s_caller); scm2XPoint(!0, CAR(sargs), &position, (char *)ARG3, s_caller); sargs = CDR(sargs); sargs = CAR(sargs); ASRTER(NIMP(sargs) && STRINGP(sargs), sargs, ARG4, s_caller); proc(XWINDISPLAY(sdbl), XWINDOW(sdbl), XGCONTEXT(sgc), position.x, position.y, CHARS(sargs), LENGTH(sargs)); } SCM x_draw_string(sdbl, sgc, sargs) SCM sdbl, sgc, sargs; { xldraw_string(sdbl, sgc, sargs, &XDrawString, s_x_draw_string); return UNSPECIFIED; } SCM x_image_string(sdbl, sgc, sargs) SCM sdbl, sgc, sargs; { xldraw_string(sdbl, sgc, sargs, &XDrawImageString, s_x_image_string); return UNSPECIFIED; } SCM x_draw_points(sdbl, sgc, sargs) SCM sdbl, sgc, sargs; { XPoint pos[1]; int len; SCM sarg; ASRTER(NIMP(sdbl) && WINDOWP(sdbl), sdbl, ARG1, s_x_draw_points); ASRTER(NIMP(sgc) && GCONTEXTP(sgc), sgc, ARG2, s_x_draw_points); loop: if (NULLP(sargs)) return UNSPECIFIED; sarg = CAR(sargs); sargs = CDR(sargs); if (INUMP(sarg)) { ASRTER(NNULLP(sargs), sargs, WNA, s_x_draw_points); pos[0].x = INUM(sarg); GET_NEXT_INT(pos[0].y, sargs, ARGn, s_x_draw_points); goto drawshort; } len = scm2xpointslen(sarg, s_x_draw_points); if (len < 0) { scm2XPoint(!0, sarg, &(pos[0]), (char *)ARG3, s_x_draw_points); drawshort: XDrawPoints(XWINDISPLAY(sdbl), XWINDOW(sdbl), XGCONTEXT(sgc), &(pos[0]), 1, CoordModeOrigin); goto loop; } else { ASRTER(NULLP(sargs), sargs, WNA, s_x_draw_points); XDrawPoints(XWINDISPLAY(sdbl), XWINDOW(sdbl), XGCONTEXT(sgc), (XPoint *)scm_base_addr(sarg, s_x_draw_points), len, CoordModeOrigin); return UNSPECIFIED; } } SCM xldraw_lines(sdbl, sgc, sargs, funcod, s_caller) SCM sdbl, sgc, sargs; int funcod; char *s_caller; { XPoint pos[2]; int len; SCM sarg; ASRTER(NIMP(sdbl) && WINDOWP(sdbl), sdbl, ARG1, s_caller); ASRTER(NIMP(sgc) && GCONTEXTP(sgc), sgc, ARG2, s_caller); loop: if (NULLP(sargs)) return UNSPECIFIED; sarg = CAR(sargs); sargs = CDR(sargs); if (INUMP(sarg)) { ASRTER(NNULLP(sargs), sargs, WNA, s_caller); pos[0].x = INUM(sarg); GET_NEXT_INT(pos[0].y, sargs, ARGn, s_caller); GET_NEXT_INT(pos[1].x, sargs, ARGn, s_caller); GET_NEXT_INT(pos[1].y, sargs, ARGn, s_caller); goto drawshort; } len = scm2xpointslen(sarg, s_caller); if (len < 0) { scm2XPoint(!0, sarg, &(pos[0]), (char *)ARG3, s_caller); scm2XPoint(!0, sarg, &(pos[1]), (char *)ARG4, s_caller); drawshort: switch (funcod) { default: wna: wta(sargs, (char *)WNA, s_caller); case 0: XDrawSegments(XWINDISPLAY(sdbl), XWINDOW(sdbl), XGCONTEXT(sgc), (XSegment *) &(pos[0]), 1); goto loop; case 1: XDrawLines(XWINDISPLAY(sdbl), XWINDOW(sdbl), XGCONTEXT(sgc), &(pos[0]), 2, CoordModeOrigin); goto loop; } } else { unsigned long rabase; ASRTGO(NULLP(sargs), wna); rabase = scm_base_addr(sarg, s_caller); switch (funcod) { default: goto wna; case 0: XDrawSegments(XWINDISPLAY(sdbl), XWINDOW(sdbl), XGCONTEXT(sgc), (XSegment *)rabase, len/2); return UNSPECIFIED; case 1: XDrawLines(XWINDISPLAY(sdbl), XWINDOW(sdbl), XGCONTEXT(sgc), (XPoint *)rabase, len, CoordModeOrigin); return UNSPECIFIED; case 2: XFillPolygon(XWINDISPLAY(sdbl), XWINDOW(sdbl), XGCONTEXT(sgc), (XPoint *)rabase, len, Complex, CoordModeOrigin); return UNSPECIFIED; } } } SCM x_draw_segments(sdbl, sgc, sargs) SCM sdbl, sgc, sargs; { return xldraw_lines(sdbl, sgc, sargs, 0, s_x_draw_segments); } SCM x_draw_lines(sdbl, sgc, sargs) SCM sdbl, sgc, sargs; { return xldraw_lines(sdbl, sgc, sargs, 1, s_x_draw_lines); } SCM x_fill_poly(sdbl, sgc, sargs) SCM sdbl, sgc, sargs; { return xldraw_lines(sdbl, sgc, sargs, 2, s_x_fill_poly); } static char s_x_read_bitmap_file[] = "x:read-bitmap-file"; SCM x_read_bitmap_file(sdbl, sfname) SCM sdbl, sfname; { unsigned int w, h; int x, y; Pixmap pxmp; ASRTER(NIMP(sdbl) && WINDOWP(sdbl), sdbl, ARG1, s_x_read_bitmap_file); if (XReadBitmapFile(XWINDISPLAY(sdbl), WINDOW(sdbl)->p.pm, CHARS(sfname), &w, &h, &pxmp, &x, &y) == BitmapSuccess) return make_xwindow(WINDOW(sdbl)->display, WINDOW(sdbl)->screen_number, pxmp, (char) 1, (char) 0); else return BOOL_F; } /* XEvents */ /* x_make_bool() is used in xevent.h */ SCM x_make_bool(f) Bool f; { return f ? BOOL_F : BOOL_T; } SCM x_event_ref(sevent, sfield) SCM sevent, sfield; { void *x; ASRTER(NIMP(sevent) && XEVENTP(sevent), sevent, ARG1, s_x_event_ref); ASRTER(INUMP(sfield), sfield, ARG2, s_x_event_ref); x = (void *) CHARS(sevent); switch (((((XEvent*)x)->type)<<8)+INUM(sfield)) { default: wta(sevent, "Incompatible field for", s_x_event_ref); #define SCM_EVENT_FIELDS #include "xevent.h" } } static struct { int type; char *name; } event_names[] = { #undef SCM_EVENT_FIELDS #include "xevent.h" }; static char *x__event_name(type) int type; { int i; for (i = 0; i < sizeof(event_names) / sizeof(event_names[0]); i++) if (type==event_names[i].type) return event_names[i].name; return "unknown"; } SCM x_event_keysym(sevent) SCM sevent; { XKeyEvent *ev; KeySym ans; ASRTGO(NIMP(sevent) && XEVENTP(sevent), badarg); ev = (XKeyEvent *)CHARS(sevent); switch (((XEvent*)ev)->type) { badarg: default: wta(sevent, (char *)ARG1, s_x_event_keysym); case KeyPress: case KeyRelease: ; } ans = XLookupKeysym(ev, ev->state); if (ans) return MAKINUM(ans); else return BOOL_F; } /* SMOB print routines */ static int print_xevent(exp, f, writing) SCM exp; SCM f; int writing; { lputs("#type), f); lputc('>', f); return 1; } static int print_xdisplay(exp, f, writing) SCM exp; SCM f; int writing; { if (CLOSEDP(exp)) lputs("#", f); else { lputs("#", f); } return 1; } static int print_xwindow(exp, f, writing) SCM exp; SCM f; int writing; { lputs(CLOSEDP(exp) ? "#', f); return 1; } static int print_xcursor(exp, f, writing) SCM exp; SCM f; int writing; { lputs("#', f); return 1; } static int print_xfont(exp, f, writing) SCM exp; SCM f; int writing; { lputs("#name), f); lputs("\">", f); return 1; } static int print_xcolormap(exp, f, writing) SCM exp; SCM f; int writing; { lputs("#', f); return 1; } static int print_xgcontext(exp, f, writing) SCM exp; SCM f; int writing; { lputs("#gid, 16, f); skimu */ scm_intprint((long) XGContextFromGC(XGCONTEXT(exp)), 16, f); lputc('>', f); return 1; } char *xvisualclass2name(class) int class; { switch (class) { case StaticGray: return "StaticGray"; case GrayScale: return "GrayScale"; case StaticColor: return "StaticColor"; case PseudoColor: return "PseudoColor"; case TrueColor: return "TrueColor"; case DirectColor: return "DirectColor"; default: return "??"; } } static int print_xvisual(exp, f, writing) SCM exp; SCM f; int writing; { XVisualInfo *xvi = XVISUALINFO(exp); lputs("#visualid, 16, f); lputs(" ", f); lputs(xvisualclass2name(xvi->class), f); lputc(' ', f); scm_intprint((long) xvi->depth, 10, f); lputc('x', f); scm_intprint((long) xvi->colormap_size, 10, f); lputc('>', f); return 1; } static int print_xccc(exp, f, writing) SCM exp; SCM f; int writing; { XcmsColorSpace **papColorSpaces; XcmsCCC xccc = XCCC(exp); lputs("#pPerScrnInfo->functionSet)->DDColorSpaces; if (papColorSpaces != NULL) { while (*papColorSpaces != NULL) { lputs(" ", f); lputs((*papColorSpaces)->prefix, f); papColorSpaces++; } } lputc('>', f); return 1; } static smobfuns smob_xdisplay = {mark_xdisplay, free_xdisplay, print_xdisplay, 0}; static smobfuns smob_xwindow = {mark_xwindow, free_xwindow, print_xwindow, 0}; static smobfuns smob_xcursor = {mark_xcursor, free_xcursor, print_xcursor, 0}; static smobfuns smob_xfont = {mark_xfont, free_xfont, print_xfont, 0}; static smobfuns smob_xgcontext = {mark_xgcontext, free_xgcontext, print_xgcontext, 0}; static smobfuns smob_xcolormap = {mark_xcolormap, free_xcolormap, print_xcolormap, 0}; static smobfuns smob_xvisual = {mark0, free_visual, print_xvisual, 0}; static smobfuns smob_xccc = {mark0, free_xccc, print_xccc, 0}; static smobfuns smob_xevent = {mark0, x_free_xevent, print_xevent, 0}; static iproc x_subr3s[] = { {s_x_make_visual, x_make_visual}, {s_x_create_pixmap, x_create_pixmap}, {s_x_create_colormap, x_create_colormap}, {s_x_color_set, x_color_set}, {0, 0} }; static iproc x_lsubr2s[] = { {s_x_create_window, x_create_window}, {s_x_create_cursor, x_create_cursor}, {s_x_alloc_color_cells, x_alloc_color_cells}, {s_x_free_color_cells, x_free_color_cells}, {s_x_get_window_property, x_get_window_property}, {s_x_clear_area, x_clear_area}, {s_x_fill_rectangle, x_fill_rectangle}, {s_x_draw_string, x_draw_string}, {s_x_image_string, x_image_string}, {s_x_draw_points, x_draw_points}, {s_x_draw_segments, x_draw_segments}, {s_x_draw_lines, x_draw_lines}, {s_x_fill_poly, x_fill_poly}, {0, 0} }; static iproc x_lsubrs[] = { {s_x_create_gc, x_create_gc}, {s_x_gc_set, x_gc_set}, {s_x_gc_ref, x_gc_ref}, {s_x_copy_gc, x_copy_gc}, {s_x_window_set, x_window_set}, {s_x_window_geometry_set, x_window_geometry_set}, {s_x_window_ref, x_window_ref}, {0, 0} }; static iproc x_subr2s[] = { {s_x_event_ref, x_event_ref}, {s_x_find_color, x_find_color}, {s_x_color_ref, x_color_ref}, {s_x_load_font, x_load_font}, {s_x_read_bitmap_file, x_read_bitmap_file}, {0, 0} }; static iproc x_subr2os[] = { {s_x_display_debug, x_display_debug}, {s_x_screen_cells, x_screen_cells}, {s_x_screen_depth, x_screen_depth}, {s_x_screen_depths, x_screen_depths}, {s_x_screen_size, x_screen_size}, {s_x_screen_dimm, x_screen_dimm}, {s_x_screen_black, x_screen_black}, {s_x_screen_white, x_screen_white}, {s_x_protocol_version, x_protocol_version}, {s_x_vendor_release, x_vendor_release}, {s_x_server_vendor, x_server_vendor}, {s_x_screen_count, x_screen_count}, {s_x_events_queued, x_events_queued}, {s_x_next_event, x_next_event}, {s_x_peek_event, x_peek_event}, {s_x_pending, x_pending}, {s_x_q_length, x_q_length}, {s_x_root_window, x_root_window}, {s_x_default_gcontext, x_default_gcontext}, {s_x_default_visual, x_default_visual}, {s_x_default_colormap, x_default_colormap}, {s_x_install_colormap, x_install_colormap}, {s_x_default_ccc, x_default_ccc}, {s_x_flush, x_flush}, {0, 0} }; static iproc x_subr1s[] = { {s_x_open_display, x_open_display}, {s_x_close, x_close}, {s_x_default_screen, x_default_screen}, {s_x_window_geometry, x_window_geometry}, {s_x_list_properties, x_list_properties}, {s_x_map_window, x_map_window}, {s_x_map_subwindows, x_map_subwindows}, {s_x_unmap_window, x_unmap_window}, {s_x_unmap_subwindows, x_unmap_subwindows}, {s_x_recreate_colormap, x_recreate_colormap}, {s_x_visual_geometry, x_visual_geometry}, {s_x_visual_class, x_visual_class}, {s_x_event_keysym, x_event_keysym}, /* {s_x_colormap_basis, x_colormap_basis}, */ /* {s_x_colormap_limits, x_colormap_limits}, */ {0, 0} }; int (*x_scm_prev_error_handler)() = 0; void x_scm_final() { if (x_scm_prev_error_handler) XSetErrorHandler(x_scm_prev_error_handler); x_scm_prev_error_handler = 0; } void init_x() { init_iprocs(x_subr3s, tc7_subr_3); init_iprocs(x_lsubr2s, tc7_lsubr_2); init_iprocs(x_lsubrs, tc7_lsubr); init_iprocs(x_subr2s, tc7_subr_2); init_iprocs(x_subr2os, tc7_subr_2o); init_iprocs(x_subr1s, tc7_subr_1); tc16_xdisplay = newsmob(&smob_xdisplay); tc16_xwindow = newsmob(&smob_xwindow); tc16_xcursor = newsmob(&smob_xcursor); tc16_xfont = newsmob(&smob_xfont); tc16_xcolormap = newsmob(&smob_xcolormap); tc16_xgcontext = newsmob(&smob_xgcontext); tc16_xvisual = newsmob(&smob_xvisual); tc16_xevent = newsmob(&smob_xevent); tc16_xccc = newsmob(&smob_xccc); xtc_ccc = XUniqueContext(); xtc_cmp = XUniqueContext(); scm_ldprog("x11.scm"); scm_ldprog("xevent.scm"); /* Redefines STRING */ /* scm_ldprog("xatoms.scm"); */ scm_ldstr("\ (define x:ccc x:default-ccc)\n\ (define x:GC-Clip-Origin (logior x:GC-Clip-X-Origin x:GC-Clip-Y-Origin))\n\ (define x:GC-Tile-Stip-Origin \n\ (logior x:GC-Tile-Stip-X-Origin x:GC-Tile-Stip-Y-Origin))\n\ "); add_feature("xlib"); add_final(x_scm_final); XSetErrorHandler(x_scm_error_handler); } scm-5e5/setjump.s0000644001705200017500000000241506467700740011721 0ustar tbtb* setjmp on the Cray YMP does not save all registers. Although this * conforms to the ANSI standard, it is not sufficient for SCM garbage * collection and continuations. * * This is a version of setjump for the Cray YMP that does save all non- * temporary registers. It might work for the XMP. It definitely will * not work on the Cray 2. I do not know if the setjmp on the Cray 2 will * work with SCM or not. * * This has been tested under Unicos 6.1. * * --Radey Shouman * IDENT SETJUMP ENTRY setjump setjump = * A1 1,A6 A2 56 A0 A1 ,A0 T00,A2 A0 A1+A2 ,A0 B00,A2 S1 0 J B00 * ENTRY longjump longjump = * A1 1,A6 A0 A1 A2 56 T00,A2 ,A0 A0 A1+A2 B00,A2 ,A0 S1 2,A6 J B00 END ** Local Variables: ** tab-stop-list: (12 28 45) ** indent-tabs-mode: nil ** End: scm-5e5/scmhob.scm0000644001705200017500000000133010750212106012000 0ustar tbtb;;;; "scmhob.scm" Scheme runtime support for hobbit. ;For interpretation of code meant for compilation by hobbit. Never compile! ; bitwise operations: logical shift left and logical shift right (define (logsleft x y) (ash x y)) (define (logsright x y) (ash x (- 0 y))) (define logical:logand logand) (define logical:logior logior) (define logical:logxor logxor) (define logical:lognot lognot) ; immediate-integer (30-bit signed int) versions of arithmetic primitives: (define %number? number?) (define %eqv? eqv?) (define %zero? zero?) (define %negative? negative?) (define %positive? positive?) (define %= =) (define %< <) (define %> >) (define %<= <=) (define %>= >=) (define %+ +) (define %- -) (define %* *) (define %/ /) scm-5e5/setjump.h0000644001705200017500000001007410750224567011704 0ustar tbtb/* "setjump.h" memory and stack parameters. * Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1997 Free Software Foundation, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see * . */ /* Author: Aubrey Jaffer */ /* CELL_UP and CELL_DN are used by init_heap_seg to find cell aligned inner bounds for allocated storage */ #ifdef PROT386 /*in 386 protected mode we must only adjust the offset */ # define CELL_UP(p) MK_FP(FP_SEG(p), ~7&(FP_OFF(p)+7)) # define CELL_DN(p) MK_FP(FP_SEG(p), ~7&FP_OFF(p)) #else # ifdef _UNICOS # define CELL_UP(p) (CELLPTR)(~1L & ((long)(p)+1L)) # define CELL_DN(p) (CELLPTR)(~1L & (long)(p)) # else # define CELL_UP(p) (CELLPTR)(~(sizeof(cell)-1L) & ((long)(p)+sizeof(cell)-1L)) # define CELL_DN(p) (CELLPTR)(~(sizeof(cell)-1L) & (long)(p)) # endif /* UNICOS */ #endif /* PROT386 */ /* These are parameters for controlling memory allocation. The heap is the area out of which cons and object headers is allocated. Each heap object is 8 bytes on a 32 bit machine and 16 bytes on a 64 bit machine. The units of the _SIZE parameters are bytes. INIT_HEAP_SIZE is the initial size of heap. If this much heap is allocated initially the heap will grow by half its current size each subsequent time more heap is needed. If INIT_HEAP_SIZE heap cannot be allocated initially, HEAP_SEG_SIZE will be used, and the heap will grow by HEAP_SEG_SIZE when more heap is needed. HEAP_SEG_SIZE must fit into type sizet. This code is in init_storage() and alloc_some_heap() in sys.c If INIT_HEAP_SIZE can be allocated initially, the heap will grow by EXPHEAP(heap_cells) when more heap is needed. MIN_HEAP_SEG_SIZE is minimum size of heap to accept when more heap is needed. INIT_MALLOC_LIMIT is the initial amount of malloc usage which will trigger a GC. */ #define INIT_HEAP_SIZE (25000L*sizeof(cell)) #define MIN_HEAP_SEG_SIZE (2000L*sizeof(cell)) #ifdef _QC # define HEAP_SEG_SIZE 32400L #else # ifdef sequent # define HEAP_SEG_SIZE (7000L*sizeof(cell)) # else # define HEAP_SEG_SIZE (8100L*sizeof(cell)) # endif #endif #define EXPHEAP(heap_cells) (heap_cells*2) #define INIT_MALLOC_LIMIT 100000 /* ECACHE_SIZE is the number of cells in the copy-collected environment cache used for environment frames */ #define ECACHE_SIZE 2000 /* If fewer than MIN_GC_YIELD cells are recovered during a cell-requested garbage collection (GC), then another heap segment is allocated. */ #define MIN_GC_YIELD (heap_cells / 4) /* If fewer than MIN_MALLOC_YIELD cells are free after a malloc-requested garbage collection (GC), then the mtrigger limit is raised. */ #define MIN_MALLOC_YIELD (mtrigger / 8) /* NUM_HASH_BUCKETS is the number of symbol hash table buckets. */ #define NUM_HASH_BUCKETS 137 #ifdef IN_CONTINUE_C # include "scm.h" # define malloc(size) must_malloc((long)(size), s_cont) # define free(obj) must_free((char *)(obj), 0) #endif /* other.dynenv and other.parent get GCed just by being there. */ struct scm_other {SCM dynenv; SCM parent; #ifdef RECKLESS SCM stkframe[2]; #else SCM stkframe[4]; #endif SCM estk; SCM *estk_ptr; }; #define CONTINUATION_OTHER struct scm_other #define CONT(x) ((CONTINUATION *)CDR(x)) #define SETCONT SETCDR void dowinds P((SCM to)); #include "continue.h" typedef struct safeport { SCM port; jmp_buf jmpbuf; /* The usual C jmp_buf, not SCM's jump_buf */ int ccnt; } safeport; #define SAFEP_JMPBUF(sfp) (((safeport *)STREAM(sfp))->jmpbuf) scm-5e5/scmmain.c0000644001705200017500000001176210750224557011643 0ustar tbtb/* "scmmain.c" main() for SCM. * Copyright (C) 1990-1999 Free Software Foundation, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see * . */ /* Author: Aubrey Jaffer */ /* added by Dai Inukai 2001-03-21*/ #ifdef __FreeBSD__ # include #endif #ifdef _WIN32 # include #endif #include "scm.h" #include "patchlvl.h" #ifdef __IBMC__ # include #endif #ifdef __NetBSD__ # include #endif #ifdef __OpenBSD__ # include #endif #ifndef GENERIC_NAME # define GENERIC_NAME "scm" #endif #ifndef INIT_GETENV # define INIT_GETENV "SCM_INIT_PATH" #endif char *scm_find_implpath(execpath) const char *execpath; { char *implpath = 0; #ifndef nosve # ifndef POCKETCONSOLE char *getenvpath = getenv(INIT_GETENV); /* fprintf(stderr, "%s=%s\n", INIT_GETENV, getenvpath); fflush(stderr); */ if (getenvpath) implpath = scm_cat_path(0L, getenvpath, 0L); if (implpath) {/* The value of the environment variable supersedes other locations, only if the file exists. */ implpath = scm_try_path(implpath); if (!implpath) { fputs("Value of "INIT_GETENV" (=\"", stderr); fputs(getenvpath, stderr); fputs("\") not found; Trying elsewhere\n", stderr); } } # endif #endif if (!implpath && execpath) implpath = find_impl_file(execpath, GENERIC_NAME, INIT_FILE_NAME, dirsep); #ifdef IMPLINIT if (!implpath) implpath = scm_cat_path(0L, IMPLINIT, 0L); #endif return implpath; } const char * const generic_name[] = { GENERIC_NAME }; #ifdef WINSIGNALS SCM_EXPORT HANDLE scm_hMainThread; #endif void scmmain_init_user_scm(); int main(argc, argv) int argc; const char **argv; { char *script_arg = 0; /* location of SCSH style script file or 0. */ char *implpath = 0, **nargv; int nargc, iverbose = 0, buf0stdin; SCM retval; /* added by Dai Inukai 2001-03-21 */ #ifdef __FreeBSD__ fp_prec_t fpspec; #endif #ifdef WINSIGNALS /* need a handle to access the main thread from the signal handler thread */ DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &scm_hMainThread, 0, TRUE, DUPLICATE_SAME_ACCESS); #endif /* {char ** argvv = argv; */ /* for (;*argvv;argvv++) {fputs(*argvv, stderr); fputs(" ", stderr);} */ /* fputs("\n", stderr);} */ init_user_scm = scmmain_init_user_scm; if (0==argc) {argc = 1; argv = generic_name;} /* for macintosh */ #ifndef LACK_SBRK init_sbrk(); /* Do this before malloc()s. */ #endif /* added by Dai Inukai 2001-03-21 */ #ifdef __FreeBSD__ fpspec = fpsetprec(FP_PE); /* IEEE 64 bit FP mantissa*/ #endif execpath = 0; /* even when dumped */ if ((nargv = script_process_argv(argc, argv))) { /* SCSH style scripts */ script_arg = argv[2]; /* Save for scm_find_execpath() call */ nargc = script_count_argv(nargv); } else {nargv = argv; nargc = argc;} /* execpath must be set to executable's path in order to use DUMP or DLD. */ execpath = scm_find_execpath(nargc, nargv, script_arg); implpath = scm_find_implpath(execpath); if (isatty(fileno(stdin)) && isatty(fileno(stdout))) iverbose = (nargc <= 1) ? 2 : 1; buf0stdin = init_buf0(stdin); do { /* You must call scm_init_from_argv() or init_scm() to initialize SCM */ scm_init_from_argv(nargc, nargv, script_arg, iverbose, buf0stdin); init_signals(); /* signals are optional */ /* Now we are ready to run Scheme code! */ retval = scm_top_level(implpath, 0L); restore_signals(); /* signals are optional */ /* final_scm() when you are done with SCM. */ if (retval) break; dumped = 0; if (2 <= iverbose) fputs(";RESTART\n", stderr); final_scm(!0); } while (!0); final_scm( #ifdef CAREFUL_INTS 1 #else 1 /* freeall || (2 <= verbose) */ /* Free storage when we're done. */ #endif ); if (2 <= iverbose) fputs(";EXIT\n", stderr); fflush(stderr); if (implpath) free(implpath); if (execpath) free(execpath); execpath = 0; /* added by Dai Inukai 2001-03-27 */ #ifdef __FreeBSD__ fpspec = fpsetprec(fpspec); /* Set back to FP_PD which is 53 bit FP. */ /* This may not be needed because the */ /* kernel is set to FP_PD by default. */ #endif return (int)INUM(retval); } /* init_user_scm() is called by the scheme procedure SCM_INIT_EXTENSIONS in "Init5xx.scm" */ void scmmain_init_user_scm() { /* Put calls to your C initialization routines here. */ } scm-5e5/Xlibscm.texi0000644001705200017500000024131610722074036012336 0ustar tbtb\input texinfo @c -*-texinfo-*- @c %**start of header @setfilename XlibScm.info @settitle XlibScm @include version.txi @setchapternewpage on @c Choices for setchapternewpage are {on,off,odd}. @paragraphindent 0 @defcodeindex ft @syncodeindex ft cp @c %**end of header @copying @noindent This manual documents the X Interface for SCM Language (version @value{SCMVERSION}, @value{SCMDATE}). @noindent Copyright @copyright{} 1999 Free Software Foundation, Inc. @quotation Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the author. @end quotation @end copying @dircategory The Algorithmic Language Scheme @direntry * XlibScm: (XlibScm). SCM Language X Interface. @end direntry @iftex @finalout @c DL: lose the egregious vertical whitespace, esp. around examples @c but paras in @defun-like things don't have parindent @parskip 4pt plus 1pt @end iftex @titlepage @title XlibScm @subtitle SCM Language X Interface @subtitle Version @value{SCMVERSION} @author Aubrey Jaffer @page @vskip 0pt plus 1filll @insertcopying @end titlepage @contents @ifnottex @node Top, XlibScm, (dir), (dir) @top XlibScm @insertcopying @menu * XlibScm:: * Display and Screens:: * Drawables:: * Graphics Context:: * Cursor:: * Colormap:: * Rendering:: * Images:: * Event:: * Indexes:: @end menu @end ifnottex @node XlibScm, Display and Screens, Top, Top @chapter XlibScm @dfn{XlibScm} is a SCM interface to @dfn{X}. @cindex X The @ifset html @end ifset X Window System @ifset html @end ifset is a network-transparent window system that was designed at MIT. @ifset html @end ifset SCM @ifset html @end ifset is a portable Scheme implementation written in C. The interface can be compiled into SCM or, on those platforms supporting dynamic linking, compiled separately and loaded with @code{(require 'Xlib)}. @ftindex Xlib @iftex @noindent The most recent information about SCM can be found on SCM's @dfn{WWW} home page: @center @url{http://swiss.csail.mit.edu/~jaffer/SCM} @end iftex Much of this X documentation is dervied from: @center Xlib - C Language X Interface @center X Consortium Standard @center X Version 11, Release 6.3 The X Window System is a trademark of X Consortium, Inc. TekHVC is a trademark of Tektronix, Inc. Copyright (C) 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1994, 1996 X Consortium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium. Copyright (C) 1985, 1986, 1987, 1988, 1989, 1990, 1991 by Digital Equipment Corporation Portions Copyright (C) 1990, 1991 by Tektronix, Inc. Permission to use, copy, modify and distribute this documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appears in all copies and that both that copyright notice and this permission notice appear in all copies, and that the names of Digital and Tektronix not be used in in advertising or publicity pertaining to this documentation without specific, written prior permission. Digital and Tektronix makes no representations about the suitability of this documentation for any purpose. It is provided ``as is'' without express or implied warranty. @node Display and Screens, Drawables, XlibScm, Top @chapter Display and Screens @defun x:open-display display-name @var{display-name} Specifies the hardware display name, which determines the display and communications domain to be used. On a POSIX-conformant system, if the display-name is #f, it defaults to the value of the @var{DISPLAY} environment variable. The encoding and interpretation of @var{display-name} is implementation-dependent. On POSIX-conformant systems, the @var{display-name} or @var{DISPLAY} environment variable can be a string in the format: @defspec hostname:number.screen-number @var{hostname} specifies the name of the host machine on which the display is physically attached. Follow the @var{hostname} with either a single colon (:) or a double colon (::). @var{number} specifies the number of the display server on that host machine. You may optionally follow this display number with a period (.). A single CPU can have more than one display. Multiple displays are usually numbered starting with zero. @var{screen-number} specifies the screen to be used on that server. Multiple screens can be controlled by a single X server. The @var{screen-number} sets an internal variable that can be accessed by using the x:default-screen procedure. @end defspec @end defun @defun x:close display @var{display} specifies the connection to the X server. The @code{x:close} function closes the connection to the X server for the @var{display} specified and destroys all windows, resource IDs (Window, Font, Pixmap, Colormap, Cursor, and GContext), or other resources that the client has created on this display, unless the close-down mode of the resource has been changed (see @code{x:set-close-down-mode}). Therefore, these windows, resource IDs, and other resources should not be used again or an error will be generated. Before exiting, you should call @var{x:close-display} or @var{x:flush} explicitly so that any pending errors are reported. @end defun @defun x:protocol-version display Returns cons of the major version number (11) of the X protocol associated with the connected @var{display} and the minor protocol revision number of the X server. @end defun @defun x:server-vendor display Returns a string that provides some identification of the owner of the X server implementation. The contents of the string are implementation-dependent. @end defun @defun x:vendor-release display Returns a number related to a vendor's release of the X server. @end defun A display consists of one or more @dfn{Screen}s. Each screen has a @dfn{root-window}, @dfn{default-graphics-context}, and @dfn{colormap}. @defun x:screen-count display Returns the number of available screens. @end defun @defun x:default-screen display Returns the default screen number specified by the @code{x:open-display} function. Use this screen number in applications which will use only a single screen. @end defun @defun x:root-window display screen-number @defunx x:root-window display @var{screen-number}, if givien, specifies the appropriate screen number on the host server. Otherwise the default-screen for @var{display} is used. Returns the root window for the specified @var{screen-number}. Use @code{x:root-window} for functions that need a drawable of a particular screen or for creating top-level windows. @defunx x:root-window window Returns the root window for the specified @var{window}'s screen. @end defun @defun x:default-colormap display screen-number @defunx x:default-colormap display @defunx x:default-colormap window Returns the default colormap of the specified screen. @end defun @defun x:default-ccc display screen-number @defunx x:default-ccc display @defunx x:default-ccc window Returns the default Color-Conversion-Context (ccc) of the specified screen. @end defun @defun x:default-gc display screen-number @defunx x:default-gc display @defunx x:default-gc window Returns the default graphics-context of the specified screen. @end defun @defun x:screen-depths display screen-number @defunx x:screen-depths display @defunx x:screen-depths window Returns an array of depths supported by the specified screen. @end defun The @dfn{Visual} type describes possible colormap depths and arrangements. @defun x:default-visual display screen-number @defunx x:default-visual display @defunx x:default-visual window Returns the default Visual type for the specified screen. @cindex visual @cindex Visual @end defun @defun x:make-visual display depth class @defunx x:make-visual window depth class The integer @var{depth} specifies the number of bits per pixel. The @var{class} argument specifies one of the possible visual classes for a screen: @itemize @bullet @item x:Static-Gray @item x:Static-Color @item x:True-Color @item x:Gray-Scale @item x:Pseudo-Color @item x:Direct-Color @end itemize @code{X:make-visual} returns a visual type for the screen specified by @var{display} or @var{window} if successful; #f if not. @end defun @defun x:visual-class visual @defunx x:visual-class screen @defunx x:visual-class display Returns the (integer) visual class of its argument. @end defun @defun x:visual-geometry visual @defunx x:visual-geometry screen @defunx x:visual-geometry display Returns a list of the: @itemize @bullet @item red_mask @item green_mask @item blue_mask @item colormap_size @end itemize @end defun @defun x:screen-cells display screen-number @defunx x:screen-cells display @defunx x:screen-cells window Returns the number of entries in the default colormap. @end defun @defun x:screen-depth display screen-number Returns the depth of the root window of the specified screen. @defunx x:screen-depth display @defunx x:screen-depth window @defunx x:screen-depth visual Returns the depth of argument. @cindex depth The @dfn{depth} of a window or pixmap is the number of bits per pixel it has. The @dfn{depth} of a graphics context is the depth of the drawables it can be used in conjunction with graphics output. @end defun @defun x:screen-size display screen-number @defunx x:screen-size display @defunx x:screen-size window Returns a list of integer height and width of the screen in pixels. @end defun @defun x:screen-dimensions display screen-number @defunx x:screen-dimensions display @defunx x:screen-dimensions window Returns a list of integer height and width of the screen in millimeters. @end defun @defun x:screen-white display screen-number @defunx x:screen-white display @defunx x:screen-white window Returns the white pixel value of the specified screen. @end defun @defun x:screen-black display screen-number @defunx x:screen-black display @defunx x:screen-black window Returns the black pixel value of the specified screen. @end defun @node Drawables, Graphics Context, Display and Screens, Top @chapter Drawables @cindex Drawable @cindex drawable A @dfn{Drawable} is either a window or pixmap. @menu * Windows and Pixmaps:: * Window Attributes:: * Window Properties and Visibility:: @end menu @node Windows and Pixmaps, Window Attributes, Drawables, Drawables @section Windows and Pixmaps @defun x:create-window window position size border-width depth class visual field-name value @dots{} Creates and returns an unmapped Input-Output subwindow for a specified parent @var{window} and causes the X server to generate a CreateNotify event. The created window is placed on top in the stacking order with respect to siblings. Any part of the window that extends outside its parent @var{window} is clipped. The @var{border-width} for an x:Input-Only window must be zero. The coordinate system has the X axis horizontal and the Y axis vertical with the origin [0, 0] at the upper-left corner. Coordinates are integral, in terms of pixels, and coincide with pixel centers. Each window and pixmap has its own coordinate system. For a window, the origin is inside the border at the inside, upper-left corner. @var{Class} can be x:Input-Output, x:Input-Only, or x:Copy-From-Parent. For class x:Input-Output, the @var{visual} type and @var{depth} must be a combination supported for the screen. The @var{depth} need not be the same as the parent, but the parent must not be a window of class x:Input-Only. For an x:Input-Only window, the @var{depth} must be zero, and the @var{visual} must be one supported by the screen. The returned window will have the attributes specified by @var{field-name}s and @var{value}. @defunx x:create-window window position size border-width border background The returned window inherits its depth, class, and visual from its parent. All other window attributes, except @var{background} and @var{border}, have their default values. @end defun @defun x:create-pixmap drawable size depth @defunx x:create-pixmap display size depth @var{size} is a list, vector, or pair of nonzero integers specifying the width and height desired in the new pixmap. @var{x:create-pixmap} returns a new pixmap of the width, height, and @var{depth} specified. It is valid to pass an x:Input-Only window to the drawable argument. The @var{depth} argument must be one of the depths supported by the screen of the specified @var{drawable}. @end defun @defun x:close window Destroys the specified @var{window} as well as all of its subwindows and causes the X server to generate a DestroyNotify event for each window. The window should not be used again. If the window specified by the @var{window} argument is mapped, it is unmapped automatically. The ordering of the DestroyNotify events is such that for any given window being destroyed, DestroyNotify is generated on any inferiors of the window before being generated on the window itself. The ordering among siblings and across subhierarchies is not otherwise constrained. If the @var{window} you specified is a root window, an error is signaled. Destroying a mapped @var{window} will generate x:Expose events on other windows that were obscured by the window being destroyed. @end defun @defun x:close pixmap Deletes the association between the @var{pixmap} and its storage. The X server frees the pixmap storage when there are no references to it. @end defun @defun x:window-geometry drawable Returns a list of: @table @asis @item coordinates @code{list} of x and y coordinates that define the location of the @var{drawable}. For a window, these coordinates specify the upper-left outer corner relative to its parent's origin. For pixmaps, these coordinates are always zero. @item size @code{list} of the @var{drawable}'s dimensions (width and height). For a window, these dimensions specify the inside size, not including the border. @item border-width The border width in pixels. If the @var{drawable} is a pixmap, this is zero. @item depth The depth of the @var{drawable} (bits per pixel for the object). @end table @end defun @defun x:window-geometry-set! window field-name value @dots{} Changes the @dfn{Configuration} components specified by @var{field-name}s for the specified @var{window}. @end defun @noindent These are the attributes settable by @code{x:window-geometry-set!}. That these attributes are encoded by small integers -- just like those of the next section. Be warned therefore that confusion of attribute names will likely not signal errors, just cause mysterious behavior. @defvr Attribute x:CWX @defvrx Attribute x:CWY @defvrx Attribute x:CW-Width @defvrx Attribute x:CW-Height The x:CWX and x:CYY members are used to set the window's x and y coordinates, which are relative to the parent's origin and indicate the position of the upper-left outer corner of the window. The x:CW-Width and x:CW-Height members are used to set the inside size of the window, not including the border, and must be nonzero. Attempts to configure a root window have no effect. If a window's size actually changes, the window's subwindows move according to their window gravity. Depending on the window's bit gravity, the contents of the window also may be moved @end defvr @defvr Attribute x:CW-Border-Width The integer x:CW-Border-Width is used to set the width of the border in pixels. Note that setting just the border width leaves the outer-left corner of the window in a fixed position but moves the absolute position of the window's origin. It is an error to set the border-width attribute of an InputOnly window nonzero. @end defvr @defvr Attribute x:CW-Sibling The sibling member is used to set the sibling window for stacking operations. @end defvr @defvr Attribute x:CW-Stack-Mode The x:CW-Stack-Mode member is used to set how the window is to be restacked and can be set to x:Above, x:Below, x:Top-If, x:Bottom-If, or x:Opposite. @end defvr @noindent If a sibling and a stack-mode are specified, the window is restacked as follows: @table @code @item x:Above The window is placed just above the sibling. @item x:Below The window is placed just below the sibling. @item x:Top-If If the sibling occludes the window, the window is placed at the top of the stack. @item x:Bottom-If If the window occludes the sibling, the window is placed at the bottom of the stack. @item x:Opposite If the sibling occludes the window, the window is placed at the top of the stack. If the window occludes the sibling, the window is placed at the bottom of the stack. @end table @noindent If a stack-mode is specified but no sibling is specified, the window is restacked as follows: @table @code @item x:Above The window is placed at the top of the stack. @item x:Below The window is placed at the bottom of the stack. @item x:Top-If If any sibling occludes the window, the window is placed at the top of the stack. @item x:Bottom-If If the window occludes any sibling, the window is placed at the bottom of the stack. @item x:Opposite If any sibling occludes the window, the window is placed at the top of the stack. If the window occludes any sibling, the window is placed at the bottom of the stack. @end table @node Window Attributes, Window Properties and Visibility, Windows and Pixmaps, Drawables @section Window Attributes @defun x:window-set! window field-name value @dots{} Changes the components specified by @var{field-name}s for the specified @var{window}. The restrictions are the same as for @code{x:create-window}. The order in which components are verified and altered is server dependent. If an error occurs, a subset of the components may have been altered. @end defun @noindent The @code{x:create-window} and @code{x:window-set!} procedures take five and one argument (respectively) followed by pairs of arguments, where the first is one of the property-name symbols (or its top-level value) listed below; and the second is the value to associate with that property. @defvr Attribute x:CW-Back-Pixmap Sets the background pixmap of the @var{window} to the specified pixmap. The background pixmap can immediately be freed if no further explicit references to it are to be made. If x:Parent-Relative is specified, the background pixmap of the window's parent is used, or on the root window, the default background is restored. It is an error to perform this operation on an x:Input-Only window. If the background is set to #f or None, the window has no defined background. @end defvr @defvr Attribute x:CW-Back-Pixel Sets the background of the @var{window} to the specified pixel value. Changing the background does not cause the @var{window} contents to be changed. It is an error to perform this operation on an x:Input-Only window. @end defvr @defvr Attribute x:CW-Border-Pixmap Sets the border pixmap of the @var{window} to the pixmap you specify. The border pixmap can be freed if no further explicit references to it are to be made. If you specify x:Copy-From-Parent, a copy of the parent window's border pixmap is used. It is an error to perform this operation on an x:Input-Only @var{window}. @end defvr @defvr Attribute x:CW-Border-Pixel Sets the border of the @var{window} to the pixel @var{value}. It is an error to perform this operation on an x:Input-Only window. @end defvr @defvr Attribute x:CW-Bit-Gravity @defvrx Attribute x:CW-Win-Gravity The bit gravity of a window defines which region of the window should be retained when an x:Input-Output window is resized. The default value for the bit-gravity attribute is x:Forget-Gravity. The window gravity of a window allows you to define how the x:Input-Output or x:Input-Only window should be repositioned if its parent is resized. The default value for the win-gravity attribute is x:North-West-Gravity. If the inside width or height of a window is not changed and if the window is moved or its border is changed, then the contents of the window are not lost but move with the window. Changing the inside width or height of the window causes its contents to be moved or lost (depending on the bit-gravity of the window) and causes children to be reconfigured (depending on their win-gravity). For a change of width and height, the (x, y) pairs are defined: @multitable @columnfractions .5 .5 @item Gravity Direction @tab Coordinates @item x:North-West-Gravity @tab (0, 0) @item x:North-Gravity @tab (Width/2, 0) @item x:North-East-Gravity @tab (Width, 0) @item x:West-Gravity @tab (0, Height/2) @item x:Center-Gravity @tab (Width/2, Height/2) @item x:East-Gravity @tab (Width, Height/2) @item x:South-West-Gravity @tab (0, Height) @item x:South-Gravity @tab (Width/2, Height) @item x:South-East-Gravity @tab (Width, Height) @end multitable When a window with one of these bit-gravity values is resized, the corresponding pair defines the change in position of each pixel in the window. When a window with one of these win-gravities has its parent window resized, the corresponding pair defines the change in position of the window within the parent. When a window is so repositioned, a x:Gravity-Notify event is generated (see section 10.10.5). A bit-gravity of x:Static-Gravity indicates that the contents or origin should not move relative to the origin of the root window. If the change in size of the window is coupled with a change in position (x, y), then for bit-gravity the change in position of each pixel is (-x, -y), and for win-gravity the change in position of a child when its parent is so resized is (-x, -y). Note that x:Static-Gravity still only takes effect when the width or height of the window is changed, not when the window is moved. A bit-gravity of x:Forget-Gravity indicates that the window's contents are always discarded after a size change, even if a backing store or save under has been requested. The window is tiled with its background and zero or more x:Expose events are generated. If no background is defined, the existing screen contents are not altered. Some X servers may also ignore the specified bit-gravity and always generate x:Expose events. The contents and borders of inferiors are not affected by their parent's bit-gravity. A server is permitted to ignore the specified bit-gravity and use x:Forget-Gravity instead. A win-gravity of x:Unmap-Gravity is like x:North-West-Gravity (the window is not moved), except the child is also unmapped when the parent is resized, and an x:Unmap-Notify event is generated. @end defvr @defvr Attribute x:CW-Backing-Store Some implementations of the X server may choose to maintain the contents of x:Input-Output windows. If the X server maintains the contents of a window, the off-screen saved pixels are known as backing store. The backing store advises the X server on what to do with the contents of a window. The backing-store attribute can be set to x:Not-Useful (default), x:When-Mapped, or x:Always. A backing-store attribute of x:Not-Useful advises the X server that maintaining contents is unnecessary, although some X implementations may still choose to maintain contents and, therefore, not generate x:Expose events. A backing-store attribute of x:When-Mapped advises the X server that maintaining contents of obscured regions when the window is mapped would be beneficial. In this case, the server may generate an x:Expose event when the window is created. A backing-store attribute of x:Always advises the X server that maintaining contents even when the window is unmapped would be beneficial. Even if the window is larger than its parent, this is a request to the X server to maintain complete contents, not just the region within the parent window boundaries. While the X server maintains the window's contents, x:Expose events normally are not generated, but the X server may stop maintaining contents at any time. When the contents of obscured regions of a window are being maintained, regions obscured by noninferior windows are included in the destination of graphics requests (and source, when the window is the source). However, regions obscured by inferior windows are not included. @end defvr @defvr Attribute x:CW-Backing-Planes @defvrx Attribute x:CW-Backing-Pixel You can set backing planes to indicate (with bits set to 1) which bit planes of an x:Input-Output window hold dynamic data that must be preserved in backing store and during save unders. The default value for the backing-planes attribute is all bits set to 1. You can set backing pixel to specify what bits to use in planes not covered by backing planes. The default value for the backing-pixel attribute is all bits set to 0. The X server is free to save only the specified bit planes in the backing store or the save under and is free to regenerate the remaining planes with the specified pixel value. Any extraneous bits in these values (that is, those bits beyond the specified depth of the window) may be simply ignored. If you request backing store or save unders, you should use these members to minimize the amount of off-screen memory required to store your window. @end defvr @defvr Attribute x:CW-Override-Redirect To control window placement or to add decoration, a window manager often needs to intercept (redirect) any map or configure request. Pop-up windows, however, often need to be mapped without a window manager getting in the way. To control whether an x:Input-Output or x:Input-Only window is to ignore these structure control facilities, use the override-redirect flag. The override-redirect flag specifies whether map and configure requests on this window should override a x:Substructure-Redirect-Mask on the parent. You can set the override-redirect flag to #t or #f (default). Window managers use this information to avoid tampering with pop-up windows. @end defvr @defvr Attribute x:CW-Save-Under Some server implementations may preserve contents of x:Input-Output windows under other x:Input-Output windows. This is not the same as preserving the contents of a window for you. You may get better visual appeal if transient windows (for example, pop-up menus) request that the system preserve the screen contents under them, so the temporarily obscured applications do not have to repaint. You can set the save-under flag to True or False (default). If save-under is True, the X server is advised that, when this window is mapped, saving the contents of windows it obscures would be beneficial. @end defvr @defvr Attribute x:CW-Event-Mask The event mask defines which events the client is interested in for this x:Input-Output or x:Input-Only window (or, for some event types, inferiors of this window). The event mask is the bitwise inclusive OR of zero or more of the valid event mask bits. You can specify that no maskable events are reported by setting x:No-Event-Mask (default). The following table lists the event mask constants you can pass to the event-mask argument and the circumstances in which you would want to specify the event mask: @multitable @columnfractions .45 .55 @item Event Mask @tab Circumstances @item x:No-Event-Mask @tab No events wanted @item x:Key-Press-Mask @tab Keyboard down events wanted @item x:Key-Release-Mask @tab Keyboard up events wanted @item x:Button-Press-Mask @tab Pointer button down events wanted @item x:Button-Release-Mask @tab Pointer button up events wanted @item x:Enter-Window-Mask @tab Pointer window entry events wanted @item x:Leave-Window-Mask @tab Pointer window leave events wanted @item x:Pointer-Motion-Mask @tab Pointer motion events wanted @item x:Pointer-Motion-Hint-Mask @tab If x:Pointer-Motion-Hint-Mask is selected in combination with one or more motion-masks, the X server is free to send only one x:Motion-Notify event (with the is_hint member of the X:Pointer-Moved-Event structure set to x:Notify-Hint) to the client for the event window, until either the key or button state changes, the pointer leaves the event window, or the client calls X:Query-Pointer or X:Get-Motion-Events. The server still may send x:Motion-Notify events without is_hint set to x:Notify-Hint. @item x:Button1-Motion-Mask @tab Pointer motion while button 1 down @item x:Button2-Motion-Mask @tab Pointer motion while button 2 down @item x:Button3-Motion-Mask @tab Pointer motion while button 3 down @item x:Button4-Motion-Mask @tab Pointer motion while button 4 down @item x:Button5-Motion-Mask @tab Pointer motion while button 5 down @item x:Button-Motion-Mask @tab Pointer motion while any button down @item x:Keymap-State-Mask @tab Keyboard state wanted at window entry and focus in @item x:Exposure-Mask @tab Any exposure wanted @item x:Visibility-Change-Mask @tab Any change in visibility wanted @item x:Structure-Notify-Mask @tab Any change in window structure wanted @item x:Resize-Redirect-Mask @tab Redirect resize of this window @item x:Substructure-Notify-Mask @tab Substructure notification wanted @item x:Substructure-Redirect-Mask @tab Redirect structure requests on children @item x:Focus-Change-Mask @tab Any change in input focus wanted @item x:Property-Change-Mask @tab Any change in property wanted @item x:Colormap-Change--Mask @tab Any change in colormap wanted @item x:Owner-Grab-Button--Mask @tab Automatic grabs should activate with owner_events set to True @end multitable @end defvr @defvr Attribute x:CW-Dont-Propagate The do-not-propagate-mask attribute defines which events should not be propagated to ancestor windows when no client has the event type selected in this x:Input-Output or x:Input-Only window. The do-not-propagate-mask is the bitwise inclusive OR of zero or more of the following masks: x:Key-Press, x:Key-Release, x:Button-Press, x:Button-Release, x:Pointer-Motion, x:Button1Motion, x:Button2Motion, x:Button3Motion, x:Button4Motion, x:Button5Motion, and x:Button-Motion. You can specify that all events are propagated by setting x:No-Event-Mask (default). @end defvr @defvr Attribute x:CW-Colormap The colormap attribute specifies which colormap best reflects the true colors of the x:Input-Output window. The colormap must have the same visual type as the window. X servers capable of supporting multiple hardware colormaps can use this information, and window managers can use it for calls to X:Install-Colormap. You can set the colormap attribute to a colormap or to x:Copy-From-Parent (default). If you set the colormap to x:Copy-From-Parent, the parent window's colormap is copied and used by its child. However, the child window must have the same visual type as the parent. The parent window must not have a colormap of x:None. The colormap is copied by sharing the colormap object between the child and parent, not by making a complete copy of the colormap contents. Subsequent changes to the parent window's colormap attribute do not affect the child window. @end defvr @defvr Attribute x:CW-Cursor The cursor attribute specifies which cursor is to be used when the pointer is in the x:Input-Output or x:Input-Only window. You can set the cursor to a cursor or x:None (default). If you set the cursor to x:None, the parent's cursor is used when the pointer is in the x:Input-Output or x:Input-Only window, and any change in the parent's cursor will cause an immediate change in the displayed cursor. On the root window, the default cursor is restored. @end defvr @defun x:window-ref window field-name @dots{} Returns a list of the components specified by @var{field-name}s for the specified @var{window}. Allowable @var{field-name}s are a subset of those for @code{x:window-set!}: @itemize @bullet @item x:CW-Back-Pixel @item x:CW-Bit-Gravity @item x:CW-Win-Gravity @item x:CW-Backing-Store @item x:CW-Backing-Planes @item x:CW-Backing-Pixel @item x:CW-Override-Redirect @item x:CW-Save-Under @item x:CW-Event-Mask @item x:CW-Dont-Propagate @item x:CW-Colormap @end itemize @end defun @node Window Properties and Visibility, , Window Attributes, Drawables @section Window Properties and Visibility @defun x:get-window-property window property Returns the (string or list of numbers) value of @var{property} of @var{window}. @defunx x:get-window-property window property #t Removes and returns the (string or list of numbers) value of @var{property} of @var{window}. @end defun @defun x:list-properties window Returns a list of the properties (strings) defined for @var{window}. @end defun @noindent In X parlance, a window which is hidden even when not obscured by other windows is @dfn{unmapped}; one which @cindex map @cindex unmap @cindex mapped @cindex unmapped shows is @dfn{mapped}. It is an unfortunate name-collision with Scheme, and is ingrained in the attribute names. @defun x:map-window window Maps the @var{window} and all of its subwindows that have had map requests. Mapping a window that has an unmapped ancestor does not display the window but marks it as eligible for display when the ancestor becomes mapped. Such a window is called unviewable. When all its ancestors are mapped, the window becomes viewable and will be visible on the screen if it is not obscured by another window. This function has no effect if the @var{window} is already mapped. If the override-redirect of the window is False and if some other client has selected x:Substructure-Redirect-Mask on the parent window, then the X server generates a MapRequest event, and the @code{x:map-window} function does not map the @var{window}. Otherwise, the @var{window} is mapped, and the X server generates a MapNotify event. If the @var{window} becomes viewable and no earlier contents for it are remembered, the X server tiles the @var{window} with its background. If the window's background is undefined, the existing screen contents are not altered, and the X server generates zero or more x:Expose events. If backing-store was maintained while the @var{window} was unmapped, no x:Expose events are generated. If backing-store will now be maintained, a full-window exposure is always generated. Otherwise, only visible regions may be reported. Similar tiling and exposure take place for any newly viewable inferiors. If the window is an Input-Output window, @code{x:map-window} generates x:Expose events on each Input-Output window that it causes to be displayed. If the client maps and paints the window and if the client begins processing events, the window is painted twice. To avoid this, first ask for x:Expose events and then map the window, so the client processes input events as usual. The event list will include x:Expose for each window that has appeared on the screen. The client's normal response to an x:Expose event should be to repaint the window. This method usually leads to simpler programs and to proper interaction with window managers. @end defun @defun x:map-subwindows window Maps all subwindows of a specified @var{window} in top-to-bottom stacking order. The X server generates x:Expose events on each newly displayed window. This may be much more efficient than mapping many windows one at a time because the server needs to perform much of the work only once, for all of the windows, rather than for each window. @end defun @defun x:unmap-window window Unmaps the specified @var{window} and causes the X server to generate an UnmapNotify event. If the specified @var{window} is already unmapped, @code{x:unmap-window} has no effect. Normal exposure processing on formerly obscured windows is performed. Any child window will no longer be visible until another map call is made on the parent. In other words, the subwindows are still mapped but are not visible until the parent is mapped. Unmapping a @var{window} will generate x:Expose events on windows that were formerly obscured by it. @end defun @defun x:unmap-subwindows window Unmaps all subwindows for the specified @var{window} in bottom-to-top stacking order. It causes the X server to generate an UnmapNotify event on each subwindow and x:Expose events on formerly obscured windows. Using this function is much more efficient than unmapping multiple windows one at a time because the server needs to perform much of the work only once, for all of the windows, rather than for each window. @end defun @node Graphics Context, Cursor, Drawables, Top @chapter Graphics Context @noindent Most attributes of graphics operations are stored in @dfn{GC}s. These include line width, line style, plane mask, foreground, background, tile, stipple, clipping region, end style, join style, and so on. Graphics operations (for example, drawing lines) use these values to determine the actual drawing operation. @defun x:create-gc drawable field-name value @dots{} Creates and returns graphics context. The graphics context can be used with any destination drawable having the same root and depth as the specified @var{drawable}. @end defun @defun x:gc-set! graphics-context field-name value @dots{} Changes the components specified by @var{field-name}s for the specified @var{graphics-context}. The restrictions are the same as for @code{x:create-gc}. The order in which components are verified and altered is server dependent. If an error occurs, a subset of the components may have been altered. @end defun @defun x:copy-gc-fields! gcontext-src gcontext-dst field-name @dots{} Copies the components specified by @var{field-name}s from @var{gcontext-src} to @var{gcontext-dst}. @var{Gcontext-src} and @var{gcontext-dst} must have the same root and depth. @end defun @defun x:gc-ref graphics-context field-name @dots{} Returns a list of the components specified by @var{field-name}s @dots{} from the specified @var{graphics-context}. @end defun @heading GC Attributes @noindent Both @code{x:create-gc} and @code{x:change-gc} take one argument followed by pairs of arguments, where the first is one of the property-name symbols (or its top-level value) listed below; and the second is the value to associate with that property. @defvr Attribute x:GC-Function The function attributes of a GC are used when you update a section of a drawable (the destination) with bits from somewhere else (the source). The function in a GC defines how the new destination bits are to be computed from the source bits and the old destination bits. x:G-Xcopy is typically the most useful because it will work on a color display, but special applications may use other functions, particularly in concert with particular planes of a color display. The 16 functions are: @format @t{ x:G-Xclear 0 x:G-Xand (AND src dst) x:G-Xand-Reverse (AND src (NOT dst)) x:G-Xcopy src x:G-Xand-Inverted (AND (NOT src) dst) x:G-Xnoop dst x:G-Xxor (XOR src dst) x:G-Xor (OR src dst) x:G-Xnor (AND (NOT src) (NOT dst)) x:G-Xequiv (XOR (NOT src) dst) x:G-Xinvert (NOT dst) x:G-Xor-Reverse (OR src (NOT dst)) x:G-Xcopy-Inverted (NOT src) x:G-Xor-Inverted (OR (NOT src) dst) x:G-Xnand (OR (NOT src) (NOT dst)) x:G-Xset 1} @end format @end defvr @defvr Attribute x:GC-Plane-Mask Many graphics operations depend on either pixel values or planes in a GC. The planes attribute is an integer which specifies which planes of the destination are to be modified, one bit per plane. A monochrome display has only one plane and will be the least significant bit of the integer. As planes are added to the display hardware, they will occupy more significant bits in the plane mask. In graphics operations, given a source and destination pixel, the result is computed bitwise on corresponding bits of the pixels. That is, a Boolean operation is performed in each bit plane. The plane-mask restricts the operation to a subset of planes. @code{x:All-Planes} can be used to refer to all planes of the screen simultaneously. The result is computed by the following: @format (OR (AND (FUNC src dst) plane-mask) (AND dst (NOT plane-mask))) @end format Range checking is not performed on a plane-mask value. It is simply truncated to the appropriate number of bits. @end defvr @defvr Attribute x:GC-Foreground @defvrx Attribute x:GC-Background Range checking is not performed on the values for foreground or background. They are simply truncated to the appropriate number of bits. Note that foreground and background are not initialized to any values likely to be useful in a window. @end defvr @defvr Attribute x:GC-Line-Width The line-width is measured in pixels and either can be greater than or equal to one (wide line) or can be the special value zero (thin line). Thin lines (zero line-width) are one-pixel-wide lines drawn using an unspecified, device-dependent algorithm. There are only two constraints on this algorithm. @itemize @bullet @item If a line is drawn unclipped from [x1,y1] to [x2,y2] and if another line is drawn unclipped from [x1+dx,y1+dy] to [x2+dx,y2+dy], a point [x,y] is touched by drawing the first line if and only if the point [x+dx,y+dy] is touched by drawing the second line. @item The effective set of points comprising a line cannot be affected by clipping. That is, a point is touched in a clipped line if and only if the point lies inside the clipping region and the point would be touched by the line when drawn unclipped. @end itemize A wide line drawn from [x1,y1] to [x2,y2] always draws the same pixels as a wide line drawn from [x2,y2] to [x1,y1], not counting cap-style and join-style. It is recommended that this property be true for thin lines, but this is not required. A line-width of zero may differ from a line-width of one in which pixels are drawn. This permits the use of many manufacturers' line drawing hardware, which may run many times faster than the more precisely specified wide lines. In general, drawing a thin line will be faster than drawing a wide line of width one. However, because of their different drawing algorithms, thin lines may not mix well aesthetically with wide lines. If it is desirable to obtain precise and uniform results across all displays, a client should always use a line-width of one rather than a linewidth of zero. @end defvr @defvr Attribute x:GC-Line-Style The line-style defines which sections of a line are drawn: @table @t @item x:Line-Solid The full path of the line is drawn. @item x:Line-Double-Dash The full path of the line is drawn, but the even dashes are filled differently from the odd dashes (see fill-style) with x:Cap-Butt style used where even and odd dashes meet. @item x:Line-On-Off-Dash Only the even dashes are drawn, and cap-style applies to all internal ends of the individual dashes, except x:Cap-Not-Last is treated as x:Cap-Butt. @end table @end defvr @defvr Attribute x:GC-Cap-Style The cap-style defines how the endpoints of a path are drawn: @table @t @item x:Cap-Not-Last This is equivalent to x:Cap-Butt except that for a line-width of zero the final endpoint is not drawn. @item x:Cap-Butt The line is square at the endpoint (perpendicular to the slope of the line) with no projection beyond. @item x:Cap-Round The line has a circular arc with the diameter equal to the line-width, centered on the endpoint. (This is equivalent to x:Cap-Butt for line-width of zero). @item x:Cap-Projecting The line is square at the end, but the path continues beyond the endpoint for a distance equal to half the line-width. (This is equivalent to x:Cap-Butt for line-width of zero). @end table @end defvr @defvr Attribute x:GC-Join-Style The join-style defines how corners are drawn for wide lines: @table @t @item x:Join-Miter The outer edges of two lines extend to meet at an angle. However, if the angle is less than 11 degrees, then a x:Join-Bevel join-style is used instead. @item x:Join-Round The corner is a circular arc with the diameter equal to the line-width, centered on the x:Join-point. @item x:Join-Bevel The corner has x:Cap-Butt endpoint styles with the triangular notch filled. @end table @end defvr @defvr Attribute x:GC-Fill-Style The fill-style defines the contents of the source for line, text, and fill requests. For all text and fill requests (for example, X:Draw-Text, X:Fill-Rectangle, X:Fill-Polygon, and X:Fill-Arc); for line requests with linestyle x:Line-Solid (for example, X:Draw-Line, X:Draw-Segments, X:Draw-Rectangle, X:Draw-Arc); and for the even dashes for line requests with line-style x:Line-On-Off-Dash or x:Line-Double-Dash, the following apply: @table @t @item x:Fill-Solid Foreground @item x:Fill-Tiled Tile @item x:Fill-Opaque-Stippled A tile with the same width and height as stipple, but with background everywhere stipple has a zero and with foreground everywhere stipple has a one @item x:Fill-Stippled Foreground masked by stipple @end table When drawing lines with line-style x:Line-Double-Dash, the odd dashes are controlled by the fill-style in the following manner: @table @t @item x:Fill-Solid Background @item x:Fill-Tiled Same as for even dashes @item x:Fill-Opaque-Stippled Same as for even dashes @item x:Fill-Stippled Background masked by stipple @end table @end defvr @defvr Attribute x:GC-Fill-Rule The fill-rule defines what pixels are inside (drawn) for paths given in X:Fill-Polygon requests and can be set to x:Even-Odd-Rule or x:Winding-Rule. @table @t @item x:Even-Odd-Rule A point is inside if an infinite ray with the point as origin crosses the path an odd number of times. @item x:Winding-Rule A point is inside if an infinite ray with the point as origin crosses an unequal number of clockwise and counterclockwise directed path segments. @end table A clockwise directed path segment is one that crosses the ray from left to right as observed from the point. A counterclockwise segment is one that crosses the ray from right to left as observed from the point. The case where a directed line segment is coincident with the ray is uninteresting because you can simply choose a different ray that is not coincident with a segment. For both x:Even-Odd-Rule and x:Winding-Rule, a point is infinitely small, and the path is an infinitely thin line. A pixel is inside if the center point of the pixel is inside and the center point is not on the boundary. If the center point is on the boundary, the pixel is inside if and only if the polygon interior is immediately to its right (x increasing direction). Pixels with centers on a horizontal edge are a special case and are inside if and only if the polygon interior is immediately below (y increasing direction). @end defvr @defvr Attribute x:GC-Tile @defvrx Attribute x:GC-Stipple The tile/stipple represents an infinite two-dimensional plane, with the tile/stipple replicated in all dimensions. The tile pixmap must have the same root and depth as the GC, or an error results. The stipple pixmap must have depth one and must have the same root as the GC, or an error results. For stipple operations where the fill-style is x:Fill-Stippled but not x:Fill-Opaque-Stippled, the stipple pattern is tiled in a single plane and acts as an additional clip mask to be ANDed with the clip-mask. Although some sizes may be faster to use than others, any size pixmap can be used for tiling or stippling. @end defvr @defvr Attribute x:GC-Tile-Stip-X-Origin @defvrx Attribute x:GC-Tile-Stip-Y-Origin When the tile/stipple plane is superimposed on a drawable for use in a graphics operation, the upper-left corner of some instance of the tile/stipple is at the coordinates within the drawable specified by the tile/stipple origin. The tile/stipple origin is interpreted relative to the origin of whatever destination drawable is specified in a graphics request. @end defvr @defvr Attribute x:GC-Font The font to be used for drawing text. @end defvr @defvr Attribute x:GC-Subwindow-Mode You can set the subwindow-mode to x:Clip-By-Children or x:Include-Inferiors. @table @t @item x:Clip-By-Children Both source and destination windows are additionally clipped by all viewable Input-Output children. @item x:Include-Inferiors Neither source nor destination window is clipped by inferiors. This will result in including subwindow contents in the source and drawing through subwindow boundaries of the destination. The use of @code{x:Include-Inferiors} on a window of one depth with mapped inferiors of differing depth is not illegal, but the semantics are undefined by the core protocol. @end table @end defvr @defvr Attribute x:GC-Graphics-Exposures The graphics-exposure flag controls x:Graphics-Expose event generation for X:Copy-Area and X:Copy-Plane requests (and any similar requests defined by extensions). @end defvr @defvr Attribute x:GC-Clip-X-Origin @defvrx Attribute x:GC-Clip-Y-Origin The clip-mask origin is interpreted relative to the origin of whatever destination drawable is specified in a graphics request. @end defvr @defvr Attribute x:GC-Clip-Mask The clip-mask restricts writes to the destination drawable. If the clip-mask is set to a pixmap, it must have depth one and have the same root as the GC, or an error results. If clip-mask is set to @cindex x:None @cindex none @dfn{x:None}, the pixels are always drawn regardless of the clip origin. The clip-mask also can be set by calling @code{X:Set-Region}. Only pixels where the clip-mask has a bit set to 1 are drawn. Pixels are not drawn outside the area covered by the clip-mask or where the clip-mask has a bit set to 0. The clip-mask affects all graphics requests. The clip-mask does not clip sources. The clip-mask origin is interpreted relative to the origin of whatever destination drawable is specified in a graphics request. @end defvr @defvr Attribute x:GC-Dash-Offset Defines the phase of the pattern, specifying how many pixels into the dash-list the pattern should actually begin in any single graphics request. Dashing is continuous through path elements combined with a join-style but is reset to the dash-offset between each sequence of joined lines. The unit of measure for dashes is the same for the ordinary coordinate system. Ideally, a dash length is measured along the slope of the line, but implementations are only required to match this ideal for horizontal and vertical lines. Failing the ideal semantics, it is suggested that the length be measured along the major axis of the line. The major axis is defined as the x axis for lines drawn at an angle of between -45 and +45 degrees or between 135 and 225 degrees from the x axis. For all other lines, the major axis is the y axis. @end defvr @defvr Attribute x:GC-Dash-List There must be at least one element in the specified @var{dash-list}. The initial and alternating elements (second, fourth, and so on) of the @var{dash-list} are the even dashes, and the others are the odd dashes. Each element specifies a dash length in pixels. All of the elements must be nonzero. Specifying an odd-length list is equivalent to specifying the same list concatenated with itself to produce an even-length list. @end defvr @defvr Attribute x:GC-Arc-Mode The arc-mode controls filling in the X:Fill-Arcs function and can be set to x:Arc-Pie-Slice or x:Arc-Chord. @table @t @item x:Arc-Pie-Slice The arcs are pie-slice filled. @item x:Arc-Chord The arcs are chord filled. @end table @end defvr @node Cursor, Colormap, Graphics Context, Top @chapter Cursor @defun x:create-cursor display shape X provides a set of standard cursor shapes in a special font named @cindex cursor @dfn{cursor}. Applications are encouraged to use this interface for their cursors because the font can be customized for the individual display type. The @var{shape} argument specifies which glyph of the standard fonts to use. The hotspot comes from the information stored in the cursor font. The initial colors of a cursor are a black foreground and a white background (see X:Recolor-Cursor). The names of all cursor shapes are defined with the prefix XC: in @file{x11.scm}. @defunx x:create-cursor source-font source-char mask-font mask-char fgc bgc Creates a cursor from the source and mask bitmaps obtained from the specified font glyphs. The integer @var{source-char} must be a defined glyph in @var{source-font}. The integer @var{mask-char} must be a defined glyph in @var{mask-font}. The origins of the @var{source-char} and @var{mask-char} glyphs are positioned coincidently and define the hotspot. The @var{source-char} and @var{mask-char} need not have the same bounding box metrics, and there is no restriction on the placement of the hotspot relative to the bounding boxes. @defunx x:create-cursor source-font source-char #f #f fgc bgc If @var{mask-font} and @var{mask-char} are #f, all pixels of the source are displayed. @defunx x:create-cursor source-pixmap mask-pixmap fgc bgc origin @var{mask-pixmap} must be the same size as the pixmap defined by the @var{source-pixmap} argument. The foreground and background RGB values must be specified using @var{foreground-color} and @var{background-color}, even if the X server only has a x:Static-Gray or x:Gray-Scale screen. The hotspot must be a point within the @var{source-pixmap}. @code{X:Create-Cursor} creates and returns a cursor. The @var{foreground-color} is used for the pixels set to 1 in the source, and the @var{background-color} is used for the pixels set to 0. Both source and mask must have depth one but can have any root. The @var{mask-pixmap} defines the shape of the cursor. The pixels set to 1 in @var{mask-pixmap} define which source pixels are displayed, and the pixels set to 0 define which pixels are ignored. @defunx x:create-cursor source-pixmap #f fgc bgc origin If @var{mask-pixmap} is #f, all pixels of the source are displayed. @end defun @node Colormap, Rendering, Cursor, Top @chapter Colormap @cindex colormap @cindex RGB A @dfn{colormap} maps pixel values to @dfn{RGB} color space values. @defun x:create-colormap window visual alloc-policy @var{window} specifies the window on whose screen you want to create a colormap. @var{visual} specifies a visual type supported on the screen. @var{alloc-policy} Specifies the colormap entries to be allocated. You can pass @code{X:Alloc-None} or @code{X:Alloc-All}. The @code{X:Create-Colormap} function creates and returns a colormap of the specified @var{visual} type for the screen on which @var{window} resides. Note that @var{window} is used only to determine the screen. @table @samp @item X:Gray-Scale @item X:Pseudo-Color @item X:Direct-Color The initial values of the colormap entries are undefined. @item X:Static-Gray @item X:Static-Color @item X:True-Color The entries have defined values, but those values are specific to @var{visual} and are not defined by X. The @var{alloc-policy} must be @samp{X:Alloc-None}. @end table For the other visual classes, if @var{alloc-policy} is @samp{X:Alloc-None}, the colormap initially has no allocated entries, and clients can allocate them. If @var{alloc-policy} is @samp{X:Alloc-All}, the entire colormap is allocated writable. The initial values of all allocated entries are undefined. @table @samp @item X:Gray-Scale @item X:Pseudo-Color The effect is as if an @code{XAllocColorCells} call returned all pixel values from zero to N - 1, where N is the colormap entries value in @var{visual}. @item X:Direct-Color The effect is as if an @code{XAllocColorPlanes} call returned a pixel value of zero and red_mask, green_mask, and blue_mask values containing the same bits as the corresponding masks in the specified visual. @end table @end defun To create a new colormap when the allocation out of a previously shared colormap has failed because of resource exhaustion, use: @defun x:copy-colormap-and-free colormap Creates and returns a colormap of the same visual type and for the same screen as the specified @var{colormap}. It also moves all of the client's existing allocation from the specified @var{colormap} to the new colormap with their color values intact and their read-only or writable characteristics intact and frees those entries in the specified colormap. Color values in other entries in the new colormap are undefined. If the specified colormap was created by the client with alloc set to @samp{X:Alloc-All}, the new colormap is also created with @samp{X:Alloc-All}, all color values for all entries are copied from the specified @var{colormap}, and then all entries in the specified @var{colormap} are freed. If the specified @var{colormap} was not created by the client with @samp{X:Alloc-All}, the allocations to be moved are all those pixels and planes that have been allocated by the client and that have not been freed since they were allocated. @end defun A @dfn{colormap} maps pixel values to elements of the @dfn{RGB} datatype. An @var{RGB} is a list or vector of 3 integers, describing the red, green, and blue intensities respectively. The integers are in the range 0 - 65535. @defun x:alloc-colormap-cells colormap ncolors nplanes @defunx x:alloc-colormap-cells colormap ncolors nplanes contiguous? The @code{X:Alloc-Color-Cells} function allocates read/write color cells. The number of colors, @var{ncolors} must be positive and the number of planes, @var{nplanes} nonnegative. If @var{ncolors} and nplanes are requested, then @var{ncolors} pixels and nplane plane masks are returned. No mask will have any bits set to 1 in common with any other mask or with any of the pixels. By ORing together each pixel with zero or more masks, @var{ncolors} * 2^@var{nplanes} distinct pixels can be produced. All of these are allocated writable by the request. @table @samp @item x:Gray-Scale @item x:Pseudo-Color Each mask has exactly one bit set to 1. If @var{contiguous?} is non-false and if all masks are ORed together, a single contiguous set of bits set to 1 is formed. @item x:Direct-Color Each mask has exactly three bits set to 1. If @var{contiguous?} is non-false and if all masks are ORed together, three contiguous sets of bits set to 1 (one within each pixel subfield) is formed. @end table The RGB values of the allocated entries are undefined. @code{X:Alloc-Color-Cells} returns a list of two uniform arrays if it succeeded or #f if it failed. The first array has the pixels allocated and the second has the plane-masks. @defunx x:alloc-colormap-cells colormap ncolors rgb @defunx x:alloc-colormap-cells colormap ncolors rgb contiguous? The specified @var{ncolors} must be positive; and @var{rgb} a list or vector of 3 nonnegative integers. If @var{ncolors} colors, @var{nreds} reds, @var{ngreens} greens, and @var{nblues} blues are requested, @var{ncolors} pixels are returned; and the masks have @var{nreds}, @var{ngreens}, and @var{nblues} bits set to 1, respectively. If @var{contiguous?} is non-false, each mask will have a contiguous set of bits set to 1. No mask will have any bits set to 1 in common with any other mask or with any of the pixels. Each mask will lie within the corresponding pixel subfield. By ORing together subsets of masks with each pixel value, @var{ncolors} * 2(@var{nreds}+@var{ngreens}+@var{nblues}) distinct pixel values can be produced. All of these are allocated by the request. However, in the colormap, there are only @var{ncolors} * 2^@var{nreds} independent red entries, @var{ncolors} * 2^@var{ngreens} independent green entries, and @var{ncolors} * 2^@var{nblues} independent blue entries. @code{X:Alloc-Color-Cells} returns a list if it succeeded or #f if it failed. The first element of the list has an array of the pixels allocated. The second, third, and fourth elements are the red, green, and blue plane-masks. @end defun @defun x:free-colormap-cells colormap pixels planes @defunx x:free-colormap-cells colormap pixels Frees the cells represented by pixels whose values are in the @var{pixels} unsigned-integer uniform-vector. The @var{planes} argument should not have any bits set to 1 in common with any of the pixels. The set of all pixels is produced by ORing together subsets of the @var{planes} argument with the pixels. The request frees all of these pixels that were allocated by the client. Note that freeing an individual pixel obtained from @code{X:Alloc-Colormap-Cells} with a planes argument may not actually allow it to be reused until all of its related pixels are also freed. Similarly, a read-only entry is not actually freed until it has been freed by all clients, and if a client allocates the same read-only entry multiple times, it must free the entry that many times before the entry is actually freed. All specified pixels that are allocated by the client in the @var{colormap} are freed, even if one or more pixels produce an error. It is an error if a specified pixel is not allocated by the client (that is, is unallocated or is only allocated by another client) or if the colormap was created with all entries writable (by passing @samp{x:Alloc-All} to @code{X:Create-Colormap}). If more than one pixel is in error, the one that gets reported is arbitrary. @end defun @defun x:colormap-find-color colormap rgb @var{rgb} is a list or vector of 3 integers, describing the red, green, and blue intensities respectively; or an integer @samp{#x@i{rrggbb}}, packing red, green and blue intensities in the range 0 - 255. @defunx x:colormap-find-color colormap color-name The case-insensitive string @var{color_name} specifies the name of a color (for example, @file{red}) @code{X:Colormap-Find-Color} allocates a read-only colormap entry corresponding to the closest RGB value supported by the hardware. @code{X:Colormap-Find-Color} returns the pixel value of the color closest to the specified @var{RGB} or @var{color_name} elements supported by the hardware, if successful; otherwise @code{X:Colormap-Find-Color} returns #f. Multiple clients that request the same effective RGB value can be assigned the same read-only entry, thus allowing entries to be shared. When the last client deallocates a shared cell, it is deallocated. @end defun @defun x:color-ref colormap pixel Returns a list of 3 integers, describing the red, green, and blue intensities respectively of the @var{colormap} entry of the cell indexed by @var{pixel}. The integer @var{pixel} must be a valid index into @var{colormap}. @end defun @defun X:Color-Set! colormap pixel rgb @var{rgb} is a list or vector of 3 integers, describing the red, green, and blue intensities respectively; or an integer @samp{#x@i{rrggbb}}, packing red, green and blue intensities in the range 0 - 255. @defunx X:Color-Set! colormap pixel color-name The case-insensitive string @var{color_name} specifies the name of a color (for example, @file{red}) The integer @var{pixel} must be a valid index into @var{colormap}. @code{X:Color-Set!} changes the @var{colormap} entry of the read/write cell indexed by @var{pixel}. If the @var{colormap} is an installed map for its screen, the changes are visible immediately. @end defun @defun x:install-colormap colormap Installs the specified @var{colormap} for its associated screen. All windows associated with @var{colormap} immediately display with true colors. A colormap is associated with a window when the window is created or its attributes changed. If the specified colormap is not already an installed colormap, the X server generates a ColormapNotify event on each window that has that colormap. @end defun @defun x:ccc colormap Returns the Color-Conversion-Context of @var{colormap}. @end defun @node Rendering, Images, Colormap, Top @chapter Rendering @defun x:flush display @defunx x:flush window Flushes the output buffer. Some client applications need not use this function because the output buffer is automatically flushed as needed by calls to X:Pending, X:Next-Event, and X:Window-Event. Events generated by the server may be enqueued into the library's event queue. @defunx x:flush gc Forces sending of GC component changes. Xlib usually defers sending changes to the components of a GC to the server until a graphics function is actually called with that GC. This permits batching of component changes into a single server request. In some circumstances, however, it may be necessary for the client to explicitly force sending the changes to the server. An example might be when a protocol extension uses the GC indirectly, in such a way that the extension interface cannot know what GC will be used. @end defun @defun x:clear-area window (x-pos y-pos) (width height) expose? Paints a rectangular area in the specified @var{window} according to the specified dimensions with the @var{window}'s background pixel or pixmap. The subwindow-mode effectively is @samp{x:Clip-By-Children}. If width is zero, it is replaced with the current width of the @var{window} minus x. If height is zero, it is replaced with the current height of the @var{window} minus y. If the @var{window} has a defined background tile, the rectangle clipped by any children is filled with this tile. If the @var{window} has background x:None, the contents of the @var{window} are not changed. In either case, if @var{expose?} is True, one or more x:Expose events are generated for regions of the rectangle that are either visible or are being retained in a backing store. If you specify a @var{window} whose class is x:Input-Only, an error results. @end defun @defun x:fill-rectangle window gcontext position size @end defun @heading Draw Strings @defun x:draw-string drawable gc position string @var{Position} specifies coordinates relative to the origin of @var{drawable} of the origin of the first character to be drawn. @code{x:draw-string} draws the characters of @var{string}, starting at @var{position}. @end defun @defun x:image-string drawable gc position string @var{Position} specifies coordinates relative to the origin of @var{drawable} of the origin of the first character to be drawn. @code{x:image-string} draws the characters @emph{and background} of @var{string}, starting at @var{position}. @end defun @heading Draw Shapes @defun x:draw-points drawable gc position @dots{} @var{Position} @dots{} specifies coordinates of the point to be drawn. @defunx x:draw-points drawable gc x y @dots{} (@var{x}, @var{y}) @dots{} specifies coordinates of the point to be drawn. @defunx x:draw-points drawable gc point-array @var{point-array} is a uniform short array of rank 2, whose rightmost index spans a range of 2. The @code{X:Draw-Points} procedure uses the foreground pixel and function components of the @var{gc} to draw points into @var{drawable} at the positions (relative to the origin of @var{drawable}) specified. @code{X:Draw-Points} uses these @var{gc} components: function, planemask, foreground, subwindow-mode, clip-x-origin, clip-y-origin, and clip-mask. @end defun @defun x:draw-segments drawable gc pos1 pos2 @dots{} @var{Pos1}, @var{pos2}, @dots{} specify coordinates to be connected by segments. @defunx x:draw-segments drawable gc x1 y1 x2 y2 @dots{} (@var{x1}, @var{y1}), (@var{x2}, @var{y2}) @dots{} specify coordinates to be connected by segments. @defunx x:draw-segments drawable gc point-array @var{point-array} is a uniform short array of rank 2, whose rightmost index spans a range of 2. The @code{X:Draw-Segments} procedure uses the components of the specified @var{gc} to draw multiple unconnected lines between disjoint adjacent pair of points passed as arguments. It draws the segments in order and does not perform joining at coincident endpoints. For any given line, @code{X:Draw-Segments} does not draw a pixel more than once. If thin (zero line-width) segments intersect, the intersecting pixels are drawn multiple times. If wide segments intersect, the intersecting pixels are drawn only once, as though the entire PolyLine protocol request were a single, filled shape. @code{X:Draw-Segments} treats all coordinates as relative to the origin of @var{drawable}. @code{X:Draw-Segments} uses these @var{gc} components: function, plane-mask, line-width, line-style, cap-style, fill-style, subwindow-mode, clip-x-origin, clip-y-origin, and clip-mask, join-style. It also use these @var{gc} mode-dependent components: foreground, background, tile, stipple, tilestipple-x-origin, tile-stipple-y-origin, dash-offset, and dash-list. @end defun @defun x:draw-lines drawable gc pos1 pos2 @dots{} @var{Pos1}, @var{pos2}, @dots{} specify coordinates to be connected by lines. @defunx x:draw-lines drawable gc x1 y1 x2 y2 @dots{} (@var{x1}, @var{y1}), (@var{x2}, @var{y2}) @dots{} specify coordinates to be connected by lines. @defunx x:draw-lines drawable gc point-array @var{point-array} is a uniform short array of rank 2, whose rightmost index spans a range of 2. The @code{X:Draw-Lines} procedure uses the components of the specified @var{gc} to draw lines between each adjacent pair of points passed as arguments. It draws the lines in order. The lines join correctly at all intermediate points, and if the first and last points coincide, the first and last lines also join correctly. For any given line, @code{X:Draw-Lines} does not draw a pixel more than once. If thin (zero line-width) lines intersect, the intersecting pixels are drawn multiple times. If wide lines intersect, the intersecting pixels are drawn only once, as though the entire PolyLine protocol request were a single, filled shape. @code{X:Draw-Lines} treats all coordinates as relative to the origin of @var{drawable}. @code{X:Draw-Lines} uses these @var{gc} components: function, plane-mask, line-width, line-style, cap-style, fill-style, subwindow-mode, clip-x-origin, clip-y-origin, and clip-mask, join-style. It also use these @var{gc} mode-dependent components: foreground, background, tile, stipple, tilestipple-x-origin, tile-stipple-y-origin, dash-offset, and dash-list. @end defun @defun x:fill-polygon drawable gc pos1 pos2 @dots{} @var{Pos1}, @var{pos2}, @dots{} specify coordinates of the border path. @defunx x:fill-polygon drawable gc x1 y1 x2 y2 @dots{} (@var{x1}, @var{y1}), (@var{x2}, @var{y2}) @dots{} specify coordinates of the border path. @defunx x:fill-polygon drawable gc point-array @var{point-array} is a uniform short array of rank 2, whose rightmost index spans a range of 2. The path is closed automatically if the last point in the list or @var{point-array} does not coincide with the first point. The @code{X:Fill-Polygon} procedure uses the components of the specified @var{gc} to fill the region closed by the specified path. @code{X:Fill-Polygon} does not draw a pixel of the region more than once. @code{X:Fill-Polygon} treats all coordinates as relative to the origin of @var{drawable}. @code{X:Fill-Polygon} uses these @var{gc} components: function, planemask, fill-style, fill-rule, subwindow-mode, clip-x-origin, clip-y-origin, and clip-mask. It also use these @var{gc} mode-dependent components: foreground, background, tile, stipple, tile-stipple-x-origin, and tile-stipple-y-origin. @end defun @node Images, Event, Rendering, Top @chapter Images @defun x:read-bitmap-file drawable file @end defun @node Event, Indexes, Images, Top @chapter Event @noindent These three status routines always return immediately if there are events already in the queue. @defun x:q-length display Returns the length of the event queue for the connected @var{display}. Note that there may be more events that have not been read into the queue yet (see X:Events-Queued). @end defun @defun x:pending display Returns the number of events that have been received from the X server but have not been removed from the event queue. @end defun @defun x:events-queued display Returns the number of events already in the queue if the number is nonzero. If there are no events in the queue, @code{X:Events-Queued} attempts to read more events out of the application's connection without flushing the output buffer and returns the number read. @end defun @noindent Both of these routines return an object of type @dfn{event}. @defun x:next-event display Removes and returns the first event from the event queue. If the event queue is empty, @code{X:Next-Event} flushes the output buffer and blocks until an event is received. @end defun @defun x:peek-event display Returns the first event from the event queue, but it does not remove the event from the queue. If the queue is empty, @code{X:Peek-Event} flushes the output buffer and blocks until an event is received. @end defun @noindent Each event object has fields dependent on its sub-type. @defun x:event-ref event field-name @multitable @columnfractions .40 .60 @item window @tab The window on which @var{event} was generated and is referred to as the event window. @item root @tab is the event window's root window. @item subwindow @tab If the source window is an inferior of the event window, the @var{subwindow} is the child of the event window that is the source window or the child of the event window that is an ancestor of the source window. Otherwise, @samp{None}. @item X-event:type @tab An integer: @var{x:Key-Press}, @var{x:Key-Release}, @var{x:Button-Press}, @var{x:Button-Release}, @var{x:Motion-Notify}, @var{x:Enter-Notify}, @var{x:Leave-Notify}, @var{x:Focus-In}, @var{x:Focus-Out}, @var{x:Keymap-Notify}, @var{x:Expose}, @var{x:Graphics-Expose}, @var{x:No-Expose}, @var{x:Visibility-Notify}, @var{x:Create-Notify}, @var{x:Destroy-Notify}, @var{x:Unmap-Notify}, @var{x:Map-Notify}, @var{x:Map-Request}, @var{x:Reparent-Notify}, @var{x:Configure-Notify}, @var{x:Configure-Request}, @var{x:Gravity-Notify}, @var{x:Resize-Request}, @var{x:Circulate-Notify}, @var{x:Circulate-Request}, @var{x:Property-Notify}, @var{x:Selection-Clear}, @var{x:Selection-Request}, @var{x:Selection-Notify}, @var{x:Colormap-Notify}, @var{x:Client-Message}, or @var{x:Mapping-Notify}. @item X-event:serial @tab The serial number of the protocol request that generated the @var{event}. @item X-event:send-event @tab Boolean that indicates whether the event was sent by a different client. @item X-event:time @tab The time when the @var{event} was generated expressed in milliseconds. @item X-event:x @item X-event:y @tab For window entry/exit events the @var{x} and @var{y} members are set to the coordinates of the pointer position in the event window. This position is always the pointer's final position, not its initial position. If the event window is on the same screen as the root window, @var{x} and @var{y} are the pointer coordinates relative to the event window's origin. Otherwise, @var{x} and @var{y} are set to zero. For expose events The @var{x} and @var{y} members are set to the coordinates relative to the drawable's origin and indicate the upper-left corner of the rectangle. For configure, create, gravity, and reparent events the @var{x} and @var{y} members are set to the window's coordinates relative to the parent window's origin and indicate the position of the upper-left outside corner of the created window. @item X-event:x-root @item X-event:y-root @tab The pointer's coordinates relative to the root window's origin at the time of the @var{event}. @item X-event:state @tab For keyboard, pointer and window entry/exit events, the state member is set to indicate the logical state of the pointer buttons and modifier keys just prior to the @var{event}, which is the bitwise inclusive OR of one or more of the button or modifier key masks: @var{x:Button1-Mask}, @var{x:Button2-Mask}, @var{x:Button3-Mask}, @var{x:Button4-Mask}, @var{x:Button5-Mask}, @var{x:Shift-Mask}, @var{x:Lock-Mask}, @var{x:Control-Mask}, @var{x:Mod1-Mask}, @var{x:Mod2-Mask}, @var{x:Mod3-Mask}, @var{x:Mod4-Mask}, and @var{x:Mod5-Mask}. For visibility events, the state of the window's visibility: @var{x:Visibility-Unobscured}, @var{x:Visibility-Partially-Obscured}, or @var{x:Visibility-Fully-Obscured}. For colormap events, indicates whether the colormap is installed or uninstalled: x:Colormap-Installed or x:Colormap-Uninstalled. For property events, indicates whether the property was changed to a new value or deleted: x:Property-New-Value or x:Property-Delete. @item X-event:keycode @tab An integer that represents a physical key on the keyboard. @item X-event:same-screen @tab Indicates whether the event window is on the same screen as the root window. If #t, the event and root windows are on the same screen. If #f, the event and root windows are not on the same screen. @item X-event:button @tab The pointer button that changed state; can be the @var{x:Button1}, @var{x:Button2}, @var{x:Button3}, @var{x:Button4}, or @var{x:Button5} value. @item X-event:is-hint @tab Detail of motion-notify events: @var{x:Notify-Normal} or @var{x:Notify-Hint}. @item X-event:mode @tab Indicates whether the @var{event} is a normal event, pseudo-motion event when a grab activates, or a pseudo-motion event when a grab deactivates: @var{x:Notify-Normal}, @var{x:Notify-Grab}, or @var{x:Notify-Ungrab}. @item X-event:detail @tab Indicates the notification detail: @var{x:Notify-Ancestor}, @var{x:Notify-Virtual}, @var{x:Notify-Inferior}, @var{x:Notify-Nonlinear}, or @var{x:Notify-Nonlinear-Virtual}. @item X-event:focus @tab If the event window is the focus window or an inferior of the focus window, #t; otherwise #f. @item X-event:width @item X-event:height @tab The size (extent) of the rectangle. @item X-event:count @tab For mapping events is the number of keycodes altered. For expose events Is the number of Expose or GraphicsExpose events that are to follow. If count is zero, no more Expose events follow for this window. However, if count is nonzero, at least that number of Expose events (and possibly more) follow for this window. Simple applications that do not want to optimize redisplay by distinguishing between subareas of its window can just ignore all Expose events with nonzero counts and perform full redisplays on events with zero counts. @item X-event:major-code @tab The major_code member is set to the graphics request initiated by the client and can be either X_CopyArea or X_CopyPlane. If it is X_CopyArea, a call to XCopyArea initiated the request. If it is X_CopyPlane, a call to XCopyPlane initiated the request. @item X-event:minor-code @tab Not currently used. @item X-event:border-width @tab For configure events, the width of the window's border, in pixels. @item X-event:override-redirect @tab The override-redirect attribute of the window. Window manager clients normally should ignore this window if it is #t. @item X-event:from-configure @tab True if the event was generated as a result of a resizing of the window's parent when the window itself had a win-gravity of x:Unmap-Gravity. @item X-event:value-mask @tab Indicates which components were specified in the ConfigureWindow protocol request. The corresponding values are reported as given in the request. The remaining values are filled in from the current geometry of the window, except in the case of above (sibling) and detail (stack-mode), which are reported as None and Above, respectively, if they are not given in the request. @item X-event:place @tab The window's position after the restack occurs and is either x:Place-On-Top or x:Place-On-Bottom. If it is x:Place-On-Top, the window is now on top of all siblings. If it is x:Place-On-Bottom, the window is now below all siblings. @item X-event:new @tab indicate whether the colormap for the specified window was changed or installed or uninstalled and can be True or False. If it is True, the colormap was changed. If it is False, the colormap was installed or uninstalled. @item X-event:format @tab Is 8, 16, or 32 and specifies whether the data should be viewed as a list of bytes, shorts, or longs @item X-event:request @tab Indicates the kind of mapping change that occurred and can be @var{x:Mapping-Modifier}, @var{x:Mapping-Keyboard}, or @var{x:Mapping-Pointer}. If it is @var{x:Mapping-Modifier}, the modifier mapping was changed. If it is @var{x:Mapping-Keyboard}, the keyboard mapping was changed. If it is @var{x:Mapping-Pointer}, the pointer button mapping was changed. @item X-event:first-keycode @tab The X-event:first-keycode is set only if the X-event:request was set to @var{x:Mapping-Keyboard}. The number in X-event:first-keycode represents the first number in the range of the altered mapping, and X-event:count represents the number of keycodes altered. @end multitable @end defun @node Indexes, , Event, Top @unnumbered Indexes @menu * Procedure and Macro Index:: * Variable Index:: * Concept Index:: @end menu @node Procedure and Macro Index, Variable Index, Indexes, Indexes @unnumberedsec Procedure and Macro Index @printindex fn @node Variable Index, Concept Index, Procedure and Macro Index, Indexes @unnumberedsec Variable Index @printindex vr @node Concept Index, , Variable Index, Indexes @unnumberedsec Concept Index @printindex cp @bye scm-5e5/wbtab.scm0000644001705200017500000004335710106534121011642 0ustar tbtb;;; "wbtab.scm" database tables using WB b-trees. ; Copyright 1996, 2000, 2001, 2003 Aubrey Jaffer ; ;Permission to copy this software, to modify it, to redistribute it, ;to distribute modified versions, and to use it for any purpose is ;granted, subject to the following restrictions and understandings. ; ;1. Any copy made of this software must include this copyright notice ;in full. ; ;2. I have made no warranty or representation that the operation of ;this software will be error-free, and I am under no obligation to ;provide any services, by way of maintenance, update, or otherwise. ; ;3. In conjunction with products arising from the use of this ;material, there shall be no use of my name in any advertising, ;promotional, or sales literature without prior written consent in ;each case. ;;;; *catalog* is informed of 'wb-table binding by "scm/mkimpcat.scm". (require 'wb) (require 'byte) (require 'byte-number) (require 'relational-database) ;for make-relational-system ;;; WB-SEG:LOCKS has one extra location at end for loop end test (defvar wb-seg:locks (let ((locks (make-vector (+ 1 wb:num-segs) #f))) (do ((i (+ -2 (vector-length locks)) (+ -1 i))) ((negative? i) locks) (vector-set! locks i (make-arbiter i))))) (defvar wb-seg:files (make-vector (+ 1 wb:num-segs) #f)) (defvar wb-seg:roots (make-vector (+ 1 wb:num-segs) #f)) (defvar wb-seg:mut?s (make-vector (+ 1 wb:num-segs) #f)) ;@ (define wb-table ;; foiled indentation so etags will recognize definitions (let ((make-handle list) (handle->base-id car) (handle->bt cadr) (catalog-id 0) (free-id "") (root-name "rwb") ;;;k30 is a key-coding system where adjacent key fields are separated ;;;by a byte with value in the range 0 (^@=#\nul) to 31 (^_=#\us). ;;;Strings are prefixed with 30 and extend to the the next byte ;;;smaller than 32, or end of the key. Numbers are prefixed by the ;;;string-length of the string representation of the number up to 30. ;;;Unsigned integers with less than 31 digits will thus sort in ;;;numerical order. Larger numbers and strings will sort ;;;lexicographically. ;;; ;;;Use of bytes with values less than 32 in key fields will wedge k30. (k30:true (bytes 1 (char->integer #\T))) (k30:false (bytes 1 (char->integer #\F))) (k30:s31 (bytes 31)) (k30:s30 (bytes 30)) (k30:s1 (bytes 1 (char->integer #\1))) (k30:s0 (bytes 0))) ;;;A suffix encoding the field number (with number length prepended) ;;;is appended to composite keys. COL-FIELD computes this field. ;;;k30:s0 and k30:s1 are constants for cases 0 and 1 respectively. ;;;Note that ks30:s0 has no digits! (define (k30:incr-key prefix) (string-append prefix k30:s31)) (define (col-field i) (let ((str (number->string i))) (string-append (bytes (string-length str)) str))) (define (k30:number-keyifier n) (define str (number->string n)) (string-append (bytes (min 30 (string-length str))) str)) ;;; These two NTHCDR procedures replicate those in "comlist.scm". (define (nthcdr k list) (do ((i k (+ -1 i)) (lst list (cdr lst))) ((<= i 0) lst))) (define (butnthcdr k lst) (cond ((or (zero? k) (null? lst)) '()) (else (let ((ans (list (car lst)))) (do ((lst (cdr lst) (cdr lst)) (tail ans (cdr tail)) (k (+ -2 k) (+ -1 k))) ((or (negative? k) (null? lst)) ans) (set-cdr! tail (list (car lst)))))))) ;;;; Segments (define (find-free-seg) (do ((i 0 (+ 1 i)) (arb (vector-ref wb-seg:locks 0) (vector-ref wb-seg:locks (+ 1 i)))) ((or (not arb) (try-arbiter arb)) (and arb i)))) (define (release-seg seg) (and seg (release-arbiter (vector-ref wb-seg:locks seg)) #f)) ;;;; Create, open, write, sync, or close database. (define (seg-open-base seg filename writable?) (vector-set! wb-seg:files seg filename) (vector-set! wb-seg:mut?s seg writable?) (vector-set! wb-seg:roots seg (open-db seg root-name)) (cond ((wb:err? (vector-ref wb-seg:roots seg)) (close-base seg) #f) (else seg))) ;;; Because B-trees grow in depth only very slowly, we might as well ;;; put everything into one B-tree named "rwb". (define (make-base filename dim types) (define seg (find-free-seg)) (cond ((not seg) #f) ((wb:err? (make-seg seg filename 2048)) (release-seg seg) #f) ((wb:err? (open-seg seg filename 2)) (release-seg seg) #f) ((or (wb:err? (bt:put! (create-db seg #\T root-name) free-id "1")) (wb:err? (bt:put! (open-bt seg 0 1) "base-table" "wb-table"))) (release-seg seg) (slib:error 'make-base "couldn't modify new base" filename) #f) (else (seg-open-base seg filename #t)))) (define (open-base filename writable?) (define seg (find-free-seg)) (cond ((wb:err? (open-seg seg filename (if writable? 2 0))) (release-seg seg) #f) (else (seg-open-base seg filename writable?)))) (define (write-base seg filename) (cond ((and filename (equal? filename (vector-ref wb-seg:files seg))) (let ((status (close-seg seg #f))) (cond ((wb:err? status) #f) ((wb:err? (open-seg seg filename 2)) #f) (else #t)))) (else ;;(slib:error 'write-base "WB can't change database filename" filename) #f))) (define (sync-base seg) (and seg (write-base seg (vector-ref wb-seg:files seg)))) (define (close-base seg) (cond ((wb:err? (close-seg seg #f)) (let ((status (close-seg seg #t))) (release-seg seg) (not (wb:err? status)))) (else (release-seg seg) #t))) ;;;; Make, open, and destroy tables. (define (make-table seg dim types) (and (vector-ref wb-seg:mut?s seg) (let* ((tns (bt:rem (vector-ref wb-seg:roots seg) free-id)) (base-id (and (string? tns) (string->number tns)))) (cond ((not tns) (slib:error 'make-table 'free-id "in use?") #f) ((not base-id) (bt:put (vector-ref wb-seg:roots seg) free-id tns) (slib:error 'make-table "free-id corrupted" base-id) #f) ((not (bt:put (vector-ref wb-seg:roots seg) free-id (number->string (+ 1 base-id)))) (slib:error 'make-table "free-id lock broken") #f) (else base-id))))) ;;; OPEN-TABLE allocates a new handle (in call to open-db) so each ;;; table handle will have its own last-block-used (define (open-table seg base-id dim types) (define (base-id->prefix base-id) (define nstr (number->string base-id)) (string-append (string #\T (integer->char (string-length nstr))) nstr (string (integer->char 1) #\D))) (make-handle (base-id->prefix base-id) (open-db seg root-name))) (define (kill-table seg base-id dim types) (let* ((handle (open-table seg base-id dim types)) (prefix (handle->base-id handle))) (not (wb:err? (bt:rem* (handle->bt handle) prefix (k30:incr-key prefix)))))) ;;;; Conversions from Scheme objects into and from strings. (define (object->wb-string type) (case type ((string) identity) ((symbol) symbol->string) ((integer number ordinal) number->string) ((boolean) (lambda (b) (if b "Y" "N"))) ((c64) (lambda (x) (string-append (ieee-double->bytes (real-part x)) (ieee-double->bytes (imag-part x))))) ((c32) (lambda (x) (string-append (ieee-float->bytes (real-part x)) (ieee-float->bytes (imag-part x))))) ((r64) (lambda (x) (ieee-double->bytes x))) ((r32) (lambda (x) (ieee-single->bytes x))) ((s64) (lambda (n) (integer->bytes n -8))) ((s32) (lambda (n) (integer->bytes n -4))) ((s16) (lambda (n) (integer->bytes n -2))) (( s8) (lambda (n) (integer->bytes n -1))) ((u64) (lambda (n) (integer->bytes n 8))) ((u32) (lambda (n) (integer->bytes n 4))) ((u16) (lambda (n) (integer->bytes n 2))) (( u8) (lambda (n) (integer->bytes n 1))) ((atom) (lambda (obj) (cond ((number? obj) (number->string obj)) ((not obj) "#f") (else (symbol->string obj))))) ((expression) (lambda (obj) (call-with-output-string (lambda (port) (write obj port))))) (else #f))) (define (wb-string->object type) (case type ((string) identity) ((symbol) string->symbol) ((integer number ordinal) string->number) ((boolean) (lambda (str) (not (equal? str "N")))) ((c64) (lambda (str) (make-rectangular (bytes->ieee-double (substring str 0 8)) (bytes->ieee-double (substring str 8 16))))) ((c32) (lambda (str) (make-rectangular (bytes->ieee-float (substring str 0 4)) (bytes->ieee-float (substring str 4 8))))) ((r64) (lambda (str) (bytes->ieee-double str))) ((r32) (lambda (str) (bytes->ieee-single str))) ((s64) (lambda (str) (integer->bytes str -8))) ((s32) (lambda (str) (integer->bytes str -4))) ((s16) (lambda (str) (integer->bytes str -2))) (( s8) (lambda (str) (bytes->integer str -1))) ((u64) (lambda (str) (integer->bytes str 8))) ((u32) (lambda (str) (integer->bytes str 4))) ((u16) (lambda (str) (integer->bytes str 2))) (( u8) (lambda (str) (bytes->integer str 1))) ((atom) (lambda (str) (cond ((string->number str)) ((string-ci=? "#f" str) #f) (else (string->symbol str))))) ((expression) (lambda (str) (call-with-input-string str read))) (else #f))) (define (supported-type? type) (case type ((ordinal atom integer number boolean string symbol expression c64 c32 r64 r32 s64 s32 s16 s8 u64 u32 u16 u8) #t) (else #f))) (define (supported-key-type? type) (case type ((atom integer number symbol string boolean) #t) (else #f))) ;;;; Keys ;;; unitary composite-key maker (define (make-keyifier-1 type) (case type ((string) (lambda (s) (string-append k30:s30 s))) ((symbol) (lambda (s) (string-append k30:s30 (symbol->string s)))) ((integer number ordinal) k30:number-keyifier) ((boolean) (lambda (b) (if b k30:true k30:false))) ((atom) (lambda (obj) (cond ((not obj) k30:false) ((number? obj) (k30:number-keyifier obj)) (else (string-append k30:s30 (symbol->string obj)))))) (else (slib:error 'make-keyifier-1 'unsupported-type type)))) ;;; composite-key maker (define (make-list-keyifier prinum types) (set! types (butnthcdr prinum types)) ;; Special case when there is just one primary key. (if (= 1 prinum) (let ((proc (make-keyifier-1 (car types)))) (lambda (lst) (proc (car lst)))) (let ((procs (map make-keyifier-1 types))) (lambda (lst) (apply string-append (map (lambda (p v) (p v)) procs lst)))))) (define (k30:width type key pos kend) (define flen (byte-ref key pos)) (set! pos (+ 1 pos)) (cond ((= flen 30) (do ((i pos (+ 1 i))) ((or (>= i kend) (<= 0 (byte-ref key i) 30)) (set! flen (- i pos)))))) flen) ;;; extracts one key-field from composite-key (define (make-key-extractor primary-limit types index) (define (wbstr->obj type) (or (wb-string->object type) (slib:error 'make-key-extractor 'unsupported-type type))) (let ((proc (wbstr->obj (list-ref types (+ -1 index))))) (lambda (key) (define kend (string-length key)) (let loop ((pos 0) (argind (+ -1 index)) (types types)) (if (positive? argind) (loop (+ 1 pos (k30:width (car types) key pos kend)) (+ -1 argind) (cdr types)) (proc (substring key (+ 1 pos) (+ 1 pos (k30:width (car types) key pos kend)) ))))))) ;;; composite-key to list (define (make-key->list prinum types) (define (wbstr->obj type) (or (wb-string->object type) (slib:error 'make-key->list 'unsupported-type type))) (let ((procs (map wbstr->obj (butnthcdr prinum types)))) (lambda (key) (define kend (string-length key)) (let loop ((pos 0) (argind (+ -1 prinum)) (types types) (procs procs)) (define flen (k30:width (car types) key pos kend)) (cons ((car procs) (substring key (+ 1 pos) (+ 1 flen pos))) (if (zero? argind) '() (loop (+ 1 flen pos) (+ -1 argind) (cdr types) (cdr procs)))))))) ;;;; for-each-key, ordered-for-each-key, and map-key (define (list-of-false? lst) (cond ((null? lst) #t) ((car lst) #f) (else (list-of-false? (cdr lst))))) (define (make-key-match? key-dimension column-types match-keys) (if (list-of-false? match-keys) (lambda (ckey) #t) (let ((keyploder (make-key->list key-dimension column-types))) (lambda (ckey) (define (key-match? match-keys keys) (cond ((null? match-keys) #t) ((not (car match-keys)) (key-match? (cdr match-keys) (cdr keys))) ((equal? (car match-keys) (car keys)) (key-match? (cdr match-keys) (cdr keys))) ((not (procedure? (car match-keys))) #f) (((car match-keys) (car keys)) (key-match? (cdr match-keys) (cdr keys))) (else #f))) (key-match? match-keys (keyploder ckey)))))) (define (ordered-for-each-key handle operation key-dimension column-types match-keys) (let* ((bt (handle->bt handle)) (prefix (handle->base-id handle)) (pl (string-length prefix)) (prefix+ (k30:incr-key prefix)) (key-match? (make-key-match? key-dimension column-types match-keys)) (maproc (lambda (k v) (let ((i (+ -1 (string-length k)))) (cond ((and (char=? #\1 (string-ref k i)) (= 1 (byte-ref k (+ -1 i)))) (and (key-match? (substring k pl (+ -1 i))) (operation (substring k pl (+ -1 i))))) ((= 0 (byte-ref k i)) (and (key-match? (substring k pl i)) (operation (substring k pl i)))))) #f))) (do ((res (bt:scan bt 0 prefix prefix+ maproc 1) (bt:scan bt 0 (caddr res) prefix+ maproc 1))) ((not (= -1 (car res))))))) (define (map-key handle operation key-dimension column-types match-keys) (define lst (list 'dummy)) (let ((tail lst)) (ordered-for-each-key handle (lambda (k) (set-cdr! tail (list (operation k))) (set! tail (cdr tail))) key-dimension column-types match-keys) (cdr lst))) ;;;; getters and putters (define (make-getter prinum types) (define (wbstr->obj type) (or (wb-string->object type) (slib:error 'make-getter 'unsupported-type type))) (case (- (length types) prinum) ((0) (lambda (handle key) (and (bt:get (handle->bt handle) (string-append (handle->base-id handle) key k30:s0)) '()))) ((1) (let ((proc (wbstr->obj (list-ref types prinum)))) (lambda (handle key) (define val (bt:get (handle->bt handle) (string-append (handle->base-id handle) key k30:s1))) (and val (list (proc val)))))) (else (let ((procs (reverse (map wbstr->obj (nthcdr prinum types))))) (lambda (handle key) (let* ((bt (handle->bt handle)) (prefix (string-append (handle->base-id handle) key)) (prefix+ (k30:incr-key prefix)) (lst '()) (maproc (lambda (k v) (set! lst (cons v lst)) #t))) (do ((res (bt:scan bt 0 prefix prefix+ maproc 1) (bt:scan bt 0 (caddr res) prefix+ maproc 1))) ((not (= -1 (car res))) (and (not (zero? (cadr res))) (do ((ps procs (cdr ps)) (ls lst (cdr ls)) (rl '() (cons ((car ps) (car ls)) rl))) ((null? (cdr ls)) (cons ((car ps) (car ls)) rl)))))))))))) (define (make-putter prinum types) (define (obj->wbstr type) (or (object->wb-string type) (slib:error 'make-putter 'unsupported-type type))) (case (- (length types) prinum) ((0) (lambda (handle ckey restcols) (bt:put! (handle->bt handle) (string-append (handle->base-id handle) ckey k30:s0) ""))) ((1) (let ((proc (obj->wbstr (list-ref types prinum)))) (lambda (handle ckey restcols) (bt:put! (handle->bt handle) (string-append (handle->base-id handle) ckey k30:s1) (proc (car restcols)))))) (else (let ((procs (map obj->wbstr (nthcdr prinum types)))) (lambda (handle ckey restcols) (define i 0) (for-each (lambda (proc val) (set! i (+ 1 i)) (cond ((wb:err? (bt:put! (handle->bt handle) (string-append (handle->base-id handle) ckey (col-field i)) (proc val))) (slib:error 'putter "couldn't put" (string-append (handle->base-id handle) ckey (col-field i)) (proc val))))) procs restcols)))))) ;;;; other table methods. (define (present? handle key) (let* ((kc (string-append (handle->base-id handle) key)) (kcl (string-length kc)) (n (bt:next (handle->bt handle) kc))) (and n (<= (+ 1 kcl) (string-length n) (+ 2 kcl)) (string=? kc (substring n 0 kcl))))) (define (delete handle key) (let ((prefix (string-append (handle->base-id handle) key))) (not (wb:err? (bt:rem* (handle->bt handle) prefix (k30:incr-key prefix)))))) (define (delete* handle key-dimension column-types match-keys) (let ((prefix (string-append (handle->base-id handle) match-keys))) (not (wb:err? (bt:rem* (handle->bt handle) prefix (k30:incr-key prefix)))))) (lambda (operation-name) #+foo ; To trace methods use this wrapper: ((lambda (proc) (if (procedure? proc) (lambda args (let ((ans (apply proc args))) (if (procedure? ans) (tracef ans operation-name) ans))) proc)) ) ;;(trace bt:scan bt:get map-key ordered-for-each-key make-key-extractor make-key->list) (set! *qp-width* 333) ;;(trace-all "rwb-isam.scm") (case operation-name ((make-base) make-base) ((open-base) open-base) ((write-base) write-base) ((sync-base) sync-base) ((close-base) close-base) ((make-table) make-table) ((open-table) open-table) ((kill-table) kill-table) ((make-keyifier-1) make-keyifier-1) ((make-list-keyifier) make-list-keyifier) ((make-key->list) make-key->list) ((make-key-extractor) make-key-extractor) ((supported-type?) supported-type?) ((supported-key-type?) supported-key-type?) ((present?) present?) ((make-putter) make-putter) ((make-getter) make-getter) ((delete) delete) ((delete*) delete*) ((for-each-key) ordered-for-each-key) ((map-key) map-key) ((ordered-for-each-key) ordered-for-each-key) ((catalog-id) catalog-id) (else #f))))) (set! *base-table-implementations* (cons (list 'wb-table (make-relational-system wb-table)) *base-table-implementations*)) scm-5e5/scm.texi0000644001705200017500000110127210752350557011524 0ustar tbtb\input texinfo @c -*-texinfo-*- @c %**start of header @setfilename scm.info @settitle scm @include version.txi @setchapternewpage on @c Choices for setchapternewpage are {on,off,odd}. @paragraphindent 0 @defcodeindex ft @syncodeindex ft tp @c %**end of header @copying @noindent This manual is for SCM (version @value{SCMVERSION}, @value{SCMDATE}), an implementation of the algorithmic language Scheme. @noindent Copyright @copyright{} 1990-2007 Free Software Foundation, Inc. @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License.'' @end quotation @end copying @dircategory The Algorithmic Language Scheme @direntry * SCM: (scm). A Scheme interpreter. @end direntry @iftex @finalout @c DL: lose the egregious vertical whitespace, esp. around examples @c but paras in @defun-like things don't have parindent @parskip 4pt plus 1pt @end iftex @titlepage @title SCM @subtitle Scheme Implementation @subtitle Version @value{SCMVERSION} @author Aubrey Jaffer @page @vskip 0pt plus 1filll @insertcopying @end titlepage @contents @ifnottex @node Top, Overview, (dir), (dir) @top SCM @insertcopying @menu * Overview:: * Installing SCM:: How to * Operational Features:: * The Language:: Reference. * Packages:: Optional Capabilities. * The Implementation:: How it works. * Index:: @end menu @end ifnottex @node Overview, Installing SCM, Top, Top @chapter Overview @noindent SCM is a portable Scheme implementation written in C. SCM provides a machine independent platform for [JACAL], a symbolic algebra system. SCM supports and requires the SLIB Scheme library. SCM, SLIB, and JACAL are GNU projects. @iftex @noindent The most recent information about SCM can be found on SCM's @dfn{WWW} home page: @ifset html @end ifset @center @url{http://swiss.csail.mit.edu/~jaffer/SCM} @ifset html @end ifset @end iftex @menu * SCM Features:: * SCM Authors:: * Copying:: * Bibliography:: @end menu @node SCM Features, SCM Authors, Overview, Overview @section Features @itemize @bullet @item Conforms to Revised^5 Report on the Algorithmic Language Scheme [R5RS] and the [IEEE] P1178 specification. @item Support for [SICP], [R2RS], [R3RS], and [R5RS] scheme code. @item Runs under Amiga, Atari-ST, MacOS, MS-DOS, OS/2, NOS/VE, Unicos, VMS, Unix and similar systems. Supports ASCII and EBCDIC character sets. @item Is fully documented in @TeX{}info form, allowing documentation to be generated in info, @TeX{}, html, nroff, and troff formats. @item Supports inexact real and complex numbers, 30 bit immediate integers and large precision integers. @item Many Common Lisp functions: @code{logand}, @code{logor}, @code{logxor}, @code{lognot}, @code{ash}, @code{logcount}, @code{integer-length}, @code{bit-extract}, @code{defmacro}, @code{macroexpand}, @code{macroexpand1}, @code{gentemp}, @code{defvar}, @code{force-output}, @code{software-type}, @code{get-decoded-time}, @code{get-internal-run-time}, @code{get-internal-real-time}, @code{delete-file}, @code{rename-file}, @code{copy-tree}, @code{acons}, and @code{eval}. @item @code{Char-code-limit}, @code{most-positive-fixnum}, @code{most-negative-fixnum}, @code{and internal-time-units-per-second} constants. @code{slib:features} and @code{*load-pathname*} variables. @item Arrays and bit-vectors. String ports and software emulation ports. I/O extensions providing ANSI C and POSIX.1 facilities. @item Interfaces to standard libraries including REGEX string regular expression matching and the CURSES screen management package. @item Available add-on packages including an interactive debugger, database, X-window graphics, BGI graphics, Motif, and Open-Windows packages. @item The Hobbit compiler and dynamic linking of compiled modules. @item User definable responses to interrupts and errors, Process-syncronization primitives. Setable levels of monitoring and timing information printed interactively (the @code{verbose} function). @code{Restart}, @code{quit}, and @code{exec}. @end itemize @node SCM Authors, Copying, SCM Features, Overview @section Authors @table @b @item Aubrey Jaffer (agj @@ alum.mit.edu) Most of SCM. @item Radey Shouman Arrays, @code{gsubr}s, compiled closures, records, Ecache, syntax-rules macros, and @dfn{safeport}s. @item Jerry D. Hedden Real and Complex functions. Fast mixed type arithmetics. @item Hugh Secker-Walker Syntax checking and memoization of special forms by evaluator. Storage allocation strategy and parameters. @item George Carrette @dfn{Siod}, written by George Carrette, was the starting point for SCM. The major innovations taken from Siod are the evaluator's use of the C-stack and being able to garbage collect off the C-stack (@pxref{Garbage Collection}). @end table @noindent There are many other contributors to SCM. They are acknowledged in the file @file{ChangeLog}, a log of changes that have been made to scm. @node Copying, Bibliography, SCM Authors, Overview @section Copyright @noindent Authors have assigned their SCM copyrights to: @sp 1 @center Free Software Foundation, Inc. @center 59 Temple Place, Suite 330, Boston, MA 02111, USA @menu * The SCM License:: * SIOD copyright:: * GNU Free Documentation License:: Copying this Manual @end menu @node The SCM License, SIOD copyright, Copying, Copying @subsection The SCM License This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see @url{http://www.gnu.org/licenses/}. @node SIOD copyright, GNU Free Documentation License, The SCM License, Copying @subsection SIOD copyright @sp 1 @center COPYRIGHT @copyright{} 1989 BY @center PARADIGM ASSOCIATES INCORPORATED, CAMBRIDGE, MASSACHUSETTS. @center ALL RIGHTS RESERVED @noindent Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Paradigm Associates Inc not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. @noindent PARADIGM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL PARADIGM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. @noindent gjc@@paradigm.com @flushright Phone: 617-492-6079 @end flushright @flushleft Paradigm Associates Inc 29 Putnam Ave, Suite 6 Cambridge, MA 02138 @end flushleft @node GNU Free Documentation License, , SIOD copyright, Copying @subsection GNU Free Documentation License @include fdl.texi @node Bibliography, , Copying, Overview @section Bibliography @table @asis @item [IEEE] @cindex IEEE @cite{IEEE Standard 1178-1990. IEEE Standard for the Scheme Programming Language.} IEEE, New York, 1991. @item [R4RS] @cindex R4RS William Clinger and Jonathan Rees, Editors. @ifset html @end ifset Revised(4) Report on the Algorithmic Language Scheme. @ifset html @end ifset @cite{ACM Lisp Pointers} Volume IV, Number 3 (July-September 1991), pp. 1-55. @ifinfo @ref{Top, , , r4rs, Revised(4) Report on the Algorithmic Language Scheme}. @end ifinfo @item [R5RS] @cindex R5RS Richard Kelsey and William Clinger and Jonathan (Rees, editors) @ifset html @end ifset Revised(5) Report on the Algorithmic Language Scheme. @ifset html @end ifset @cite{Higher-Order and Symbolic Computation} Volume 11, Number 1 (1998), pp. 7-105, and @cite{ACM SIGPLAN Notices} 33(9), September 1998. @ifinfo @ref{Top, , , r5rs, Revised(5) Report on the Algorithmic Language Scheme}. @end ifinfo @item [Exrename] @cindex Exrename William Clinger @ifset html @end ifset Hygienic Macros Through Explicit Renaming @ifset html @end ifset @cite{Lisp Pointers} Volume IV, Number 4 (December 1991), pp 17-23. @item [SICP] @cindex SICP Harold Abelson and Gerald Jay Sussman with Julie Sussman. @cite{Structure and Interpretation of Computer Programs.} MIT Press, Cambridge, 1985. @item [Simply] @cindex Simply Brian Harvey and Matthew Wright. @ifset html @end ifset @cite{Simply Scheme: Introducing Computer Science} @ifset html @end ifset MIT Press, 1994 ISBN 0-262-08226-8 @item [SchemePrimer] @cindex SchemePrimer $B8$;tBg(B(Dai Inukai) @ifset html @end ifset @cite{$BF~Lg(BScheme} @ifset html @end ifset 1999$BG/(B12$B7n=iHG(B ISBN4-87966-954-7 @c @item [GUILE] @c @cindex GUILE @c Free Software Foundation @c @ifset html @c @c @end ifset @c Guile: Project GNU's extension language @c @ifset html @c @c @end ifset @item [SLIB] @cindex SLIB Todd R. Eigenschink, Dave Love, and Aubrey Jaffer. @ifset html @end ifset SLIB, The Portable Scheme Library. @ifset html @end ifset Version 2c8, June 2000. @ifinfo @ref{Top, , , slib, SLIB}. @end ifinfo @item [JACAL] @cindex JACAL Aubrey Jaffer. @ifset html @end ifset JACAL Symbolic Mathematics System. @ifset html @end ifset Version 1b0, Sep 1999. @ifinfo @ref{Top, , , jacal, JACAL}. @end ifinfo @end table @table @file @item scm.texi @itemx scm.info Documentation of @code{scm} extensions (beyond Scheme standards). Documentation on the internal representation and how to extend or include @code{scm} in other programs. @item Xlibscm.texi @itemx Xlibscm.info Documentation of the Xlib - SCM Language X Interface. @end table @node Installing SCM, Operational Features, Overview, Top @chapter Installing SCM @menu * Making SCM:: Bootstrapping. * SLIB:: REQUIREd reading. * Building SCM:: * Installing Dynamic Linking:: * Configure Module Catalog:: * Saving Images:: Make Fast-Booting Executables * Automatic C Preprocessor Definitions:: * Problems Compiling:: * Problems Linking:: * Problems Running:: * Testing:: * Reporting Problems:: @end menu @node Making SCM, SLIB, Installing SCM, Installing SCM @section Making SCM The SCM distribution has @dfn{Makefile} which contains rules for making @dfn{scmlit}, a ``bare-bones'' version of SCM sufficient for running @file{build}. @file{build} is used to compile (or create scripts to compile) full featured versions (@pxref{Building SCM}). Makefiles are not portable to the majority of platforms. If @file{Makefile} works for you, good; If not, I don't want to hear about it. If you need to compile SCM without build, there are several ways to proceed: @itemize @bullet @item Use the @uref{http://swiss.csail.mit.edu/~jaffer/buildscm.html, build} web page to create custom batch scripts for compiling SCM. @item Use SCM on a different platform to run @file{build} to create a script to build SCM; @item Use another implementation of Scheme to run @file{build} to create a script to build SCM; @item Create your own script or @file{Makefile}. @end itemize @node SLIB, Building SCM, Making SCM, Installing SCM @section SLIB @noindent [SLIB] is a portable Scheme library meant to provide compatibility and utility functions for all standard Scheme implementations. Although SLIB is not @emph{neccessary} to run SCM, I strongly suggest you obtain and install it. Bug reports about running SCM without SLIB have very low priority. SLIB is available from the same sites as SCM: @ifclear html @itemize @bullet @item swiss.csail.mit.edu:/pub/scm/slib-3b1.tar.gz @item ftp.gnu.org:/pub/gnu/jacal/slib-3b1.tar.gz @end itemize @end ifclear @ifset html @itemize @bullet @item http://swiss.csail.mit.edu/ftpdir/scm/slib-3b1.zip @item ftp.gnu.org:/pub/gnu/jacal/slib-3b1.tar.gz @end itemize @end ifset @noindent Unpack SLIB (@samp{tar xzf slib-3b1.tar.gz} or @samp{unzip -ao slib-3b1.zip}) in an appropriate directory for your system; both @code{tar} and @code{unzip} will create the directory @file{slib}. @noindent Then create a file @file{require.scm} in the SCM @dfn{implementation-vicinity} (this is the same directory as where the file @file{Init@value{SCMVERSION}.scm} is installed). @file{require.scm} should have the contents: @example (define (library-vicinity) "/usr/local/lib/slib/") @end example @noindent where the pathname string @file{/usr/local/lib/slib/} is to be replaced by the pathname into which you installed SLIB. Absolute pathnames are recommended here; if you use a relative pathname, SLIB can get confused when the working directory is changed (@pxref{I/O-Extensions, chmod}). The way to specify a relative pathname is to append it to the implementation-vicinity, which is absolute: @example (define library-vicinity (let ((lv (string-append (implementation-vicinity) "../slib/"))) (lambda () lv))) @end example @noindent Alternatively, you can set the (shell) environment variable @code{SCHEME_LIBRARY_PATH} to the pathname of the SLIB directory (@pxref{SCM Variables, SCHEME_LIBRARY_PATH, Environment Variables}). If set, the environment variable overrides @file{require.scm}. Again, absolute pathnames are recommended. @node Building SCM, Installing Dynamic Linking, SLIB, Installing SCM @section Building SCM @cindex build @cindex build.scm The file @dfn{build} loads the file @dfn{build.scm}, which constructs a relational database of how to compile and link SCM executables. @file{build.scm} has information for the platforms which SCM has been ported to (of which I have been notified). Some of this information is old, incorrect, or incomplete. Send corrections and additions to jaffer @@ ai.mit.edu. @menu * Invoking Build:: * Build Options:: * Compiling and Linking Custom Files:: @end menu @node Invoking Build, Build Options, Building SCM, Building SCM @subsection Invoking Build @noindent The @emph{all} method will also work for MS-DOS and unix. Use the @emph{all} method if you encounter problems with @file{build}. @table @asis @item MS-DOS From the SCM source directory, type @samp{build} followed by up to 9 command line arguments. @item unix From the SCM source directory, type @samp{./build} followed by command line arguments. @item @emph{all} From the SCM source directory, start @samp{scm} or @samp{scmlit} and type @code{(load "build")}. Alternatively, start @samp{scm} or @samp{scmlit} with the command line argument @samp{-ilbuild}. @end table @noindent Invoking build without the @samp{-F} option will build or create a shell script with the @code{arrays}, @code{inexact}, and @code{bignums} options as defaults. @example bash$ ./build @print{} #! /bin/sh # unix (linux) script created by SLIB/batch # ================ Write file with C defines rm -f scmflags.h echo '#define IMPLINIT "Init@value{SCMVERSION}.scm"'>>scmflags.h echo '#define BIGNUMS'>>scmflags.h echo '#define FLOATS'>>scmflags.h echo '#define ARRAYS'>>scmflags.h # ================ Compile C source files gcc -O2 -c continue.c scm.c scmmain.c findexec.c script.c time.c repl.c scl.c eval.c sys.c subr.c debug.c unif.c rope.c # ================ Link C object files gcc -rdynamic -o scm continue.o scm.o scmmain.o findexec.o script.o time.o repl.o scl.o eval.o sys.o subr.o debug.o unif.o rope.o -lm -lc @end example @noindent To cross compile for another platform, invoke build with the @samp{-p} or @samp{--platform=} option. This will create a script for the platform named in the @samp{-p} or @samp{--platform=} option. @example bash$ ./build -o scmlit -p darwin -F lit @print{} #! /bin/sh # unix (darwin) script created by SLIB/batch # ================ Write file with C defines rm -f scmflags.h echo '#define IMPLINIT "Init@value{SCMVERSION}.scm"'>>scmflags.h # ================ Compile C source files cc -O3 -c continue.c scm.c scmmain.c findexec.c script.c time.c repl.c scl.c eval.c sys.c subr.c debug.c unif.c rope.c # ================ Link C object files mv -f scmlit scmlit~ cc -o scmlit continue.o scm.o scmmain.o findexec.o script.o time.o repl.o scl.o eval.o sys.o subr.o debug.o unif.o rope.o @end example @node Build Options, Compiling and Linking Custom Files, Invoking Build, Building SCM @subsection Build Options @noindent The options to @dfn{build} specify what, where, and how to build a SCM program or dynamically linked module. These options are unrelated to the SCM command line options. @deffn {Build Option} -p @var{platform-name} @deffnx {Build Option} ---platform=@var{platform-name} specifies that the compilation should be for a computer/operating-system combination called @var{platform-name}. @emph{Note@:} The case of @var{platform-name} is distinguised. The current @var{platform-name}s are all lower-case. The platforms defined by table @dfn{platform} in @file{build.scm} are: @end deffn @example @include platform.txi @end example @deffn {Build Option} -f @var{pathname} specifies that the build options contained in @var{pathname} be spliced into the argument list at this point. The use of option files can separate functional features from platform-specific ones. The @file{Makefile} calls out builds with the options in @samp{.opt} files: @table @file @item dlls.opt Options for Makefile targets mydlls, myturtle, and x.so. @item gdb.opt Options for udgdbscm and gdbscm. @item libscm.opt Options for libscm.a. @item pg.opt Options for pgscm, which instruments C functions. @item udscm4.opt Options for targets udscm4 and dscm4 (scm). @item udscm5.opt Options for targets udscm5 and dscm5 (scm). @end table The Makefile creates options files it depends on only if they do not already exist. @end deffn @deffn {Build Option} -o @var{filename} @deffnx {Build Option} ---outname=@var{filename} specifies that the compilation should produce an executable or object name of @var{filename}. The default is @samp{scm}. Executable suffixes will be added if neccessary, e.g. @samp{scm} @result{} @samp{scm.exe}. @end deffn @deffn {Build Option} -l @var{libname} @dots{} @deffnx {Build Option} ---libraries=@var{libname} specifies that the @var{libname} should be linked with the executable produced. If compile flags or include directories (@samp{-I}) are needed, they are automatically supplied for compilations. The @samp{c} library is always included. SCM @dfn{features} specify any libraries they need; so you shouldn't need this option often. @end deffn @deffn {Build Option} -D @var{definition} @dots{} @deffnx {Build Option} ---defines=@var{definition} specifies that the @var{definition} should be made in any C source compilations. If compile flags or include directories (@samp{-I}) are needed, they are automatically supplied for compilations. SCM @dfn{features} specify any flags they need; so you shouldn't need this option often. @end deffn @deffn {Build Option} ---compiler-options=@var{flag} specifies that that @var{flag} will be put on compiler command-lines. @end deffn @deffn {Build Option} ---linker-options=@var{flag} specifies that that @var{flag} will be put on linker command-lines. @end deffn @deffn {Build Option} -s @var{pathname} @deffnx {Build Option} ---scheme-initial=@var{pathname} specifies that @var{pathname} should be the default location of the SCM initialization file @file{Init@value{SCMVERSION}.scm}. SCM tries several likely locations before resorting to @var{pathname} (@pxref{File-System Habitat}). If not specified, the current directory (where build is building) is used. @end deffn @deffn {Build Option} -c @var{pathname} @dots{} @deffnx {Build Option} ---c-source-files=@var{pathname} specifies that the C source files @var{pathname} @dots{} are to be compiled. @end deffn @deffn {Build Option} -j @var{pathname} @dots{} @deffnx {Build Option} ---object-files=@var{pathname} specifies that the object files @var{pathname} @dots{} are to be linked. @end deffn @deffn {Build Option} -i @var{call} @dots{} @deffnx {Build Option} ---initialization=@var{call} specifies that the C functions @var{call} @dots{} are to be invoked during initialization. @end deffn @deffn {Build Option} -t @var{build-what} @deffnx {Build Option} ---type=@var{build-what} specifies in general terms what sort of thing to build. The choices are: @table @samp @item exe executable program. @item lib library module. @item dlls archived dynamically linked library object files. @item dll dynamically linked library object file. @end table The default is to build an executable. @end deffn @deffn {Build Option} -h @var{batch-syntax} @deffnx {Build Option} --batch-dialect=@var{batch-syntax} specifies how to build. The default is to create a batch file for the host system. The SLIB file @file{batch.scm} knows how to create batch files for: @itemize @bullet @item unix @item dos @item vms @item amigaos (was amigados) @item system This option executes the compilation and linking commands through the use of the @code{system} procedure. @item *unknown* This option outputs Scheme code. @end itemize @end deffn @deffn {Build Option} -w @var{batch-filename} @deffnx {Build Option} --script-name=@var{batch-filename} specifies where to write the build script. The default is to display it on @code{(current-output-port)}. @end deffn @deffn {Build Option} -F @var{feature} @dots{} @deffnx {Build Option} ---features=@var{feature} specifies to build the given features into the executable. The defined features are: @table @dfn @c @itemx none @c @cindex none @c Lightweight -- no features @include features.txi @end table @end deffn @node Compiling and Linking Custom Files, , Build Options, Building SCM @subsection Compiling and Linking Custom Files @noindent A correspondent asks: @quotation How can we link in our own c files to the SCM interpreter so that we can add our own functionality? (e.g. we have a bunch of tcp functions we want access to). Would this involve changing build.scm or the Makefile or both? @end quotation @noindent (@pxref{Changing Scm} has instructions describing the C code format). @cindex foo.c @cindex Extending Scm Suppose a C file @dfn{foo.c} has functions you wish to add to SCM. To compile and link your file at compile time, use the @samp{-c} and @samp{-i} options to build: @example bash$ ./build -c foo.c -i init_foo @print{} #! /bin/sh rm -f scmflags.h echo '#define IMPLINIT "/home/jaffer/scm/Init@value{SCMVERSION}.scm"'>>scmflags.h echo '#define COMPILED_INITS init_foo();'>>scmflags.h echo '#define BIGNUMS'>>scmflags.h echo '#define FLOATS'>>scmflags.h echo '#define ARRAYS'>>scmflags.h gcc -O2 -c continue.c scm.c findexec.c script.c time.c repl.c scl.c \ eval.c sys.c subr.c unif.c rope.c foo.c gcc -rdynamic -o scm continue.o scm.o findexec.o script.o time.o \ repl.o scl.o eval.o sys.o subr.o unif.o rope.o foo.o -lm -lc @end example @noindent To make a dynamically loadable object file use the @code{-t dll} option: @example bash$ ./build -t dll -c foo.c @print{} #! /bin/sh rm -f scmflags.h echo '#define IMPLINIT "/home/jaffer/scm/Init@value{SCMVERSION}.scm"'>>scmflags.h echo '#define BIGNUMS'>>scmflags.h echo '#define FLOATS'>>scmflags.h echo '#define ARRAYS'>>scmflags.h echo '#define DLL'>>scmflags.h gcc -O2 -fpic -c foo.c gcc -shared -o foo.so foo.o -lm -lc @end example @noindent Once @file{foo.c} compiles correctly (and your SCM build supports dynamic-loading), you can load the compiled file with the Scheme command @code{(load "./foo.so")}. See @ref{Configure Module Catalog} for how to add a compiled dll file to SLIB's catalog. @node Installing Dynamic Linking, Configure Module Catalog, Building SCM, Installing SCM @section Installing Dynamic Linking @noindent Dynamic linking has not been ported to all platforms. Operating systems in the BSD family (a.out binary format) can usually be ported to @dfn{DLD}. The @dfn{dl} library (@code{#define SUN_DL} for SCM) was a proposed POSIX standard and may be available on other machines with @dfn{COFF} binary format. For notes about porting to MS-Windows and finishing the port to VMS @ref{VMS Dynamic Linking}. @noindent @dfn{DLD} is a library package of C functions that performs @dfn{dynamic link editing} on GNU/Linux, VAX (Ultrix), Sun 3 (SunOS 3.4 and 4.0), SPARCstation (SunOS 4.0), Sequent Symmetry (Dynix), and Atari ST. It is available from: @ifclear html @itemize @bullet @item ftp.gnu.org:pub/gnu/dld-3.3.tar.gz @end itemize @end ifclear @ifset html ftp.gnu.org:pub/gnu/dld-3.3.tar.gz @end ifset @noindent These notes about using libdl on SunOS are from @file{gcc.info}: @quotation On a Sun, linking using GNU CC fails to find a shared library and reports that the library doesn't exist at all. This happens if you are using the GNU linker, because it does only static linking and looks only for unshared libraries. If you have a shared library with no unshared counterpart, the GNU linker won't find anything. We hope to make a linker which supports Sun shared libraries, but please don't ask when it will be finished--we don't know. Sun forgot to include a static version of @file{libdl.a} with some versions of SunOS (mainly 4.1). This results in undefined symbols when linking static binaries (that is, if you use @samp{-static}). If you see undefined symbols @samp{_dlclose}, @samp{_dlsym} or @samp{_dlopen} when linking, compile and link against the file @file{mit/util/misc/dlsym.c} from the MIT version of X windows. @end quotation @node Configure Module Catalog, Saving Images, Installing Dynamic Linking, Installing SCM @section Configure Module Catalog @noindent The SLIB module @dfn{catalog} can be extended to define other @code{require}-able packages by adding calls to the Scheme source file @file{mkimpcat.scm}. Within @file{mkimpcat.scm}, the following procedures are defined. @defun add-link feature object-file lib1 @dots{} @var{feature} should be a symbol. @var{object-file} should be a string naming a file containing compiled @dfn{object-code}. Each @var{lib}n argument should be either a string naming a library file or @code{#f}. If @var{object-file} exists, the @code{add-link} procedure registers symbol @var{feature} so that the first time @code{require} is called with the symbol @var{feature} as its argument, @var{object-file} and the @var{lib1} @dots{} are dynamically linked into the executing SCM session. If @var{object-file} exists, @code{add-link} returns @code{#t}, otherwise it returns @code{#f}. For example, to install a compiled dll @file{foo}, add these lines to @file{mkimpcat.scm}: @example (add-link 'foo (in-vicinity (implementation-vicinity) "foo" link:able-suffix)) @end example @end defun @defun add-alias alias feature @var{alias} and @var{feature} are symbols. The procedure @code{add-alias} registers @var{alias} as an alias for @var{feature}. An unspecified value is returned. @code{add-alias} causes @code{(require '@var{alias})} to behave like @code{(require '@var{feature})}. @end defun @defun add-source feature filename @var{feature} is a symbol. @var{filename} is a string naming a file containing Scheme source code. The procedure @code{add-source} registers @var{feature} so that the first time @code{require} is called with the symbol @var{feature} as its argument, the file @var{filename} will be @code{load}ed. An unspecified value is returned. @end defun @noindent Remember to delete the file @file{slibcat} after modifying the file @file{mkimpcat.scm} in order to force SLIB to rebuild its cache. @node Saving Images, Automatic C Preprocessor Definitions, Configure Module Catalog, Installing SCM @section Saving Images In SCM, the ability to save running program images is called @dfn{dump} (@pxref{Dump}). In order to make @code{dump} available to SCM, build with feature @samp{dump}. @code{dump}ed executables are compatible with dynamic linking. Most of the code for @dfn{dump} is taken from @file{emacs-19.34/src/unex*.c}. No modifications to the emacs source code were required to use @file{unexelf.c}. Dump has not been ported to all platforms. If @file{unexec.c} or @file{unexelf.c} don't work for you, try using the appropriate @file{unex*.c} file from emacs. The @samp{dscm4} and @samp{dscm5} targets in the SCM @file{Makefile} save images from @file{udscm4} and @file{udscm5} executables respectively. Recent GNU/Linux innovations interfere with @code{dump}. For: @table @asis @item Fedora-Core-1 Remove the @samp{#} from the line @samp{#SETARCH = setarch i386} in the @file{Makefile}. @item Fedora-Core-3 @url{http://jamesthornton.com/writing/emacs-compile.html} writes: [For FC3] combreloc has become the default for recent GNU ld, which breaks the unexec/undump on all versions of both Emacs and XEmacs... Override by adding the following to @file{udscm5.opt}: @samp{--linker-options="-z nocombreloc"} @item Kernels later than 2.6.11 @url{http://www.opensubscriber.com/message/emacs-devel@@gnu.org/1007118.html} mentions the @dfn{exec-shield} feature. Kernels later than 2.6.11 must do (as root): @example echo 0 > /proc/sys/kernel/randomize_va_space @end example before dumping. @file{Makefile} has this @file{randomize_va_space} stuffing scripted for targets @samp{dscm4} and @samp{dscm5}. You must either set @file{randomize_va_space} to 0 or run as root to dump. @end table @node Automatic C Preprocessor Definitions, Problems Compiling, Saving Images, Installing SCM @section Automatic C Preprocessor Definitions These @samp{#defines} are automatically provided by preprocessors of various C compilers. SCM uses the presence or absence of these definitions to configure @dfn{include file} locations and aliases for library functions. If the definition(s) corresponding to your system type is missing as your system is configured, add @code{-D@var{flag}} to the compilation command lines or add a @code{#define @var{flag}} line to @file{scmfig.h} or the beginning of @file{scmfig.h}. @example #define Platforms: ------- ---------- ARM_ULIB Huw Rogers free unix library for acorn archimedes AZTEC_C Aztec_C 5.2a __CYGWIN__ Cygwin __CYGWIN32__ Cygwin _DCC Dice C on AMIGA __GNUC__ Gnu CC (and DJGPP) __EMX__ Gnu C port (gcc/emx 0.8e) to OS/2 2.0 __HIGHC__ MetaWare High C __IBMC__ C-Set++ on OS/2 2.1 _MSC_VER MS VisualC++ 4.2 MWC Mark Williams C on COHERENT __MWERKS__ Metrowerks Compiler; Macintosh and WIN32 (?) _POSIX_SOURCE ?? _QC Microsoft QuickC __STDC__ ANSI C compliant __TURBOC__ Turbo C and Borland C __USE_POSIX ?? __WATCOMC__ Watcom C on MS-DOS __ZTC__ Zortech C _AIX AIX operating system __APPLE__ Apple Darwin AMIGA SAS/C 5.10 or Dice C on AMIGA __amigaos__ Gnu CC on AMIGA atarist ATARI-ST under Gnu CC __DragonflyBSD__ DragonflyBSD __FreeBSD__ FreeBSD GNUDOS DJGPP (obsolete in version 1.08) __GO32__ DJGPP (future?) hpux HP-UX linux GNU/Linux macintosh Macintosh (THINK_C and __MWERKS__ define) MCH_AMIGA Aztec_c 5.2a on AMIGA __MACH__ Apple Darwin __MINGW32__ MinGW - Minimalist GNU for Windows MSDOS Microsoft C 5.10 and 6.00A _MSDOS Microsoft CLARM and CLTHUMB compilers. __MSDOS__ Turbo C, Borland C, and DJGPP __NetBSD__ NetBSD nosve Control Data NOS/VE __OpenBSD__ OpenBSD SVR2 System V Revision 2. sun SunOS __SVR4 SunOS THINK_C developement environment for the Macintosh ultrix VAX with ULTRIX operating system. unix most Unix and similar systems and DJGPP (!?) __unix__ Gnu CC and DJGPP _UNICOS Cray operating system vaxc VAX C compiler VAXC VAX C compiler vax11c VAX C compiler VAX11 VAX C compiler _Windows Borland C 3.1 compiling for Windows _WIN32 MS VisualC++ 4.2 and Cygwin (Win32 API) _WIN32_WCE MS Windows CE vms (and VMS) VAX-11 C under VMS. __alpha DEC Alpha processor __alpha__ DEC Alpha processor hp9000s800 HP RISC processor __ia64 GCC on IA64 __ia64__ GCC on IA64 _LONGLONG GCC on IA64 __i386__ DJGPP i386 DJGPP _M_ARM Microsoft CLARM compiler defines as 4 for ARM. _M_ARMT Microsoft CLTHUMB compiler defines as 4 for Thumb. MULTIMAX Encore computer ppc PowerPC __ppc__ PowerPC pyr Pyramid 9810 processor __sgi__ Silicon Graphics Inc. sparc SPARC processor sequent Sequent computer tahoe CCI Tahoe processor vax VAX processor __x86_64 AMD Opteron @end example @node Problems Compiling, Problems Linking, Automatic C Preprocessor Definitions, Installing SCM @section Problems Compiling @multitable @columnfractions .10 .45 .45 @item FILE @tab PROBLEM / MESSAGE @tab HOW TO FIX @item *.c @tab include file not found. @tab Correct the status of @t{STDC_HEADERS} in scmfig.h. @item @tab @tab fix @t{#include} statement or add @t{#define} for system type to scmfig.h. @item *.c @tab Function should return a value. @tab Ignore. @item @tab Parameter is never used. @tab @item @tab Condition is always false. @tab @item @tab Unreachable code in function. @tab @item scm.c @tab assignment between incompatible types. @tab Change @t{SIGRETTYPE} in scm.c. @item time.c @tab CLK_TCK redefined. @tab incompatablility between and . @item @tab @tab Remove @t{STDC_HEADERS} in scmfig.h. @item @tab @tab Edit to remove incompatability. @item subr.c @tab Possibly incorrect assignment in function lgcd. @tab Ignore. @item sys.c @tab statement not reached. @tab Ignore. @item @tab constant in conditional expression. @tab @item sys.c @tab undeclared, outside of functions. @tab @t{#undef STDC_HEADERS} in scmfig.h. @item scl.c @tab syntax error. @tab @t{#define SYSTNAME} to your system type in scl.c (softtype). @end multitable @node Problems Linking, Problems Running, Problems Compiling, Installing SCM @section Problems Linking @multitable @columnfractions .5 .5 @item PROBLEM @tab HOW TO FIX @item _sin etc. missing. @tab Uncomment @t{LIBS} in makefile. @end multitable @node Problems Running, Testing, Problems Linking, Installing SCM @section Problems Running @multitable @columnfractions .5 .5 @item PROBLEM @tab HOW TO FIX @item Opening message and then machine crashes. @tab Change memory model option to C compiler (or makefile). @item @tab Make sure @t{sizet} definition is correct in scmfig.h. @item @tab Reduce the size of @t{HEAP_SEG_SIZE} in setjump.h. @item Input hangs. @tab @t{#define NOSETBUF} @item ERROR: heap: need larger initial. @tab Increase initial heap allocation using -a or @t{INIT_HEAP_SIZE}. @item ERROR: Could not allocate. @tab Check @t{sizet} definition. @item @tab Use 32 bit compiler mode. @item @tab Don't try to run as subproccess. @item remove in scmfig.h and recompile scm. @tab Do so and recompile files. @item add in scmfig.h and recompile scm. @tab @item ERROR: Init@value{SCMVERSION}.scm not found. @tab Assign correct @t{IMPLINIT} in makefile or scmfig.h. @item @tab Define environment variable @t{SCM_INIT_PATH} to be the full pathname of Init@value{SCMVERSION}.scm. @item WARNING: require.scm not found. @tab Define environment variable @t{SCHEME_LIBRARY_PATH} to be the full pathname of the scheme library [SLIB]. @item @tab Change @t{library-vicinity} in Init@value{SCMVERSION}.scm to point to library or remove. @item @tab Make sure the value of @t{(library-vicinity)} has a trailing file separator (like @t{/} or @t{\}). @end multitable @node Testing, Reporting Problems, Problems Running, Installing SCM @section Testing @noindent Loading @file{r4rstest.scm} in the distribution will run an [R4RS] conformance test on @code{scm}. @example > (load "r4rstest.scm") @print{} ;loading "r4rstest.scm" SECTION(2 1) SECTION(3 4) # # # # @dots{} @end example @noindent Loading @file{pi.scm} in the distribution will enable you to compute digits of pi. @example > (load "pi") ;loading "pi" ;done loading "pi.scm" ;Evaluation took 20 ms (0 in gc) 767 cells work, 233.B other # > (pi 100 5) 00003 14159 26535 89793 23846 26433 83279 50288 41971 69399 37510 58209 74944 59230 78164 06286 20899 86280 34825 34211 70679 ;Evaluation took 550 ms (60 in gc) 36976 cells work, 1548.B other # @end example @noindent Loading @file{bench.scm} will compute and display performance statistics of SCM running @file{pi.scm}. @samp{make bench} or @samp{make benchlit} appends the performance report to the file @file{BenchLog}, facilitating tracking effects of changes to SCM on performance. @multitable @columnfractions .5 .5 @item PROBLEM @tab HOW TO FIX @item Runs some and then machine crashes. @tab See above under machine crashes. @item Runs some and then ERROR: @dots{} (after a GC has happened). @tab Remove optimization option to C compiler and recompile. @item @tab @t{#define SHORT_ALIGN} in @file{scmfig.h}. @item Some symbol names print incorrectly. @tab Change memory model option to C compiler (or makefile). @item @tab Check that @t{HEAP_SEG_SIZE} fits within @t{sizet}. @item @tab Increase size of @t{HEAP_SEG_SIZE} (or @t{INIT_HEAP_SIZE} if it is smaller than @t{HEAP_SEG_SIZE}). @item ERROR: Rogue pointer in Heap. @tab See above under machine crashes. @item Newlines don't appear correctly in output files. @tab Check file mode (define OPEN_@dots{} in @file{Init@value{SCMVERSION}.scm}). @item Spaces or control characters appear in symbol names. @tab Check character defines in @file{scmfig.h}. @item Negative numbers turn positive. @tab Check SRS in @file{scmfig.h}. @item ;ERROR: bignum: numerical overflow @tab Increase NUMDIGS_MAX in @file{scmfig.h} and recompile. @item VMS: Couldn't unwind stack. @tab @t{#define CHEAP_CONTINUATIONS} in @file{scmfig.h}. @item VAX: botched longjmp. @end multitable @table @asis @item Sparc(SUN-4) heap is growing out of control You are experiencing a GC problem peculiar to the Sparc. The problem is that SCM doesn't know how to clear register windows. Every location which is not reused still gets marked at GC time. This causes lots of stuff which should be collected to not be. This will be a problem with any @emph{conservative} GC until we find what instruction will clear the register windows. This problem is exacerbated by using lots of call-with-current-continuations. A possible fix for dynthrow() is commented out in @file{continue.c}. @end table @node Reporting Problems, , Testing, Installing SCM @section Reporting Problems @noindent Reported problems and solutions are grouped under Compiling, Linking, Running, and Testing. If you don't find your problem listed there, you can send a bug report to @code{agj @@ alum.mit.edu}. The bug report should include: @enumerate @item The version of SCM (printed when SCM is invoked with no arguments). @item The type of computer you are using. @item The name and version of your computer's operating system. @item The values of the environment variables @code{SCM_INIT_PATH} and @code{SCHEME_LIBRARY_PATH}. @item The name and version of your C compiler. @item If you are using an executable from a distribution, the name, vendor, and date of that distribution. In this case, corresponding with the vendor is recommended. @end enumerate @node Operational Features, The Language, Installing SCM, Top @chapter Operational Features @menu * Invoking SCM:: * SCM Options:: * Invocation Examples:: * SCM Variables:: * SCM Session:: * Editing Scheme Code:: * Debugging Scheme Code:: * Debugging Continuations:: * Errors:: * Memoized Expressions:: * Internal State:: * Scripting:: @end menu @node Invoking SCM, SCM Options, Operational Features, Operational Features @section Invoking SCM @example @exdent @b{ scm } [-a @i{kbytes}] [-muvbiq] @w{[--version]} @w{[--help]} @w{[[-]-no-init-file]} @w{[--no-symbol-case-fold]} @w{[-p @i{int}]} @w{[-r @i{feature}]} @w{[-h @i{feature}]} @w{[-d @i{filename}]} @w{[-f @i{filename}]} @w{[-l @i{filename}]} @w{[-c @i{expression}]} @w{[-e @i{expression}]} @w{[-o @i{dumpname}]} @w{[-- | - | -s]} @w{[@i{filename}]} @w{[@i{arguments} @dots{}]} @end example @noindent Upon startup @code{scm} loads the file specified by by the environment variable @var{SCM_INIT_PATH}. @noindent If @var{SCM_INIT_PATH} is not defined or if the file it names is not present, @code{scm} tries to find the directory containing the executable file. If it is able to locate the executable, @code{scm} looks for the initialization file (usually @file{Init@value{SCMVERSION}.scm}) in platform-dependent directories relative to this directory. See @ref{File-System Habitat} for a blow-by-blow description. @noindent As a last resort (if initialization file cannot be located), the C compile parameter @var{IMPLINIT} (defined in the makefile or @file{scmfig.h}) is tried. @noindent Unless the option @code{-no-init-file} or @code{--no-init-file} occurs in the command line, or if @code{scm} is being invoked as a script, @file{Init@value{SCMVERSION}.scm} checks to see if there is file @file{ScmInit.scm} in the path specified by the environment variable @var{HOME} (or in the current directory if @var{HOME} is undefined). If it finds such a file, then it is loaded. @noindent @file{Init@value{SCMVERSION}.scm} then looks for command input from one of three sources: From an option on the command line, from a file named on the command line, or from standard input. @noindent This explanation applies to SCMLIT or other builds of SCM. @noindent Scheme-code files can also invoke SCM and its variants. @xref{Lexical Conventions, #!}. @node SCM Options, Invocation Examples, Invoking SCM, Operational Features @section Options @noindent The options are processed in the order specified on the command line. @deffn {Command Option} -a k specifies that @code{scm} should allocate an initial heapsize of @var{k} kilobytes. This option, if present, must be the first on the command line. If not specified, the default is @code{INIT_HEAP_SIZE} in source file @file{setjump.h} which the distribution sets at @code{25000*sizeof(cell)}. @end deffn @deffn {Command Option} -no-init-file @deffnx {Command Option} ---no-init-file Inhibits the loading of @file{ScmInit.scm} as described above. @end deffn @deffn {Command Option} --no-symbol-case-fold Symbol (and identifier) names will be case sensitive. @end deffn @deffn {Command Option} ---help prints usage information and URI; then exit. @end deffn @deffn {Command Option} ---version prints version information and exit. @end deffn @deffn {Command Option} -r feature requires @var{feature}. This will load a file from [SLIB] if that @var{feature} is not already provided. If @var{feature} is 2, 2rs, or r2rs; 3, 3rs, or r3rs; 4, 4rs, or r4rs; 5, 5rs, or r5rs; @code{scm} will require the features neccessary to support [R2RS]; [R3RS]; [R4RS]; or [R5RS], respectively. @end deffn @deffn {Command Option} -h feature provides @var{feature}. @end deffn @deffn {Command Option} -l filename @deffnx {Command Option} -f filename loads @var{filename}. @code{Scm} will load the first (unoptioned) file named on the command line if no @code{-c}, @code{-e}, @code{-f}, @code{-l}, or @code{-s} option preceeds it. @end deffn @deffn {Command Option} -d filename Loads SLIB @code{databases} feature and opens @var{filename} as a database. @end deffn @deffn {Command Option} -e expression @deffnx {Command Option} -c expression specifies that the scheme expression @var{expression} is to be evaluated. These options are inspired by @code{perl} and @code{sh} respectively. On Amiga systems the entire option and argument need to be enclosed in quotes. For instance @samp{"-e(newline)"}. @end deffn @deffn {Command Option} -o dumpname saves the current SCM session as the executable program @file{dumpname}. This option works only in SCM builds supporting @code{dump} (@pxref{Dump}). If options appear on the command line after @samp{-o @var{dumpname}}, then the saved session will continue with processing those options when it is invoked. Otherwise the (new) command line is processed as usual when the saved image is invoked. @end deffn @deffn {Command Option} -p level sets the prolixity (verboseness) to @var{level}. This is the same as the @code{scm} command (verobse @var{level}). @end deffn @deffn {Command Option} -v (verbose mode) specifies that @code{scm} will print prompts, evaluation times, notice of loading files, and garbage collection statistics. This is the same as @code{-p3}. @end deffn @deffn {Command Option} -q (quiet mode) specifies that @code{scm} will print no extra information. This is the same as @code{-p0}. @end deffn @deffn {Command Option} -m specifies that subsequent loads, evaluations, and user interactions will be with syntax-rules macro capability. To use a specific syntax-rules macro implementation from [SLIB] (instead of [SLIB]'s default) put @code{-r} @var{macropackage} before @code{-m} on the command line. @end deffn @deffn {Command Option} -u specifies that subsequent loads, evaluations, and user interactions will be without syntax-rules macro capability. Syntax-rules macro capability can be restored by a subsequent @code{-m} on the command line or from Scheme code. @end deffn @deffn {Command Option} -i specifies that @code{scm} should run interactively. That means that @code{scm} will not terminate until the @code{(quit)} or @code{(exit)} command is given, even if there are errors. It also sets the prolixity level to 2 if it is less than 2. This will print prompts, evaluation times, and notice of loading files. The prolixity level can be set by subsequent options. If @code{scm} is started from a tty, it will assume that it should be interactive unless given a subsequent @code{-b} option. @end deffn @deffn {Command Option} -b specifies that @code{scm} should run non-interactively. That means that @code{scm} will terminate after processing the command line or if there are errors. @end deffn @deffn {Command Option} -s specifies, by analogy with @code{sh}, that @code{scm} should run interactively and that further options are to be treated as program aguments. @end deffn @deffn {Command Option} - @deffnx {Command Option} --- specifies that further options are to be treated as program aguments. @end deffn @node Invocation Examples, SCM Variables, SCM Options, Operational Features @section Invocation Examples @table @code @item % scm foo.scm Loads and executes the contents of @file{foo.scm} and then enters interactive session. @item % scm -f foo.scm arg1 arg2 arg3 Parameters @code{arg1}, @code{arg2}, and @code{arg3} are stored in the global list @code{*argv*}; Loads and executes the contents of @file{foo.scm} and exits. @item % scm -s foo.scm arg1 arg2 Sets *argv* to @code{("foo.scm" "arg1" "arg2")} and enters interactive session. @item % scm -e `(write (list-ref *argv* *optind*))' bar Prints @samp{"bar"}. @item % scm -rpretty-print -r format -i Loads @code{pretty-print} and @code{format} and enters interactive session. @item % scm -r5 Loads @code{dynamic-wind}, @code{values}, and syntax-rules macros and enters interactive (with macros) session. @item % scm -r5 -r4 Like above but @code{rev4-optional-procedures} are also loaded. @end table @node SCM Variables, SCM Session, Invocation Examples, Operational Features @section Environment Variables @defvr {Environment Variable} SCM_INIT_PATH is the pathname where @code{scm} will look for its initialization code. The default is the file @file{Init@value{SCMVERSION}.scm} in the source directory. @end defvr @defvr {Environment Variable} SCHEME_LIBRARY_PATH is the [SLIB] Scheme library directory. @end defvr @defvr {Environment Variable} HOME is the directory where @file{Init@value{SCMVERSION}.scm} will look for the user initialization file @file{ScmInit.scm}. @end defvr @defvr {Environment Variable} EDITOR is the name of the program which @code{ed} will call. If @var{EDITOR} is not defined, the default is @samp{ed}. @end defvr @section Scheme Variables @defvar *argv* contains the list of arguments to the program. @code{*argv*} can change during argument processing. This list is suitable for use as an argument to [SLIB] @code{getopt}. @end defvar @defvar *syntax-rules* controls whether loading and interaction support syntax-rules macros. Define this in @file{ScmInit.scm} or files specified on the command line. This can be overridden by subsequent @code{-m} and @code{-u} options. @end defvar @defvar *interactive* controls interactivity as explained for the @code{-i} and @code{-b} options. Define this in @file{ScmInit.scm} or files specified on the command line. This can be overridden by subsequent @code{-i} and @code{-b} options. @end defvar @node SCM Session, Editing Scheme Code, SCM Variables, Operational Features @section SCM Session @itemize @bullet @item Options, file loading and features can be specified from the command line. @xref{System interface, , , scm, SCM}. @xref{Require, , , slib, SLIB}. @item Typing the end-of-file character at the top level session (while SCM is not waiting for parenthesis closure) causes SCM to exit. @item Typing the interrupt character aborts evaluation of the current form and resumes the top level read-eval-print loop. @end itemize @defun quit @defunx quit n @defunx exit @defunx exit n Aliases for @code{exit} (@pxref{System, exit, , slib, SLIB}). On many systems, SCM can also tail-call another program. @xref{I/O-Extensions, execp}. @end defun @deffn {Callback procedure} boot-tail dumped? @code{boot-tail} is called by @code{scm_top_level} just before entering interactive top-level. If @code{boot-tail} calls @code{quit}, then interactive top-level is not entered. @end deffn @defun program-arguments Returns a list of strings of the arguments scm was called with. @end defun @defun getlogin Returns the (login) name of the user logged in on the controlling terminal of the process, or #f if this information cannot be determined. @end defun @noindent For documentation of the procedures @code{getenv} and @code{system} @xref{System Interface, , , slib, SLIB}. @defun vms-debug If SCM is compiled under VMS this @code{vms-debug} will invoke the VMS debugger. @end defun @node Editing Scheme Code, Debugging Scheme Code, SCM Session, Operational Features @section Editing Scheme Code @defun ed arg1 @dots{} The value of the environment variable @code{EDITOR} (or just @code{ed} if it isn't defined) is invoked as a command with arguments @var{arg1} @dots{}. @defunx ed filename If SCM is compiled under VMS @code{ed} will invoke the editor with a single the single argument @var{filename}. @end defun @table @asis @item Gnu Emacs: Editing of Scheme code is supported by emacs. Buffers holding files ending in .scm are automatically put into scheme-mode. If your Emacs can run a process in a buffer you can use the Emacs command @samp{M-x run-scheme} with SCM. Otherwise, use the emacs command @samp{M-x suspend-emacs}; or see ``other systems'' below. @item Epsilon (MS-DOS): There is lisp (and scheme) mode available by use of the package @samp{LISP.E}. It offers several different indentation formats. With this package, buffers holding files ending in @samp{.L}, @samp{.LSP}, @samp{.S}, and @samp{.SCM} (my modification) are automatically put into lisp-mode. It is possible to run a process in a buffer under Epsilon. With Epsilon 5.0 the command line options @samp{-e512 -m0} are neccessary to manage RAM properly. It has been reported that when compiling SCM with Turbo C, you need to @samp{#define NOSETBUF} for proper operation in a process buffer with Epsilon 5.0. One can also call out to an editor from SCM if RAM is at a premium; See ``under other systems'' below. @item other systems: Define the environment variable @samp{EDITOR} to be the name of the editing program you use. The SCM procedure @code{(ed arg1 @dots{})} will invoke your editor and return to SCM when you exit the editor. The following definition is convenient: @example (define (e) (ed "work.scm") (load "work.scm")) @end example Typing @samp{(e)} will invoke the editor with the file of interest. After editing, the modified file will be loaded. @end table @node Debugging Scheme Code, Debugging Continuations, Editing Scheme Code, Operational Features @section Debugging Scheme Code @noindent The @code{cautious} option of @code{build} (@pxref{Build Options}) supports debugging in Scheme. @table @dfn @item CAUTIOUS If SCM is built with the @samp{CAUTIOUS} flag, then when an error occurs, a @dfn{stack trace} of certain pending calls are printed as part of the default error response. A (memoized) expression and newline are printed for each partially evaluated combination whose procedure is not builtin. See @ref{Memoized Expressions} for how to read memoized expressions. Also as the result of the @samp{CAUTIOUS} flag, both @code{error} and @code{user-interrupt} (invoked by @key{C-c}) to print stack traces and conclude by calling @code{breakpoint} (@pxref{Breakpoints, , , slib, SLIB}) instead of aborting to top level. Under either condition, program execution can be resumed by @code{(continue)}. In this configuration one can interrupt a running Scheme program with @key{C-c}, inspect or modify top-level values, trace or untrace procedures, and continue execution with @code{(continue)}. @end table If @code{verbose} (@pxref{Internal State, verbose}) is called with an argument greater than 2, then the interpreter will check stack size periodically. If the size of stack in use exceeds the C #define @code{STACK_LIMIT} (default is @code{HEAP_SEG_SIZE}), SCM generates a @samp{stack} @code{segment violation}. @noindent There are several SLIB macros which so useful that SCM automatically loads the appropriate module from SLIB if they are invoked. @defmac trace proc1 @dots{} Traces the top-level named procedures given as arguments. @defmacx trace With no arguments, makes sure that all the currently traced identifiers are traced (even if those identifiers have been redefined) and returns a list of the traced identifiers. @end defmac @defmac untrace proc1 @dots{} Turns tracing off for its arguments. @defmacx untrace With no arguments, untraces all currently traced identifiers and returns a list of these formerly traced identifiers. @end defmac The routines I use most frequently for debugging are: @defun print arg1 @dots{} @code{Print} writes all its arguments, separated by spaces. @code{Print} outputs a @code{newline} at the end and returns the value of the last argument. One can just insert @samp{(print '