~ chicken-core (master) /library.scm


   1;;;; library.scm - R5RS/R7RS library for the CHICKEN compiler
   2;
   3; Copyright (c) 2008-2022, The CHICKEN Team
   4; Copyright (c) 2000-2007, Felix L. Winkelmann
   5; All rights reserved.
   6;
   7; Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
   8; conditions are met:
   9;
  10;   Redistributions of source code must retain the above copyright notice, this list of conditions and the following
  11;     disclaimer.
  12;   Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
  13;     disclaimer in the documentation and/or other materials provided with the distribution.
  14;   Neither the name of the author nor the names of its contributors may be used to endorse or promote
  15;     products derived from this software without specific prior written permission.
  16;
  17; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
  18; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  19; AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
  20; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  21; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  22; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  23; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  24; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  25; POSSIBILITY OF SUCH DAMAGE.
  26
  27
  28(declare
  29  (unit library)
  30  (uses build-version)
  31  (disable-interrupts)
  32  (hide ##sys#dynamic-unwind
  33	##sys#vector-resize ##sys#default-parameter-vector
  34	setter-tag
  35	##sys#print-exit ##sys#r7rs-exn-handlers
  36	##sys#format-here-doc-warning
  37	exit-in-progress cleanup-before-exit chicken.base#cleanup-tasks
  38        maximal-string-length find-ratio-between find-ratio
  39	make-complex flonum->ratnum ratnum
  40	+maximum-allowed-exponent+ mantexp->dbl ldexp ldexp*
  41	round-quotient
  42	fllog1+ ##sys#sign ##sys#atanh ##sys#internal-atanh
  43	##sys#sign-bit ##sys#tanh
  44	##sys#string->compnum ##sys#internal-gcd)
  45  (not inline chicken.base#sleep-hook ##sys#change-directory-hook
  46       ##sys#user-read-hook ##sys#error-hook ##sys#signal-hook ##sys#signal-hook/errno
  47       ##sys#default-read-info-hook ##sys#infix-list-hook
  48       ##sys#sharp-number-hook ##sys#user-print-hook
  49       ##sys#user-interrupt-hook ##sys#windows-platform
  50       ##sys#resume-thread-on-event ##sys#suspend-thread-on-event
  51       ##sys#schedule ##sys#features)
  52  (foreign-declare #<<EOF
  53#include <errno.h>
  54#include <float.h>
  55
  56#ifdef HAVE_SYSEXITS_H
  57# include <sysexits.h>
  58#endif
  59
  60#ifndef EX_SOFTWARE
  61# define EX_SOFTWARE	70
  62#endif
  63
  64#define C_close_file(p)	      (C_fclose((C_FILEPTR)(C_port_file(p))), C_SCHEME_UNDEFINED)
  65#define C_a_f64peek(ptr, c, b, i)  C_flonum(ptr, ((double *)C_data_pointer(b))[ C_unfix(i) ])
  66#define C_fetch_c_strlen(b, i) C_fix(strlen((C_char *)C_block_item(b, C_unfix(i))))
  67#define C_asciiz_strlen(str) C_fix(strlen(C_c_string(str)))
  68#define C_peek_c_string(b, i, to, len) (C_memcpy(C_data_pointer(to), (C_char *)C_block_item(b, C_unfix(i)), C_unfix(len)), C_SCHEME_UNDEFINED)
  69#define C_free_mptr(p, i)     (C_free((void *)C_block_item(p, C_unfix(i))), C_SCHEME_UNDEFINED)
  70#define C_free_sptr(p, i)     (C_free((void *)(((C_char **)C_block_item(p, 0))[ C_unfix(i) ])), C_SCHEME_UNDEFINED)
  71
  72#define C_a_get_current_seconds(ptr, c, dummy)  C_int64_to_num(ptr, time(NULL))
  73#define C_peek_c_string_at(ptr, i)    ((C_char *)(((C_char **)ptr)[ i ]))
  74
  75#define C_flush_all_files(dummy)    (C_fflush(NULL), C_SCHEME_UNDEFINED)
  76
  77static C_word
  78fast_read_line_from_file(C_word str, C_word start, C_word port, C_word size) {
  79  int n = C_unfix(size);
  80  int i;
  81  int c;
  82  int p = C_unfix(start);
  83  char *buf = C_c_string(str) + p;
  84  C_FILEPTR fp = C_port_file(port);
  85
  86  if ((c = C_getc(fp)) == EOF) {
  87    if (ferror(fp)) {
  88      clearerr(fp);
  89      if(p) return start;
  90      return C_fix(-1);
  91    } else { /* feof (fp) */
  92      if(p) return start;
  93      return C_SCHEME_END_OF_FILE;
  94    }
  95  }
  96
  97  C_ungetc(c, fp);
  98
  99  for (i = 0; i < n; i++) {
 100    c = C_getc(fp);
 101
 102    if(c == EOF && ferror(fp)) {
 103      clearerr(fp);
 104      return C_fix(-(i + 1) + p);
 105    }
 106
 107    switch (c) {
 108    case '\r':	if ((c = C_getc(fp)) != '\n') C_ungetc(c, fp);
 109    case EOF:	clearerr(fp);
 110    case '\n':	return C_fix(i + p);
 111    }
 112    buf[i] = c;
 113  }
 114  if(p) return start;
 115  return C_SCHEME_FALSE;
 116}
 117
 118static C_word
 119fast_read_string_from_file(C_word dest, C_word port, C_word len, C_word pos)
 120{
 121  size_t m;
 122  int n = C_unfix (len);
 123  C_char * buf = C_c_string(dest) + C_unfix(pos);
 124  C_FILEPTR fp = C_port_file (port);
 125
 126  if(feof(fp)) return C_SCHEME_END_OF_FILE;
 127
 128  m = fread (buf, sizeof (char), n, fp);
 129
 130  if (m < n) {
 131    if (ferror(fp)) /* Report to Scheme, which may retry, so clear errors */
 132      clearerr(fp);
 133    else if (feof(fp) && 0 == m) /* eof but m > 0? Return data first, below */
 134      return C_SCHEME_END_OF_FILE; /* Calling again will get us here */
 135  }
 136
 137  return C_fix (m);
 138}
 139
 140static C_word
 141shallow_equal(C_word x, C_word y)
 142{
 143  /* assumes x and y are non-immediate */
 144  int i, len = C_header_size(x);
 145
 146  if(C_header_size(y) != len) return C_SCHEME_FALSE;
 147  else return C_mk_bool(!C_memcmp((void *)x, (void *)y, len * sizeof(C_word)));
 148}
 149
 150static C_word
 151signal_debug_event(C_word mode, C_word msg, C_word args)
 152{
 153  C_DEBUG_INFO cell;
 154  C_word av[ 3 ];
 155  cell.enabled = 1;
 156  cell.event = C_DEBUG_SIGNAL;
 157  cell.loc = "";
 158  cell.val = "";
 159  av[ 0 ] = mode;
 160  av[ 1 ] = msg;
 161  av[ 2 ] = args;
 162  C_debugger(&cell, 3, av);
 163  return C_SCHEME_UNDEFINED;
 164}
 165
 166static C_word C_i_sleep_until_interrupt(C_word secs)
 167{
 168   while(C_i_process_sleep(secs) == C_fix(-1) && errno == EINTR);
 169   return C_SCHEME_UNDEFINED;
 170}
 171
 172#ifdef NO_DLOAD2
 173# define HAVE_DLOAD 0
 174#else
 175# define HAVE_DLOAD 1
 176#endif
 177
 178#ifdef C_ENABLE_PTABLES
 179# define HAVE_PTABLES 1
 180#else
 181# define HAVE_PTABLES 0
 182#endif
 183
 184#ifdef C_GC_HOOKS
 185# define HAVE_GCHOOKS 1
 186#else
 187# define HAVE_GCHOOKS 0
 188#endif
 189
 190#if defined(C_CROSS_CHICKEN) && C_CROSS_CHICKEN
 191# define IS_CROSS_CHICKEN 1
 192#else
 193# define IS_CROSS_CHICKEN 0
 194#endif
 195EOF
 196) )
 197
 198;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 199;; NOTE: Modules defined here will typically exclude syntax
 200;; definitions, those are handled by expand.scm or modules.scm.
 201;; Handwritten import libraries (or a special-case module in
 202;; modules.scm for scheme) contain the value exports merged with
 203;; syntactic exports.  The upshot of this is that any module that
 204;; refers to another module defined *earlier* in this file cannot use
 205;; macros from the earlier module!
 206;;
 207;; We get around this problem by using the "chicken.internal.syntax"
 208;; module, which is baked in and exports *every* available core macro.
 209;; See modules.scm, expand.scm and chicken-syntax.scm for details.
 210;;
 211;; NOTE #2: The module "scheme" is a legacy artifact, with CHICKEN
 212;; 6 "scheme" being just an alias for "scheme.r5rs", and "scheme.base"
 213;; is what used to be the standard Scheme module. We use it only
 214;; to provide a prefix ("scheme#") for the exported toplevel
 215;; identifiers, which now represent what is in the "scheme.base"
 216;; standard module. Yes, this is somewhat confusing, but changing
 217;; all prefixes to use the "proper" name would cause too many
 218;; bootstrapping problems.
 219;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 220
 221;; Pre-declaration of scheme, so it can be used later on.  We only use
 222;; scheme macros and core language forms in here, to avoid a cyclic
 223;; dependency on itself.  All actual definitions are set! below.
 224;; Also, this declaration is incomplete: the module itself is defined
 225;; as a primitive module due to syntax exports, which are missing
 226;; here.  See modules.scm for the full definition.
 227(module scheme
 228    (;; [syntax]
 229     ;; We are reexporting these because otherwise the module here
 230     ;; will be inconsistent with the built-in one, and be void of
 231     ;; syntax definitions, causing problems below.
 232     begin and case cond define define-syntax delay do lambda
 233     if let let* let-syntax letrec letrec-syntax or
 234     quasiquote quote set! syntax-rules
 235
 236     not boolean? eq? eqv? equal? pair? boolean=? symbol=?
 237     cons car cdr caar cadr cdar cddr caaar caadr cadar caddr cdaar
 238     cdadr cddar cdddr caaaar caaadr caadar caaddr cadaar cadadr
 239     caddar cadddr cdaaar cdaadr cdadar cdaddr cddaar cddadr cdddar
 240     cddddr set-car! set-cdr!
 241     null? list? list length list-tail list-ref append reverse memq memv
 242     member assq assv assoc symbol? symbol->string string->symbol number?
 243     integer? exact? real? complex? inexact? rational? zero? odd? even?
 244     positive? negative?  max min + - * / = > < >= <= quotient remainder
 245     exact-integer?
 246     modulo gcd lcm abs floor ceiling truncate round rationalize
 247     exact->inexact inexact->exact exp log expt sqrt
 248     sin cos tan asin acos atan
 249     number->string string->number char? char=? char>? char<? char>=?
 250     char<=? char-ci=? char-ci<? char-ci>?  char-ci>=? char-ci<=?
 251     char-alphabetic? char-whitespace? char-numeric? char-upper-case?
 252     char-lower-case? char-upcase char-downcase
 253     char->integer integer->char
 254     string? string=?  string>? string<? string>=? string<=? string-ci=?
 255     string-ci<? string-ci>? string-ci>=? string-ci<=?  make-string
 256     string-length string-ref string-set! string-append string-copy string-copy!
 257     string->list list->string substring string-fill! vector? make-vector
 258     vector-ref vector-set! string vector vector-length vector->list
 259     list->vector vector-fill! procedure? map for-each apply force
 260     call-with-current-continuation call/cc input-port? output-port?
 261     current-input-port current-output-port call-with-input-file
 262     call-with-output-file open-input-file open-output-file
 263     close-input-port close-output-port
 264     read read-char peek-char write display write-char newline
 265     eof-object? with-input-from-file with-output-to-file
 266     char-ready? imag-part real-part make-rectangular make-polar angle
 267     magnitude numerator denominator values call-with-values dynamic-wind
 268
 269     open-input-string open-output-string open-input-bytevector
 270     open-output-bytevector get-output-string get-output-bytevector
 271     features make-list port? call-with-port peek-u8 make-parameter
 272     string-map vector-map string-for-each vector-for-each u8-ready?
 273     make-list list-set! write-string eof-object list-copy
 274     string->vector vector->string textual-port? binary-port?
 275     input-port-open? output-port-open? floor/ truncate/
 276     exact inexact floor-remainder floor-quotient close-port
 277     
 278     char-foldcase string-foldcase string-upcase string-downcase
 279
 280     ;; The following procedures are overwritten in eval.scm:
 281     eval interaction-environment null-environment
 282     scheme-report-environment load)
 283
 284(import chicken.internal.syntax) ;; See note above
 285
 286;;; Operations on booleans:
 287
 288(define (not x) (##core#inline "C_i_not" x))
 289(define (boolean? x) (##core#inline "C_booleanp" x))
 290
 291
 292;;; Equivalence predicates:
 293
 294(define (eq? x y) (##core#inline "C_eqp" x y))
 295(define (eqv? x y) (##core#inline "C_i_eqvp" x y))
 296(define (equal? x y) (##core#inline "C_i_equalp" x y))
 297
 298(define (boolean=? x y . more)
 299  (##sys#check-boolean x 'boolean=?)
 300  (##sys#check-boolean y 'boolean=?)
 301  (let loop ((bs more) (f (eq? x y)))
 302    (if (null? bs)
 303        f
 304        (let ((b (##sys#slot bs 0)))
 305          (##sys#check-boolean b 'boolean=?)
 306          (loop (##sys#slot bs 1)
 307                (and f (eq? b y)))))))
 308
 309(define (symbol=? x y . more)
 310  (##sys#check-symbol x 'symbol=?)
 311  (##sys#check-symbol y 'symbol=?)
 312  (let loop ((bs more) (f (eq? x y)))
 313    (if (null? bs)
 314        f
 315        (let ((b (##sys#slot bs 0)))
 316          (##sys#check-symbol b 'symbol=?)
 317          (loop (##sys#slot bs 1)
 318                (and f (eq? b y)))))))
 319
 320
 321;;; Pairs and lists:
 322
 323(define (pair? x) (##core#inline "C_i_pairp" x))
 324(define (cons x y) (##core#inline_allocate ("C_a_i_cons" 3) x y))
 325(define (car x) (##core#inline "C_i_car" x))
 326(define (cdr x) (##core#inline "C_i_cdr" x))
 327
 328(define (set-car! x y) (##core#inline "C_i_set_car" x y))
 329(define (set-cdr! x y) (##core#inline "C_i_set_cdr" x y))
 330(define (cadr x) (##core#inline "C_i_cadr" x))
 331(define (caddr x) (##core#inline "C_i_caddr" x))
 332(define (cadddr x) (##core#inline "C_i_cadddr" x))
 333(define (cddddr x) (##core#inline "C_i_cddddr" x))
 334
 335(define (caar x) (##core#inline "C_i_caar" x))
 336(define (cdar x) (##core#inline "C_i_cdar" x))
 337(define (cddr x) (##core#inline "C_i_cddr" x))
 338(define (caaar x) (car (car (car x))))
 339(define (caadr x) (car (##core#inline "C_i_cadr" x)))
 340(define (cadar x) (##core#inline "C_i_cadr" (car x)))
 341(define (cdaar x) (cdr (car (car x))))
 342(define (cdadr x) (cdr (##core#inline "C_i_cadr" x)))
 343(define (cddar x) (cdr (cdr (car x))))
 344(define (cdddr x) (cdr (cdr (cdr x))))
 345(define (caaaar x) (car (car (car (car x)))))
 346(define (caaadr x) (car (car (##core#inline "C_i_cadr" x))))
 347(define (caadar x) (car (##core#inline "C_i_cadr" (car x))))
 348(define (caaddr x) (car (##core#inline "C_i_caddr" x)))
 349(define (cadaar x) (##core#inline "C_i_cadr" (car (car x))))
 350(define (cadadr x) (##core#inline "C_i_cadr" (##core#inline "C_i_cadr" x)))
 351(define (caddar x) (##core#inline "C_i_caddr" (car x)))
 352(define (cdaaar x) (cdr (car (car (car x)))))
 353(define (cdaadr x) (cdr (car (##core#inline "C_i_cadr" x))))
 354(define (cdadar x) (cdr (##core#inline "C_i_cadr" (car x))))
 355(define (cdaddr x) (cdr (##core#inline "C_i_caddr" x)))
 356(define (cddaar x) (cdr (cdr (car (car x)))))
 357(define (cddadr x) (cdr (cdr (##core#inline "C_i_cadr" x))))
 358(define (cdddar x) (cdr (cdr (cdr (car x)))))
 359
 360(define (null? x) (eq? x '()))
 361(define (list . lst) lst)
 362(define (length lst) (##core#inline "C_i_length" lst))
 363(define (list-tail lst i) (##core#inline "C_i_list_tail" lst i))
 364(define (list-ref lst i) (##core#inline "C_i_list_ref" lst i))
 365
 366(define append)
 367
 368(define (reverse lst0)
 369  (let loop ((lst lst0) (rest '()))
 370    (cond ((eq? lst '()) rest)
 371	  ((pair? lst)
 372	   (loop (##sys#slot lst 1) (cons (##sys#slot lst 0) rest)) )
 373	  (else (##sys#error-not-a-proper-list lst0 'reverse)) ) ))
 374
 375(define (memq x lst) (##core#inline "C_i_memq" x lst))
 376(define (memv x lst) (##core#inline "C_i_memv" x lst))
 377
 378(define (member x lst #!optional eq)
 379  (if eq
 380      (let loop ((lst lst))
 381        (and (pair? lst)
 382             (if (eq x (##sys#slot lst 0))
 383                 lst
 384                 (loop (##sys#slot lst 1)))))
 385      (##core#inline "C_i_member" x lst)))
 386
 387(define (assq x lst) (##core#inline "C_i_assq" x lst))
 388(define (assv x lst) (##core#inline "C_i_assv" x lst))
 389
 390(define (assoc x lst #!optional eq)
 391  (if eq
 392      (let loop ((lst lst))
 393        (and (pair? lst)
 394             (if (eq x (car (##sys#slot lst 0)))
 395                 (car lst)
 396                 (loop (##sys#slot lst 1)))))
 397      (##core#inline "C_i_assoc" x lst)))
 398
 399(define (list? x) (##core#inline "C_i_listp" x))
 400
 401;;; Strings:
 402
 403(define make-string)
 404
 405(define (string? x) (##core#inline "C_i_stringp" x))
 406(define (string-length s) (##core#inline "C_i_string_length" s))
 407(define (string-ref s i) (##core#inline "C_i_string_ref" s i))
 408(define (string-set! s i c) (##core#inline "C_i_string_set" s i c))
 409
 410(define (string=? x y . more)
 411  (let loop ((s y) (ss more) (f (##core#inline "C_i_string_equal_p" x y)))
 412    (if (null? ss)
 413        f
 414        (let ((s2 (##sys#slot ss 0)))
 415          (##sys#check-string s2 'string=?)
 416          (loop s2 (##sys#slot ss 1)
 417                (and f (##core#inline "C_i_string_equal_p" s s2)))))))
 418
 419(define (string-ci=? x y . more)
 420  (let loop ((s y) (ss more) (f (##core#inline "C_i_string_ci_equal_p" x y)))
 421    (if (null? ss)
 422        f
 423        (let ((s2 (##sys#slot ss 0)))
 424          (##sys#check-string s2 'string-ci=?)
 425          (loop s2 (##sys#slot ss 1)
 426                (and f (##core#inline "C_i_string_ci_equal_p" s s2)))))))
 427
 428(define string->list)
 429(define list->string)
 430(define string-copy)
 431(define string-copy!)
 432(define substring)
 433(define string-fill!)
 434
 435(define string<?)
 436(define string>?)
 437(define string<=?)
 438(define string>=?)
 439
 440(define string-ci<?)
 441(define string-ci>?)
 442(define string-ci<=?)
 443(define string-ci>=?)
 444
 445(define string)
 446(define string-append)
 447
 448(define open-input-string)
 449(define open-output-string)
 450(define open-input-bytevector)
 451(define open-output-bytevector)
 452(define get-output-string)
 453(define get-output-bytevector)
 454(define features)
 455(define make-list)
 456(define port?)
 457(define call-with-port)
 458(define close-port)
 459(define peek-u8)
 460(define string-map)
 461(define vector-map)
 462(define string-for-each)
 463(define vector-for-each)
 464(define make-list)
 465(define list-set!)
 466(define write-string)
 467(define eof-object)
 468(define list-copy)
 469(define string->vector)
 470(define vector->string)
 471(define input-port-open?)
 472(define output-port-open?)
 473(define floor/)
 474(define truncate/)
 475(define exact)
 476(define inexact)
 477(define floor-remainder)
 478(define floor-quotient)
 479(define make-parameter)
 480
 481;; Complex numbers
 482(define make-rectangular)
 483(define make-polar)
 484(define real-part)
 485(define imag-part)
 486(define angle)
 487(define magnitude)
 488
 489;; Rational numbers
 490(define numerator)
 491(define denominator)
 492(define inexact->exact)
 493(define (exact->inexact x)
 494  (##core#inline_allocate ("C_a_i_exact_to_inexact" 12) x))
 495
 496;; Numerical operations
 497(define (abs x) (##core#inline_allocate ("C_s_a_i_abs" 7) x))
 498(define + (##core#primitive "C_plus"))
 499(define - (##core#primitive "C_minus"))
 500(define * (##core#primitive "C_times"))
 501(define /)
 502(define floor)
 503(define ceiling)
 504(define truncate)
 505(define round)
 506(define rationalize)
 507
 508(define (quotient a b) (##core#inline_allocate ("C_s_a_i_quotient" 5) a b))
 509(define (remainder a b) (##core#inline_allocate ("C_s_a_i_remainder" 5) a b))
 510(define (modulo a b) (##core#inline_allocate ("C_s_a_i_modulo" 5) a b))
 511
 512(define (even? n) (##core#inline "C_i_evenp" n))
 513(define (odd? n) (##core#inline "C_i_oddp" n))
 514
 515(define max)
 516(define min)
 517(define exp)
 518(define log)
 519(define sin)
 520(define cos)
 521(define tan)
 522(define asin)
 523(define acos)
 524(define atan)
 525
 526(define sqrt)
 527(define expt)
 528(define gcd)
 529(define lcm)
 530
 531(define = (##core#primitive "C_nequalp"))
 532(define > (##core#primitive "C_greaterp"))
 533(define < (##core#primitive "C_lessp"))
 534(define >= (##core#primitive "C_greater_or_equal_p"))
 535(define <= (##core#primitive "C_less_or_equal_p"))
 536(define (number? x) (##core#inline "C_i_numberp" x))
 537(define complex? number?)
 538(define (real? x) (##core#inline "C_i_realp" x))
 539(define (rational? n) (##core#inline "C_i_rationalp" n))
 540(define (integer? x) (##core#inline "C_i_integerp" x))
 541(define (exact? x) (##core#inline "C_i_exactp" x))
 542(define (inexact? x) (##core#inline "C_i_inexactp" x))
 543(define (zero? n) (##core#inline "C_i_zerop" n))
 544(define (positive? n) (##core#inline "C_i_positivep" n))
 545(define (negative? n) (##core#inline "C_i_negativep" n))
 546(define (exact-integer? x) (##core#inline "C_i_exact_integerp" x))
 547
 548(define number->string (##core#primitive "C_number_to_string"))
 549(define string->number)
 550
 551
 552;;; Symbols:
 553
 554(define (symbol? x) (##core#inline "C_i_symbolp" x))
 555(define symbol->string)
 556(define string->symbol)
 557
 558;;; Vectors:
 559
 560(define (vector? x) (##core#inline "C_i_vectorp" x))
 561(define (vector-length v) (##core#inline "C_i_vector_length" v))
 562(define (vector-ref v i) (##core#inline "C_i_vector_ref" v i))
 563(define (vector-set! v i x) (##core#inline "C_i_vector_set" v i x))
 564(define make-vector)
 565(define list->vector)
 566(define vector->list)
 567(define vector)
 568(define vector-fill!)
 569
 570;;; Characters:
 571
 572(define (char? x) (##core#inline "C_charp" x))
 573
 574(define (char->integer c)
 575  (##sys#check-char c 'char->integer)
 576  (##core#inline "C_fix" (##core#inline "C_character_code" c)) )
 577
 578(define (##sys#check-char-code n loc)
 579  (if (or (##core#inline "C_fixnum_lessp" n 0)
 580          (##core#inline "C_fixnum_greaterp" n #x10ffff))
 581    (##sys#signal-hook
 582      #:domain-error loc "character code is out of valid range" n)
 583    n))
 584
 585(define-inline (fast-i->c n)
 586  (##core#inline "C_make_character" (##core#inline "C_unfix" n)) )
 587
 588(define (integer->char n)
 589  (##sys#check-fixnum n 'integer->char)
 590  (##sys#check-char-code n 'integer->char)
 591  (fast-i->c n))
 592 
 593(define (char=? c1 c2 . more)
 594  (##sys#check-char c1 'char=?)
 595  (##sys#check-char c2 'char=?)
 596  (let loop ((c c2) (cs more)
 597             (f (##core#inline "C_u_i_char_equalp" c1 c2)))
 598    (if (null? cs)
 599        f
 600        (let ((c2 (##sys#slot cs 0)))
 601          (##sys#check-char c2 'char=?)
 602          (loop c2 (##sys#slot cs 1)
 603                (and f (##core#inline "C_u_i_char_equalp" c c2)))))))
 604
 605(define (char>? c1 c2 . more)
 606  (##sys#check-char c1 'char>?)
 607  (##sys#check-char c2 'char>?)
 608  (let loop ((c c2) (cs more)
 609             (f (##core#inline "C_u_i_char_greaterp" c1 c2)))
 610    (if (null? cs)
 611        f
 612        (let ((c2 (##sys#slot cs 0)))
 613          (##sys#check-char c2 'char>?)
 614          (loop c2 (##sys#slot cs 1)
 615                (and f (##core#inline "C_u_i_char_greaterp" c c2)))))))
 616
 617(define (char<? c1 c2 . more)
 618  (##sys#check-char c1 'char<?)
 619  (##sys#check-char c2 'char<?)
 620  (let loop ((c c2) (cs more)
 621             (f (##core#inline "C_u_i_char_lessp" c1 c2)))
 622    (if (null? cs)
 623        f
 624        (let ((c2 (##sys#slot cs 0)))
 625          (##sys#check-char c2 'char<?)
 626          (loop c2 (##sys#slot cs 1)
 627                (and f (##core#inline "C_u_i_char_lessp" c c2)))))))
 628
 629(define (char>=? c1 c2 . more)
 630  (##sys#check-char c1 'char>=?)
 631  (##sys#check-char c2 'char>=?)
 632  (let loop ((c c2) (cs more)
 633             (f (##core#inline "C_u_i_char_greater_or_equal_p" c1 c2)))
 634    (if (null? cs)
 635        f
 636        (let ((c2 (##sys#slot cs 0)))
 637          (##sys#check-char c2 'char>=?)
 638          (loop c2 (##sys#slot cs 1)
 639                (and f (##core#inline "C_u_i_char_greater_or_equal_p" c c2)))))))
 640
 641(define (char<=? c1 c2 . more)
 642  (##sys#check-char c1 'char<=?)
 643  (##sys#check-char c2 'char<=?)
 644  (let loop ((c c2) (cs more)
 645             (f (##core#inline "C_u_i_char_less_or_equal_p" c1 c2)))
 646    (if (null? cs)
 647        f
 648        (let ((c2 (##sys#slot cs 0)))
 649          (##sys#check-char c2 'char<=?)
 650          (loop c2 (##sys#slot cs 1)
 651                (and f (##core#inline "C_u_i_char_less_or_equal_p" c c2)))))))
 652
 653(define (char-upcase c)
 654  (##sys#check-char c 'char-upcase)
 655  (##core#inline "C_u_i_char_upcase" c))
 656
 657(define (char-downcase c)
 658  (##sys#check-char c 'char-downcase)
 659  (##core#inline "C_u_i_char_downcase" c))
 660
 661(define char-ci=?)
 662(define char-ci>?)
 663(define char-ci<?)
 664(define char-ci>=?)
 665(define char-ci<=?)
 666
 667(define (char-upper-case? c)
 668  (##sys#check-char c 'char-upper-case?)
 669  (##core#inline "C_u_i_char_upper_casep" c) )
 670
 671(define (char-lower-case? c)
 672  (##sys#check-char c 'char-lower-case?)
 673  (##core#inline "C_u_i_char_lower_casep" c) )
 674
 675(define (char-numeric? c)
 676  (##sys#check-char c 'char-numeric?)
 677  (##core#inline "C_u_i_char_numericp" c) )
 678
 679(define (char-whitespace? c)
 680  (##sys#check-char c 'char-whitespace?)
 681  (##core#inline "C_u_i_char_whitespacep" c) )
 682
 683(define (char-alphabetic? c)
 684  (##sys#check-char c 'char-alphabetic?)
 685  (##core#inline "C_u_i_char_alphabeticp" c) )
 686
 687(define (scheme.char#digit-value c)
 688  (##sys#check-char c 'digit-value)
 689  (let ((n (##core#inline "C_u_i_digit_value" c)))
 690    (and (not (eq? n 0))
 691         (##core#inline "C_fixnum_difference" n 1))))
 692
 693;; case folding and conversion
 694
 695(define (char-foldcase c)
 696  (##sys#check-char c 'char-foldcase)
 697  (##core#inline "C_utf_char_foldcase" c))
 698
 699(define (string-foldcase str)
 700  (##sys#check-string str 'string-foldcase)
 701  (let* ((bv (##sys#slot str 0))
 702         (n (##core#inline "C_fixnum_difference" (##sys#size bv) 1))
 703         (buf (##sys#make-bytevector (##core#inline "C_fixnum_times" n 2)))
 704         (len (##core#inline "C_utf_string_foldcase" bv buf n)))
 705    (##sys#buffer->string! buf len)))
 706    
 707(define (string-downcase str)
 708  (##sys#check-string str 'string-downcase)
 709  (let* ((bv (##sys#slot str 0))
 710         (n (##core#inline "C_fixnum_difference" (##sys#size bv) 1))
 711         (buf (##sys#make-bytevector (##core#inline "C_fixnum_times" n 2)))
 712         (len (##core#inline "C_utf_string_downcase" bv buf n)))
 713    (##sys#buffer->string! buf len)))
 714
 715(define (string-upcase str)
 716  (##sys#check-string str 'string-upcase)
 717  (let* ((bv (##sys#slot str 0))
 718         (n (##core#inline "C_fixnum_difference" (##sys#size bv) 1))
 719         (buf (##sys#make-bytevector (##core#inline "C_fixnum_times" n 2)))
 720         (len (##core#inline "C_utf_string_upcase" bv buf n)))
 721    (##sys#buffer->string! buf len)))
 722
 723;;; Procedures:
 724
 725(define (procedure? x) (##core#inline "C_i_closurep" x))
 726(define apply (##core#primitive "C_apply"))
 727(define values (##core#primitive "C_values"))
 728(define call-with-values (##core#primitive "C_call_with_values"))
 729(define call-with-current-continuation)
 730(define call/cc)
 731
 732;;; Ports:
 733
 734(define (input-port? x)
 735  (and (##core#inline "C_blockp" x)
 736       (##core#inline "C_input_portp" x)))
 737
 738(define (output-port? x)
 739  (and (##core#inline "C_blockp" x)
 740       (##core#inline "C_output_portp" x)))
 741
 742(define (binary-port? port)
 743  (and (port? port)
 744       (eq? 'binary (##sys#slot port 14))))
 745
 746(define (textual-port? port)
 747  (and (port? port)
 748       (eq? 'textual (##sys#slot port 14))))
 749
 750(set! scheme#port?
 751  (lambda (x)
 752    (and (##core#inline "C_blockp" x)
 753         (##core#inline "C_portp" x))))
 754
 755(set! scheme#input-port-open?
 756  (lambda (p)
 757    (##sys#check-input-port p 'input-port-open?)
 758    (##core#inline "C_input_port_openp" p)))
 759
 760(set! scheme#output-port-open?
 761  (lambda (p)
 762    (##sys#check-output-port p 'output-port-open?)
 763    (##core#inline "C_output_port_openp" p)))
 764
 765(define current-input-port)
 766(define current-output-port)
 767(define open-input-file)
 768(define open-output-file)
 769(define close-input-port)
 770(define close-output-port)
 771(define call-with-input-file)
 772(define call-with-output-file)
 773(define with-input-from-file)
 774(define with-output-to-file)
 775
 776;;; Input:
 777
 778(define (eof-object? x) (##core#inline "C_eofp" x))
 779(define char-ready?)
 780(define u8-ready?)
 781(define read-char)
 782(define peek-char)
 783(define read)
 784
 785;;; Output:
 786
 787(define write-char)
 788(define newline)
 789(define write)
 790(define display)
 791
 792;;; Evaluation environments:
 793
 794;; All of the stuff below is overwritten with their "real"
 795;; implementations by chicken.eval (see eval.scm)
 796
 797(define (eval x . env)
 798  (##sys#error 'eval "`eval' is not defined - the `eval' unit was probably not linked with this executable"))
 799
 800(define (interaction-environment)
 801  (##sys#error 'interaction-environment "`interaction-environment' is not defined - the `eval' unit was probably not linked with this executable"))
 802
 803(define (scheme-report-environment n)
 804  (##sys#error 'scheme-report-environment "`scheme-report-environment' is not defined - the `eval' unit was probably not linked with this executable"))
 805
 806(define (null-environment)
 807  (##sys#error 'null-environment "`null-environment' is not defined - the `eval' unit was probably not linked with this executable"))
 808
 809(define (load filename . evaluator)
 810  (##sys#error 'load "`load' is not defined - the `eval' unit was probably not linked with this executable"))
 811
 812;; Other stuff:
 813
 814(define force)
 815(define for-each)
 816(define map)
 817(define dynamic-wind)
 818
 819) ; scheme
 820
 821(import scheme)
 822(import (only (scheme base) make-parameter open-output-string get-output-string))
 823
 824;; Pre-declaration of chicken.base, so it can be used later on.  Much
 825;; like the "scheme" module, most declarations will be set! further
 826;; down in this file, mostly to avoid a cyclic dependency on itself.
 827;; The full definition (with macros) is in its own import library.
 828(module chicken.base
 829  (;; [syntax] and-let* case-lambda cut cute declare define-constant
 830   ;; define-inline define-record define-record-type
 831   ;; define-values delay-force fluid-let include
 832   ;; include-relative let-optionals let-values let*-values letrec*
 833   ;; letrec-values nth-value optional parameterize rec receive
 834   ;; require-library require-extension set!-values syntax unless when
 835   bignum? flonum? fixnum? ratnum? cplxnum? finite? infinite? nan?
 836   exact-integer-sqrt exact-integer-nth-root
 837
 838   port-closed? flush-output
 839   get-call-chain print print* add1 sub1 sleep
 840   current-error-port error void gensym print-call-chain
 841   char-name enable-warnings
 842   equal=? finite? foldl foldr getter-with-setter
 843   notice procedure-information setter signum string->uninterned-symbol
 844   subvector symbol-append vector-resize
 845   warning quotient&remainder quotient&modulo
 846   record-printer set-record-printer!
 847   make-promise promise?
 848   alist-ref alist-update alist-update! rassoc atom? butlast chop
 849   compress flatten intersperse join list-of? tail? constantly
 850   complement compose conjoin disjoin each flip identity o
 851
 852   case-sensitive keyword-style parentheses-synonyms symbol-escape
 853
 854   on-exit exit exit-handler implicit-exit-handler emergency-exit
 855   bwp-object? weak-cons weak-pair?)
 856
 857(import scheme chicken.internal.syntax)
 858
 859(define (fixnum? x) (##core#inline "C_fixnump" x))
 860(define (flonum? x) (##core#inline "C_i_flonump" x))
 861(define (bignum? x) (##core#inline "C_i_bignump" x))
 862(define (ratnum? x) (##core#inline "C_i_ratnump" x))
 863(define (cplxnum? x) (##core#inline "C_i_cplxnump" x))
 864(define exact-integer-sqrt)
 865(define exact-integer-nth-root)
 866
 867(define quotient&remainder (##core#primitive "C_quotient_and_remainder"))
 868;; Modulo's sign follows y (whereas remainder's sign follows x)
 869;; Inlining this is not much use: quotient&remainder is primitive
 870(define (quotient&modulo x y)
 871  (call-with-values (lambda () (quotient&remainder x y))
 872    (lambda (div rem)
 873      (if (positive? y)
 874	  (if (negative? rem)
 875	      (values div (+ rem y))
 876	      (values div rem))
 877	  (if (positive? rem)
 878	      (values div (+ rem y))
 879	      (values div rem))))))
 880
 881
 882(define (finite? x) (##core#inline "C_i_finitep" x))
 883(define (infinite? x) (##core#inline "C_i_infinitep" x))
 884(define (nan? x) (##core#inline "C_i_nanp" x))
 885
 886(define signum (##core#primitive "C_signum"))
 887
 888(define equal=?)
 889(define get-call-chain)
 890(define print-call-chain)
 891(define print)
 892(define print*)
 893(define (add1 n) (+ n 1))
 894(define (sub1 n) (- n 1))
 895(define current-error-port)
 896
 897(define (error . args)
 898  (if (pair? args)
 899      (apply ##sys#signal-hook #:error args)
 900      (##sys#signal-hook #:error #f)))
 901
 902(define (void . _) (##core#undefined))
 903
 904(define sleep)
 905
 906(define char-name)
 907(define enable-warnings)
 908; (define enable-notices)???
 909(define getter-with-setter)
 910(define procedure-information)
 911(define setter)
 912(define string->uninterned-symbol)
 913(define record-printer)
 914(define set-record-printer!)
 915
 916(define gensym)
 917
 918(define subvector)
 919(define vector-resize)
 920
 921(define symbol-append)
 922(define warning)
 923(define notice)
 924
 925(define port-closed?)
 926(define flush-output)
 927
 928;;; Promises:
 929
 930(define (promise? x)
 931  (##sys#structure? x 'promise))
 932
 933(define (##sys#make-promise proc)
 934  (##sys#make-structure 'promise proc))
 935
 936(define (make-promise obj)
 937  (if (promise? obj) obj
 938      (##sys#make-promise (lambda () obj))))
 939
 940;;; fast folds with correct argument order
 941
 942(define (foldl f z lst)
 943  (##sys#check-list lst 'foldl)
 944  (let loop ((lst lst) (z z))
 945    (if (not (pair? lst))
 946	z
 947	(loop (##sys#slot lst 1) (f z (##sys#slot lst 0))))))
 948
 949(define (foldr f z lst)
 950  (##sys#check-list lst 'foldr)
 951  (let loop ((lst lst))
 952    (if (not (pair? lst))
 953	z
 954	(f (##sys#slot lst 0) (loop (##sys#slot lst 1))))))
 955
 956;;; Exit:
 957
 958(define implicit-exit-handler)
 959(define exit-handler)
 960
 961(define chicken.base#cleanup-tasks '())
 962
 963(define (on-exit thunk)
 964  (set! cleanup-tasks (cons thunk chicken.base#cleanup-tasks)))
 965
 966(define (exit #!optional (code 0))
 967  ((exit-handler) code))
 968
 969(define (emergency-exit #!optional (code 0))
 970  (##sys#check-fixnum code 'emergency-exit)
 971  (##core#inline "C_exit_runtime" code))
 972
 973;;; Parameters:
 974
 975(define case-sensitive)
 976(define keyword-style)
 977(define parentheses-synonyms)
 978(define symbol-escape)
 979
 980;;; Combinators:
 981
 982(define (identity x) x)
 983
 984(define (conjoin . preds)
 985  (lambda (x)
 986    (let loop ((preds preds))
 987      (or (null? preds)
 988	  (and ((##sys#slot preds 0) x)
 989	       (loop (##sys#slot preds 1)) ) ) ) ) )
 990
 991(define (disjoin . preds)
 992  (lambda (x)
 993    (let loop ((preds preds))
 994      (and (not (null? preds))
 995	   (or ((##sys#slot preds 0) x)
 996	       (loop (##sys#slot preds 1)) ) ) ) ) )
 997
 998(define (constantly . xs)
 999  (if (eq? 1 (length xs))
 1000      (let ((x (car xs)))
1001	(lambda _ x) )
1002      (lambda _ (apply values xs)) ) )
1003
1004(define (flip proc) (lambda (x y) (proc y x)))
1005
1006(define complement
1007  (lambda (p)
1008    (lambda args (not (apply p args))) ) )
1009
1010(define (compose . fns)
1011  (define (rec f0 . fns)
1012    (if (null? fns)
1013	f0
1014	(lambda args
1015	  (call-with-values
1016	      (lambda () (apply (apply rec fns) args))
1017	    f0) ) ) )
1018  (if (null? fns)
1019      values
1020      (apply rec fns) ) )
1021
1022(define (o . fns)
1023  (if (null? fns)
1024      identity
1025      (let loop ((fns fns))
1026	(let ((h (##sys#slot fns 0))
1027	      (t (##sys#slot fns 1)) )
1028	  (if (null? t)
1029	      h
1030	      (lambda (x) (h ((loop t) x))))))))
1031
1032(define (list-of? pred)
1033  (lambda (lst)
1034    (let loop ((lst lst))
1035      (cond ((null? lst) #t)
1036	    ((not (pair? lst)) #f)
1037	    ((pred (##sys#slot lst 0)) (loop (##sys#slot lst 1)))
1038	    (else #f) ) ) ) )
1039
1040(define (each . procs)
1041  (cond ((null? procs) (lambda _ (void)))
1042	((null? (##sys#slot procs 1)) (##sys#slot procs 0))
1043	(else
1044	 (lambda args
1045	   (let loop ((procs procs))
1046	     (let ((h (##sys#slot procs 0))
1047		   (t (##sys#slot procs 1)) )
1048	       (if (null? t)
1049		   (apply h args)
1050		   (begin
1051		     (apply h args)
1052		     (loop t) ) ) ) ) ) ) ) )
1053
1054
1055;;; Weak pairs:
1056(define (bwp-object? x) (##core#inline "C_bwpp" x))
1057(define (weak-cons x y) (##core#inline_allocate ("C_a_i_weak_cons" 3) x y))
1058(define (weak-pair? x) (##core#inline "C_i_weak_pairp" x))
1059
1060;;; List operators:
1061
1062(define (atom? x) (##core#inline "C_i_not_pair_p" x))
1063
1064(define (tail? x y)
1065  (##sys#check-list y 'tail?)
1066  (let loop ((y y))
1067    (cond ((##core#inline "C_eqp" x y) #t)
1068          ((and (##core#inline "C_blockp" y)
1069                (##core#inline "C_pairp" y))
1070           (loop (##sys#slot y 1)))
1071          (else #f))))
1072
1073(define intersperse
1074  (lambda (lst x)
1075    (let loop ((ns lst))
1076      (if (##core#inline "C_eqp" ns '())
1077	  ns
1078	  (let ((tail (cdr ns)))
1079	    (if (##core#inline "C_eqp" tail '())
1080		ns
1081		(cons (##sys#slot ns 0) (cons x (loop tail))) ) ) ) ) ) )
1082
1083(define (butlast lst)
1084  (##sys#check-pair lst 'butlast)
1085  (let loop ((lst lst))
1086    (let ((next (##sys#slot lst 1)))
1087      (if (and (##core#inline "C_blockp" next) (##core#inline "C_pairp" next))
1088	  (cons (##sys#slot lst 0) (loop next))
1089	  '() ) ) ) )
1090
1091(define (flatten . lists0)
1092  (let loop ((lists lists0) (rest '()))
1093    (cond ((null? lists) rest)
1094	  (else
1095	   (let ((head (##sys#slot lists 0))
1096		 (tail (##sys#slot lists 1)) )
1097	     (if (list? head)
1098		 (loop head (loop tail rest))
1099		 (cons head (loop tail rest)) ) ) ) ) ) )
1100
1101(define chop)
1102
1103(define (join lsts . lst)
1104  (let ((lst (if (pair? lst) (car lst) '())))
1105    (##sys#check-list lst 'join)
1106    (let loop ((lsts lsts))
1107      (cond ((null? lsts) '())
1108	    ((not (pair? lsts))
1109	     (##sys#error-not-a-proper-list lsts) )
1110	    (else
1111	     (let ((l (##sys#slot lsts 0))
1112		   (r (##sys#slot lsts 1)) )
1113	       (if (null? r)
1114		   l
1115		   (##sys#append l lst (loop r)) ) ) ) ) ) ) )
1116
1117(define compress
1118  (lambda (blst lst)
1119    (let ((msg "bad argument type - not a proper list"))
1120      (##sys#check-list lst 'compress)
1121      (let loop ((blst blst) (lst lst))
1122	(cond ((null? blst) '())
1123	      ((not (pair? blst))
1124	       (##sys#signal-hook #:type-error 'compress msg blst) )
1125	      ((not (pair? lst))
1126	       (##sys#signal-hook #:type-error 'compress msg lst) )
1127	      ((##sys#slot blst 0)
1128	       (cons (##sys#slot lst 0) (loop (##sys#slot blst 1) (##sys#slot lst 1))))
1129	      (else (loop (##sys#slot blst 1) (##sys#slot lst 1))) ) ) ) ) )
1130
1131
1132;;; Alists:
1133
1134(define (alist-update! x y lst #!optional (cmp eqv?))
1135  (let* ((aq (cond ((eq? eq? cmp) assq)
1136		   ((eq? eqv? cmp) assv)
1137		   ((eq? equal? cmp) assoc)
1138		   (else
1139		    (lambda (x lst)
1140		      (let loop ((lst lst))
1141			(and (pair? lst)
1142			     (let ((a (##sys#slot lst 0)))
1143			       (if (and (pair? a) (cmp x (##sys#slot a 0)))
1144				   a
1145				   (loop (##sys#slot lst 1)) ) ) ) ) ) ) ) )
1146	 (item (aq x lst)) )
1147    (if item
1148	(begin
1149	  (##sys#setslot item 1 y)
1150	  lst)
1151	(cons (cons x y) lst) ) ) )
1152
1153(define (alist-update k v lst #!optional (cmp eqv?))
1154  (let loop ((lst lst))
1155    (cond ((null? lst)
1156           (list (cons k v)))
1157          ((not (pair? lst))
1158           (error 'alist-update "bad argument type" lst))
1159          (else
1160           (let ((a (##sys#slot lst 0)))
1161             (cond ((not (pair? a))
1162                    (error 'alist-update "bad argument type" a))
1163                   ((cmp k (##sys#slot a 0))
1164                    (cons (cons k v) (##sys#slot lst 1)))
1165                   (else
1166                    (cons (cons (##sys#slot a 0) (##sys#slot a 1))
1167                          (loop (##sys#slot lst 1))))))))))
1168
1169(define (alist-ref x lst #!optional (cmp eqv?) (default #f))
1170  (let* ((aq (cond ((eq? eq? cmp) assq)
1171		   ((eq? eqv? cmp) assv)
1172		   ((eq? equal? cmp) assoc)
1173		   (else
1174		    (lambda (x lst)
1175		      (let loop ((lst lst))
1176			(cond
1177			 ((null? lst) #f)
1178			 ((pair? lst)
1179			  (let ((a (##sys#slot lst 0)))
1180			    (##sys#check-pair a 'alist-ref)
1181			    (if (cmp x (##sys#slot a 0))
1182				a
1183				(loop (##sys#slot lst 1)) ) ))
1184			 (else (error 'alist-ref "bad argument type" lst)) )  ) ) ) ) )
1185	 (item (aq x lst)) )
1186    (if item
1187	(##sys#slot item 1)
1188	default) ) )
1189
1190;; TODO: Make inlineable in C without "tst", to be more like assoc?
1191(define (rassoc x lst . tst)
1192  (##sys#check-list lst 'rassoc)
1193  (let ((tst (if (pair? tst) (car tst) eqv?)))
1194    (let loop ((l lst))
1195      (and (pair? l)
1196	   (let ((a (##sys#slot l 0)))
1197	     (##sys#check-pair a 'rassoc)
1198	     (if (tst x (##sys#slot a 1))
1199		 a
1200		 (loop (##sys#slot l 1)) ) ) ) ) ) )
1201
1202) ; chicken.base
1203
1204(import chicken.base)
1205
1206(define-constant output-string-initial-size 256)
1207
1208(set! scheme#open-input-string
1209  (lambda (string)
1210    (##sys#check-string string 'open-input-string)
1211    (let* ((port (##sys#make-port 1 ##sys#string-port-class "(string)" 'string))
1212           (bv (##sys#slot string 0))
1213           (len (##core#inline "C_fixnum_difference" (##sys#size bv) 1))
1214           (bv2 (##sys#make-bytevector len)))
1215      (##core#inline "C_copy_memory" bv2 bv len)
1216      (##sys#setislot port 10 0)
1217      (##sys#setislot port 11 len)
1218      (##sys#setslot port 12 bv2)
1219      port)))
1220
1221(set! scheme#open-output-string
1222  (lambda ()
1223    (let ((port (##sys#make-port 2 ##sys#string-port-class "(string)" 'string)))
1224      (##sys#setislot port 10 0)
1225      (##sys#setislot port 11 output-string-initial-size)
1226      (##sys#setslot port 12 (##sys#make-bytevector output-string-initial-size))
1227      port)))
1228
1229(set! scheme#get-output-string
1230  (lambda (port)
1231    (##sys#check-output-port port #f 'get-output-string)
1232    (if (not (eq? 'string (##sys#slot port 7)))
1233        (##sys#signal-hook
1234         #:type-error 'get-output-string "argument is not a string-output-port" port)
1235        (##sys#buffer->string (##sys#slot port 12) 0 (##sys#slot port 10)))))
1236
1237(set! scheme#open-input-bytevector
1238 (lambda (bv)
1239  (let ((port (##sys#make-port 1 #f "(bytevector)" 'custom)))
1240    (##sys#check-bytevector bv 'open-input-bytevector)
1241    (##sys#setslot port 14 'binary)
1242    (##sys#setslot
1243     port
1244     2
1245     (let ((index 0)
1246           (bv-len (##sys#size bv)))
1247       (vector (lambda (_) ; read-char
1248                 (if (eq? index bv-len)
1249                     #!eof
1250                     (let ((c (##core#inline "C_i_bytevector_ref" bv index)))
1251                       (set! index (##core#inline "C_fixnum_plus" index 1))
1252                       (fast-i->c c))))
1253               (lambda (_) ; peek-char
1254                 (if (eq? index bv-len)
1255                     #!eof
1256                     (##core#inline "C_i_bytevector_ref" bv index)))
1257               #f    ; write-char
1258               #f    ; write-bytevector
1259               (lambda (_ _) ; close
1260                 (##sys#setislot port 8 #t))
1261               #f    ; flush-output
1262               (lambda (_) #t) ; u8-ready?
1263               (lambda (p n dest start)    ; read-bytevector!
1264                 (let ((n2 (min n (##core#inline "C_fixnum_difference" bv-len index))))
1265                   (##core#inline "C_copy_memory_with_offset" dest bv start index n2)
1266                   (set! index (##core#inline "C_fixnum_plus" index n2))
1267                   n2))
1268               #f    ; read-line
1269               #f    ; read-buffered
1270               (lambda (_) #t)  ; char-ready?
1271               )))
1272     port)))
1273
1274(set! scheme#open-output-bytevector
1275 (lambda ()
1276  (let ((port (##sys#make-port 2 #f "(bytevector)" 'custom))
1277        (buffer (##sys#make-bytevector 256))
1278        (index 0)
1279        (size 256))
1280    (define (add bv start end)
1281      (let* ((len (##core#inline "C_fixnum_difference" end start))
1282             (i2 (##core#inline "C_fixnum_plus" index len)))
1283        (when (##core#inline "C_fixnum_greaterp" i2 size)
1284          (let* ((sz2 (##core#inline "C_fixnum_plus" size i2))
1285                 (bv2 (##sys#make-bytevector sz2)))
1286            (##core#inline "C_copy_memory_with_offset" bv2 buffer 0 0 index)
1287            (set! size sz2)
1288            (set! buffer bv2)))
1289        (##core#inline "C_copy_memory_with_offset" buffer bv index start len)
1290        (set! index i2)))
1291    (define (getter)
1292      (let ((bv (##sys#make-bytevector index)))
1293        (##core#inline "C_copy_memory_with_offset" bv buffer 0 0 index)
1294        bv))
1295    (##sys#setslot port 9 getter)
1296    (##sys#setslot port 14 'binary)
1297    (##sys#setslot
1298     port
1299     2
1300     (vector #f ; read-char
1301             #f ; peek-char
1302             (lambda (p c)    ; write-char
1303               (let* ((s (string c))
1304                      (bv (##sys#slot s 0)))
1305                 (add bv 0 (##core#inline "C_fixnum_difference" (##sys#size bv) 1))))
1306             (lambda (p bv start end)    ; write-bytevector
1307               (add bv start end))
1308             (lambda (_ _) ; close
1309               (##sys#setislot port 8 #t))
1310             #f    ; flush-output
1311             #f ; u8-ready?
1312             #f  ; read-bytevector!
1313             #f    ; read-line
1314             #f ; read-buffered
1315             #f ; char-ready?
1316             ))
1317     port)))
1318
1319(set! scheme#get-output-bytevector
1320 (lambda (p)
1321  (define (fail) (error 'get-output-bytevector "not an output-bytevector" p))
1322  (##sys#check-port p 'get-output-bytevector)
1323  (if (eq? (##sys#slot p 7) 'custom)
1324      (let ((getter (##sys#slot p 9)))
1325        (if (procedure? getter)
1326            (getter)
1327            (fail)))
1328      (fail))))
1329
1330(define-constant char-name-table-size 37)
1331(define-constant read-line-buffer-initial-size 1024)
1332(define-constant default-parameter-vector-size 16)
1333(define maximal-string-length (- (foreign-value "C_HEADER_SIZE_MASK" unsigned-long) 1))
1334
1335;;; Fixnum arithmetic:
1336
1337(module chicken.fixnum *
1338(import scheme)
1339(import chicken.foreign)
1340
1341(define most-positive-fixnum (foreign-value "C_MOST_POSITIVE_FIXNUM" int))
1342(define most-negative-fixnum (foreign-value "C_MOST_NEGATIVE_FIXNUM" int))
1343(define fixnum-bits (foreign-value "(C_WORD_SIZE - 1)" int))
1344(define fixnum-precision (foreign-value "(C_WORD_SIZE - (1 + 1))" int))
1345
1346(define (fx+ x y) (##core#inline "C_fixnum_plus" x y))
1347(define (fx- x y) (##core#inline "C_fixnum_difference" x y))
1348(define (fx* x y) (##core#inline "C_fixnum_times" x y))
1349(define (fx= x y) (eq? x y))
1350(define (fx> x y) (##core#inline "C_fixnum_greaterp" x y))
1351(define (fx< x y) (##core#inline "C_fixnum_lessp" x y))
1352(define (fx>= x y) (##core#inline "C_fixnum_greater_or_equal_p" x y))
1353(define (fx<= x y) (##core#inline "C_fixnum_less_or_equal_p" x y))
1354(define (fxmin x y) (##core#inline "C_i_fixnum_min" x y))
1355(define (fxmax x y) (##core#inline "C_i_fixnum_max" x y))
1356(define (fxneg x) (##core#inline "C_fixnum_negate" x))
1357(define (fxand x y) (##core#inline "C_fixnum_and" x y))
1358(define (fxior x y) (##core#inline "C_fixnum_or" x y))
1359(define (fxxor x y) (##core#inline "C_fixnum_xor" x y))
1360(define (fxnot x) (##core#inline "C_fixnum_not" x))
1361(define (fxshl x y) (##core#inline "C_fixnum_shift_left" x y))
1362(define (fxshr x y) (##core#inline "C_fixnum_shift_right" x y))
1363(define (fxodd? x) (##core#inline "C_i_fixnumoddp" x))
1364(define (fxeven? x) (##core#inline "C_i_fixnumevenp" x))
1365(define (fxlen x) (##core#inline "C_i_fixnum_length" x))
1366(define (fx/ x y) (##core#inline "C_fixnum_divide" x y) )
1367(define (fxgcd x y) (##core#inline "C_i_fixnum_gcd" x y))
1368(define (fxmod x y) (##core#inline "C_fixnum_modulo" x y) )
1369(define (fxrem x y) (##core#inline "C_i_fixnum_remainder_checked" x y) )
1370
1371;; Overflow-detecting versions of some of the above
1372(define (fx+? x y) (##core#inline "C_i_o_fixnum_plus" x y) )
1373(define (fx-? x y) (##core#inline "C_i_o_fixnum_difference" x y) )
1374(define (fx*? x y) (##core#inline "C_i_o_fixnum_times" x y) )
1375(define (fx/? x y) (##core#inline "C_i_o_fixnum_quotient" x y))
1376
1377) ; chicken.fixnum
1378
1379(import chicken.fixnum)
1380
1381
1382;;; System routines:
1383
1384(define (##sys#debug-mode?) (##core#inline "C_i_debug_modep"))
1385
1386(define ##sys#warnings-enabled #t)
1387(define ##sys#notices-enabled (##sys#debug-mode?))
1388
1389(set! chicken.base#warning
1390  (lambda (msg . args)
1391    (when ##sys#warnings-enabled
1392      (apply ##sys#signal-hook #:warning msg args))))
1393
1394(set! chicken.base#notice
1395  (lambda (msg . args)
1396    (when (and ##sys#notices-enabled
1397	       ##sys#warnings-enabled)
1398      (apply ##sys#signal-hook #:notice msg args))))
1399
1400(set! chicken.base#enable-warnings
1401  (lambda bool
1402    (if (pair? bool)
1403	(set! ##sys#warnings-enabled (car bool))
1404	##sys#warnings-enabled)))
1405
1406(define ##sys#error error)
1407(define ##sys#warn warning)
1408(define ##sys#notice notice)
1409
1410(define (##sys#error/errno err . args)
1411  (if (pair? args)
1412      (apply ##sys#signal-hook/errno #:error err #f args)
1413      (##sys#signal-hook/errno #:error err #f)))
1414
1415(define-foreign-variable strerror c-string "strerror(errno)")
1416
1417(define ##sys#gc (##core#primitive "C_gc"))
1418(define (##sys#setslot x i y) (##core#inline "C_i_setslot" x i y))
1419(define (##sys#setislot x i y) (##core#inline "C_i_set_i_slot" x i y))
1420(define ##sys#allocate-vector (##core#primitive "C_allocate_vector"))
1421(define ##sys#allocate-bytevector (##core#primitive "C_allocate_bytevector"))
1422(define ##sys#make-structure (##core#primitive "C_make_structure"))
1423(define ##sys#ensure-heap-reserve (##core#primitive "C_ensure_heap_reserve"))
1424(define ##sys#symbol-table-info (##core#primitive "C_get_symbol_table_info"))
1425(define ##sys#memory-info (##core#primitive "C_get_memory_info"))
1426
1427(define (##sys#start-timer)
1428  (##sys#gc #t)
1429  (##core#inline "C_start_timer"))
1430
1431(define (##sys#stop-timer)
1432  (let ((info ((##core#primitive "C_stop_timer"))))
1433    ;; Run a major GC one more time to get memory usage information in
1434    ;; case there was no major GC while the timer was running
1435    (##sys#gc #t)
1436    (##sys#setslot info 6 (##sys#slot ((##core#primitive "C_stop_timer")) 6))
1437    info))
1438
1439(define (##sys#immediate? x) (not (##core#inline "C_blockp" x)))
1440(define (##sys#message str) (##core#inline "C_message" str))
1441(define (##sys#byte x i) (##core#inline "C_subbyte" x i))
1442(define ##sys#void void)
1443(define ##sys#undefined-value (##core#undefined))
1444(define (##sys#halt msg) (##core#inline "C_halt" msg))
1445(define ##sys#become! (##core#primitive "C_become"))
1446(define (##sys#block-ref x i) (##core#inline "C_i_block_ref" x i))
1447(define ##sys#apply-values (##core#primitive "C_apply_values"))
1448(define ##sys#copy-closure (##core#primitive "C_copy_closure"))
1449
1450(define (##sys#block-set! x i y)
1451  (when (or (not (##core#inline "C_blockp" x))
1452	    (and (##core#inline "C_specialp" x) (fx= i 0))
1453	    (##core#inline "C_byteblockp" x) )
1454    (##sys#signal-hook '#:type-error '##sys#block-set! "slot not accessible" x) )
1455  (##sys#check-range i 0 (##sys#size x) '##sys#block-set!)
1456  (##sys#setslot x i y) )
1457
1458(module chicken.time
1459    ;; NOTE: We don't emit the import lib.  Due to syntax exports, it has
1460    ;; to be a hardcoded primitive module.
1461    ;;
1462    ;; [syntax] time
1463    (cpu-time
1464     current-process-milliseconds current-seconds)
1465
1466(import scheme)
1467(import (only chicken.module reexport))
1468
1469(define (current-process-milliseconds)
1470  (##core#inline_allocate ("C_a_i_current_process_milliseconds" 7) #f))
1471
1472(define (current-seconds)
1473  (##core#inline_allocate ("C_a_get_current_seconds" 7) #f))
1474
1475(define cpu-time
1476  (let () ;; ((buf (vector #f #f))) Disabled for now: vector is defined below!
1477    (lambda ()
1478      (let ((buf (vector #f #f)))
1479	;; should be thread-safe as no context-switch will occur after
1480	;; function entry and `buf' contents will have been extracted
1481	;; before `values' gets called.
1482	(##core#inline_allocate ("C_a_i_cpu_time" 8) buf)
1483	(values (##sys#slot buf 0) (##sys#slot buf 1)) )) ))
1484
1485) ; chicken.time
1486
1487(define (##sys#check-structure x y . loc)
1488  (if (pair? loc)
1489      (##core#inline "C_i_check_structure_2" x y (car loc))
1490      (##core#inline "C_i_check_structure" x y) ) )
1491
1492;; DEPRECATED
1493(define (##sys#check-blob x . loc)
1494  (if (pair? loc)
1495      (##core#inline "C_i_check_bytevector_2" x (car loc))
1496      (##core#inline "C_i_check_bytevector" x) ) )
1497
1498(define ##sys#check-bytevector ##sys#check-blob)
1499
1500(define (##sys#check-pair x . loc)
1501  (if (pair? loc)
1502      (##core#inline "C_i_check_pair_2" x (car loc))
1503      (##core#inline "C_i_check_pair" x) ) )
1504
1505(define (##sys#check-list x . loc)
1506  (if (pair? loc)
1507      (##core#inline "C_i_check_list_2" x (car loc))
1508      (##core#inline "C_i_check_list" x) ) )
1509
1510(define (##sys#check-string x . loc)
1511  (if (pair? loc)
1512      (##core#inline "C_i_check_string_2" x (car loc))
1513      (##core#inline "C_i_check_string" x) ) )
1514
1515(define (##sys#check-number x . loc)
1516  (if (pair? loc)
1517      (##core#inline "C_i_check_number_2" x (car loc))
1518      (##core#inline "C_i_check_number" x) ) )
1519
1520(define (##sys#check-fixnum x . loc)
1521  (if (pair? loc)
1522      (##core#inline "C_i_check_fixnum_2" x (car loc))
1523      (##core#inline "C_i_check_fixnum" x) ) )
1524
1525(define (##sys#check-bytevector x . loc)
1526  (if (pair? loc)
1527      (##core#inline "C_i_check_bytevector_2" x (car loc))
1528      (##core#inline "C_i_check_bytevector" x) ) )
1529
1530(define (##sys#check-inexact x . loc)
1531  (if (pair? loc)
1532      (##core#inline "C_i_check_inexact_2" x (car loc))
1533      (##core#inline "C_i_check_inexact" x) ) )
1534
1535(define (##sys#check-symbol x . loc)
1536  (if (pair? loc)
1537      (##core#inline "C_i_check_symbol_2" x (car loc))
1538      (##core#inline "C_i_check_symbol" x) ) )
1539
1540(define (##sys#check-keyword x . loc)
1541  (if (pair? loc)
1542      (##core#inline "C_i_check_keyword_2" x (car loc))
1543      (##core#inline "C_i_check_keyword" x) ) )
1544
1545(define (##sys#check-vector x . loc)
1546  (if (pair? loc)
1547      (##core#inline "C_i_check_vector_2" x (car loc))
1548      (##core#inline "C_i_check_vector" x) ) )
1549
1550(define (##sys#check-char x . loc)
1551  (if (pair? loc)
1552      (##core#inline "C_i_check_char_2" x (car loc))
1553      (##core#inline "C_i_check_char" x) ) )
1554
1555(define (##sys#check-boolean x . loc)
1556  (if (pair? loc)
1557      (##core#inline "C_i_check_boolean_2" x (car loc))
1558      (##core#inline "C_i_check_boolean" x) ) )
1559
1560(define (##sys#check-locative x . loc)
1561  (if (pair? loc)
1562      (##core#inline "C_i_check_locative_2" x (car loc))
1563      (##core#inline "C_i_check_locative" x) ) )
1564
1565(define (##sys#check-integer x . loc)
1566  (unless (##core#inline "C_i_integerp" x)
1567    (##sys#error-bad-integer x (and (pair? loc) (car loc))) ) )
1568
1569(define (##sys#check-exact-integer x . loc)
1570  (unless (##core#inline "C_i_exact_integerp" x)
1571    (##sys#error-bad-exact-integer x (and (pair? loc) (car loc))) ) )
1572
1573(define (##sys#check-exact-uinteger x . loc)
1574  (when (or (not (##core#inline "C_i_exact_integerp" x))
1575	    (##core#inline "C_i_integer_negativep" x))
1576    (##sys#error-bad-exact-uinteger x (and (pair? loc) (car loc))) ) )
1577
1578(define (##sys#check-real x . loc)
1579  (unless (##core#inline "C_i_realp" x)
1580    (##sys#error-bad-real x (and (pair? loc) (car loc))) ) )
1581
1582(define (##sys#check-range i from to . loc)
1583  (if (pair? loc)
1584      (##core#inline "C_i_check_range_2" i from to (car loc))
1585      (##core#inline "C_i_check_range" i from to) ) )
1586
1587(define (##sys#check-range/including i from to . loc)
1588  (if (pair? loc)
1589      (##core#inline "C_i_check_range_including_2" i from to (car loc))
1590      (##core#inline "C_i_check_range_including" i from to) ) )
1591
1592(define (##sys#check-special ptr . loc)
1593  (unless (and (##core#inline "C_blockp" ptr) (##core#inline "C_specialp" ptr))
1594    (##sys#signal-hook #:type-error (and (pair? loc) (car loc)) "bad argument type - not a pointer-like object" ptr) ) )
1595
1596(define (##sys#check-closure x . loc)
1597  (if (pair? loc)
1598      (##core#inline "C_i_check_closure_2" x (car loc))
1599      (##core#inline "C_i_check_closure" x) ) )
1600
1601(set! scheme#force
1602  (lambda (obj)
1603    (if (##sys#structure? obj 'promise)
1604	(let lp ((promise obj)
1605		 (forward #f))
1606	  (let ((val (##sys#slot promise 1)))
1607	    (cond ((null? val) (##sys#values))
1608		  ((pair? val) (apply ##sys#values val))
1609		  ((procedure? val)
1610		   (when forward (##sys#setslot forward 1 promise))
1611		   (let ((results (##sys#call-with-values val ##sys#list)))
1612		     (cond ((not (procedure? (##sys#slot promise 1)))
1613			    (lp promise forward)) ; in case of reentrance
1614			   ((and (not (null? results)) (null? (cdr results))
1615				 (##sys#structure? (##sys#slot results 0) 'promise))
1616			    (let ((result0 (##sys#slot results 0)))
1617			      (##sys#setslot promise 1 (##sys#slot result0 1))
1618			      (lp promise result0)))
1619			   (else
1620			    (##sys#setslot promise 1 results)
1621			    (apply ##sys#values results)))))
1622		  ((##sys#structure? val 'promise)
1623		   (lp val forward)))))
1624	obj)))
1625
1626
1627;;; Dynamic Load
1628
1629(define ##sys#dload (##core#primitive "C_dload"))
1630(define ##sys#set-dlopen-flags! (##core#primitive "C_set_dlopen_flags"))
1631
1632(define (##sys#error-not-a-proper-list arg #!optional loc)
1633  (##sys#error-hook
1634   (foreign-value "C_NOT_A_PROPER_LIST_ERROR" int) loc arg))
1635
1636(define (##sys#error-bad-number arg #!optional loc)
1637  (##sys#error-hook
1638   (foreign-value "C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR" int) loc arg))
1639
1640(define (##sys#error-bad-integer arg #!optional loc)
1641  (##sys#error-hook
1642   (foreign-value "C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR" int) loc arg))
1643
1644(define (##sys#error-bad-exact-integer arg #!optional loc)
1645  (##sys#error-hook
1646   (foreign-value "C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR" int) loc arg))
1647
1648(define (##sys#error-bad-exact-uinteger arg #!optional loc)
1649  (##sys#error-hook
1650   (foreign-value "C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR" int) loc arg))
1651
1652(define (##sys#error-bad-inexact arg #!optional loc)
1653  (##sys#error-hook
1654   (foreign-value "C_CANT_REPRESENT_INEXACT_ERROR" int) loc arg))
1655
1656(define (##sys#error-bad-real arg #!optional loc)
1657  (##sys#error-hook
1658   (foreign-value "C_BAD_ARGUMENT_TYPE_NO_REAL_ERROR" int) loc arg))
1659
1660(define (##sys#error-bad-base arg #!optional loc)
1661  (##sys#error-hook
1662   (foreign-value "C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR" int) loc arg))
1663
1664(set! scheme#append
1665  (lambda lsts
1666    (if (eq? lsts '())
1667	lsts
1668	(let loop ((lsts lsts))
1669	  (if (eq? (##sys#slot lsts 1) '())
1670	      (##sys#slot lsts 0)
1671	      (let copy ((node (##sys#slot lsts 0)))
1672		(cond ((eq? node '()) (loop (##sys#slot lsts 1)))
1673		      ((pair? node)
1674		       (cons (##sys#slot node 0) (copy (##sys#slot node 1))) )
1675		      (else
1676		       (##sys#error-not-a-proper-list
1677			(##sys#slot lsts 0) 'append)) ) )))) ) )
1678
1679(define (##sys#fast-reverse lst0)
1680  (let loop ((lst lst0) (rest '()))
1681    (if (pair? lst)
1682	(loop (##sys#slot lst 1) (cons (##sys#slot lst 0) rest))
1683	rest)))
1684
1685
1686;;; Strings:
1687
1688(define (##sys#make-bytevector size #!optional (fill 0))
1689  (##sys#allocate-bytevector size fill))
1690
1691(define (##sys#make-string size #!optional (fill #\space))
1692  (let* ((count (##core#inline "C_utf_bytes" fill))
1693         (n (fx* count size))
1694         (bv (##sys#allocate-bytevector (fx+ n 1) 0)))
1695    (##core#inline "C_utf_fill" bv fill)
1696    (##core#inline_allocate ("C_a_ustring" 5) bv size)))
1697
1698(define (##sys#buffer->string! buf len)
1699  (##core#inline "C_utf_set_bv_size" buf len)
1700  (##core#inline_allocate ("C_a_ustring" 5) buf
1701                          (##core#inline "C_utf_range_length" buf 0 len)))
1702
1703(define (##sys#buffer->string buf start len)
1704  (let ((bv (##sys#make-bytevector (fx+ len 1))))
1705    (##core#inline "C_copy_memory_with_offset" bv buf 0 start len)
1706    (##core#inline_allocate ("C_a_ustring" 5) bv
1707                            (##core#inline "C_utf_range_length" bv 0 len))))
1708
1709(define (##sys#utf-decoder buf start len k)
1710  (k buf start len))
1711
1712(define (##sys#utf-encoder buf start len k)
1713  (k buf start len))
1714
1715(define (##sys#utf-scanner state byte)
1716  (if state
1717      (if (fx> state 1)
1718          (fx- state 1)
1719          #f)
1720      (let ((n (##core#inline "C_utf_bytes_needed" byte)))
1721        (if (eq? n 1)
1722            #f
1723            (fx- n 1)))))
1724
1725(define (##sys#latin-decoder bv start len k)
1726  (let* ((buf (##sys#make-bytevector (fx* len 2)))
1727         (n (##core#inline "C_latin_to_utf" bv buf start len)))
1728    (k buf 0 n)))
1729
1730(define (##sys#latin-encoder bv start len k)
1731  (let* ((buf (##sys#make-bytevector (fx+ len 1)))
1732         (n (##core#inline "C_utf_to_latin" bv buf start len)))
1733    (k buf 0 n)))
1734
1735(define (##sys#latin-scanner state byte) #f)
1736
1737(define (##sys#binary-decoder bv start len k)
1738  (k bv start len) )
1739
1740(define (##sys#binary-encoder bv start len k)
1741  (k bv start len) )
1742
1743(define (##sys#binary-scanner state byte) #f)
1744
1745;; invokes k with encoding and decoding procedures
1746(define (##sys#encoding-hook enc k)
1747  (case enc
1748    ((binary) (k ##sys#binary-decoder ##sys#binary-encoder ##sys#binary-scanner))
1749    ((utf-8) (k ##sys#utf-decoder ##sys#utf-encoder ##sys#utf-scanner))
1750    ((latin-1) (k ##sys#latin-decoder ##sys#latin-encoder ##sys#latin-scanner))
1751    (else (##sys#signal-hook #:type-error #f "invalid file port encoding" enc))))
1752
1753(define (##sys#register-encoding names dec enc scan)
1754  (let ((old ##sys#encoding-hook))
1755    (set! ##sys#encoding-hook
1756      (lambda (enc k)
1757        (if (or (eq? enc names)
1758                (and (pair? names) (memq enc names)))
1759            (k dec enc scan)
1760            (old enc k))))))
1761
1762;; decode buffer and create string
1763(define (##sys#buffer->string/encoding buf start len enc)
1764  (##sys#encoding-hook
1765    enc
1766    (lambda (decoder _ _) (decoder buf start len ##sys#buffer->string))))
1767
1768;; encode buffer into bytevector
1769(define (##sys#encode-buffer bv start len enc k)
1770  (##sys#encoding-hook
1771    enc
1772    (lambda (_ encoder _) (encoder bv start len k))))
1773
1774;; decode buffer into bytevector
1775(define (##sys#decode-buffer bv start len enc k)
1776  (##sys#encoding-hook
1777    enc
1778    (lambda (decoder _ _) (decoder bv start len k))))
1779
1780;; encode a single character into bytevector, return number of bytes
1781(define (##sys#encode-char c bv enc)
1782  (##sys#encoding-hook
1783    enc
1784    (lambda (_ encoder _)
1785      (let* ((bv1 (##sys#make-bytevector 4))
1786             (n (##core#inline "C_utf_insert" bv1 0 c)))
1787        (encoder bv1 0 n
1788                 (lambda (buf start len)
1789                   (##core#inline "C_copy_memory_with_offset" bv buf 0 start len)
1790                   len))))))
1791
1792(define (##sys#decode-char bv enc start)
1793  (##sys#decode-buffer
1794    bv start (##sys#size bv) enc
1795    (lambda (buf start _)
1796      (##core#inline "C_utf_decode" buf start))))
1797
1798;; how many extra bytes are needed for a complete codepoint?
1799(define (##sys#scan-read-ahead enc byte)
1800  (##sys#encoding-hook
1801    enc
1802    (lambda (_ _ scan) (scan #f byte))))
1803
1804;; read char from port with encoding, scanning minimal number of bytes ahead
1805(define (##sys#read-char/encoding p enc k)
1806  (##sys#encoding-hook
1807    enc
1808    (lambda (dec _ scan)
1809      (let ((buf (##sys#make-bytevector 5))
1810            (rbv! (##sys#slot (##sys#slot p 2) 7))) ; read-bytevector!
1811        (let loop ((state #f) (i 0))
1812          (let ((rn (rbv! p 1 buf i)))
1813            (if (eq? 0 rn)
1814                (if (eq? i 0)
1815                    #!eof
1816                    (##sys#signal-hook #:file-error 'read-char "incomplete character sequence while decoding" buf i))
1817                (let ((s2 (scan state (##core#inline "C_subbyte" buf i))))
1818                  (if s2
1819                      (loop s2 (fx+ i 1))
1820                      (k buf 0 (fx+ i 1) dec))))))))))
1821
1822(set! scheme#make-string
1823  (lambda (size . fill)
1824    (##sys#check-fixnum size 'make-string)
1825    (when (fx< size 0)
1826      (##sys#signal-hook #:bounds-error 'make-string "size is negative" size))
1827    (##sys#make-string
1828     size
1829     (if (null? fill)
1830	 #\space
1831	 (let ((c (car fill)))
1832	   (##sys#check-char c 'make-string)
1833	   c ) ) ) ) )
1834
1835(set! scheme#string->list
1836  (lambda (s #!optional start end)
1837    (##sys#check-string s 'string->list)
1838    (let ((len (##sys#slot s 1)))
1839      (if start
1840          (##sys#check-range/including start 0 len 'string->list)
1841          (set! start 0))
1842      (if end
1843          (##sys#check-range/including end 0 len 'string->list)
1844          (set! end len))
1845      (let loop ((i (fx- end 1)) (ls '()))
1846	(if (fx< i start)
1847	    ls
1848	    (loop (fx- i 1)
1849		  (cons (string-ref s i) ls)) ) ) )))
1850
1851(define ##sys#string->list string->list)
1852
1853(set! scheme#list->string
1854  (lambda (lst0)
1855    (if (not (list? lst0))
1856	(##sys#error-not-a-proper-list lst0 'list->string)
1857	(let* ((len (##core#inline "C_utf_list_size" lst0))
1858	       (bv (##sys#make-bytevector (fx+ 1 len))))
1859	  (let loop ((i 0)
1860                     (p 0)
1861                     (lst lst0))
1862            (if (not (pair? lst))
1863                (##core#inline_allocate ("C_a_ustring" 5) bv i)
1864                (let ((c (##sys#slot lst 0)))
1865                  (##sys#check-char c 'list->string)
1866                  (##core#inline "C_utf_insert" bv p c)
1867                  (loop (fx+ i 1)
1868                        (fx+ p (##core#inline "C_utf_bytes" c))
1869                        (##sys#slot lst 1)))))))))
1870
1871(define ##sys#list->string list->string)
1872
1873(define (##sys#reverse-list->string l)
1874  (let* ((sz (##core#inline "C_utf_list_size" l))
1875         (bv (##sys#make-bytevector (fx+ sz 1))))
1876    (let loop ((p sz) (l l) (n 0))
1877      (cond ((null? l)
1878             (##core#inline_allocate ("C_a_ustring" 5) bv n))
1879            ((pair? l)
1880             (let ((c (##sys#slot l 0)))
1881               (##sys#check-char c 'reverse-list->string)
1882               (let* ((bs (##core#inline "C_utf_bytes" c))
1883                      (p2 (fx- p bs)))
1884                 (##core#inline "C_utf_insert" bv p2 c)
1885                 (loop p2 (##sys#slot l 1) (fx+ n 1)))))
1886            (else (##sys#error-not-a-proper-list l 'reverse-list->string) ) ))))
1887
1888(set! scheme#string-fill!
1889  (lambda (s c #!optional start end)
1890    (##sys#check-string s 'string-fill!)
1891    (##sys#check-char c 'string-fill!)
1892    (let ((len (string-length s)))
1893      (cond (start (##sys#check-range start 0 len 'string-fill!)
1894                   (if end
1895                       (##sys#check-range end 0 len 'string-fill!)
1896                       (set! end len)))
1897            (else
1898              (set! start 0)
1899              (set! end len))))
1900    (let* ((bv (##sys#slot s 0))
1901           (bvlen (##sys#size bv))
1902           (count (fxmax 0 (fx- end start)))
1903           (code (char->integer c)))
1904      (if (and (eq? (fx- bvlen 1) (##sys#slot s 1))
1905               (fx< code 128))
1906          (##core#inline "C_fill_bytevector" bv code start count)
1907          (do ((i start (fx+ i 1)))
1908              ((fx>= i end))
1909              (string-set! s i c))))))
1910
1911(set! scheme#string-copy
1912  (lambda (s #!optional start end)
1913    (##sys#check-string s 'string-copy)
1914    (let ((len (string-length s))
1915          (start1 0))
1916      (when start
1917        (##sys#check-range/including start 0 len 'string-copy)
1918        (set! start1 start))
1919      (if end
1920          (##sys#check-range/including end 0 len 'string-copy)
1921          (set! end len))
1922      (let* ((bv (##sys#slot (if start (##sys#substring s start1 end) s) 0))
1923             (len (##sys#size bv))
1924             (n (fx- end start1))
1925             (bv2 (##sys#make-bytevector len)) )
1926        (##core#inline "C_copy_memory" bv2 bv len)
1927        (##core#inline_allocate ("C_a_ustring" 5) bv2 n)))))
1928
1929(set! scheme#string-copy!
1930  (lambda (to at from #!optional start end)
1931    (##sys#check-string to 'string-copy!)
1932    (##sys#check-string from 'string-copy!)
1933    (let ((tlen (string-length to))
1934          (flen (string-length from))
1935          (d (fx- end start)))
1936      (##sys#check-range at 0 tlen 'string-copy!)
1937      (if start
1938          (begin
1939            (##sys#check-range/including start 0 flen 'string-copy!)
1940            (if end
1941                (##sys#check-range/including end 0 flen 'string-copy!)
1942                (set! end flen)))
1943          (set! start 0))
1944      (if (and (eq? to from) (fx< start at))
1945          (do ((at (fx- (fx+ at d) 1) (fx- at 1))
1946               (i (fx- end 1) (fx- i 1)))
1947              ((fx< i start))
1948              (string-set! to at (string-ref from i)))
1949          (do ((at at (fx+ at 1))
1950               (i start (fx+ i 1)))
1951              ((fx>= i end))
1952              (string-set! to at (string-ref from i)))))))
1953
1954(define (##sys#substring s start end)
1955  (let* ((n (##core#inline "C_utf_range" s start end))
1956         (bv (##sys#make-bytevector (fx+ n 1)))
1957         (str (##core#inline_allocate ("C_a_ustring" 5) bv (fx- end start))))
1958    (##core#inline "C_utf_copy" s str start end 0)
1959    str ) )
1960
1961(set! scheme#substring
1962  (lambda (s start . end)
1963    (##sys#check-string s 'substring)
1964    (##sys#check-fixnum start 'substring)
1965    (let ((end (if (pair? end)
1966                   (let ((end (car end)))
1967                     (##sys#check-fixnum end 'substring)
1968                     end)
1969                   (string-length s) ) ) )
1970      (let ((len (string-length s)))
1971        (if (and (fx<= start end)
1972                 (fx>= start 0)
1973                 (fx<= end len) )
1974            (##sys#substring s start end)
1975            (##sys#error-hook
1976             (foreign-value "C_OUT_OF_BOUNDS_ERROR" int)
1977             'substring s start) ) ) )))
1978
1979(let ((compare
1980        (lambda (s1 s2 more loc cmp)
1981          (##sys#check-string s1 loc)
1982          (##sys#check-string s2 loc)
1983          (let* ((len1 (string-length s1))
1984                 (len2 (string-length s2))
1985                 (c (##core#inline "C_utf_compare"
1986                     s1 s2 0 0
1987                     (if (fx< len1 len2) len1 len2))))
1988            (let loop ((s s2) 
1989                       (len len2) 
1990                       (ss more)
1991                       (f (cmp c len1 len2)))
1992              (and f 
1993                   (or (null? ss)
1994                       (let* ((s2 (##sys#slot ss 0))
1995                              (len2 (string-length s2))
1996                              (c (##core#inline "C_utf_compare"
1997                                  s s2 0 0
1998                                  (if (fx< len len2) len len2))))
1999                         (loop s2 len2 (##sys#slot ss 1)
2000                               (cmp c len len2))))))))))
2001  (set! scheme#string<? (lambda (s1 s2 . more)
2002                          (compare
2003                            s1 s2 more 'string<?
2004                            (lambda (cmp len1 len2)
2005                              (or (fx< cmp 0)
2006                                  (and (fx< len1 len2)
2007                                       (eq? cmp 0) ) ) ) ) ) )
2008  (set! scheme#string>? (lambda (s1 s2 . more)
2009                          (compare
2010                            s1 s2 more 'string>?
2011                            (lambda (cmp len1 len2)
2012                              (or (fx> cmp 0)
2013                                  (and (fx> len1 len2)
2014                                       (eq? cmp 0) ) ) ) ) ) )
2015  (set! scheme#string<=? (lambda (s1 s2 . more)
2016                           (compare
2017                             s1 s2 more 'string<=?
2018                             (lambda (cmp len1 len2)
2019                               (if (eq? cmp 0)
2020                                   (fx<= len1 len2)
2021                                   (fx< cmp 0) ) ) ) ) )
2022  (set! scheme#string>=? (lambda (s1 s2 . more)
2023                           (compare
2024                             s1 s2 more 'string>=?
2025                             (lambda (cmp len1 len2)
2026                               (if (eq? cmp 0)
2027                                   (fx>= len1 len2)
2028                                   (fx> cmp 0) ) ) ) ) ) )
2029
2030(let ((compare
2031        (lambda (s1 s2 more loc cmp)
2032          (##sys#check-string s1 loc)
2033          (##sys#check-string s2 loc)
2034          (let* ((len1 (string-length s1))
2035                 (len2 (string-length s2))
2036                 (c (##core#inline "C_utf_compare_ci"
2037                     s1 s2 0 0
2038                     (if (fx< len1 len2) len1 len2))))
2039            (let loop ((s s2)
2040                       (len len2)
2041                       (ss more)
2042                       (f (cmp c len1 len2)))
2043              (and f
2044                   (or (null? ss)
2045                       (let* ((s2 (##sys#slot ss 0))
2046                              (len2 (string-length s2))
2047                              (c (##core#inline "C_utf_compare_ci"
2048                                  s s2 0 0
2049                                  (if (fx< len len2) len len2))))
2050                         (loop s2 len2 (##sys#slot ss 1)
2051                               (cmp c len len2))))))))))
2052  (set! scheme#string-ci<? (lambda (s1 s2 . more)
2053                             (compare
2054                               s1 s2 more 'string-ci<?
2055                               (lambda (cmp len1 len2)
2056                                 (or (fx< cmp 0)
2057                                     (and (fx< len1 len2)
2058                                          (eq? cmp 0) ) )))))
2059  (set! scheme#string-ci>? (lambda (s1 s2 . more)
2060                             (compare
2061                               s1 s2 more 'string-ci>?
2062                               (lambda (cmp len1 len2)
2063                                 (or (fx> cmp 0)
2064                                     (and (fx> len1 len2)
2065                                          (eq? cmp 0) ) ) ) ) ) )
2066  (set! scheme#string-ci<=? (lambda (s1 s2 . more)
2067                              (compare
2068                                s1 s2 more 'string-ci<=?
2069                                (lambda (cmp len1 len2)
2070                                  (if (eq? cmp 0)
2071                                      (fx<= len1 len2)
2072                                      (fx< cmp 0) ) ) ) ) )
2073  (set! scheme#string-ci>=? (lambda (s1 s2 . more)
2074                              (compare
2075                                s1 s2 more 'string-ci>=?
2076                                (lambda (cmp len1 len2)
2077                                  (if (eq? cmp 0)
2078                                      (fx>= len1 len2)
2079                                      (fx> cmp 0) ) ) ) ) ) )
2080
2081(define (##sys#string-append x y)
2082  (let* ((bv1 (##sys#slot x 0))
2083         (bv2 (##sys#slot y 0))
2084         (s1 (fx- (##sys#size bv1) 1))
2085	 (s2 (fx- (##sys#size bv2) 1))
2086	 (z (##sys#make-bytevector (fx+ s1 (fx+ s2 1)) 0)))
2087    (##core#inline "C_copy_memory_with_offset" z bv1 0 0 s1)
2088    (##core#inline "C_copy_memory_with_offset" z bv2 s1 0 s2)
2089    (##core#inline_allocate ("C_a_ustring" 5) z
2090                            (fx+ (##sys#slot x 1) (##sys#slot y 1)))))
2091
2092(set! scheme#string-append
2093  (lambda all
2094    (let ((snew #f)
2095          (slen 0))
2096      (let loop ((strs all) (n 0) (ul 0))
2097	(cond ((eq? strs '())
2098                (set! snew (##sys#make-bytevector (fx+ n 1) 0))
2099                (set! slen ul))
2100              (else
2101                (let ((s (##sys#slot strs 0)))
2102                  (##sys#check-string s 'string-append)
2103                  (let* ((bv (##sys#slot s 0))
2104                         (len (fx- (##sys#size bv) 1))
2105                         (ulen (##sys#slot s 1)))
2106                    (loop (##sys#slot strs 1) (fx+ n len) (fx+ ul ulen))
2107                    (##core#inline "C_copy_memory_with_offset" snew bv n 0 len) ) ) ) ) )
2108      (##core#inline_allocate ("C_a_ustring" 5) snew slen))))
2109
2110(set! scheme#string
2111  (let ([list->string list->string])
2112    (lambda chars (list->string chars)) ) )
2113
2114;; legacy procedure, used in some eggs, should be removed one day...
2115(define (##sys#char->utf8-string c)
2116  (scheme#string c))
2117
2118(set! chicken.base#chop
2119  (lambda (lst n)
2120    (##sys#check-fixnum n 'chop)
2121    (when (fx<= n 0) (##sys#error 'chop "invalid numeric argument" n))
2122    (let ((len (length lst)))
2123      (let loop ((lst lst) (i len))
2124	(cond ((null? lst) '())
2125	      ((fx< i n) (list lst))
2126	      (else
2127	       (do ((hd '() (cons (##sys#slot tl 0) hd))
2128		    (tl lst (##sys#slot tl 1))
2129		    (c n (fx- c 1)) )
2130		   ((fx= c 0)
2131		    (cons (reverse hd) (loop tl (fx- i n))) ) ) ) ) ) ) ) )
2132
2133;;; Numeric routines:
2134;; Abbreviations of paper and book titles used in comments are:
2135;; [Knuth] Donald E. Knuth, "The Art of Computer Programming", Volume 2
2136;; [MpNT]  Tiplea at al., "MpNT: A Multi-Precision Number Theory Package"
2137;; [MCA]   Richard P. Brent & Paul Zimmermann, "Modern Computer Arithmetic"
2138
2139(module chicken.flonum *
2140(import scheme)
2141(import chicken.foreign)
2142(import (only chicken.base flonum?))
2143(import chicken.internal.syntax)
2144
2145(define maximum-flonum (foreign-value "DBL_MAX" double))
2146(define minimum-flonum (foreign-value "DBL_MIN" double))
2147(define flonum-radix (foreign-value "FLT_RADIX" int))
2148(define flonum-epsilon (foreign-value "DBL_EPSILON" double))
2149(define flonum-precision (foreign-value "DBL_MANT_DIG" int))
2150(define flonum-decimal-precision (foreign-value "DBL_DIG" int))
2151(define flonum-maximum-exponent (foreign-value "DBL_MAX_EXP" int))
2152(define flonum-minimum-exponent (foreign-value "DBL_MIN_EXP" int))
2153(define flonum-maximum-decimal-exponent (foreign-value "DBL_MAX_10_EXP" int))
2154(define flonum-minimum-decimal-exponent (foreign-value "DBL_MIN_10_EXP" int))
2155
2156(define-inline (fp-check-flonum x loc)
2157  (unless (flonum? x)
2158    (##sys#error-hook (foreign-value "C_BAD_ARGUMENT_TYPE_NO_FLONUM_ERROR" int) loc x) ) )
2159
2160(define-inline (fp-check-flonums x y loc)
2161  (unless (and (flonum? x) (flonum? y))
2162    (##sys#error-hook (foreign-value "C_BAD_ARGUMENT_TYPE_NO_FLONUM_ERROR" int) loc x y) ) )
2163
2164(define (fp+ x y)
2165  (fp-check-flonums x y 'fp+)
2166  (##core#inline_allocate ("C_a_i_flonum_plus" 4) x y) )
2167
2168(define (fp- x y)
2169  (fp-check-flonums x y 'fp-)
2170  (##core#inline_allocate ("C_a_i_flonum_difference" 4) x y) )
2171
2172(define (fp* x y)
2173  (fp-check-flonums x y 'fp*)
2174  (##core#inline_allocate ("C_a_i_flonum_times" 4) x y) )
2175
2176(define (fp/ x y)
2177  (fp-check-flonums x y 'fp/)
2178  (##core#inline_allocate ("C_a_i_flonum_quotient" 4) x y) )
2179
2180(define (fp*+ x y z)
2181  (unless (and (flonum? x) (flonum? y) (flonum? z))
2182    (##sys#error-hook (foreign-value "C_BAD_ARGUMENT_TYPE_NO_FLONUM_ERROR" int)
2183      'fp*+ x y z) )
2184  (##core#inline_allocate ("C_a_i_flonum_multiply_add" 4) x y z) )
2185
2186(define (fpgcd x y)
2187  (fp-check-flonums x y 'fpgcd)
2188  (##core#inline_allocate ("C_a_i_flonum_gcd" 4) x y))
2189
2190(define (fp/? x y)			; undocumented
2191  (fp-check-flonums x y 'fp/?)
2192  (##core#inline_allocate ("C_a_i_flonum_quotient_checked" 4) x y) )
2193
2194(define (fp= x y)
2195  (fp-check-flonums x y 'fp=)
2196  (##core#inline "C_flonum_equalp" x y) )
2197
2198(define (fp> x y)
2199  (fp-check-flonums x y 'fp>)
2200  (##core#inline "C_flonum_greaterp" x y) )
2201
2202(define (fp< x y)
2203  (fp-check-flonums x y 'fp<)
2204  (##core#inline "C_flonum_lessp" x y) )
2205
2206(define (fp>= x y)
2207  (fp-check-flonums x y 'fp>=)
2208  (##core#inline "C_flonum_greater_or_equal_p" x y) )
2209
2210(define (fp<= x y)
2211  (fp-check-flonums x y 'fp<=)
2212  (##core#inline "C_flonum_less_or_equal_p" x y) )
2213
2214(define (fpneg x)
2215  (fp-check-flonum x 'fpneg)
2216  (##core#inline_allocate ("C_a_i_flonum_negate" 4) x) )
2217
2218(define (fpmax x y)
2219  (fp-check-flonums x y 'fpmax)
2220  (##core#inline "C_i_flonum_max" x y) )
2221
2222(define (fpmin x y)
2223  (fp-check-flonums x y 'fpmin)
2224  (##core#inline "C_i_flonum_min" x y) )
2225
2226(define (fpfloor x)
2227  (fp-check-flonum x 'fpfloor)
2228  (##core#inline_allocate ("C_a_i_flonum_floor" 4) x))
2229
2230(define (fptruncate x)
2231  (fp-check-flonum x 'fptruncate)
2232  (##core#inline_allocate ("C_a_i_flonum_truncate" 4) x))
2233
2234(define (fpround x)
2235  (fp-check-flonum x 'fpround)
2236  (##core#inline_allocate ("C_a_i_flonum_round" 4) x))
2237
2238(define (fpceiling x)
2239  (fp-check-flonum x 'fpceiling)
2240  (##core#inline_allocate ("C_a_i_flonum_ceiling" 4) x))
2241
2242(define (fpsin x)
2243  (fp-check-flonum x 'fpsin)
2244  (##core#inline_allocate ("C_a_i_flonum_sin" 4) x))
2245
2246(define (fpcos x)
2247  (fp-check-flonum x 'fpcos)
2248  (##core#inline_allocate ("C_a_i_flonum_cos" 4) x))
2249
2250(define (fptan x)
2251  (fp-check-flonum x 'fptan)
2252  (##core#inline_allocate ("C_a_i_flonum_tan" 4) x))
2253
2254(define (fpasin x)
2255  (fp-check-flonum x 'fpasin)
2256  (##core#inline_allocate ("C_a_i_flonum_asin" 4) x))
2257
2258(define (fpacos x)
2259  (fp-check-flonum x 'fpacos)
2260  (##core#inline_allocate ("C_a_i_flonum_acos" 4) x))
2261
2262(define (fpatan x)
2263  (fp-check-flonum x 'fpatan)
2264  (##core#inline_allocate ("C_a_i_flonum_atan" 4) x))
2265
2266(define (fpatan2 x y)
2267  (fp-check-flonums x y 'fpatan2)
2268  (##core#inline_allocate ("C_a_i_flonum_atan2" 4) x y))
2269
2270(define (fpsinh x)
2271  (fp-check-flonum x 'fpsinh)
2272  (##core#inline_allocate ("C_a_i_flonum_sinh" 4) x))
2273
2274(define (fpcosh x)
2275  (fp-check-flonum x 'fpcosh)
2276  (##core#inline_allocate ("C_a_i_flonum_cosh" 4) x))
2277
2278(define (fptanh x)
2279  (fp-check-flonum x 'fptanh)
2280  (##core#inline_allocate ("C_a_i_flonum_tanh" 4) x))
2281
2282(define (fpasinh x)
2283  (fp-check-flonum x 'fpasinh)
2284  (##core#inline_allocate ("C_a_i_flonum_asinh" 4) x))
2285
2286(define (fpacosh x)
2287  (fp-check-flonum x 'fpacosh)
2288  (##core#inline_allocate ("C_a_i_flonum_acosh" 4) x))
2289
2290(define (fpatanh x)
2291  (fp-check-flonum x 'fpatanh)
2292  (##core#inline_allocate ("C_a_i_flonum_atanh" 4) x))
2293
2294(define (fpexp x)
2295  (fp-check-flonum x 'fpexp)
2296  (##core#inline_allocate ("C_a_i_flonum_exp" 4) x))
2297
2298(define (fpexpt x y)
2299  (fp-check-flonums x y 'fpexpt)
2300  (##core#inline_allocate ("C_a_i_flonum_expt" 4) x y))
2301
2302(define (fplog x)
2303  (fp-check-flonum x 'fplog)
2304  (##core#inline_allocate ("C_a_i_flonum_log" 4) x))
2305
2306(define (fpsqrt x)
2307  (fp-check-flonum x 'fpsqrt)
2308  (##core#inline_allocate ("C_a_i_flonum_sqrt" 4) x))
2309
2310(define (fpabs x)
2311  (fp-check-flonum x 'fpabs)
2312  (##core#inline_allocate ("C_a_i_flonum_abs" 4) x))
2313
2314(define (fpinteger? x)
2315  (fp-check-flonum x 'fpinteger?)
2316  (##core#inline "C_u_i_fpintegerp" x))
2317
2318(define (flonum-print-precision #!optional prec)
2319  (let ((prev (##core#inline "C_get_print_precision")))
2320    (when prec
2321      (##sys#check-fixnum prec 'flonum-print-precision)
2322      (##core#inline "C_set_print_precision" prec))
2323    prev)))
2324
2325(import chicken.flonum)
2326
2327(define-inline (integer-negate x)
2328  (##core#inline_allocate ("C_s_a_u_i_integer_negate" 5) x))
2329
2330;;; Complex numbers
2331
2332(define-inline (%cplxnum-real c) (##core#inline "C_u_i_cplxnum_real" c))
2333(define-inline (%cplxnum-imag c) (##core#inline "C_u_i_cplxnum_imag" c))
2334
2335(define (make-complex r i)
2336  (if (eq? i 0)
2337      r
2338      (##core#inline_allocate ("C_a_i_cplxnum" 3)
2339			      (if (inexact? i) (exact->inexact r) r)
2340			      (if (inexact? r) (exact->inexact i) i)) ) )
2341
2342(set! scheme#make-rectangular
2343  (lambda (r i)
2344    (##sys#check-real r 'make-rectangular)
2345    (##sys#check-real i 'make-rectangular)
2346    (make-complex r i) ))
2347
2348(set! scheme#make-polar
2349  (lambda (r phi)
2350    (##sys#check-real r 'make-polar)
2351    (##sys#check-real phi 'make-polar)
2352    (let ((fphi (exact->inexact phi)))
2353      (make-complex
2354       (* r (##core#inline_allocate ("C_a_i_cos" 4) fphi))
2355       (* r (##core#inline_allocate ("C_a_i_sin" 4) fphi))) ) ))
2356
2357(set! scheme#real-part
2358  (lambda (x)
2359    (cond ((cplxnum? x) (%cplxnum-real x))
2360	  ((number? x) x)
2361	  (else (##sys#error-bad-number x 'real-part)) )))
2362
2363(set! scheme#imag-part
2364  (lambda (x)
2365    (cond ((cplxnum? x) (%cplxnum-imag x))
2366	  ((number? x) 0)
2367	  (else (##sys#error-bad-number x 'imag-part)) )))
2368
2369(set! scheme#angle
2370  (lambda (n)
2371    (##sys#check-number n 'angle)
2372    (##core#inline_allocate ("C_a_i_atan2" 4)
2373			    (exact->inexact (imag-part n))
2374			    (exact->inexact (real-part n))) ))
2375
2376(set! scheme#magnitude
2377  (lambda (x)
2378    (cond ((cplxnum? x)
2379	   (let ((r (%cplxnum-real x))
2380		 (i (%cplxnum-imag x)) )
2381	     (sqrt (+ (* r r) (* i i))) ))
2382	  ((number? x) (abs x))
2383	  (else (##sys#error-bad-number x 'magnitude))) ))
2384
2385;;; Rational numbers
2386
2387(define-inline (%ratnum-numerator r) (##core#inline "C_u_i_ratnum_num" r))
2388(define-inline (%ratnum-denominator r) (##core#inline "C_u_i_ratnum_denom" r))
2389(define-inline (%make-ratnum n d) (##core#inline_allocate ("C_a_i_ratnum" 3) n d))
2390
2391(define (ratnum m n)
2392  (cond
2393   ((eq? n 1) m)
2394   ((eq? n -1) (integer-negate m))
2395   ((negative? n)
2396    (%make-ratnum (integer-negate m) (integer-negate n)))
2397   (else (%make-ratnum m n))))
2398
2399(set! scheme#numerator
2400  (lambda (n)
2401    (cond ((##core#inline "C_i_exact_integerp" n) n)
2402          ((##core#inline "C_i_flonump" n)
2403           (cond ((not (finite? n)) (##sys#error-bad-inexact n 'numerator))
2404                 ((##core#inline "C_u_i_fpintegerp" n) n)
2405                 (else (exact->inexact (numerator (inexact->exact n))))))
2406          ((ratnum? n) (%ratnum-numerator n))
2407          (else (##sys#signal-hook
2408                 #:type-error 'numerator
2409                 "bad argument type - not a rational number" n) ) )))
2410
2411
2412(set! scheme#denominator
2413  (lambda (n)
2414    (cond ((##core#inline "C_i_exact_integerp" n) 1)
2415          ((##core#inline "C_i_flonump" n)
2416           (cond ((not (finite? n)) (##sys#error-bad-inexact n 'denominator))
2417                 ((##core#inline "C_u_i_fpintegerp" n) 1.0)
2418                 (else (exact->inexact (denominator (inexact->exact n))))))
2419          ((ratnum? n) (%ratnum-denominator n))
2420          (else (##sys#signal-hook
2421                 #:type-error 'numerator
2422                 "bad argument type - not a rational number" n) ) )))
2423
2424
2425(define (##sys#extended-signum x)
2426  (cond
2427   ((ratnum? x) (##core#inline "C_u_i_integer_signum" (%ratnum-numerator x)))
2428   ((cplxnum? x) (make-polar 1 (angle x)))
2429   (else (##sys#error-bad-number x 'signum))))
2430
2431(define-inline (%flo->int x)
2432  (##core#inline_allocate ("C_s_a_u_i_flo_to_int" 5) x))
2433
2434(define (flonum->ratnum x)
2435  ;; Try to multiply by two until we reach an integer
2436  (define (float-fraction-length x)
2437    (do ((x x (fp* x 2.0))
2438         (i 0 (fx+ i 1)))
2439        ((##core#inline "C_u_i_fpintegerp" x) i)))
2440
2441  (define (deliver y d)
2442    (let* ((q (##sys#integer-power 2 (float-fraction-length y)))
2443           (scaled-y (* y (exact->inexact q))))
2444      (if (finite? scaled-y)          ; Shouldn't this always be true?
2445          (##sys#/-2 (##sys#/-2 (%flo->int scaled-y) q) d)
2446          (##sys#error-bad-inexact x 'inexact->exact))))
2447
2448  (if (and (fp< x 1.0)         ; Watch out for denormalized numbers
2449           (fp> x -1.0))       ; XXX: Needs a test, it seems pointless
2450      (deliver (* x (expt 2.0 flonum-precision))
2451               ;; Can be bignum (is on 32-bit), so must wait until after init.
2452               ;; We shouldn't need to calculate this every single time, tho..
2453               (##sys#integer-power 2 flonum-precision))
2454      (deliver x 1)))
2455
2456(set! scheme#inexact->exact
2457  (lambda (x)
2458    (cond ((exact? x) x)
2459	  ((##core#inline "C_i_flonump" x)
2460	   (cond ((##core#inline "C_u_i_fpintegerp" x) (%flo->int x))
2461		 ((##core#inline "C_u_i_flonum_finitep" x) (flonum->ratnum x))
2462		 (else (##sys#error-bad-inexact x 'inexact->exact))))
2463	  ((cplxnum? x)
2464	   (make-complex (inexact->exact (%cplxnum-real x))
2465			 (inexact->exact (%cplxnum-imag x))))
2466	  (else (##sys#error-bad-number x 'inexact->exact)) )))
2467
2468
2469;;; Bitwise operations:
2470
2471;; From SRFI-33
2472
2473(module chicken.bitwise *
2474(import scheme)
2475(define bitwise-and (##core#primitive "C_bitwise_and"))
2476(define bitwise-ior (##core#primitive "C_bitwise_ior"))
2477(define bitwise-xor (##core#primitive "C_bitwise_xor"))
2478(define (bitwise-not n) (##core#inline_allocate ("C_s_a_i_bitwise_not" 5) n))
2479(define (bit->boolean n i) (##core#inline "C_i_bit_to_bool" n i)) ; DEPRECATED
2480;; XXX NOT YET! Reintroduce at a later time.  See #1385:
2481;; (define (bit-set? i n) (##core#inline "C_i_bit_setp" i n))
2482(define (integer-length x) (##core#inline "C_i_integer_length" x))
2483(define (arithmetic-shift n m)
2484  (##core#inline_allocate ("C_s_a_i_arithmetic_shift" 5) n m))
2485
2486) ; chicken.bitwise
2487
2488(import chicken.bitwise)
2489
2490;;; Basic arithmetic:
2491
2492(define-inline (%integer-gcd a b)
2493  (##core#inline_allocate ("C_s_a_u_i_integer_gcd" 5) a b))
2494
2495(set! scheme#/
2496  (lambda (arg1 . args)
2497    (if (null? args)
2498	(##sys#/-2 1 arg1)
2499	(let loop ((args (##sys#slot args 1))
2500		   (x (##sys#/-2 arg1 (##sys#slot args 0))))
2501	  (if (null? args)
2502	      x
2503	      (loop (##sys#slot args 1)
2504		    (##sys#/-2 x (##sys#slot args 0))) ) ) ) ))
2505
2506(define-inline (%integer-quotient a b)
2507  (##core#inline_allocate ("C_s_a_u_i_integer_quotient" 5) a b))
2508
2509(define (##sys#/-2 x y)
2510  (when (eq? y 0)
2511    (##sys#error-hook (foreign-value "C_DIVISION_BY_ZERO_ERROR" int) '/ x y))
2512  (cond ((eq? x 0) 0)
2513        ((and (##core#inline "C_i_exact_integerp" x)
2514              (##core#inline "C_i_exact_integerp" y))
2515         (let ((g (%integer-gcd x y)))
2516           (ratnum (%integer-quotient x g) (%integer-quotient y g))))
2517        ;; Compnum *must* be checked first
2518        ((or (cplxnum? x) (cplxnum? y))
2519          (if (cplxnum? y)
2520              (let* ((a (real-part x)) (b (imag-part x))
2521                     (c (real-part y)) (d (imag-part y))
2522                     (r (+ (* c c) (* d d)))
2523                     (x (##sys#/-2 (+ (* a c) (* b d)) r))
2524                     (y (##sys#/-2 (- (* b c) (* a d)) r)) )
2525                (make-complex x y) )
2526              (let* ((a (real-part x)) (b (imag-part x))
2527                     (xu (##sys#/-2 a y))
2528                     (yu (##sys#/-2 b y)))
2529                (make-complex xu yu))))
2530       ((or (##core#inline "C_i_flonump" x) (##core#inline "C_i_flonump" y))
2531         ;; This may be incorrect when one is a ratnum consisting of bignums
2532         (fp/ (exact->inexact x) (exact->inexact y)))
2533        ((ratnum? x)
2534         (if (ratnum? y)
2535             ;; a/b / c/d = a*d / b*c  [generic]
2536             ;;   = ((a / g1) * (d / g2) * sign(a)) / abs((b / g2) * (c / g1))
2537             ;; With   g1 = gcd(a, c)   and    g2 = gcd(b, d) [Knuth, 4.5.1 ex. 4]
2538             (let* ((a (%ratnum-numerator x)) (b (%ratnum-denominator x))
2539                    (c (%ratnum-numerator y)) (d (%ratnum-denominator y))
2540                    (g1 (%integer-gcd a c))
2541                    (g2 (%integer-gcd b d)))
2542               (ratnum (* (quotient a g1) (quotient d g2))
2543                       (* (quotient b g2) (quotient c g1))))
2544             ;; a/b / c/d = a*d / b*c  [with d = 1]
2545             ;;   = ((a / g) * sign(a)) / abs(b * (c / g))
2546             ;; With   g = gcd(a, c)   and  c = y  [Knuth, 4.5.1 ex. 4]
2547             (let* ((a (%ratnum-numerator x))
2548                    (g (##sys#internal-gcd '/ a y))
2549                    (num (quotient a g))
2550                    (denom (* (%ratnum-denominator x) (quotient y g))))
2551               (if (##core#inline "C_i_flonump" denom)
2552                   (##sys#/-2 num denom)
2553                   (ratnum num denom)))))
2554        ((ratnum? y)
2555         ;; a/b / c/d = a*d / b*c  [with b = 1]
2556         ;;   = ((a / g1) * d * sign(a)) / abs(c / g1)
2557         ;; With   g1 = gcd(a, c)   and   a = x  [Knuth, 4.5.1 ex. 4]
2558         (let* ((c (%ratnum-numerator y))
2559                (g (##sys#internal-gcd '/ x c))
2560                (num (* (quotient x g) (%ratnum-denominator y)))
2561                (denom (quotient c g)))
2562           (if (##core#inline "C_i_flonump" denom)
2563               (##sys#/-2 num denom)
2564               (ratnum num denom))))
2565        ((not (number? x)) (##sys#error-bad-number x '/))
2566        (else (##sys#error-bad-number y '/))) )
2567
2568(set! scheme#floor
2569  (lambda (x)
2570    (cond ((##core#inline "C_i_exact_integerp" x) x)
2571          ((##core#inline "C_i_flonump" x) (fpfloor x))
2572          ;; (floor x) = greatest integer <= x
2573          ((ratnum? x) (let* ((n (%ratnum-numerator x))
2574                              (q (quotient n (%ratnum-denominator x))))
2575                         (if (>= n 0) q (- q 1))))
2576          (else (##sys#error-bad-real x 'floor)) )))
2577
2578(set! scheme#ceiling
2579  (lambda (x)
2580    (cond ((##core#inline "C_i_exact_integerp" x) x)
2581          ((##core#inline "C_i_flonump" x) (fpceiling x))
2582          ;; (ceiling x) = smallest integer >= x
2583          ((ratnum? x) (let* ((n (%ratnum-numerator x))
2584                              (q (quotient n (%ratnum-denominator x))))
2585                         (if (>= n 0) (+ q 1) q)))
2586          (else (##sys#error-bad-real x 'ceiling)) )))
2587
2588(set! scheme#truncate
2589  (lambda (x)
2590    (cond ((##core#inline "C_i_exact_integerp" x) x)
2591          ((##core#inline "C_i_flonump" x) (fptruncate x))
2592          ;; (rational-truncate x) = integer of largest magnitude <= (abs x)
2593          ((ratnum? x) (quotient (%ratnum-numerator x)
2594                                 (%ratnum-denominator x)))
2595          (else (##sys#error-bad-real x 'truncate)) )))
2596
2597(set! scheme#round
2598  (lambda (x)
2599    (cond ((##core#inline "C_i_exact_integerp" x) x)
2600          ((##core#inline "C_i_flonump" x)
2601           (##core#inline_allocate ("C_a_i_flonum_round_proper" 4) x))
2602          ((ratnum? x)
2603           (let* ((x+1/2 (+ x (%make-ratnum 1 2)))
2604                  (r (floor x+1/2)))
2605             (if (and (= r x+1/2) (odd? r)) (- r 1) r)))
2606          (else (##sys#error-bad-real x 'round)) )))
2607
2608(define (find-ratio-between x y)
2609  (define (sr x y)
2610    (let ((fx (inexact->exact (floor x)))
2611	  (fy (inexact->exact (floor y))))
2612      (cond ((not (< fx x)) (list fx 1))
2613	    ((= fx fy)
2614	     (let ((rat (sr (##sys#/-2 1 (- y fy))
2615			    (##sys#/-2 1 (- x fx)))))
2616	       (list (+ (cadr rat) (* fx (car rat)))
2617		     (car rat))))
2618	    (else (list (+ 1 fx) 1)))))
2619  (cond ((< y x) (find-ratio-between y x))
2620	((not (< x y)) (list x 1))
2621	((positive? x) (sr x y))
2622	((negative? y) (let ((rat (sr (- y) (- x))))
2623                         (list (- (car rat)) (cadr rat))))
2624	(else '(0 1))))
2625
2626(define (find-ratio x e) (find-ratio-between (- x e) (+ x e)))
2627
2628(set! scheme#rationalize
2629  (lambda (x e)
2630    (let ((result (apply ##sys#/-2 (find-ratio x e))))
2631      (if (or (inexact? x) (inexact? e))
2632	  (exact->inexact result)
2633	  result)) ))
2634
2635(set! scheme#max
2636  (lambda (x1 . xs)
2637    (##sys#check-number x1 'max)
2638    (let loop ((i (##core#inline "C_i_flonump" x1))
2639               (m x1) 
2640               (xs xs) 
2641               (n (##core#inline "C_i_nanp" x1)))
2642      (if (null? xs)
2643	  (if i (exact->inexact m) m)
2644	  (let* ((h (##sys#slot xs 0))
2645                 (_ (##sys#check-number h 'max))
2646                 (f (##core#inline "C_i_flonump" h))
2647                 (nxt (##sys#slot xs 1)))
2648            (cond ((##core#inline "C_i_nanp" h) (loop i m nxt n))
2649                  (n (loop (or i f) h nxt #f))
2650                  ((> h m) (loop (or i f) h nxt #f))
2651                  (else (loop (or i f) m nxt n))))))))
2652
2653(set! scheme#min
2654  (lambda (x1 . xs)
2655    (##sys#check-number x1 'min)
2656    (let loop ((i (##core#inline "C_i_flonump" x1))
2657               (m x1) 
2658               (xs xs) 
2659               (n (##core#inline "C_i_nanp" x1)))
2660      (if (null? xs)
2661	  (if i (exact->inexact m) m)
2662	  (let* ((h (##sys#slot xs 0))
2663                 (_ (##sys#check-number h 'min))
2664                 (f (##core#inline "C_i_flonump" h))
2665                 (nxt (##sys#slot xs 1)))
2666            (cond ((##core#inline "C_i_nanp" h) (loop i m nxt n))
2667                  (n (loop (or i f) h nxt #f))
2668                  ((< h m) (loop (or i f) h nxt #f))
2669                  (else (loop (or i f) m nxt n))))))))
2670
2671(set! scheme#exp
2672  (lambda (n)
2673    (##sys#check-number n 'exp)
2674    (if (cplxnum? n)
2675	(* (##core#inline_allocate ("C_a_i_exp" 4)
2676				   (exact->inexact (%cplxnum-real n)))
2677	   (let ((p (%cplxnum-imag n)))
2678	     (make-complex
2679	      (##core#inline_allocate ("C_a_i_cos" 4) (exact->inexact p))
2680	      (##core#inline_allocate ("C_a_i_sin" 4) (exact->inexact p)) ) ) )
2681	(##core#inline_allocate ("C_a_i_flonum_exp" 4) (exact->inexact n)) ) ))
2682
2683(define (##sys#log-1 x)		       ; log_e(x)
2684  (cond
2685   ((eq? x 0)			       ; Exact zero?  That's undefined
2686    (##sys#signal-hook #:arithmetic-error 'log "log of exact 0 is undefined" x))
2687   ;; avoid calling inexact->exact on X here (to avoid overflow?)
2688   ((or (cplxnum? x) (negative? x)) ; General case
2689    (+ (##sys#log-1 (magnitude x))
2690       (* (make-complex 0 1) (angle x))))
2691   (else ; Real number case (< already ensured the argument type is a number)
2692    (##core#inline_allocate ("C_a_i_log" 4) (exact->inexact x)))))
2693
2694(set! scheme#log
2695  (lambda (a #!optional b)
2696    (if b (##sys#/-2 (##sys#log-1 a) (##sys#log-1 b)) (##sys#log-1 a))))
2697
2698(set! scheme#sin
2699  (lambda (n)
2700    (##sys#check-number n 'sin)
2701    (if (cplxnum? n)
2702	(let ((in (* +i n)))
2703	  (##sys#/-2 (- (exp in) (exp (- in))) +2i))
2704	(##core#inline_allocate ("C_a_i_sin" 4) (exact->inexact n)) ) ))
2705
2706(set! scheme#cos
2707  (lambda (n)
2708    (##sys#check-number n 'cos)
2709    (if (cplxnum? n)
2710	(let ((in (* +i n)))
2711	  (##sys#/-2 (+ (exp in) (exp (- in))) 2) )
2712	(##core#inline_allocate ("C_a_i_cos" 4) (exact->inexact n)) ) ))
2713
2714(define (##sys#tanh z)
2715  (let* ((x (real-part z))
2716         (y (imag-part z))
2717         (tanh-overflow-treshold (/ (fpasinh maximum-flonum) 2))
2718         (tanh-overflow-low-treshold (/ (fpasinh maximum-flonum) 4))
2719         (ax (abs x)))
2720    (cond
2721      ((eqv? z 0) 0)
2722      ((> ax tanh-overflow-treshold)
2723       (if (real? z)
2724           (* 1.0 (##sys#sign-bit x))
2725           (make-rectangular (* 1.0 (##sys#sign-bit x))
2726                             (* 0.0 (##sys#sign-bit y)))))
2727      ((> ax tanh-overflow-low-treshold)
2728       (if (real? z)
2729           (* 1.0 (##sys#sign-bit x))
2730           (let ((y*2 (* y 2.0))
2731                 (cosh-x*2 (fpcosh (* 2.0 x))))
2732             (cond
2733               ((finite? y*2)
2734                (make-rectangular (* 1.0 (##sys#sign-bit x))
2735                                  (/ (sin y*2)
2736                                     cosh-x*2)))
2737               ((finite? y)
2738                (make-rectangular (* 1.0 (##sys#sign-bit x))
2739                                  (/ (* 2.0 (sin y) (cos y))
2740                                     cosh-x*2)))
2741               (else (make-rectangular (* 1.0 (##sys#sign-bit sign x))
2742                                       (* 0.0 (##sys#sign-bit sign y))))))))
2743      (else
2744       (let* ((t (tan y))
2745              (beta (+ 1.0 (* t t)))
2746              (s (if (eqv? x 0)
2747                     0.0              ; Avoid divide-by-exact-zero errors
2748                     (fpsinh x)))
2749              (rho (sqrt (+ 1.0 (* s s)))))
2750         (if (infinite? t)
2751             (make-rectangular (/ rho s) (/ t))
2752             (let ((ret (if (real? z)
2753                            (* beta rho s)
2754                            (make-rectangular (* beta rho s)
2755                                              t))))
2756               (/ ret (+ 1.0 (* beta (* s s)))))))))))
2757
2758
2759
2760(set! scheme#tan
2761  (lambda (n)
2762    (##sys#check-number n 'tan)
2763    (if (cplxnum? n)
2764        (* -i (##sys#tanh (* +i n)))   ; Kahan's version
2765	(##core#inline_allocate ("C_a_i_tan" 4) (exact->inexact n)) ) ))
2766
2767(define (##sys#conjugate z)
2768  (make-rectangular (real-part z) (- (imag-part z))))
2769
2770;; General case: sin^{-1}(z) = -i\ln(iz + \sqrt{1-z^2})
2771(set! scheme#asin
2772  (lambda (n)
2773    (##sys#check-number n 'asin)
2774    (cond ((and (##core#inline "C_i_flonump" n) (fp>= n -1.0) (fp<= n 1.0))
2775	   (##core#inline_allocate ("C_a_i_asin" 4) n))
2776	  ((and (##core#inline "C_fixnump" n) (fx>= n -1) (fx<= n 1))
2777	   (##core#inline_allocate ("C_a_i_asin" 4)
2778				   (##core#inline_allocate
2779				    ("C_a_i_fix_to_flo" 4) n)))
2780	  ;; General definition can return compnums
2781	  (else
2782	    (cond
2783	      ;; These should fall out of the algorithm below,
2784	      ;; but inexactness-promotion rules end up generating
2785	      ;; a NaN somewhere.
2786	      ;;
2787	      ;; These are the special cases -inf.0+0.0i and
2788	      ;; +inf.0+0.0i from Gambit. Since Gambit has mixed exactness numbers,
2789	      ;; this doesn't copy -inf.0+0i and +inf.0+0i. Basically, unsigned
2790	      ;; zero is approached counterclockwise, and signed zero from the
2791	      ;; side with that sign. So unsigned zero approches from the bottom
2792	      ;; and matches -0.0, which is probably not what we want.
2793	      ((eqv? n +inf.0)  1.5707963267948966+inf.0i)
2794	      ((eqv? n -inf.0) -1.5707963267948966+inf.0i)
2795	      (else
2796	       (let* ((x (real-part n))
2797	              (s:1-n (sqrt (- 1 n)))
2798	              (s:1+n (sqrt (+ 1 n)))
2799	              (ipart (imag-part (* (##sys#conjugate s:1-n)
2800	                                   s:1+n))))
2801	         (make-rectangular (atan x (real-part (* s:1-n s:1+n)))
2802	                           (if (and (exact? ipart) (zero? ipart))
2803	                               0
2804	                               (fpasinh ipart))))))))))
2805
2806;; General case:
2807;; cos^{-1}(z) = 1/2\pi + i\ln(iz + \sqrt{1-z^2}) = 1/2\pi - sin^{-1}(z) = sin(1) - sin(z)
2808(set! scheme#acos
2809  (let ((asin1 (##core#inline_allocate ("C_a_i_asin" 4) 1)))
2810    (lambda (n)
2811      (##sys#check-number n 'acos)
2812      (cond ((and (##core#inline "C_i_flonump" n) (fp>= n -1.0) (fp<= n 1.0))
2813             (##core#inline_allocate ("C_a_i_acos" 4) n))
2814            ((and (##core#inline "C_fixnump" n) (fx>= n -1) (fx<= n 1))
2815             (##core#inline_allocate ("C_a_i_acos" 4)
2816                                     (##core#inline_allocate
2817                                      ("C_a_i_fix_to_flo" 4) n)))
2818            ;; General definition can return compnums
2819            (else
2820              (let* ((s:1-n (sqrt (- 1 n)))
2821                     (s:1+n (sqrt (+ 1 n)))
2822                     (x (* 2 (atan (real-part s:1-n) (real-part s:1+n))))
2823                     (w (imag-part (* (##sys#conjugate s:1+n)
2824                                      s:1-n)))
2825                     (y (if (eq? w 0)
2826                            0
2827                            (fpasinh w))))
2828                (make-rectangular x y)))))))
2829
2830;;; Start Kahan's atan (with modifications from Gambit)
2831
2832(define fllog1+
2833  (foreign-lambda double "log1p" double))
2834
2835(define (##sys#sign-bit x)
2836  (cond
2837    ((eq? x 0) +1)
2838    ((eqv? x +0.0) +1.0)
2839    ((eqv? x -0.0) -1.0)
2840    (else (signum x))))
2841
2842(define (##sys#internal-atanh z)
2843  (let* ((z (* (##sys#sign-bit (real-part z)) (##sys#conjugate z)))
2844         (x (real-part z))
2845         (y (imag-part z))
2846         (theta (/ (sqrt maximum-flonum) 4))
2847         (rho (/ theta))
2848         (fl-pi/2  1.57079632679489661923132169163975144)
2849         (fl-pi/4 0.785398163397448309615660845819875721))
2850    (cond
2851      ((or (> x theta) (> (abs y) theta))
2852       (make-rectangular (real-part (/ z))
2853                         (* fl-pi/2 (##sys#sign-bit y))))
2854      ((and (= x 1.0) (zero? y))
2855       (make-rectangular +inf.0
2856                         (* (##sys#sign-bit y) fl-pi/4)))
2857      ((= x 1.0)
2858       (let ((absy (abs y)))
2859         (make-rectangular (log (/ (sqrt (sqrt (+ 4.0 (* y y))))
2860                                   (sqrt absy)))
2861                           (* (/ (+ fl-pi/2
2862                                    (atan absy 2.0))
2863                                 2.0)
2864                              (##sys#sign-bit y)))))
2865      (else
2866       (let ((y^2 (* y y)))
2867         (make-rectangular (cond
2868                             ((eqv? x 0) 0)
2869                             (else
2870                              (/ (fllog1+ (/ (* 4.0 x)
2871                                             (+ (* (- 1.0 x) (- 1.0 x))
2872                                                y^2)))
2873                                 4.0)))
2874                           (/ (angle (+ (* (- 1.0 x) (+ 1.0 x))
2875                                        (- y^2)
2876                                        (make-rectangular
2877                                         0.0
2878                                         (* 2.0 y))))
2879                              2.0)))))))
2880
2881(define (##sys#atanh z)
2882  (cond
2883    ((eqv? z 0) 0)
2884    ((and (real? z) (eqv? (abs z) 1))
2885     (error 'atanh "atanh has a singularity at 1 and -1"))
2886    ((and (real? z) (< -1.0 z 1.0))
2887     (fpatanh (exact->inexact z)))
2888    (else (* (##sys#sign-bit (real-part z)) (##sys#conjugate (##sys#internal-atanh z))))))
2889
2890(set! scheme#atan
2891  (lambda (n #!optional b)
2892    (##sys#check-number n 'atan)
2893    (cond ((cplxnum? n)
2894	   (if b
2895	       (##sys#error-bad-real n 'atan)
2896	       (* -i (##sys#atanh (* +i n)))))
2897	  (b
2898	   (##core#inline_allocate
2899	    ("C_a_i_atan2" 4) (exact->inexact n) (exact->inexact b)))
2900	  (else
2901	   (##core#inline_allocate
2902	    ("C_a_i_atan" 4) (exact->inexact n))) ) ))
2903
2904;;; End kahan algorithm
2905
2906;; This is "Karatsuba Square Root" as described by Paul Zimmermann,
2907;; which is 3/2K(n) + O(n log n) for an input of 2n words, where K(n)
2908;; is the number of operations performed by Karatsuba multiplication.
2909(define (##sys#exact-integer-sqrt a)
2910  ;; Because we assume a3b+a2 >= b^2/4, we must check a few edge cases:
2911  (if (and (fixnum? a) (fx<= a 4))
2912      (case a
2913        ((0 1) (values a 0))
2914        ((2)   (values 1 1))
2915        ((3)   (values 1 2))
2916        ((4)   (values 2 0))
2917        (else  (error "this should never happen")))
2918      (let*-values
2919          (((len/4) (fxshr (fx+ (integer-length a) 1) 2))
2920           ((len/2) (fxshl len/4 1))
2921           ((s^ r^) (##sys#exact-integer-sqrt
2922		     (arithmetic-shift a (fxneg len/2))))
2923           ((mask)  (- (arithmetic-shift 1 len/4) 1))
2924           ((a0)    (bitwise-and a mask))
2925           ((a1)    (bitwise-and (arithmetic-shift a (fxneg len/4)) mask))
2926           ((q u)   ((##core#primitive "C_u_integer_quotient_and_remainder")
2927		     (+ (arithmetic-shift r^ len/4) a1)
2928		     (arithmetic-shift s^ 1)))
2929           ((s)     (+ (arithmetic-shift s^ len/4) q))
2930           ((r)     (+ (arithmetic-shift u len/4) (- a0 (* q q)))))
2931        (if (negative? r)
2932            (values (- s 1)
2933		    (- (+ r (arithmetic-shift s 1)) 1))
2934            (values s r)))))
2935
2936(set! scheme#exact-integer-sqrt
2937  (lambda (x)
2938    (##sys#check-exact-uinteger x 'exact-integer-sqrt)
2939    (##sys#exact-integer-sqrt x)))
2940
2941;; Complex square root according to Kahan's algorithm.
2942
2943(define logb (foreign-lambda double "logb" double))
2944(define (ldexp* x k)
2945  (if (inexact? x)
2946      (ldexp x k)
2947      (* x (expt 2 k))))
2948
2949(define (##sys#cssqs z)
2950  (let* ((x (real-part z))
2951         (y (imag-part z))
2952         (x^2 (* x x))
2953         (y^2 (* y y))
2954         (rho (+ x^2 y^2)))
2955    (if (and (or (nan? rho) (infinite? rho))
2956             (or (infinite? x) (infinite? y)))
2957        (values +inf.0 0)
2958        (let ((underflowed? (or (< x^2 minimum-flonum)
2959                                (< y^2 minimum-flonum)))
2960              (overflowed? (or (infinite? rho)
2961                               (infinite? x^2)
2962                               (infinite? y^2))))
2963          (if (or overflowed?
2964                  (and underflowed? (< rho (/ minimum-flonum
2965                                              flonum-epsilon))))
2966              (let* ((k (logb (inexact (max (abs x) (abs y)))))
2967                     (x* (ldexp* x (- k)))
2968                     (y* (ldexp* y (- k))))
2969                (values (+ (* x* x*) (* y* y*)) k))
2970              (values rho 0))))))
2971
2972(define (##sys#csqrt z)
2973   (define (even*? k)
2974     (and (integer? k) (even? k)))
2975   (define (odd*? k)
2976     (and (integer? k) (odd? k)))
2977   (let*-values (((x) (real-part z))
2978                 ((y) (imag-part z))
2979                 ((rho k) (##sys#cssqs z))
2980                 ((rho) (if (not (nan? x))
2981                            (+ (ldexp* (abs x) (- k))
2982                               (sqrt rho))
2983                            rho))
2984                 ((rho) (if (even*? k)
2985                            (+ rho rho)
2986                            rho))
2987                 ((k) (if (odd*? k)
2988                          (/ (- k 1) 2)
2989                          (- (/ k 2) 1)))
2990                 ((rho) (ldexp* (sqrt rho) k))
2991                 ((zeta) rho)
2992                 ((eta) y)
2993                 ((eta) (if (and (not (zero? rho)) (not (infinite? eta)))
2994                            (/ eta rho 2.0)
2995                            eta)))
2996     (if (and (not (zero? rho)) (negative? x))
2997         (make-rectangular (abs eta) (* rho (##sys#sign-bit y)))
2998         (make-rectangular zeta eta))))
2999
3000;; This procedure is so large because it tries very hard to compute
3001;; exact results if at all possible.
3002(define (##sys#sqrt/loc loc n)
3003  (cond ((cplxnum? n)     ; Must be checked before we call "negative?"
3004         (##sys#csqrt n))
3005        ((negative? n)
3006         (make-complex .0 (##core#inline_allocate
3007			   ("C_a_i_sqrt" 4) (exact->inexact (- n)))))
3008        ((##core#inline "C_i_exact_integerp" n)
3009         (receive (s^2 r) (##sys#exact-integer-sqrt n)
3010           (if (eq? 0 r)
3011               s^2
3012               (##core#inline_allocate ("C_a_i_sqrt" 4) (exact->inexact n)))))
3013        ((ratnum? n) ; Try to compute exact sqrt (we already know n is positive)
3014         (receive (ns^2 nr) (##sys#exact-integer-sqrt (%ratnum-numerator n))
3015           (if (eq? nr 0)
3016               (receive (ds^2 dr)
3017		   (##sys#exact-integer-sqrt (%ratnum-denominator n))
3018                 (if (eq? dr 0)
3019                     (##sys#/-2 ns^2 ds^2)
3020                     (##sys#sqrt/loc loc (exact->inexact n))))
3021               (##sys#sqrt/loc loc (exact->inexact n)))))
3022        (else (##core#inline_allocate ("C_a_i_sqrt" 4) (exact->inexact n)))))
3023
3024(set! scheme#sqrt (lambda (x) (##sys#sqrt/loc 'sqrt x)))
3025
3026;; XXX These are bad bad bad definitions; very inefficient.
3027;; But to improve it we would need to provide another implementation
3028;; of the quotient procedure which floors instead of truncates.
3029(define scheme#truncate/ quotient&remainder)
3030
3031(define (scheme#floor/ x y)
3032  (receive (div rem) (quotient&remainder x y)
3033    (if (positive? y)
3034        (if (negative? rem)
3035            (values (- div 1) (+ rem y))
3036            (values div rem))
3037        (if (positive? rem)
3038            (values (- div 1) (+ rem y))
3039            (values div rem)))))
3040
3041(define (scheme#floor-remainder x y)
3042  (receive (div rem) (scheme#floor/ x y) rem))
3043
3044(define (scheme#floor-quotient x y)
3045  (receive (div rem) (scheme#floor/ x y) div))
3046
3047(define (scheme#square n) (* n n))
3048
3049(set! chicken.base#exact-integer-nth-root
3050  (lambda (k n)
3051    (##sys#check-exact-uinteger k 'exact-integer-nth-root)
3052    (##sys#check-exact-uinteger n 'exact-integer-nth-root)
3053    (##sys#exact-integer-nth-root/loc 'exact-integer-nth-root k n)))
3054
3055;; Generalized Newton's algorithm for positive integers, with a little help
3056;; from Wikipedia ;)  https://en.wikipedia.org/wiki/Nth_root_algorithm
3057(define (##sys#exact-integer-nth-root/loc loc k n)
3058  (if (or (eq? 0 k) (eq? 1 k) (eq? 1 n)) ; Maybe call exact-integer-sqrt on n=2?
3059      (values k 0)
3060      (let ((len (integer-length k)))
3061	(if (< len n)	  ; Idea from Gambit: 2^{len-1} <= k < 2^{len}
3062	    (values 1 (- k 1)) ; Since x >= 2, we know x^{n} can't exist
3063	    ;; Set initial guess to (at least) 2^ceil(ceil(log2(k))/n)
3064	    (let* ((shift-amount (inexact->exact (ceiling (/ (fx+ len 1) n))))
3065		   (g0 (arithmetic-shift 1 shift-amount))
3066		   (n-1 (- n 1)))
3067	      (let lp ((g0 g0)
3068		       (g1 (quotient
3069			    (+ (* n-1 g0)
3070			       (quotient k (##sys#integer-power g0 n-1)))
3071			    n)))
3072		(if (< g1 g0)
3073		    (lp g1 (quotient
3074			    (+ (* n-1 g1)
3075			       (quotient k (##sys#integer-power g1 n-1)))
3076			    n))
3077		    (values g0 (- k (##sys#integer-power g0 n))))))))))
3078
3079(define (##sys#integer-power base e)
3080  (define (square x) (* x x))
3081  (if (negative? e)
3082      (##sys#/-2 1 (##sys#integer-power base (integer-negate e)))
3083      (let lp ((res 1) (e2 e))
3084        (cond
3085         ((eq? e2 0) res)
3086         ((even? e2)	     ; recursion is faster than iteration here
3087          (* res (square (lp 1 (arithmetic-shift e2 -1)))))
3088         (else
3089          (lp (* res base) (- e2 1)))))))
3090
3091(set! scheme#expt
3092  (lambda (a b)
3093    (define (log-expt a b)
3094      (exp (* b (##sys#log-1 a))))
3095    (define (slow-expt a b)
3096      (if (eq? 0 a)
3097	  (##sys#signal-hook
3098	   #:arithmetic-error 'expt
3099	   "exponent of exact 0 with complex argument is undefined" a b)
3100	  (exp (* b (##sys#log-1 a)))))
3101    (cond ((not (number? a)) (##sys#error-bad-number a 'expt))
3102	  ((not (number? b)) (##sys#error-bad-number b 'expt))
3103	  ((and (ratnum? a) (not (inexact? b)))
3104	   ;; (n*d)^b = n^b * d^b = n^b * x^{-b}  | x = 1/b
3105	   ;; Hopefully faster than integer-power
3106	   (* (expt (%ratnum-numerator a) b)
3107	      (expt (%ratnum-denominator a) (- b))))
3108	  ((ratnum? b)
3109	   ;; x^{a/b} = (x^{1/b})^a
3110	   (cond
3111	    ((##core#inline "C_i_exact_integerp" a)
3112	     (if (negative? a)
3113		 (log-expt (exact->inexact a) (exact->inexact b))
3114		 (receive (ds^n r)
3115		     (##sys#exact-integer-nth-root/loc
3116		      'expt a (%ratnum-denominator b))
3117		   (if (eq? r 0)
3118		       (##sys#integer-power ds^n (%ratnum-numerator b))
3119		       (##core#inline_allocate ("C_a_i_flonum_expt" 4)
3120					       (exact->inexact a)
3121					       (exact->inexact b))))))
3122	    ((##core#inline "C_i_flonump" a)
3123	     (log-expt a (exact->inexact b)))
3124	    (else (slow-expt a b))))
3125	  ((or (cplxnum? b) (and (cplxnum? a) (not (integer? b))))
3126	   (slow-expt a b))
3127	  ((and (##core#inline "C_i_flonump" b)
3128		(not (##core#inline "C_u_i_fpintegerp" b)))
3129	   (if (negative? a)
3130	       (log-expt (exact->inexact a) (exact->inexact b))
3131	       (##core#inline_allocate
3132		("C_a_i_flonum_expt" 4) (exact->inexact a) b)))
3133	  ((##core#inline "C_i_flonump" a)
3134	   (##core#inline_allocate ("C_a_i_flonum_expt" 4) a (exact->inexact b)))
3135	  ;; this doesn't work that well, yet...
3136	  ;; (XXX: What does this mean? why not? I do know this is ugly... :P)
3137	  (else (if (or (inexact? a) (inexact? b))
3138		    (exact->inexact (##sys#integer-power a (inexact->exact b)))
3139		    (##sys#integer-power a b)))) ))
3140
3141;; Useful for sane error messages
3142(define (##sys#internal-gcd loc a b)
3143  (cond ((##core#inline "C_i_exact_integerp" a)
3144         (cond ((##core#inline "C_i_exact_integerp" b)
3145                (%integer-gcd a b))
3146               ((and (##core#inline "C_i_flonump" b)
3147                     (##core#inline "C_u_i_fpintegerp" b))
3148                (exact->inexact (%integer-gcd a (inexact->exact b))))
3149               (else (##sys#error-bad-integer b loc))))
3150        ((and (##core#inline "C_i_flonump" a)
3151              (##core#inline "C_u_i_fpintegerp" a))
3152         (cond ((##core#inline "C_i_flonump" b)
3153                (##core#inline_allocate ("C_a_i_flonum_gcd" 4) a b))
3154               ((##core#inline "C_i_exact_integerp" b)
3155                (exact->inexact (%integer-gcd (inexact->exact a) b)))
3156               (else (##sys#error-bad-integer b loc))))
3157        (else (##sys#error-bad-integer a loc))))
3158;; For compat reasons, we define this
3159(define (##sys#gcd a b) (##sys#internal-gcd 'gcd a b))
3160
3161(set! scheme#gcd
3162  (lambda ns
3163    (if (eq? ns '())
3164	0
3165	(let loop ((head (##sys#slot ns 0))
3166		   (next (##sys#slot ns 1)))
3167	  (if (null? next)
3168	      (if (integer? head) (abs head) (##sys#error-bad-integer head 'gcd))
3169	      (let ((n2 (##sys#slot next 0)))
3170		(loop (##sys#internal-gcd 'gcd head n2)
3171		      (##sys#slot next 1)) ) ) ) ) ))
3172
3173(define (##sys#lcm x y)
3174  (let ((gcd (##sys#internal-gcd 'lcm x y))) ; Ensure better error message
3175    (abs (quotient (* x y) gcd) ) ) )
3176
3177(set! scheme#lcm
3178  (lambda ns
3179    (if (null? ns)
3180	1
3181	(let loop ((head (##sys#slot ns 0))
3182		   (next (##sys#slot ns 1)))
3183	  (if (null? next)
3184	      (if (integer? head) (abs head) (##sys#error-bad-integer head 'lcm))
3185	      (let* ((n2 (##sys#slot next 0))
3186		     (gcd (##sys#internal-gcd 'lcm head n2)))
3187		(loop (quotient (* head n2) gcd)
3188		      (##sys#slot next 1)) ) ) ) ) ))
3189
3190;; This simple enough idea is from
3191;; http://www.numberworld.org/y-cruncher/internals/radix-conversion.html
3192(define (##sys#integer->string/recursive n base expected-string-size)
3193  (let*-values (((halfsize) (fxshr (fx+ expected-string-size 1) 1))
3194                ((b^M/2) (##sys#integer-power base halfsize))
3195                ((hi lo) ((##core#primitive "C_u_integer_quotient_and_remainder")
3196			  n b^M/2))
3197                ((strhi) (number->string hi base))
3198                ((strlo) (number->string (abs lo) base)))
3199    (string-append strhi
3200                   ;; Fix up any leading zeroes that were stripped from strlo
3201                   (make-string (fx- halfsize (string-length strlo)) #\0)
3202                   strlo)))
3203
3204(define ##sys#extended-number->string
3205  (let ((string-append string-append))
3206    (lambda (n base)
3207      (cond
3208       ((ratnum? n)
3209	(string-append (number->string (%ratnum-numerator n) base)
3210		       "/"
3211		       (number->string (%ratnum-denominator n) base)))
3212       ((cplxnum? n) (let ((r (%cplxnum-real n))
3213                           (i (%cplxnum-imag n)) )
3214                       (string-append
3215                        (number->string r base)
3216                        ;; The infinities and NaN always print their sign
3217                        (if (and (finite? i) (>= i 0) (not (eqv? i -0.0))) "+" "")
3218                        (number->string i base) "i") ))
3219       (else (##sys#error-bad-number n 'number->string)))  ) ) )
3220
3221(define ##sys#number->string number->string) ; for printer
3222
3223;; We try to prevent memory exhaustion attacks by limiting the
3224;; maximum exponent value.  Perhaps this should be a parameter?
3225(define-constant +maximum-allowed-exponent+ 10000)
3226
3227;; From "Easy Accurate Reading and Writing of Floating-Point Numbers"
3228;; by Aubrey Jaffer.
3229(define (mantexp->dbl mant point)
3230  (if (not (negative? point))
3231      (exact->inexact (* mant (##sys#integer-power 10 point)))
3232      (let* ((scl (##sys#integer-power 10 (abs point)))
3233	     (bex (fx- (fx- (integer-length mant)
3234			    (integer-length scl))
3235                       flonum-precision)))
3236        (if (fx< bex 0)
3237            (let* ((num (arithmetic-shift mant (fxneg bex)))
3238                   (quo (round-quotient num scl)))
3239              (cond ((> (integer-length quo) flonum-precision)
3240                     ;; Too many bits of quotient; readjust
3241                     (set! bex (fx+ 1 bex))
3242                     (set! quo (round-quotient num (* scl 2)))))
3243              (ldexp (exact->inexact quo) bex))
3244            ;; Fall back to exact calculation in extreme cases
3245            (* mant (##sys#integer-power 10 point))))))
3246
3247(define ldexp (foreign-lambda double "ldexp" double int))
3248
3249;; Should we export this?
3250(define (round-quotient n d)
3251  (let ((q (%integer-quotient n d)))
3252    (if ((if (even? q) > >=) (* (abs (remainder n d)) 2) (abs d))
3253        (+ q (if (eqv? (negative? n) (negative? d)) 1 -1))
3254        q)))
3255
3256(define (##sys#string->compnum radix str offset exactness)
3257  ;; Flipped when a sign is encountered (for inexact numbers only)
3258  (define negative #f)
3259  ;; Go inexact unless exact was requested (with #e prefix)
3260  (define (go-inexact! neg?)
3261    (unless (eq? exactness 'e)
3262      (set! exactness 'i)
3263      (set! negative (or negative neg?))))
3264  (define (safe-exponent value e)
3265    (and e (cond
3266            ((not value) 0)
3267            ((> e +maximum-allowed-exponent+)
3268             (and (eq? exactness 'i)
3269                  (cond ((zero? value) 0.0)
3270                        ((> value 0.0) +inf.0)
3271                        (else -inf.0))))
3272            ((< e (fxneg +maximum-allowed-exponent+))
3273             (and (eq? exactness 'i) +0.0))
3274            ((eq? exactness 'i) (mantexp->dbl value e))
3275            (else (* value (##sys#integer-power 10 e))))))
3276  (define (make-nan)
3277    ;; Return fresh NaNs, so eqv? returns #f on two read NaNs.  This
3278    ;; is not mandated by the standard, but compatible with earlier
3279    ;; CHICKENs and it just makes more sense.
3280    (##core#inline_allocate ("C_a_i_flonum_quotient" 4) 0.0 0.0))
3281  (let* ((len (string-length str))
3282         (0..r (fast-i->c (fx+ (char->integer #\0) (fx- radix 1))))
3283         (a..r (fast-i->c (fx+ (char->integer #\a) (fx- radix 11))))
3284         (A..r (fast-i->c (fx+ (char->integer #\A) (fx- radix 11))))
3285         ;; Ugly flag which we need (note that "exactness" is mutated too!)
3286         ;; Since there is (almost) no backtracking we can do this.
3287         (seen-hashes? #f)
3288         ;; All these procedures return #f or an object consed onto an end
3289         ;; position.  If the cdr is false, that's the end of the string.
3290         ;; If just #f is returned, the string contains invalid number syntax.
3291         (scan-digits
3292          (lambda (start cplx?)
3293            (let lp ((i start)
3294                     ;; Drop is true when the last read character is
3295                     ;; an "i" while reading the second part of a
3296                     ;; rectangular complex number literal *and* the
3297                     ;; radix is 19 or above.  In that case, we back
3298                     ;; up one character to ensure we don't consume
3299                     ;; the trailing "i", which we otherwise would.
3300                     (drop? #f))
3301              (if (fx= i len)
3302                  (and (fx> i start)
3303                       (if drop?
3304                           (cons (sub1 i) (sub1 i))
3305                           (cons i #f)))
3306                  (let ((c (string-ref str i)))
3307                    (if (fx<= radix 10)
3308                        (if (and (char>=? c #\0) (char<=? c 0..r))
3309                            (lp (fx+ i 1) #f)
3310                            (and (fx> i start) (cons i i)))
3311                        (if (or (and (char>=? c #\0) (char<=? c #\9))
3312                                (and (char>=? c #\a) (char<=? c a..r))
3313                                (and (char>=? c #\A) (char<=? c A..r)))
3314                            (lp (fx+ i 1)
3315                                (and cplx? (fx>= radix 19)
3316                                     (or (char=? c #\i)
3317                                         (char=? c #\I))))
3318                            (and (fx> i start)
3319                                 (if (and drop? (not (char=? c #\/))) ;; Fractional numbers are an exception - the i may only come after the slash
3320                                     (cons (sub1 i) (sub1 i))
3321                                     (cons i i))))))))))
3322         (scan-hashes
3323          (lambda (start)
3324            (let lp ((i start))
3325              (if (fx= i len)
3326                  (and (fx> i start) (cons i #f))
3327                  (let ((c (string-ref str i)))
3328                    (if (eq? c #\#)
3329                        (lp (fx+ i 1))
3330                        (and (fx> i start) (cons i i))))))))
3331         (scan-digits+hashes
3332          (lambda (start neg? cplx? all-hashes-ok?)
3333            (let* ((digits (and (not seen-hashes?) (scan-digits start cplx?)))
3334                   (hashes (if digits
3335                               (and (cdr digits) (scan-hashes (cdr digits)))
3336                               (and all-hashes-ok? (scan-hashes start))))
3337                   (end (or hashes digits)))
3338              (and-let* ((end)
3339                         (num (##core#inline_allocate
3340			       ("C_s_a_i_digits_to_integer" 6)
3341			       str start (car end) radix neg?)))
3342                (when hashes            ; Eeewww. Feeling dirty yet?
3343                  (set! seen-hashes? #t)
3344                  (go-inexact! neg?))
3345                (cons num (cdr end))))))
3346         (scan-exponent
3347          (lambda (start)
3348            (and (fx< start len)
3349                 (let ((sign (case (string-ref str start)
3350                               ((#\+) 'pos) ((#\-) 'neg) (else #f))))
3351                   (and-let* ((start (if sign (fx+ start 1) start))
3352                              (end (scan-digits start #f)))
3353                     (cons (##core#inline_allocate
3354			    ("C_s_a_i_digits_to_integer" 6)
3355			    str start (car end) radix (eq? sign 'neg))
3356                           (cdr end)))))))
3357         (scan-decimal-tail             ; The part after the decimal dot
3358          (lambda (start neg? decimal-head)
3359            (and (fx< start len)
3360                 (let* ((tail (scan-digits+hashes start neg? #f decimal-head))
3361                        (next (if tail (cdr tail) start)))
3362                   (and (or decimal-head (not next)
3363                            (fx> next start)) ; Don't allow empty "."
3364                        (case (and next (string-ref str next))
3365                          ((#\e #\s #\f #\d #\l
3366                            #\E #\S #\F #\D #\L)
3367                           (and-let* (((fx> len next))
3368                                      (ee (scan-exponent (fx+ next 1)))
3369                                      (e (car ee))
3370                                      (h (safe-exponent decimal-head e)))
3371                             (let* ((te (and tail (fx- e (fx- (cdr tail) start))))
3372                                    (num (and tail (car tail)))
3373                                    (t (safe-exponent num te)))
3374                               (cons (if t (+ h t) h) (cdr ee)))))
3375                          (else (let* ((last (or next len))
3376                                       (te (and tail (fx- start last)))
3377                                       (num (and tail (car tail)))
3378                                       (t (safe-exponent num te))
3379                                       (h (or decimal-head 0)))
3380                                  (cons (if t (+ h t) h) next)))))))))
3381         (scan-ureal
3382          (lambda (start neg? cplx?)
3383            (if (and (fx> len (fx+ start 1)) (eq? radix 10)
3384                     (eq? (string-ref str start) #\.))
3385                (begin
3386                  (go-inexact! neg?)
3387                  (scan-decimal-tail (fx+ start 1) neg? #f))
3388                (and-let* ((end (scan-digits+hashes start neg? cplx? #f)))
3389                  (case (and (cdr end) (string-ref str (cdr end)))
3390                    ((#\.)
3391                     (go-inexact! neg?)
3392                     (and (eq? radix 10)
3393                          (if (fx> len (fx+ (cdr end) 1))
3394                              (scan-decimal-tail (fx+ (cdr end) 1) neg? (car end))
3395                              (cons (car end) #f))))
3396                    ((#\e #\s #\f #\d #\l
3397                      #\E #\S #\F #\D #\L)
3398                     (go-inexact! neg?)
3399                     (and-let* (((eq? radix 10))
3400                                ((fx> len (cdr end)))
3401                                (ee (scan-exponent (fx+ (cdr end) 1)))
3402                                (num (car end))
3403                                (val (safe-exponent num (car ee))))
3404                       (cons val (cdr ee))))
3405                    ((#\/)
3406                     (set! seen-hashes? #f) ; Reset flag for denominator
3407                     (and-let* (((fx> len (cdr end)))
3408                                (d (scan-digits+hashes (fx+ (cdr end) 1) #f cplx? #f))
3409                                (num (car end))
3410                                (denom (car d)))
3411                       (if (not (eq? denom 0))
3412                           (cons (##sys#/-2 num denom) (cdr d))
3413                           ;; Hacky: keep around an inexact until we decide we
3414                           ;; *really* need exact values, then fail at the end.
3415                           (and (not (eq? exactness 'e))
3416                                (case (signum num)
3417                                  ((-1) (cons -inf.0 (cdr d)))
3418                                  ((0)  (cons (make-nan) (cdr d)))
3419                                  ((+1) (cons +inf.0 (cdr d))))))))
3420                    (else end))))))
3421         (scan-real
3422          (lambda (start cplx?)
3423            (and (fx< start len)
3424                 (let* ((sign (case (string-ref str start)
3425                                ((#\+) 'pos) ((#\-) 'neg) (else #f)))
3426                        (next (if sign (fx+ start 1) start)))
3427                   (and (fx< next len)
3428                        (case (string-ref str next)
3429                          ((#\i #\I)
3430                           (or (and sign
3431                                    (cond
3432                                     ((and (fx= (fx+ next 1) len)  ; [+-]i
3433                                           ;; Reject bare "+i" in higher radixes where this would be ambiguous
3434                                           (or cplx?
3435                                               (fx< radix 19)))
3436                                      (cons (if (eq? sign 'neg) -1 1) next))
3437                                     ((and (fx<= (fx+ next 5) len)
3438                                           (string-ci=? (substring str next (fx+ next 5)) "inf.0"))
3439                                      (go-inexact! (eq? sign 'neg))
3440                                      (cons (if (eq? sign 'neg) -inf.0 +inf.0)
3441                                            (and (fx< (fx+ next 5) len)
3442                                                 (fx+ next 5))))
3443                                     (else #f)))
3444                               (scan-ureal next (eq? sign 'neg) cplx?)))
3445                          ((#\n #\N)
3446                           (or (and sign
3447                                    (fx<= (fx+ next 5) len)
3448                                    (string-ci=? (substring str next (fx+ next 5)) "nan.0")
3449                                    (begin (go-inexact! (eq? sign 'neg))
3450                                           (cons (make-nan)
3451                                                 (and (fx< (fx+ next 5) len)
3452                                                      (fx+ next 5)))))
3453                               (scan-ureal next (eq? sign 'neg) cplx?)))
3454                          (else (scan-ureal next (eq? sign 'neg) cplx?))))))))
3455         (number (and-let* ((r1 (scan-real offset #f)))
3456                   (let ((nf (and r1 (zero? (car r1)) negative)))
3457                     (case (and (cdr r1) (string-ref str (cdr r1)))
3458                       ((#f) (car r1))
3459                       ((#\i #\I) (and (fx= len (fx+ (cdr r1) 1))
3460                                     (or (eq? (string-ref str offset) #\+) ; ugh
3461                                         (eq? (string-ref str offset) #\-))
3462                                     (make-rectangular 0 (if nf (- (car r1)) (car r1)))))
3463                       ((#\+ #\-)
3464                        (set! seen-hashes? #f) ; Reset flag for imaginary part
3465                        (set! negative #f)
3466                        (and-let* ((r2 (scan-real (cdr r1) #t))
3467                                   ((cdr r2))
3468                                   ((fx= len (fx+ (cdr r2) 1)))
3469                                   ((or (eq? (string-ref str (cdr r2)) #\i)
3470                                        (eq? (string-ref str (cdr r2)) #\I))))
3471                          (make-rectangular 
3472                            (car r1) 
3473                            (let ((n2 (if (and (exact? (car r2)) (eq? exactness 'i))
3474                                          (exact->inexact (car r2))
3475                                          (car r2))))
3476                              (if (and negative (>= n2 0) (not (eqv? n2 -0.0)))
3477                                  (- n2)
3478                                  n2)))))
3479                       ((#\@)
3480                        (set! seen-hashes? #f) ; Reset flag for angle
3481                        (and-let* ((r2 (scan-real (fx+ (cdr r1) 1) #f))
3482                                   ((not (cdr r2))))
3483                          (make-polar (car r1) (car r2))))
3484                       (else #f))))))
3485    (and number (if (eq? exactness 'i)
3486                    (let ((r (exact->inexact number)))
3487                      ;; Stupid hack because flonums can represent negative zero,
3488                      ;; but we're coming from an exact which has no such thing.
3489                      (if (and negative (zero? r)) (fpneg r) r))
3490                    ;; Ensure we didn't encounter +inf.0 or +nan.0 with #e
3491                    (and (finite? number) number)))))
3492
3493(set! scheme#string->number
3494  (lambda (str #!optional (base 10))
3495    (##sys#check-string str 'string->number)
3496    (unless (and (##core#inline "C_fixnump" base)
3497		 (fx< 1 base) (fx< base 37)) ; We only have 0-9 and the alphabet!
3498      (##sys#error-bad-base base 'string->number))
3499    (let scan-prefix ((i 0)
3500		      (exness #f)
3501		      (radix #f)
3502		      (len (string-length str)))
3503      (if (and (fx< (fx+ i 2) len) (eq? (string-ref str i) #\#))
3504	  (case (string-ref str (fx+ i 1))
3505	    ((#\i #\I) (and (not exness) (scan-prefix (fx+ i 2) 'i radix len)))
3506	    ((#\e #\E) (and (not exness) (scan-prefix (fx+ i 2) 'e radix len)))
3507	    ((#\b #\B) (and (not radix) (scan-prefix (fx+ i 2) exness 2 len)))
3508	    ((#\o #\O) (and (not radix) (scan-prefix (fx+ i 2) exness 8 len)))
3509	    ((#\d #\D) (and (not radix) (scan-prefix (fx+ i 2) exness 10 len)))
3510	    ((#\x #\X) (and (not radix) (scan-prefix (fx+ i 2) exness 16 len)))
3511	    (else #f))
3512	  (##sys#string->compnum (or radix base) str i exness)))))
3513
3514(define (##sys#string->number str #!optional (radix 10) exactness)
3515  (##sys#string->compnum radix str 0 exactness))
3516
3517(define ##sys#fixnum->string (##core#primitive "C_fixnum_to_string"))
3518(define ##sys#flonum->string (##core#primitive "C_flonum_to_string"))
3519(define ##sys#integer->string (##core#primitive "C_integer_to_string"))
3520(define ##sys#number->string number->string)
3521
3522(set! chicken.base#equal=?
3523  (lambda (x y)
3524    (define (compare-slots x y start)
3525      (let ((l1 (##sys#size x))
3526	    (l2 (##sys#size y)))
3527	(and (eq? l1 l2)
3528	     (or (fx<= l1 start)
3529		 (let ((l1n (fx- l1 1)))
3530		   (let loop ((i start))
3531		     (if (fx= i l1n)
3532			 (walk (##sys#slot x i) (##sys#slot y i)) ; tailcall
3533			 (and (walk (##sys#slot x i) (##sys#slot y i))
3534			      (loop (fx+ i 1))))))))))
3535    (define (walk x y)
3536      (cond ((eq? x y))
3537	    ((number? x)
3538	     (if (number? y)
3539		 (= x y)
3540		 (eq? x y)))
3541	    ((not (##core#inline "C_blockp" x)) #f)
3542	    ((not (##core#inline "C_blockp" y)) #f)
3543	    ((not (##core#inline "C_sametypep" x y)) #f)
3544	    ((##core#inline "C_specialp" x)
3545	     (and (##core#inline "C_specialp" y)
3546		  (if (##core#inline "C_closurep" x)
3547		      (##core#inline "shallow_equal" x y)
3548		      (compare-slots x y 1))))
3549            ((##core#inline "C_stringp" x)
3550             (walk (##sys#slot x 0) (##sys#slot y 0)))
3551	    ((##core#inline "C_byteblockp" x)
3552	     (and (##core#inline "C_byteblockp" y)
3553		  (let ((s1 (##sys#size x)))
3554		    (and (eq? s1 (##sys#size y))
3555			 (##core#inline "C_bv_compare" x y s1)))))
3556	    (else
3557	     (let ((s1 (##sys#size x)))
3558	       (and (eq? s1 (##sys#size y))
3559		    (compare-slots x y 0))))))
3560    (walk x y) ))
3561
3562
3563;;; Symbols:
3564
3565(define ##sys#snafu '##sys#fnord)
3566(define ##sys#intern-symbol (##core#primitive "C_string_to_symbol"))
3567(define ##sys#intern-keyword (##core#primitive "C_string_to_keyword"))
3568(define ##sys#make-symbol (##core#primitive "C_make_symbol"))
3569(define (##sys#interned-symbol? x) (##core#inline "C_lookup_symbol" x))
3570
3571(define (##sys#string->symbol-name s)
3572  (let* ((bv (##sys#slot s 0))
3573         (len (##sys#size bv))
3574         (s2 (##sys#make-bytevector len)))
3575    (##core#inline "C_copy_bytevector" bv s2 len)))
3576
3577(define (##sys#symbol->string/shared s)
3578  (let* ((bv (##sys#slot s 1))
3579         (count (##core#inline "C_utf_length" bv)))
3580    (##core#inline_allocate ("C_a_ustring" 5)
3581                            bv
3582                            count)))
3583
3584(define (##sys#symbol->string s)
3585  (let* ((bv (##sys#slot s 1))
3586         (len (##sys#size bv))
3587         (s2 (##sys#make-bytevector len))
3588         (count (##core#inline "C_utf_length" bv)))
3589    (##core#inline_allocate ("C_a_ustring" 5)
3590                            (##core#inline "C_copy_bytevector" bv s2 len)
3591                            count)))
3592
3593(define (##sys#string->symbol str)
3594  (##sys#intern-symbol (##sys#string->symbol-name str) ))
3595
3596(set! scheme#symbol->string
3597  (lambda (s)
3598    (##sys#check-symbol s 'symbol->string)
3599    (##sys#symbol->string s) ) )
3600
3601(set! scheme#string->symbol
3602  (lambda (str)
3603    (##sys#check-string str 'string->symbol)
3604    (##sys#string->symbol str)))
3605
3606(set! chicken.base#string->uninterned-symbol
3607  (lambda (str)
3608    (##sys#check-string str 'string->uninterned-symbol)
3609    (##sys#make-symbol (##sys#string->symbol-name str))))
3610
3611(set! chicken.base#gensym
3612  (let ((counter -1))
3613    (lambda str-or-sym
3614      (let ((err (lambda (prefix) (##sys#signal-hook #:type-error 'gensym "argument is not a string or symbol" prefix))))
3615	(set! counter (fx+ counter 1))
3616	(##sys#make-symbol
3617         (##sys#string->symbol-name
3618	 (##sys#string-append
3619	  (if (eq? str-or-sym '())
3620	      "g"
3621	      (let ((prefix (car str-or-sym)))
3622		(or (and (##core#inline "C_blockp" prefix)
3623			 (cond ((##core#inline "C_stringp" prefix) prefix)
3624			       ((##core#inline "C_symbolp" prefix) (##sys#symbol->string/shared prefix))
3625			       (else (err prefix))))
3626		    (err prefix) ) ) )
3627	  (##sys#number->string counter) ) ) ) ) ) ) )
3628
3629(set! chicken.base#symbol-append
3630  (let ((string-append string-append))
3631    (lambda ss
3632      (##sys#string->symbol
3633       (apply
3634	string-append
3635	(map (lambda (s)
3636	       (##sys#check-symbol s 'symbol-append)
3637	       (##sys#symbol->string/shared s))
3638	     ss))))))
3639
3640;;; Keywords:
3641
3642(module chicken.keyword
3643  (keyword? get-keyword keyword->string string->keyword)
3644
3645(import scheme)
3646(import chicken.fixnum)
3647
3648(define (keyword? x) (##core#inline "C_i_keywordp" x) )
3649
3650(define string->keyword
3651  (let ([string string] )
3652    (lambda (s)
3653      (##sys#check-string s 'string->keyword)
3654      (##sys#intern-keyword (##sys#string->symbol-name s) ) ) ))
3655
3656(define keyword->string
3657  (let ([keyword? keyword?])
3658    (lambda (kw)
3659      (if (keyword? kw)
3660	  (##sys#symbol->string kw)
3661	  (##sys#signal-hook #:type-error 'keyword->string "bad argument type - not a keyword" kw) ) ) ) )
3662
3663(define get-keyword
3664  (let ((tag (list 'tag)))
3665    (lambda (key args #!optional thunk)
3666      (##sys#check-keyword key 'get-keyword)
3667      (##sys#check-list args 'get-keyword)
3668      (let ((r (##core#inline "C_i_get_keyword" key args tag)))
3669	(if (eq? r tag)			; not found
3670	    (and thunk (thunk))
3671	    r)))))
3672
3673(define ##sys#get-keyword get-keyword))
3674
3675(import chicken.keyword)
3676
3677
3678;;; bytevectors:
3679
3680(define (##sys#bytevector->list v)
3681  (let ((n (##sys#size v)))
3682    (let loop ((i (fx- n 1)) (lst '()))
3683      (if (fx< i 0)
3684          lst
3685          (loop (fx- i 1)
3686                (cons (##core#inline "C_subbyte" v i) lst))))))
3687
3688(define (##sys#list->bytevector lst0)
3689  (let* ((n (length lst0))
3690         (bv (##sys#make-bytevector n)))
3691    (let loop ((lst lst0) (i 0))
3692      (if (null? lst)
3693          bv
3694          (let ((b (car lst)))
3695            (if (##core#inline "C_fixnump" b)
3696                (##core#inline "C_setsubbyte" bv i b)
3697                (##sys#signal-hook #:type-error "can not convert list to bytevector" lst0))
3698            (loop (cdr lst) (fx+ i 1)))))))
3699
3700(module chicken.bytevector
3701  (bytevector? bytevector=? bytevector-length
3702               make-bytevector bytevector bytevector-u8-ref
3703               bytevector-u8-set! bytevector-copy bytevector-copy!
3704               bytevector-append utf8->string string->utf8
3705               latin1->string string->latin1 bytes->string)
3706
3707(import scheme (chicken foreign))
3708
3709(define (make-bytevector size #!optional fill)
3710  (##sys#check-fixnum size 'make-bytevector)
3711  (if fill (##sys#check-fixnum fill 'make-bytevector))
3712  (##sys#make-bytevector size fill) )
3713
3714(define (bytevector? x)
3715  (##core#inline "C_i_bytevectorp" x) )
3716
3717(define (bytevector-length bv)
3718  (##sys#check-bytevector bv 'bytevector-size)
3719  (##sys#size bv) )
3720
3721(define (bytevector-u8-ref bv i)
3722  (##core#inline "C_i_bytevector_ref" bv i))
3723
3724(define (bytevector-u8-set! bv i b)
3725  (##core#inline "C_i_bytevector_set" bv i b))
3726
3727(define (string->utf8 s)
3728  (##sys#check-string s 'string->utf8)
3729  (let* ((sbv (##sys#slot s 0))
3730         (n (##core#inline "C_fixnum_difference" (##sys#size sbv) 1))
3731	 (bv (##sys#make-bytevector n)) )
3732    (##core#inline "C_copy_memory" bv sbv n)
3733    bv) )
3734
3735(define (utf8->string bv #!optional (start 0) end)
3736  (##sys#check-bytevector bv 'utf8->string)
3737  (let* ((n (##sys#size bv))
3738         (to (or end n)))
3739    (##sys#check-range/including start 0 n 'utf8->string)
3740    (if end
3741        (##sys#check-range/including end 0 n 'utf8->string))
3742    (let ((count (##core#inline "C_utf_validate" bv n start to)))
3743      (if (not count)
3744          (##sys#error-hook (foreign-value "C_DECODING_ERROR" int) 'utf8->string bv))
3745      (let* ((len (##core#inline "C_fixnum_difference" to start))
3746             (dest (##sys#make-bytevector (##core#inline "C_fixnum_plus" len 1))))
3747        (##core#inline "C_copy_memory_with_offset" dest bv 0 start len)
3748        (##core#inline_allocate ("C_a_ustring" 5) dest count)))))
3749
3750(define (bytes->string bv #!optional (start 0) end)
3751  (##sys#check-bytevector bv 'bytes->string)
3752  (let* ((n (##sys#size bv))
3753         (to (or end n)))
3754    (##sys#check-range/including start 0 n 'bytes->string)
3755    (if end
3756        (##sys#check-range/including end 0 n 'bytes->string))
3757    (##sys#buffer->string bv start (##core#inline "C_fixnum_difference" to start))))
3758
3759(define (string->latin1 s)
3760  (##sys#check-string s 'string->latin1)
3761  (let* ((sbv (##sys#slot s 0))
3762         (len (##sys#slot s 1))
3763         (blen (##core#inline "C_fixnum_difference" (##sys#size sbv) 1))
3764	 (bv (##sys#make-bytevector len)) )
3765    (##core#inline "C_utf_to_latin" sbv bv 0 blen)
3766    bv))
3767
3768(define (latin1->string bv)
3769  (##sys#check-bytevector bv 'latin1->string)
3770  (let* ((len (##sys#size bv))
3771         (buf (##sys#make-bytevector (##core#inline "C_fixnum_times" len 2)))
3772         (n (##core#inline "C_latin_to_utf" bv buf 0 len)))
3773    (##sys#buffer->string! buf n)))
3774
3775(define (bytevector=? b1 b2)
3776  (##sys#check-bytevector b1 'bytevector=?)
3777  (##sys#check-bytevector b2 'bytevector=?)
3778  (let ((n (##sys#size b1)))
3779    (and (eq? (##sys#size b2) n)
3780	 (##core#inline "C_bv_compare" b1 b2 n))))
3781
3782(define (bytevector . args)
3783  (let* ((n (length args))
3784         (bv (##sys#make-bytevector n)))
3785    (let loop ((args args) (i 0))
3786      (cond ((null? args) bv)
3787            (else
3788              (let ((b (car args)))
3789                (##sys#check-fixnum b 'bytevector)
3790                (##core#inline "C_setsubbyte" bv i b)
3791                (loop (cdr args) (##core#inline "C_fixnum_plus" i 1))))))))
3792
3793(define (bytevector-copy bv #!optional (start 0) end)
3794  (##sys#check-bytevector bv 'bytevector-copy)
3795  (let* ((n (##sys#size bv))
3796         (to (or end n)))
3797    (if end
3798      (##sys#check-range/including end 0 n 'bytevector->copy))
3799    (cond ((and (eq? n 0) (eq? start 0) (eq? 0 to))
3800           (##sys#make-bytevector 0))
3801          (else
3802            (##sys#check-range/including start 0 n 'bytevector->copy)
3803            (let* ((n2 (##core#inline "C_fixnum_difference" to start))
3804                   (v2 (##sys#make-bytevector n2)))
3805              (##core#inline "C_copy_memory_with_offset" v2 bv 0 start n2)
3806              v2)))))
3807
3808(define (bytevector-copy! bv1 at bv2 #!optional (start 0) end)
3809  (##sys#check-bytevector bv1 'bytevector-copy!)
3810  (##sys#check-bytevector bv2 'bytevector-copy!)
3811  (let* ((n1 (##sys#size bv1))
3812         (n2 (##sys#size bv2))
3813         (to (or end n2))
3814         (nc (##core#inline "C_fixnum_difference" to start)))
3815    (cond ((and (eq? n2 0) (eq? nc 0) (eq? start 0)) (##core#undefined))
3816          (else
3817            (##sys#check-range/including start 0 n2 'bytevector->copy!)
3818            (##sys#check-range/including at 0 n1 'bytevector->copy!)
3819            (##sys#check-range/including (##core#inline "C_fixnum_plus" at nc)
3820                               0 n1 'bytevector->copy!)
3821            (##core#inline "C_copy_memory_with_offset" bv1 bv2 at start nc)))))
3822
3823(define (bytevector-append . bvs)
3824  (let loop ((lst bvs) (len 0))
3825    (if (null? lst)
3826        (let ((bv (##sys#make-bytevector len)))
3827          (let loop ((lst bvs) (i 0))
3828            (if (null? lst)
3829                bv
3830                (let* ((bv1 (car lst))
3831                       (n (##sys#size bv1)))
3832                  (##core#inline "C_copy_memory_with_offset" bv bv1 i 0 n)
3833                  (loop (cdr lst) (##core#inline "C_fixnum_plus" i n))))))
3834        (let ((bv (car lst)))
3835          (##sys#check-bytevector bv 'bytevector-append)
3836          (loop (cdr lst) (##core#inline "C_fixnum_plus" len (##sys#size bv)))))))
3837
3838) ; chicken.bytevector
3839
3840
3841;;; Vectors:
3842(set! scheme#make-vector
3843  (lambda (size . fill)
3844    (##sys#check-fixnum size 'make-vector)
3845    (when (fx< size 0) (##sys#error 'make-vector "size is negative" size))
3846    (##sys#allocate-vector
3847     size
3848     (if (null? fill)
3849	 (##core#undefined)
3850	 (car fill) ))))
3851
3852(define ##sys#make-vector make-vector)
3853
3854(set! scheme#list->vector
3855  (lambda (lst0)
3856    (if (not (list? lst0))
3857	(##sys#error-not-a-proper-list lst0 'list->vector)
3858	(let* ([len (length lst0)]
3859	       [v (##sys#make-vector len)] )
3860	  (let loop ([lst lst0]
3861		     [i 0])
3862	    (if (null? lst)
3863		v
3864		(begin
3865		  (##sys#setslot v i (##sys#slot lst 0))
3866		  (loop (##sys#slot lst 1) (fx+ i 1)) ) ) ) ) )))
3867
3868(set! scheme#vector->list
3869  (lambda (v #!optional start end)
3870    (##sys#check-vector v 'vector->list)
3871    (let ((len (##sys#size v)))
3872      (if start
3873          (##sys#check-range/including start 0 len 'vector->list)
3874          (set! start 0))
3875      (if end
3876          (##sys#check-range/including end 0 len 'vector->list)
3877          (set! end len))
3878      (let loop ((i start))
3879	(if (fx>= i end)
3880	    '()
3881	    (cons (##sys#slot v i)
3882		  (loop (fx+ i 1)) ) ) ) ) ))
3883
3884(set! scheme#vector (lambda xs (list->vector xs) ))
3885
3886(set! scheme#vector-fill!
3887  (lambda (v x #!optional start end)
3888    (##sys#check-vector v 'vector-fill!)
3889    (let ((len (##sys#size v)))
3890      (if start
3891          (##sys#check-range/including start 0 len 'vector-fill!)
3892          (set! start 0))
3893      (if end
3894          (##sys#check-range/including end 0 len 'vector-fill!)
3895          (set! end len))
3896      (do ((i start (fx+ i 1)))
3897	  ((fx>= i end))
3898	(##sys#setslot v i x) ) ) ))
3899
3900(define (scheme#vector-copy v #!optional start end)
3901  (##sys#check-vector v 'vector-copy)
3902  (let ((copy (lambda (v start end)
3903                (let* ((len (##sys#size v)))
3904                  (##sys#check-range/including start 0 end 'vector-copy)
3905                  (##sys#check-range/including end start len 'vector-copy)
3906                  (let ((vec (##sys#make-vector (fx- end start))))
3907                    (do ((ti 0 (fx+ ti 1))
3908                         (fi start (fx+ fi 1)))
3909                        ((fx>= fi end) vec)
3910                      (##sys#setslot vec ti (##sys#slot v fi))))))))
3911    (if end
3912        (copy v start end)
3913        (copy v (or start 0) (##sys#size v)))))
3914
3915(define (scheme#vector-copy! to at from #!optional start end)
3916  (##sys#check-vector to 'vector-copy!)
3917  (##sys#check-vector from 'vector-copy!)
3918  (let ((copy! (lambda (to at from start end)
3919                 (let* ((tlen (##sys#size to))
3920                        (flen (##sys#size from))
3921                        (d (fx- end start)))
3922                   (##sys#check-range/including at 0 tlen 'vector-copy!)
3923                   (##sys#check-range/including start 0 end 'vector-copy!)
3924                   (##sys#check-range/including end start flen 'vector-copy!)
3925                   (##sys#check-range/including d 0 (fx- tlen at) 'vector-copy!)
3926                   (if (and (eq? to from) (fx< start at))
3927                       (do ((fi (fx- end 1) (fx- fi 1))
3928                            (ti (fx- (fx+ at d) 1) (fx- ti 1)))
3929                           ((fx< fi start))
3930                           (##sys#setslot to ti (##sys#slot from fi)))
3931                       (do ((fi start (fx+ fi 1))
3932                            (ti at (fx+ ti 1)))
3933                           ((fx= fi end))
3934                           (##sys#setslot to ti (##sys#slot from fi))))))))
3935    (if end
3936        (copy! to at from start end)
3937        (copy! to at from (or start 0) (##sys#size from)))))
3938
3939(define (scheme#vector-append . vs)
3940  (##sys#for-each (cut ##sys#check-vector <> 'vector-append) vs)
3941  (let* ((lens (map ##sys#size vs))
3942         (vec  (##sys#make-vector (foldl fx+ 0 lens))))
3943    (do ((vs vs (cdr vs))
3944         (lens lens (cdr lens))
3945         (i 0 (fx+ i (car lens))))
3946        ((null? vs) vec)
3947      (scheme#vector-copy! vec i (car vs) 0 (car lens)))))
3948
3949(set! chicken.base#subvector
3950  (lambda (v i #!optional j)
3951    (##sys#check-vector v 'subvector)
3952    (let* ((len (##sys#size v))
3953	   (j (or j len))
3954	   (len2 (fx- j i)))
3955      (##sys#check-range/including i 0 len 'subvector)
3956      (##sys#check-range/including j 0 len 'subvector)
3957      (let ((v2 (make-vector len2)))
3958	(do ((k 0 (fx+ k 1)))
3959	    ((fx>= k len2) v2)
3960	  (##sys#setslot v2 k (##sys#slot v (fx+ k i))))))))
3961
3962(set! chicken.base#vector-resize
3963  (lambda (v n #!optional init)
3964    (##sys#check-vector v 'vector-resize)
3965    (##sys#check-fixnum n 'vector-resize)
3966    (##sys#vector-resize v n init)))
3967
3968(define (##sys#vector-resize v n init)
3969  (let ((v2 (##sys#make-vector n init))
3970	(len (min (##sys#size v) n)) )
3971    (do ((i 0 (fx+ i 1)))
3972	((fx>= i len) v2)
3973      (##sys#setslot v2 i (##sys#slot v i)) ) ) )
3974
3975;;; Characters:
3976
3977(set! scheme#char-ci=?
3978  (lambda (x y . more)
3979    (##sys#check-char x 'char-ci=?)
3980    (##sys#check-char y 'char-ci=?)
3981    (let ((c2 (##core#inline "C_utf_char_foldcase" y)))
3982      (let loop ((c c2) (cs more)
3983                 (f (eq? (##core#inline "C_utf_char_foldcase" x) c2)))
3984        (if (null? cs)
3985            f
3986            (let ((c2 (##sys#slot cs 0)))
3987              (##sys#check-char c2 'char-ci=?)
3988              (let ((c2 ((##core#inline "C_utf_char_foldcase" c2))))
3989                (loop c2 (##sys#slot cs 1)
3990                      (and f (eq? c c2))))))))))
3991
3992(set! scheme#char-ci>?
3993  (lambda (x y . more)
3994    (##sys#check-char x 'char-ci>?)
3995    (##sys#check-char y 'char-ci>?)
3996    (let ((c2 (##core#inline "C_utf_char_foldcase" y)))
3997      (let loop ((c c2) (cs more)
3998                 (f (##core#inline "C_u_i_char_greaterp"
3999                                   (##core#inline "C_utf_char_foldcase" x)
4000                                   c2)))
4001        (if (null? cs)
4002            f
4003            (let ((c2 (##sys#slot cs 0)))
4004              (##sys#check-char c2 'char-ci>?)
4005              (let ((c2 ((##core#inline "C_utf_char_foldcase" c2))))
4006                (loop c2 (##sys#slot cs 1)
4007                      (and f (##core#inline "C_u_i_char_greaterp" c c2))))))))))
4008
4009(set! scheme#char-ci<?
4010  (lambda (x y . more)
4011    (##sys#check-char x 'char-ci<?)
4012    (##sys#check-char y 'char-ci<?)
4013    (let ((c2 (##core#inline "C_utf_char_foldcase" y)))
4014      (let loop ((c c2) (cs more)
4015                 (f (##core#inline "C_u_i_char_lessp"
4016                                   (##core#inline "C_utf_char_foldcase" x)
4017                                   c2)))
4018        (if (null? cs)
4019            f
4020            (let ((c2 (##sys#slot cs 0)))
4021              (##sys#check-char c2 'char-ci<?)
4022              (let ((c2 ((##core#inline "C_utf_char_foldcase" c2))))
4023                (loop c2 (##sys#slot cs 1)
4024                      (and f (##core#inline "C_u_i_char_lessp" c c2))))))))))
4025
4026(set! scheme#char-ci>=?
4027  (lambda (x y . more)
4028    (##sys#check-char x 'char-ci>=?)
4029    (##sys#check-char y 'char-ci>=?)
4030    (let ((c2 (##core#inline "C_utf_char_foldcase" y)))
4031      (let loop ((c c2) (cs more)
4032                 (f (##core#inline "C_u_i_char_greater_or_equal_p"
4033                                   (##core#inline "C_utf_char_foldcase" x)
4034                                   c2)))
4035        (if (null? cs)
4036            f
4037            (let ((c2 (##sys#slot cs 0)))
4038              (##sys#check-char c2 'char-ci>=?)
4039              (let ((c2 ((##core#inline "C_utf_char_foldcase" c2))))
4040                (loop c2 (##sys#slot cs 1)
4041                      (and f (##core#inline "C_u_i_char_greater_or_equal_p" c c2))))))))))
4042
4043(set! scheme#char-ci<=?
4044  (lambda (x y . more)
4045    (##sys#check-char x 'char-ci<=?)
4046    (##sys#check-char y 'char-ci<=?)
4047    (let ((c2 (##core#inline "C_utf_char_foldcase" y)))
4048      (let loop ((c c2) (cs more)
4049                 (f (##core#inline "C_u_i_char_less_or_equal_p"
4050                                   (##core#inline "C_utf_char_foldcase" x)
4051                                   c2)))
4052        (if (null? cs)
4053            f
4054            (let ((c2 (##sys#slot cs 0)))
4055              (##sys#check-char c2 'char-ci<=?)
4056              (let ((c2 ((##core#inline "C_utf_char_foldcase" c2))))
4057                (loop c2 (##sys#slot cs 1)
4058                      (and f (##core#inline "C_u_i_char_less_or_equal_p" c c2))))))))))
4059
4060(set! chicken.base#char-name
4061  (let ((chars-to-names (make-vector char-name-table-size '()))
4062        (names-to-chars '()))
4063    (define (lookup-char c)
4064      (let* ((code (char->integer c))
4065             (key (##core#inline "C_fixnum_modulo" code char-name-table-size)) )
4066        (let loop ((b (##sys#slot chars-to-names key)))
4067          (and (pair? b)
4068               (let ((a (##sys#slot b 0)))
4069                 (if (eq? (##sys#slot a 0) c)
4070                     a
4071                     (loop (##sys#slot b 1)) ) ) ) ) ) )
4072    (lambda (x #!optional (chr #:none))
4073      (cond ((char? x)
4074             (and-let* ((a (lookup-char x)))
4075               (case chr
4076                 ((#:none)
4077                  (##sys#slot a 1) )
4078                 ((#f)
4079                  (##sys#setslot a 0 #f)
4080                  (##sys#setslot (assq (##sys#slot a 1) names-to-chars) 0 #f)
4081                  (##core#undefined))
4082                 (else
4083                   (##sys#signal-hook #:type-error 'char-name 
4084                    "expected second boolean argument" chr) ))))
4085            ((symbol? x)
4086             (let ((a (assq x names-to-chars)))
4087               (case chr
4088                 ((#:none) (and a (##sys#slot a 1)))
4089                 ((#f) 
4090                  (when a 
4091                    (##sys#setslot a 0 #f)
4092                    (##sys#setslot (lookup-char (##sys#slot a 1)) 0 #f))
4093                  (##core#undefined))
4094                 (else
4095                   (##sys#check-char chr 'char-name)
4096                   (when (fx< (##sys#size (##sys#slot x 1)) 2)
4097                     (##sys#signal-hook #:type-error 'char-name "invalid character name" x) )
4098                   (let ((a (lookup-char chr)))
4099                     (if a
4100                         (let ((b (assq x names-to-chars)))
4101                           (##sys#setslot a 1 x)
4102                           (if b
4103                               (##sys#setislot b 1 chr)
4104                               (set! names-to-chars (cons (cons x chr) names-to-chars)) ) )
4105                         (let ((key (##core#inline "C_fixnum_modulo" (char->integer chr) 
4106                                     char-name-table-size)))
4107                           (set! names-to-chars (cons (cons x chr) names-to-chars))
4108                           (##sys#setslot
4109                            chars-to-names key
4110                            (cons (cons chr x) (##sys#slot chars-to-names key))) ) ) ) ))))
4111            (else (##sys#signal-hook #:type-error 'char-name "invalid argument type" x))))))
4112
4113;; TODO: Use the character names here in the next release?  Or just
4114;; use the numbers everywhere, for clarity?
4115(char-name 'space #\space)
4116(char-name 'tab #\tab)
4117(char-name 'linefeed #\linefeed)
4118(char-name 'newline #\newline)
4119(char-name 'vtab (integer->char 11))
4120(char-name 'delete (integer->char 127))
4121(char-name 'esc (integer->char 27))
4122(char-name 'escape (integer->char 27))
4123(char-name 'alarm (integer->char 7))
4124(char-name 'nul (integer->char 0))
4125(char-name 'null (integer->char 0))
4126(char-name 'return #\return)
4127(char-name 'page (integer->char 12))
4128(char-name 'backspace (integer->char 8))
4129
4130
4131;;; Procedures:
4132
4133(define ##sys#call-with-current-continuation (##core#primitive "C_call_cc"))
4134(define ##sys#call-with-cthulhu (##core#primitive "C_call_with_cthulhu"))
4135(define ##sys#call-with-values call-with-values)
4136
4137(define (##sys#for-each p lst0)
4138  (let loop ((lst lst0))
4139    (cond ((eq? lst '()) (##core#undefined))
4140	  ((pair? lst)
4141	   (p (##sys#slot lst 0))
4142	   (loop (##sys#slot lst 1)) )
4143	  (else (##sys#error-not-a-proper-list lst0 'for-each)) ) ))
4144
4145(define (##sys#map p lst0)
4146  (let loop ((lst lst0))
4147    (cond ((eq? lst '()) lst)
4148	  ((pair? lst)
4149	   (cons (p (##sys#slot lst 0)) (loop (##sys#slot lst 1))) )
4150	  (else (##sys#error-not-a-proper-list lst0 'map)) ) ))
4151
4152(letrec ((mapsafe
4153	  (lambda (p lsts loc)
4154	    (call-with-current-continuation
4155	     (lambda (empty)
4156	       (let lp ((lsts lsts))
4157		 (if (eq? lsts '())
4158		     lsts
4159		     (let ((item (##sys#slot lsts 0)))
4160		       (cond ((eq? item '()) (empty '()))
4161			     ((pair? item)
4162			      (cons (p item) (lp (##sys#slot lsts 1))))
4163			     (else (##sys#error-not-a-proper-list item loc)))))))))))
4164
4165  (set! scheme#for-each
4166    (lambda (fn lst1 . lsts)
4167      (if (null? lsts)
4168	  (##sys#for-each fn lst1)
4169	  (let loop ((all (cons lst1 lsts)))
4170	    (let* ((first (##sys#slot all 0))
4171		   (safe-args (mapsafe (lambda (x) (car x)) all 'for-each))) ; ensure inlining
4172	      (when (pair? safe-args)
4173		(apply fn safe-args)
4174		(loop (mapsafe (lambda (x) (cdr x)) all 'for-each))))))))
4175
4176  (set! scheme#map
4177    (lambda (fn lst1 . lsts)
4178      (if (null? lsts)
4179	  (##sys#map fn lst1)
4180	  (let loop ((all (cons lst1 lsts)))
4181	    (let* ((first (##sys#slot all 0))
4182		   (safe-args (mapsafe (lambda (x) (car x)) all 'map)))
4183	      (if (pair? safe-args)
4184		  (cons (apply fn safe-args)
4185			(loop (mapsafe (lambda (x) (cdr x)) all 'map)))
4186		  '())))))))
4187
4188
4189;;; dynamic-wind:
4190;
4191; (taken more or less directly from SLIB)
4192;
4193; This implementation is relatively costly: we have to shadow call/cc
4194; with a new version that unwinds suspended thunks, but for this to
4195; happen the return-values of the escaping procedure have to be saved
4196; temporarily in a list. Since call/cc is very efficient under this
4197; implementation, and because allocation of memory that is to be
4198; garbage soon has also quite low overhead, the performance-penalty
4199; might be acceptable (ctak needs about 4 times longer).
4200
4201(define ##sys#dynamic-winds '())
4202
4203(set! scheme#dynamic-wind
4204  (lambda (before thunk after)
4205    (before)
4206    (set! ##sys#dynamic-winds (cons (cons before after) ##sys#dynamic-winds))
4207    (##sys#call-with-values
4208     thunk
4209     (lambda results
4210       (set! ##sys#dynamic-winds (##sys#slot ##sys#dynamic-winds 1))
4211       (after)
4212       (apply ##sys#values results) ) ) ))
4213
4214(define ##sys#dynamic-wind dynamic-wind)
4215
4216(set! scheme#call-with-current-continuation
4217  (lambda (proc)
4218    (let ((winds ##sys#dynamic-winds))
4219      (##sys#call-with-current-continuation
4220       (lambda (cont)
4221	 (define (continuation . results)
4222	   (unless (eq? ##sys#dynamic-winds winds)
4223	     (##sys#dynamic-unwind winds (fx- (length ##sys#dynamic-winds) (length winds))) )
4224	   (apply cont results) )
4225	 (proc continuation) ))) ))
4226
4227(set! scheme#call/cc call-with-current-continuation)
4228
4229(define (##sys#dynamic-unwind winds n)
4230  (cond [(eq? ##sys#dynamic-winds winds)]
4231	[(fx< n 0)
4232	 (##sys#dynamic-unwind (##sys#slot winds 1) (fx+ n 1))
4233	 ((##sys#slot (##sys#slot winds 0) 0))
4234	 (set! ##sys#dynamic-winds winds) ]
4235	[else
4236	 (let ([after (##sys#slot (##sys#slot ##sys#dynamic-winds 0) 1)])
4237	   (set! ##sys#dynamic-winds (##sys#slot ##sys#dynamic-winds 1))
4238	   (after)
4239	   (##sys#dynamic-unwind winds (fx- n 1)) ) ] ) )
4240
4241
4242;;; Ports:
4243
4244(set! chicken.base#port-closed?
4245  (lambda (p)
4246    (##sys#check-port p 'port-closed?)
4247    (eq? (##sys#slot p 8) 0)))
4248
4249;;; Custom ports:
4250
4251;;; Port layout:
4252;
4253; 0:  file ptr (special)
4254; 1:  direction (fixnum, 1 = input)
4255; 2:  class (vector of procedures)
4256; 3:  name (string)
4257; 4:  row (fixnum)
4258; 5:  col (fixnum)
4259; 6:  EOF (bool)
4260; 7:  type ('stream | 'custom | 'string | 'socket)
4261; 8:  closed (fixnum)
4262; 9:  data
4263; 10-12: reserved, port class specific
4264; 13: case sensitive? (boolean)
4265; 14: mode ('textual | 'binary)
4266; 15: reserved (encoding)
4267;
4268; Port-class:
4269;
4270; 0:  (read-char PORT) -> CHAR | EOF
4271; 1:  (peek-char PORT) -> CHAR | EOF
4272; 2:  (write-char PORT CHAR)
4273; 3:  (write-bytevector PORT BYTEVECTOR START END)
4274; 4:  (close PORT DIRECTION)
4275; 5:  (flush-output PORT)
4276; 6:  (u8-ready? PORT) -> BOOL
4277; 7:  (read-bytevector! PORT COUNT BYTEVECTOR START) -> COUNT'
4278; 8:  (read-line PORT LIMIT) -> STRING | EOF
4279; 9:  (read-buffered PORT) -> STRING
4280; [10: (char-ready? PORT) -> BOOL    (optional)]
4281
4282(define (##sys#make-port i/o class name type)
4283  (let ((port (##core#inline_allocate ("C_a_i_port" 17))))
4284    (##sys#setislot port 1 i/o)
4285    (##sys#setslot port 2 class)
4286    (##sys#setslot port 3 name)
4287    (##sys#setislot port 4 1)
4288    (##sys#setislot port 5 0)
4289    (##sys#setislot port 6 #f)
4290    (##sys#setslot port 7 type)
4291    (##sys#setslot port 8 i/o)
4292    (##sys#setislot port 10 #f)
4293    (##sys#setislot port 13 #t)
4294    (##sys#setislot port 14 'textual)  ; default, only used for R7RS port predicates
4295    (##sys#setslot port 15 'utf-8)
4296    port) )
4297
4298;;; Stream ports:
4299; Input port slots:
4300;   10: peek buffer
4301;   12: Static buffer for read-line, allocated on-demand
4302
4303(define ##sys#stream-port-class
4304  (vector (lambda (p)      ; read-char
4305            (let loop ()
4306              (let ((peeked (##sys#slot p 10)))
4307                (cond (peeked
4308                        (##sys#setislot p 10 #f)
4309                        (##sys#decode-char peeked (##sys#slot p 15) 0))
4310                      ((eq? 'utf-8  (##sys#slot p 15)) ; fast path
4311                       (let ((c (##core#inline "C_read_char" p)))
4312                         (if (eq? -1 c)
4313                             (let ((err (##sys#update-errno)))
4314                               (if (eq? err (foreign-value "EINTR" int))
4315                                   (##sys#dispatch-interrupt loop)
4316                                   (##sys#signal-hook/errno
4317                                    #:file-error err 'read-char
4318                                    (##sys#string-append "cannot read from port - " strerror)
4319                                    p)))
4320                             c)))
4321                      (else (##sys#read-char/encoding
4322                             p (##sys#slot p 15)
4323                             (lambda (buf start len dec)
4324                               (dec buf start len
4325                                    (lambda (buf start len)
4326                                      (##core#inline "C_utf_decode" buf start))))))))))
4327          (lambda (p)      ; peek-char
4328            (let ((pb (##sys#slot p 10))
4329                  (enc (##sys#slot p 15)))
4330              (if pb
4331                  (##sys#decode-char pb enc 0)
4332                  (##sys#read-char/encoding
4333                   p enc
4334                   (lambda (buf start len dec)
4335                     (let ((pb (##sys#make-bytevector len 1)))
4336                       (##core#inline "C_copy_memory_with_offset" pb buf 0 start len)
4337                       (##sys#setslot p 10 pb)
4338                       (dec buf start len
4339                            (lambda (buf start _)
4340                              (##core#inline "C_utf_decode" buf start)))))))))
4341          (lambda (p c)                ; write-char
4342            (let ((enc (##sys#slot p 15)))
4343              (if (eq? enc 'utf-8) ;; fast path
4344                  (##core#inline "C_display_char" p c)
4345                  (let* ((bv (##sys#make-bytevector 4))
4346                         (n (##sys#encode-char c bv enc)))
4347                    ((##sys#slot (##sys#slot p 2) 3) p bv 0 n))))) ; write-bytevector
4348          (lambda (p bv from to)                     ; write-bytevector
4349            (##sys#encode-buffer
4350             bv from (fx- to from) (##sys#slot p 15)
4351             (lambda (bv start len)
4352               (##core#inline "C_display_string" p bv start len))))
4353          (lambda (p d)                ; close
4354            (##core#inline "C_close_file" p)
4355            (##sys#update-errno) )
4356          (lambda (p)      ; flush-output
4357            (##core#inline "C_flush_output" p) )
4358          (lambda (p)      ; u8-ready?
4359            (or (##sys#slot p 10)
4360                (##core#inline "C_char_ready_p" p) ))
4361          (lambda (p n dest start)           ; read-bytevector!
4362            (let ((pb (##sys#slot p 10))
4363                  (nc 0))
4364              (when pb
4365                (set! nc (##sys#size pb))
4366                (##core#inline "C_copy_memory_with_offset" dest pb start 0 nc)
4367                (set! start (fx+ start nc))
4368                (set! n (fx- n nc))
4369                (##sys#setislot p 10 #f))
4370              ;;XXX "n" below always true?
4371              (let loop ((rem (or n (fx- (##sys#size dest) start)))
4372                         (act nc)
4373                         (start start))
4374                (let ((len (##core#inline "fast_read_string_from_file" dest p rem start)))
4375                  (cond ((eof-object? len) ; EOF returns 0 bytes read
4376                         act)
4377                        ((fx< len 0)
4378                         (let ((err (##sys#update-errno)))
4379                           (if (eq? err (foreign-value "EINTR" int))
4380                               (##sys#dispatch-interrupt
4381                                (lambda () (loop rem act start)))
4382                               (##sys#signal-hook/errno
4383                                #:file-error err 'read-bytevector!
4384                                (##sys#string-append "cannot read from port - " strerror)
4385                                p n dest start))))
4386                        ((fx< len rem)
4387                         (loop (fx- rem len) (fx+ act len) (fx+ start len)))
4388                        (else (fx+ act len) ) ) ))))
4389          (lambda (p rlimit)       ; read-line
4390            (when rlimit (##sys#check-fixnum rlimit 'read-line))
4391            (let ((sblen read-line-buffer-initial-size)
4392                  (pb (##sys#slot p 10))
4393                  (buffer (##sys#slot p 12))
4394                  (bpos 0))
4395              (unless buffer
4396                (set! buffer (##sys#make-bytevector sblen))
4397                (##sys#setslot p 12 buffer))
4398              (when pb
4399                (set! bpos (##sys#size pb))
4400                (##core#inline "C_copy_memory_with_offset" buffer pb 0 0 bpos)
4401                (##sys#setislot p 10 #f))
4402              (let loop ([len sblen]
4403                         [limit (or rlimit maximal-string-length)]
4404                         [buffer buffer]
4405                         [result ""]
4406                         [f #f])
4407                (let* ((nlimit (fxmin limit len))
4408                       (n (##core#inline "fast_read_line_from_file" buffer bpos
4409                          p nlimit)))
4410                  (set! bpos 0)
4411                  (cond ((eof-object? n) (if f result #!eof))
4412                        ((not n)
4413                         (let ((prev (##sys#buffer->string/encoding buffer 0 nlimit
4414                                      (##sys#slot p 15))))
4415                           (if (fx< limit len)
4416                               (##sys#string-append result prev)
4417                               (loop (fx* len 2)
4418                                     (fx- limit len)
4419                                     (##sys#make-bytevector (fx* len 2))
4420                                     (##sys#string-append result prev)
4421                                     #t)) ) )
4422                        ((fx< n 0)
4423                         (let ((err (##sys#update-errno)))
4424                           (if (eq? err (foreign-value "EINTR" int))
4425                                (let ((n (fx- (fxneg n) 1)))
4426                                  (##sys#dispatch-interrupt
4427                                   (lambda ()
4428                                     (loop len limit buffer
4429                                           (##sys#string-append
4430                                            result
4431                                            (##sys#buffer->string/encoding buffer 0 n (##sys#slot p 15)))
4432                                           #t))))
4433                               (##sys#signal-hook/errno
4434                                #:file-error err 'read-line
4435                                (##sys#string-append "cannot read from port - " strerror)
4436                                p rlimit))))
4437                        (f (##sys#setislot p 4 (fx+ (##sys#slot p 4) 1))
4438                           (##sys#string-append result
4439                            (##sys#buffer->string/encoding buffer 0 n (##sys#slot p 15))))
4440                        (else
4441                          (##sys#setislot p 4 (fx+ (##sys#slot p 4) 1))
4442                          (##sys#buffer->string/encoding buffer 0 n (##sys#slot p 15))))))))
4443          #f  ; read-buffered
4444          (lambda (p)      ; char-ready? (effectively u8-ready?)
4445            (or (##sys#slot p 10)
4446                (##core#inline "C_char_ready_p" p) ))
4447          ) )
4448
4449(define ##sys#open-file-port (##core#primitive "C_open_file_port"))
4450
4451(define ##sys#standard-input (##sys#make-port 1 ##sys#stream-port-class "(stdin)" 'stream))
4452(define ##sys#standard-output (##sys#make-port 2 ##sys#stream-port-class "(stdout)" 'stream))
4453(define ##sys#standard-error (##sys#make-port 2 ##sys#stream-port-class "(stderr)" 'stream))
4454
4455(##sys#open-file-port ##sys#standard-input 0 #f)
4456(##sys#open-file-port ##sys#standard-output 1 #f)
4457(##sys#open-file-port ##sys#standard-error 2 #f)
4458
4459(define (##sys#check-input-port x open . loc)
4460  (if (pair? loc)
4461      (##core#inline "C_i_check_port_2" x 1 open (car loc))
4462      (##core#inline "C_i_check_port" x 1 open)))
4463
4464(define (##sys#check-output-port x open . loc)
4465  (if (pair? loc)
4466      (##core#inline "C_i_check_port_2" x 2 open (car loc))
4467      (##core#inline "C_i_check_port" x 2 open)))
4468
4469(define (##sys#check-port x . loc)
4470  (if (pair? loc)
4471      (##core#inline "C_i_check_port_2" x 0 #f (car loc))
4472      (##core#inline "C_i_check_port" x 0 #f) ) )
4473
4474(define (##sys#check-open-port x . loc)
4475  (if (pair? loc)
4476      (##core#inline "C_i_check_port_2" x 0 #t (car loc))
4477      (##core#inline "C_i_check_port" x 0 #t) ) )
4478
4479(set! scheme#current-input-port
4480  (lambda args
4481    (if (null? args)
4482	##sys#standard-input
4483	(let ((p (car args)))
4484	  (##sys#check-port p 'current-input-port)
4485	  (let-optionals (cdr args) ((convert? #t) (set? #t))
4486	    (when set? (set! ##sys#standard-input p)))
4487	  p) ) ))
4488
4489(set! scheme#current-output-port
4490  (lambda args
4491    (if (null? args)
4492	##sys#standard-output
4493	(let ((p (car args)))
4494	  (##sys#check-port p 'current-output-port)
4495	  (let-optionals (cdr args) ((convert? #t) (set? #t))
4496	    (when set? (set! ##sys#standard-output p)))
4497	  p) ) ))
4498
4499(set! chicken.base#current-error-port
4500  (lambda args
4501    (if (null? args)
4502	##sys#standard-error
4503	(let ((p (car args)))
4504	  (##sys#check-port p 'current-error-port)
4505	  (let-optionals (cdr args) ((convert? #t) (set? #t))
4506	    (when set? (set! ##sys#standard-error p)))
4507	  p))))
4508
4509(define (##sys#tty-port? port)
4510  (and (not (zero? (##sys#peek-unsigned-integer port 0)))
4511       (##core#inline "C_tty_portp" port) ) )
4512
4513(define (##sys#port-data port) (##sys#slot port 9))
4514(define (##sys#set-port-data! port data) (##sys#setslot port 9 data))
4515
4516(define ##sys#default-file-encoding)
4517
4518(let ()
4519  (define (open name inp modes loc)
4520    (##sys#check-string name loc)
4521    (let ((fmode (if inp "r" "w"))
4522          (bmode "")
4523          (enc (##sys#default-file-encoding)))
4524      (do ((modes modes (##sys#slot modes 1)))
4525        ((null? modes))
4526        (let ((o (##sys#slot modes 0)))
4527          (case o
4528            ((#:binary binary)
4529             (set! bmode "b")
4530             (set! enc 'binary))
4531            ((#:text text) (set! bmode ""))
4532            ((#:utf-8 utf-8)
4533             (set! enc 'utf-8))
4534            ((#:latin-1 latin-1 #:iso-8859-1 iso-8859-1)
4535             (set! enc 'latin-1))
4536            ((#:unix #:nl unix nl)
4537             (set! bmode "b"))
4538            ((#:crnl crnl)
4539             (set! bmode ""))
4540            ((#:append append)
4541             (if inp
4542               (##sys#error loc "cannot use append mode with input file")
4543               (set! fmode "a") ) )
4544            (else (##sys#error loc "invalid file option" o)) ) ) )
4545      (let ((port (##sys#make-port (if inp 1 2) ##sys#stream-port-class name 'stream)))
4546        (##sys#setslot port 15 enc)
4547        (unless (##sys#open-file-port port name (##sys#string-append fmode bmode))
4548          (##sys#signal-hook/errno #:file-error (##sys#update-errno) loc
4549                                   (##sys#string-append "cannot open file - " strerror)
4550                                   name))
4551        port) ) )
4552
4553  (define (close port inp loc)
4554    (##sys#check-port port loc)
4555    ; repeated closing is ignored
4556    (let ((direction (if inp 1 2)))
4557      (when (##core#inline "C_port_openp" port direction)
4558	(##sys#setislot port 8 (fxand (##sys#slot port 8) (fxnot direction)))
4559	((##sys#slot (##sys#slot port 2) 4) port direction))))
4560
4561  (set! scheme#open-input-file (lambda (name . mode) (open name #t mode 'open-input-file)))
4562  (set! scheme#open-output-file (lambda (name . mode) (open name #f mode 'open-output-file)))
4563  (set! scheme#close-input-port (lambda (port) (close port #t 'close-input-port)))
4564  (set! scheme#close-output-port (lambda (port) (close port #f 'close-output-port))))
4565
4566(set! scheme#call-with-input-file
4567  (let ((open-input-file open-input-file)
4568	(close-input-port close-input-port) )
4569    (lambda (name p . mode)
4570      (let ((f (apply open-input-file name mode)))
4571	(##sys#call-with-values
4572	 (lambda () (p f))
4573	 (lambda results
4574	   (close-input-port f)
4575	   (apply ##sys#values results) ) ) ) ) ) )
4576
4577(set! scheme#call-with-output-file
4578  (let ((open-output-file open-output-file)
4579	(close-output-port close-output-port) )
4580    (lambda (name p . mode)
4581      (let ((f (apply open-output-file name mode)))
4582	(##sys#call-with-values
4583	 (lambda () (p f))
4584	 (lambda results
4585	   (close-output-port f)
4586	   (apply ##sys#values results) ) ) ) ) ) )
4587
4588(set! scheme#with-input-from-file
4589  (let ((open-input-file open-input-file)
4590	(close-input-port close-input-port) )
4591    (lambda (str thunk . mode)
4592      (let ((file (apply open-input-file str mode)))
4593	(fluid-let ((##sys#standard-input file))
4594	  (##sys#call-with-values thunk
4595	    (lambda results
4596	      (close-input-port file)
4597	      (apply ##sys#values results) ) ) ) ) ) ) )
4598
4599(set! scheme#with-output-to-file
4600  (let ((open-output-file open-output-file)
4601	(close-output-port close-output-port) )
4602    (lambda (str thunk . mode)
4603      (let ((file (apply open-output-file str mode)))
4604	(fluid-let ((##sys#standard-output file))
4605	  (##sys#call-with-values thunk
4606	    (lambda results
4607	      (close-output-port file)
4608	      (apply ##sys#values results) ) ) ) ) ) ) )
4609
4610(define (##sys#file-exists? name file? dir? loc)
4611  (case (##core#inline "C_i_file_exists_p" (##sys#make-c-string name loc) file? dir?)
4612    ((#f) #f)
4613    ((#t) #t)
4614    (else
4615     (##sys#signal-hook
4616      #:file-error loc "system error while trying to access file"
4617      name))))
4618
4619(define (##sys#flush-output port)
4620  ((##sys#slot (##sys#slot port 2) 5) port) ; flush-output
4621  (##core#undefined) )
4622
4623(set! chicken.base#flush-output
4624  (lambda (#!optional (port ##sys#standard-output))
4625    (##sys#check-output-port port #t 'flush-output)
4626    (##sys#flush-output port)))
4627
4628(define (##sys#port-line port)
4629  (and (##core#inline "C_input_portp" port)
4630       (##sys#slot port 4) ) )
4631
4632;;; Decorate procedure with arbitrary data
4633;
4634; warning: may modify proc, if it already has a suitable decoration!
4635
4636(define (##sys#decorate-lambda proc pred decorator)
4637  (let ((len (##sys#size proc)))
4638    (let loop ((i (fx- len 1)))
4639      (cond ((zero? i)
4640	     (let ((p2 (make-vector (fx+ len 1))))
4641	       (do ((i 1 (fx+ i 1)))
4642		   ((fx>= i len)
4643		    (##core#inline "C_vector_to_closure" p2)
4644		    (##core#inline "C_copy_pointer" proc p2)
4645		    (decorator p2 i) )
4646		 (##sys#setslot p2 i (##sys#slot proc i)) ) ) )
4647	    (else
4648	     (let ((x (##sys#slot proc i)))
4649	       (if (pred x)
4650		   (decorator proc i)
4651		   (loop (fx- i 1)) ) ) ) ) ) ) )
4652
4653(define (##sys#lambda-decoration proc pred)
4654  (let loop ((i (fx- (##sys#size proc) 1)))
4655    (and (fx> i 0)
4656	 (let ((x (##sys#slot proc i)))
4657	   (if (pred x)
4658	       x
4659	       (loop (fx- i 1)) ) ) ) ) )
4660
4661
4662;;; Create lambda-info object
4663
4664(define (##sys#make-lambda-info str)
4665  (let* ((bv (##sys#slot str 0))
4666         (sz (fx- (##sys#size bv) 1))
4667	 (info (##sys#make-bytevector sz)))
4668    (##core#inline "C_copy_memory" info bv sz)
4669    (##core#inline "C_bytevector_to_lambdainfo" info)
4670    info) )
4671
4672
4673;;; Function debug info:
4674
4675(define (##sys#lambda-info? x)
4676  (and (not (##sys#immediate? x)) (##core#inline "C_lambdainfop" x)))
4677
4678(define (##sys#lambda-info proc)
4679  (##sys#lambda-decoration proc ##sys#lambda-info?))
4680
4681(define (##sys#lambda-info->string info)
4682  (let* ((sz (##sys#size info))
4683	 (bv (##sys#make-bytevector (fx+ sz 1))) )
4684    (##core#inline "C_copy_memory" bv info sz)
4685    (##core#inline_allocate ("C_a_ustring" 5) bv
4686                            (##core#inline "C_utf_length" bv))))
4687
4688(set! chicken.base#procedure-information
4689  (lambda (x)
4690    (##sys#check-closure x 'procedure-information)
4691    (and-let* ((info (##sys#lambda-info x)))
4692      (##sys#read (scheme#open-input-string (##sys#lambda-info->string info)) #f) ) ) )
4693
4694
4695;;; SRFI-17
4696
4697(define setter-tag (vector 'setter))
4698
4699(define-inline (setter? x)
4700  (and (pair? x) (eq? setter-tag (##sys#slot x 0))) )
4701
4702(set! chicken.base#setter
4703  (##sys#decorate-lambda
4704   (lambda (proc)
4705     (or (and-let* (((procedure? proc))
4706		    (d (##sys#lambda-decoration proc setter?)) )
4707	   (##sys#slot d 1) )
4708	 (##sys#error 'setter "no setter defined" proc) ) )
4709   setter?
4710   (lambda (proc i)
4711     (##sys#setslot
4712      proc i
4713      (cons
4714       setter-tag
4715       (lambda (get set)
4716	 (if (procedure? get)
4717	     (let ((get2 (##sys#decorate-lambda
4718			  get
4719			  setter?
4720			  (lambda (proc i) (##sys#setslot proc i (cons setter-tag set)) proc))))
4721	       (if (eq? get get2)
4722		   get
4723		   (##sys#become! (list (cons get get2))) ) )
4724	     (error "can not set setter of non-procedure" get) ) ) ) )
4725     proc) ) )
4726
4727(define ##sys#setter setter)
4728
4729(set! chicken.base#getter-with-setter
4730  (lambda (get set #!optional info)
4731    (##sys#check-closure get 'getter-with-setter)
4732    (##sys#check-closure set 'getter-with-setter)
4733    (let ((getdec (cond (info
4734			 (##sys#check-string info 'getter-with-setter)
4735			 (##sys#make-lambda-info info))
4736			(else (##sys#lambda-info get))))
4737	  (p1 (##sys#decorate-lambda
4738	       (##sys#copy-closure get)
4739	       setter?
4740	       (lambda (proc i)
4741		 (##sys#setslot proc i (cons setter-tag set))
4742		 proc))))
4743      (if getdec
4744	  (##sys#decorate-lambda
4745	   p1
4746	   ##sys#lambda-info?
4747	   (lambda (p i)
4748	     (##sys#setslot p i getdec)
4749	     p))
4750	  p1))))
4751
4752(set! scheme#car (getter-with-setter scheme#car set-car!))
4753(set! scheme#cdr (getter-with-setter scheme#cdr set-cdr!))
4754(set! scheme#caar (getter-with-setter scheme#caar (lambda (x y) (set-car! (car x) y))))
4755(set! scheme#cadr (getter-with-setter scheme#cadr (lambda (x y) (set-car! (cdr x) y))))
4756(set! scheme#cdar (getter-with-setter scheme#cdar (lambda (x y) (set-cdr! (car x) y))))
4757(set! scheme#cddr (getter-with-setter scheme#cddr (lambda (x y) (set-cdr! (cdr x) y))))
4758(set! scheme#caaar (getter-with-setter scheme#caaar (lambda (x y) (set-car! (caar x) y))))
4759(set! scheme#caadr (getter-with-setter scheme#caadr (lambda (x y) (set-car! (cadr x) y))))
4760(set! scheme#cadar (getter-with-setter scheme#cadar (lambda (x y) (set-car! (cdar x) y))))
4761(set! scheme#caddr (getter-with-setter scheme#caddr (lambda (x y) (set-car! (cddr x) y))))
4762(set! scheme#cdaar (getter-with-setter scheme#cdaar (lambda (x y) (set-cdr! (caar x) y))))
4763(set! scheme#cdadr (getter-with-setter scheme#cdadr (lambda (x y) (set-cdr! (cadr x) y))))
4764(set! scheme#cddar (getter-with-setter scheme#cddar (lambda (x y) (set-cdr! (cdar x) y))))
4765(set! scheme#cdddr (getter-with-setter scheme#cdddr (lambda (x y) (set-cdr! (cddr x) y))))
4766(set! scheme#string-ref (getter-with-setter scheme#string-ref string-set!))
4767(set! scheme#vector-ref (getter-with-setter scheme#vector-ref vector-set!))
4768
4769(set! scheme#list-ref
4770  (getter-with-setter
4771   scheme#list-ref
4772   (lambda (x i y) (set-car! (list-tail x i) y))))
4773
4774(set! chicken.bytevector#bytevector-u8-ref
4775  (getter-with-setter chicken.bytevector#bytevector-u8-ref
4776                      chicken.bytevector#bytevector-u8-set!
4777                      "(chicken.bytevector#bytevector-u8-ref v i)"))
4778
4779
4780;;; Parameters:
4781
4782(define ##sys#default-parameter-vector (##sys#make-vector default-parameter-vector-size))
4783(define ##sys#current-parameter-vector '#())
4784
4785(set! scheme#make-parameter
4786  (let ((count 0))
4787    (lambda (init #!optional (guard (lambda (x) x)))
4788      (let* ((val (guard init))
4789	     (i count)
4790	     (assign (lambda (val n convert? set?)
4791		       (when (fx>= i n)
4792			 (set! ##sys#current-parameter-vector
4793			   (##sys#vector-resize
4794			    ##sys#current-parameter-vector
4795			    (fx+ i 1)
4796			    ##sys#snafu) ) )
4797		       (let ((val (if convert? (guard val) val)))
4798			 (when set?
4799			   (##sys#setslot ##sys#current-parameter-vector i val))
4800			 val))))
4801
4802	(set! count (fx+ count 1))
4803	(when (fx>= i (##sys#size ##sys#default-parameter-vector))
4804	  (set! ##sys#default-parameter-vector
4805	    (##sys#vector-resize
4806	     ##sys#default-parameter-vector
4807	     (fx+ i 1)
4808	     (##core#undefined)) ) )
4809	(##sys#setslot ##sys#default-parameter-vector i val)
4810	(getter-with-setter
4811	 (lambda args
4812	   (let ((n (##sys#size ##sys#current-parameter-vector)))
4813	     (cond ((pair? args)
4814		    (let-optionals (cdr args) ((convert? #t)
4815					       (set? #t))
4816		      (assign (car args) n convert? set?)))
4817		   ((fx>= i n)
4818		    (##sys#slot ##sys#default-parameter-vector i) )
4819		   (else
4820		    (let ((val (##sys#slot ##sys#current-parameter-vector i)))
4821		      (if (eq? val ##sys#snafu)
4822			  (##sys#slot ##sys#default-parameter-vector i)
4823			  val) ) ) ) ) )
4824	 (lambda (val)
4825	   (let ((n (##sys#size ##sys#current-parameter-vector)))
4826	     (assign val n #f #t))))))))
4827
4828
4829;;; Input:
4830
4831(set! scheme#char-ready?
4832  (lambda (#!optional (port ##sys#standard-input))
4833    (##sys#check-input-port port #t 'char-ready?)
4834    (let ((class (##sys#slot port 2)))
4835      ;; check size - for backwards compatibility we still allow missing method
4836      ((if (fx> (##sys#size class) 10)
4837           (##sys#slot class 10)        ; char-ready?
4838           (##sys#slot class 6))        ; u8-ready?
4839       port))))
4840    
4841(set! scheme#u8-ready? 
4842  (lambda (#!optional (port ##sys#standard-input))
4843    (##sys#check-input-port port #t 'u8-ready?)
4844    ((##sys#slot (##sys#slot port 2) 6) port) )) ; u8-ready?
4845
4846(set! scheme#read-char
4847  (lambda (#!optional (port ##sys#standard-input))
4848    (##sys#check-input-port port #t 'read-char)
4849    (##sys#read-char-0 port) ))
4850
4851(define (##sys#read-char-0 p)
4852  (let ([c (if (##sys#slot p 6)
4853	       (begin
4854		 (##sys#setislot p 6 #f)
4855		 #!eof)
4856	       ((##sys#slot (##sys#slot p 2) 0) p) ) ] ) ; read-char
4857    (cond [(eq? c #\newline)
4858	   (##sys#setislot p 4 (fx+ (##sys#slot p 4) 1))
4859	   (##sys#setislot p 5 0) ]
4860	  [(not (##core#inline "C_eofp" c))
4861	   (##sys#setislot p 5 (fx+ (##sys#slot p 5) 1)) ] )
4862    c) )
4863
4864(define (##sys#read-char/port port)
4865  (##sys#check-input-port port #t 'read-char)
4866  (##sys#read-char-0 port) )
4867
4868(define (##sys#peek-char-0 p)
4869  (if (##sys#slot p 6)
4870      #!eof
4871      (let ((c ((##sys#slot (##sys#slot p 2) 1) p))) ; peek-char
4872	(when (##core#inline "C_eofp" c)
4873	  (##sys#setislot p 6 #t) )
4874	c) ) )
4875
4876(set! scheme#peek-char
4877  (lambda (#!optional (port ##sys#standard-input))
4878    (##sys#check-input-port port #t 'peek-char)
4879    (##sys#peek-char-0 port) ))
4880
4881(set! scheme#read
4882  (lambda (#!optional (port ##sys#standard-input))
4883    (##sys#check-input-port port #t 'read)
4884    (##sys#read port ##sys#default-read-info-hook) ))
4885
4886(define ##sys#default-read-info-hook #f)
4887(define ##sys#read-error-with-line-number #f)
4888(define (##sys#read-prompt-hook) #f)	; just here so that srfi-18 works without eval
4889(define (##sys#infix-list-hook lst) lst)
4890
4891(set! ##sys#default-file-encoding (make-parameter 'utf-8))
4892
4893(define (##sys#sharp-number-hook port n)
4894  (##sys#read-error port "invalid `#...' read syntax" n) )
4895
4896(set! chicken.base#case-sensitive (make-parameter #t))
4897(set! chicken.base#parentheses-synonyms (make-parameter #t))
4898(set! chicken.base#symbol-escape (make-parameter #t))
4899
4900(set! chicken.base#keyword-style
4901  (make-parameter #:suffix (lambda (x) (when x (##sys#check-keyword x 'keyword-style)) x)))
4902
4903(define ##sys#current-read-table (make-parameter (##sys#make-structure 'read-table '() '() '())))
4904
4905(define ##sys#read-warning
4906  (let ([string-append string-append])
4907    (lambda (port msg . args)
4908      (apply
4909       ##sys#warn
4910       (let ((ln (##sys#port-line port)))
4911	 (if (and ##sys#read-error-with-line-number ln)
4912	     (string-append "(line " (##sys#number->string ln) ") " msg)
4913	     msg) )
4914       args) ) ) )
4915
4916(define ##sys#read-error
4917  (let ([string-append string-append] )
4918    (lambda (port msg . args)
4919      (apply
4920       ##sys#signal-hook
4921       #:syntax-error
4922       (let ((ln (##sys#port-line port)))
4923	 (if (and ##sys#read-error-with-line-number ln)
4924	     (string-append "(line " (##sys#number->string ln) ") " msg)
4925	     msg) )
4926       args) ) ) )
4927
4928(define ##sys#read
4929  (let ((string-append string-append)
4930	(keyword-style keyword-style)
4931	(parentheses-synonyms parentheses-synonyms)
4932        (case-sensitive case-sensitive)
4933	(symbol-escape symbol-escape)
4934        (integer->char integer->char)
4935	(current-read-table ##sys#current-read-table))
4936    (lambda (port infohandler)
4937      (let ((csp (and (case-sensitive) (##sys#slot port 13)))
4938	    (ksp (keyword-style))
4939	    (psp (parentheses-synonyms))
4940	    (sep (symbol-escape))
4941	    (crt (current-read-table))
4942	    (warn #f)
4943            (shared '())
4944	    ; set below - needs more state to make a decision
4945	    (terminating-characters '(#\, #\; #\( #\) #\' #\" #\[ #\] #\{ #\}))
4946	    (reserved-characters #f) )
4947
4948	(define (container c)
4949	  (##sys#read-error port "unexpected list terminator" c) )
4950
4951	(define (info class data val)
4952	  (if infohandler
4953	      (infohandler class data val)
4954	      data) )
4955
4956	(define (skip-to-eol)
4957	  (let skip ((c (##sys#read-char-0 port)))
4958	    (if (and (not (##core#inline "C_eofp" c)) (not (eq? #\newline c)))
4959		(skip (##sys#read-char-0 port)) ) ) )
4960
4961        (define (reserved-character c)
4962          (##sys#read-char-0 port)
4963          (##sys#read-error port "reserved character" c) )
4964
4965        (define (read-unreserved-char-0 port)
4966          (let ((c (##sys#read-char-0 port)))
4967            (if (memq c reserved-characters)
4968                (reserved-character c)
4969                c) ) )
4970
4971        (define (register-shared! n thunk)
4972          (set! shared (cons (cons n thunk) shared)))
4973
4974        (define (unthunk o fail)
4975          (let ((v (o)))
4976            (cond ((not (procedure? v)) v)
4977                  ((eq? v o)
4978                   (fail "self-referential datum"))
4979                  (else
4980                    (unthunk v fail)))))
4981
4982        ;; Fills holes in `o` destructively.
4983        (define (unthunkify! o fail)
4984          (let loop! ((o o))
4985            (cond ((pair? o)
4986                   (if (not (procedure? (car o)))
4987                       (loop! (car o))
4988                       (set-car! o (unthunk (car o) fail)))
4989                   (if (not (procedure? (cdr o)))
4990                       (loop! (cdr o))
4991                       (set-cdr! o (unthunk (cdr o) fail))))
4992                  ((vector? o)
4993                   (let ((len (##sys#size o)))
4994                     (do ((i 0 (fx+ i 1)))
4995                         ((eq? i len))
4996                         (let ((v (##sys#slot o i)))
4997                           (if (not (procedure? v))
4998                               (loop! v)
4999                               (##sys#setslot o i (unthunk v fail))))))))))
5000
5001	(define (readrec)
5002
5003	  (define (r-spaces)
5004	    (let loop ([c (##sys#peek-char-0 port)])
5005	      (cond ((##core#inline "C_eofp" c))
5006		    ((eq? #\; c)
5007		     (skip-to-eol)
5008		     (loop (##sys#peek-char-0 port)) )
5009		    ((char-whitespace? c)
5010		     (##sys#read-char-0 port)
5011		     (loop (##sys#peek-char-0 port)) ) ) ) )
5012
5013	  (define (r-usequence u n base)
5014	    (let loop ((seq '()) (n n))
5015	      (if (eq? n 0)
5016		  (let* ((str (##sys#reverse-list->string seq))
5017			 (n (string->number str base)))
5018		    (or n
5019			(##sys#read-error
5020			 port
5021			 (string-append
5022			  "invalid escape-sequence '\\" u str "\'")) ) )
5023		  (let ((x (##sys#read-char-0 port)))
5024		    (if (or (eof-object? x) (char=? #\" x))
5025			(##sys#read-error port "unterminated string constant")
5026			(loop (cons x seq) (fx- n 1)) ) ) ) ) )
5027
5028          (define (r-xsequence delim)
5029            (define (parse seq)
5030              (let* ((str (##sys#reverse-list->string seq))
5031                     (n (string->number str 16)))
5032                (or n
5033                    (##sys#read-error port
5034                     (string-append "invalid escape-sequence '\\x"
5035                                    str ";\'")))))
5036            (define (complain)
5037              (set! warn "unterminated hexadecimal escape sequence"))
5038            (define (abort)
5039              (##sys#read-error port "unterminated hexadecimal escape sequence") )
5040            (let loop ((seq '()))
5041              (let ((x (##sys#peek-char-0 port)))
5042                (cond ((eof-object? x) (abort))
5043                      ((eq? delim x)
5044                       (let ((n (parse seq)))
5045                         (if (fx> n #x1ffff)
5046                             (abort)
5047                             (begin (complain) n))))
5048                      ((eq? #\; x)
5049                       (##sys#read-char-0 port)
5050		       (parse seq))
5051                      ((or (and (char>=? x #\0) (char<=? x #\9))
5052                           (and (char>=? x #\a) (char<=? x #\f))
5053                           (and (char>=? x #\A) (char<=? x #\F)))
5054                       (loop (cons (##sys#read-char-0 port) seq)))
5055                      (else
5056                        (let ((n (parse seq)))
5057                          (if (fx> n #x1ffff)
5058                              (abort)
5059                              (begin (complain) n))))))))
5060
5061	  (define (r-string term)
5062	    (let loop ((c (##sys#read-char-0 port)) (lst '()))
5063	      (cond ((##core#inline "C_eofp" c)
5064		     (##sys#read-error port "unterminated string") )
5065		    ((eq? #\\ c)
5066		     (set! c (##sys#read-char-0 port))
5067		     (case c
5068		       ((#\t) (loop (##sys#read-char-0 port) (cons #\tab lst)))
5069		       ((#\r) (loop (##sys#read-char-0 port) (cons #\return lst)))
5070		       ((#\b) (loop (##sys#read-char-0 port) (cons #\backspace lst)))
5071		       ((#\n) (loop (##sys#read-char-0 port) (cons #\newline lst)))
5072		       ((#\a) (loop (##sys#read-char-0 port) (cons (integer->char 7) lst)))
5073		       ((#\v) (loop (##sys#read-char-0 port) (cons (integer->char 11) lst)))
5074		       ((#\f) (loop (##sys#read-char-0 port) (cons (integer->char 12) lst)))
5075		       ((#\x)
5076			(let ((ch (integer->char (r-xsequence term))))
5077			  (loop (##sys#read-char-0 port) (cons ch lst)) ) )
5078		       ((#\u)
5079			(let ((n (r-usequence "u" 4 16)))
5080                           (loop (##sys#read-char-0 port)
5081                                 (cons (integer->char n) lst)) ) )
5082		       ((#\U)
5083			(let ((n (r-usequence "U" 8 16)))
5084                           (loop (##sys#read-char-0 port)
5085                                 (cons (integer->char n) lst)) ))
5086		       ((#\\ #\' #\" #\|)
5087			(loop (##sys#read-char-0 port) (cons c lst)))
5088		       ((#\newline #\return #\space #\tab)
5089			;; Read "escaped" <intraline ws>* <nl> <intraline ws>*
5090			(let eat-ws ((c c) (nl? #f))
5091			  (case c
5092			    ((#\space #\tab)
5093			     (eat-ws (##sys#read-char-0 port) nl?))
5094			    ((#\return)
5095			     (if nl?
5096				 (loop c lst)
5097			         (let ((nc (##sys#read-char-0 port)))
5098			           (if (eq? nc #\newline) ; collapse \r\n
5099				       (eat-ws (##sys#read-char-0 port) #t)
5100				       (eat-ws nc #t)))))
5101			    ((#\newline)
5102			     (if nl?
5103				 (loop c lst)
5104				 (eat-ws (##sys#read-char-0 port) #t)))
5105			    (else
5106                             (unless nl?
5107                               (##sys#read-warning
5108				port
5109				"escaped whitespace, but no newline - collapsing anyway"))
5110                             (loop c lst)))))
5111		       (else
5112			(cond ((##core#inline "C_eofp" c)
5113			       (##sys#read-error port "unterminated string"))
5114			      ((and (char-numeric? c)
5115				    (char>=? c #\0)
5116				    (char<=? c #\7))
5117			       (let ((ch (integer->char
5118					  (fx+ (fx* (fx- (char->integer c) 48) 64)
5119					       (r-usequence "" 2 8)))))
5120				 (loop (##sys#read-char-0 port) (cons ch lst)) ))
5121			      (else
5122			       (##sys#read-warning
5123				port
5124				"undefined escape sequence in string - probably forgot backslash"
5125				c)
5126			       (loop (##sys#read-char-0 port) (cons c lst))) ) )))
5127		    ((eq? term c) (##sys#reverse-list->string lst))
5128		    (else (loop (##sys#read-char-0 port) (cons c lst))) ) ))
5129
5130	  (define (r-list start end)
5131	    (if (eq? (##sys#read-char-0 port) start)
5132		(let ((first #f)
5133		      (ln0 #f)
5134		      (outer-container container) )
5135		  (define (starting-line msg)
5136		    (if (and ln0 ##sys#read-error-with-line-number)
5137			(string-append
5138			 msg ", starting in line "
5139			 (##sys#number->string ln0))
5140			msg))
5141		  (##sys#call-with-current-continuation
5142		   (lambda (return)
5143		     (set! container
5144		       (lambda (c)
5145			 (if (eq? c end)
5146			     (return #f)
5147			     (##sys#read-error
5148			      port
5149			      (starting-line "list-terminator mismatch")
5150			      c end) ) ) )
5151		     (let loop ([last '()])
5152		       (r-spaces)
5153		       (unless first (set! ln0 (##sys#port-line port)))
5154		       (let ([c (##sys#peek-char-0 port)])
5155			 (cond ((##core#inline "C_eofp" c)
5156				(##sys#read-error
5157				 port
5158				 (starting-line "unterminated list") ) )
5159			       ((eq? c end)
5160				(##sys#read-char-0 port) )
5161			       ((eq? c #\.)
5162				(##sys#read-char-0 port)
5163				(let ((c2 (##sys#peek-char-0 port)))
5164				  (cond ((or (char-whitespace? c2)
5165					     (eq? c2 #\()
5166					     (eq? c2 #\))
5167					     (eq? c2 #\")
5168					     (eq? c2 #\;) )
5169					 (unless (pair? last)
5170					   (##sys#read-error port "invalid use of `.'") )
5171					 (r-spaces)
5172					 (##sys#setslot last 1 (readrec))
5173					 (r-spaces)
5174					 (unless (eq? (##sys#read-char-0 port) end)
5175					   (##sys#read-error
5176					    port
5177					    (starting-line "missing list terminator")
5178					    end)))
5179					(else
5180					 (r-xtoken
5181					  (lambda (tok kw)
5182					    (let* ((tok (##sys#string-append "." tok))
5183						   (val
5184						    (cond ((and (string=? tok ".:")
5185								(eq? ksp #:suffix))
5186							   ;; Edge case: r-xtoken sees
5187							   ;; a bare ":" and sets kw to #f
5188							   (build-keyword "."))
5189							  (kw (build-keyword tok))
5190							  ((and (char-numeric? c2)
5191								(##sys#string->number tok)))
5192							  (else (build-symbol tok))))
5193						   (node (cons val '())))
5194					      (if first
5195						  (##sys#setslot last 1 node)
5196						  (set! first node) )
5197					      (loop node))))))))
5198			       (else
5199				(let ([node (cons (readrec) '())])
5200				  (if first
5201				      (##sys#setslot last 1 node)
5202				      (set! first node) )
5203				  (loop node) ) ) ) ) ) ) )
5204		  (set! container outer-container)
5205		  (if first
5206		      (info 'list-info (##sys#infix-list-hook first) ln0)
5207		      '() ) )
5208		(##sys#read-error port "missing token" start) ) )
5209
5210	  (define (r-vector)
5211	    (let ((lst (r-list #\( #\))))
5212	      (if (list? lst)
5213		  (##sys#list->vector lst)
5214		  (##sys#read-error port "invalid vector syntax" lst) ) ) )
5215
5216	  (define (r-number radix exactness)
5217	    (r-xtoken
5218	     (lambda (tok kw)
5219	       (cond (kw
5220		      (let ((s (build-keyword tok)))
5221			(info 'symbol-info s (##sys#port-line port)) ))
5222		     ((string=? tok ".")
5223		      (##sys#read-error port "invalid use of `.'"))
5224		     ((and (fx> (string-length tok) 0) (char=? (string-ref tok 0) #\#))
5225		      (##sys#read-error port "unexpected prefix in number syntax" tok))
5226		     ((##sys#string->number tok (or radix 10) exactness))
5227		     (radix (##sys#read-error port "illegal number syntax" tok))
5228		     (else (build-symbol tok))  ) ) ))
5229
5230	  (define (r-number-with-exactness radix)
5231	    (cond [(eq? #\# (##sys#peek-char-0 port))
5232		   (##sys#read-char-0 port)
5233		   (let ([c2 (##sys#read-char-0 port)])
5234		     (cond [(eof-object? c2)
5235			    (##sys#read-error port "unexpected end of numeric literal")]
5236			   [(char=? c2 #\i) (r-number radix 'i)]
5237			   [(char=? c2 #\e) (r-number radix 'e)]
5238			   [else
5239			    (##sys#read-error
5240			     port
5241			     "illegal number syntax - invalid exactness prefix" c2)] ) ) ]
5242		  [else (r-number radix #f)] ) )
5243
5244	  (define (r-number-with-radix exactness)
5245	    (cond [(eq? #\# (##sys#peek-char-0 port))
5246		   (##sys#read-char-0 port)
5247		   (let ([c2 (##sys#read-char-0 port)])
5248		     (cond [(eof-object? c2) (##sys#read-error port "unexpected end of numeric literal")]
5249			   [(char=? c2 #\x) (r-number 16 exactness)]
5250			   [(char=? c2 #\d) (r-number 10 exactness)]
5251			   [(char=? c2 #\o) (r-number 8 exactness)]
5252			   [(char=? c2 #\b) (r-number 2 exactness)]
5253			   [else (##sys#read-error port "illegal number syntax - invalid radix" c2)] ) ) ]
5254		  [else (r-number 10 exactness)] ) )
5255
5256	  (define (r-token)
5257	    (let loop ((c (##sys#peek-char-0 port)) (lst '()))
5258	      (cond ((or (eof-object? c)
5259			 (char-whitespace? c)
5260			 (memq c terminating-characters) )
5261		     (##sys#reverse-list->string lst) )
5262		    ((char=? c #\x00)
5263		     (##sys#read-error port "attempt to read expression from something that looks like binary data"))
5264		    (else
5265		     (read-unreserved-char-0 port)
5266		     (loop (##sys#peek-char-0 port)
5267		           (cons (if csp 
5268		                     c 
5269		                     (##core#inline "C_utf_char_foldcase" c) )
5270		                 lst) ) ) ) ) )
5271
5272	  (define (r-digits)
5273	    (let loop ((c (##sys#peek-char-0 port)) (lst '()))
5274	      (cond ((or (eof-object? c) (not (char-numeric? c)))
5275		     (##sys#reverse-list->string lst) )
5276		    (else
5277		     (##sys#read-char-0 port)
5278		     (loop (##sys#peek-char-0 port) (cons c lst)) ) ) ) )
5279
5280	  (define (r-symbol)
5281	    (r-xtoken
5282	     (lambda (str kw)
5283	       (let ((s (if kw (build-keyword str) (build-symbol str))))
5284		 (info 'symbol-info s (##sys#port-line port)) ) )))
5285
5286	  (define (r-xtoken k)
5287	    (define pkw ; check for prefix keyword immediately
5288	      (and (eq? ksp #:prefix)
5289		   (eq? #\: (##sys#peek-char-0 port))
5290		   (begin (##sys#read-char-0 port) #t)))
5291	    (let loop ((lst '()) (skw #f) (qtd #f))
5292	      (let ((c (##sys#peek-char-0 port)))
5293		(cond ((or (eof-object? c)
5294			   (char-whitespace? c)
5295			   (memq c terminating-characters))
5296		       ;; The various cases here cover:
5297		       ;; - Nonempty keywords formed with colon in the ksp position
5298		       ;; - Empty keywords formed explicitly with vbar quotes
5299		       ;; - Bare colon, which should always be a symbol
5300		       (cond ((and skw (eq? ksp #:suffix) (or qtd (not (null? (cdr lst)))))
5301			      (k (##sys#reverse-list->string (cdr lst)) #t))
5302			     ((and pkw (or qtd (not (null? lst))))
5303			      (k (##sys#reverse-list->string lst) #t))
5304			     ((and pkw (not qtd) (null? lst))
5305			      (k ":" #f))
5306			     (else
5307			      (k (##sys#reverse-list->string lst) #f))))
5308		      ((memq c reserved-characters)
5309		       (reserved-character c))
5310		      (else
5311		       (let ((c (##sys#read-char-0 port)))
5312			 (case c
5313			   ((#\|)
5314			    (let ((part (r-string #\|)))
5315			      (loop (append (##sys#fast-reverse (##sys#string->list part)) lst)
5316				    #f #t)))
5317			   ((#\newline)
5318			    (##sys#read-warning
5319			     port "escaped symbol syntax spans multiple lines"
5320			     (##sys#reverse-list->string lst))
5321			    (loop (cons #\newline lst) #f qtd))
5322			   ((#\:)
5323			    (loop (cons #\: lst) #t qtd))
5324			   ((#\\)
5325			    (let ((c (##sys#read-char-0 port)))
5326			      (if (eof-object? c)
5327				  (##sys#read-error
5328				   port
5329				   "unexpected end of file while reading escaped character")
5330				  (loop (cons c lst) #f qtd))))
5331			   (else
5332			    (loop
5333			     (cons (if csp 
5334			               c 
5335			               (##core#inline "C_utf_char_foldcase" c))
5336			           lst)
5337			     #f qtd)))))))))
5338
5339	  (define (r-char)
5340	    ;; Code contributed by Alex Shinn
5341	    (let* ([c (##sys#peek-char-0 port)]
5342		   [tk (r-token)]
5343		   [len (string-length tk)])
5344	      (cond [(fx> len 1)
5345		     (cond [(and (or (char=? #\x c) (char=? #\u c) (char=? #\U c))
5346				 (##sys#string->number (##sys#substring tk 1 len) 16) )
5347			    => (lambda (n) (integer->char n)) ]
5348			   [(and-let* ((c0 (char->integer (string-ref tk 0)))
5349				       ((fx<= #xC0 c0)) ((fx<= c0 #xF7))
5350				       (n0 (fxand (fxshr c0 4) 3))
5351				       (n (fx+ 2 (fxand (fxior n0 (fxshr n0 1)) (fx- n0 1))))
5352				       ((fx= len n))
5353				       (res (fx+ (fxshl (fxand c0 (fx- (fxshl 1 (fx- 8 n)) 1))
5354							6)
5355						 (fxand (char->integer
5356							 (string-ref tk 1))
5357							#b111111))))
5358			      (cond ((fx>= n 3)
5359				     (set! res (fx+ (fxshl res 6)
5360						    (fxand
5361						     (char->integer
5362						      (string-ref tk 2))
5363						     #b111111)))
5364				     (if (fx= n 4)
5365					 (set! res (fx+ (fxshl res 6)
5366							(fxand (char->integer
5367								(string-ref tk 3))
5368							       #b111111))))))
5369			      (integer->char res))]
5370			   [(char-name (##sys#string->symbol tk))]
5371			   [else (##sys#read-error port "unknown named character" tk)] ) ]
5372		    [(memq c terminating-characters) (##sys#read-char-0 port)]
5373		    [else c] ) ) )
5374
5375	  (define (r-comment)
5376	    (let loop ((i 0))
5377	      (let ((c (##sys#read-char-0 port)))
5378		(case c
5379		  ((#\|) (if (eq? #\# (##sys#read-char-0 port))
5380			     (if (not (eq? i 0))
5381				 (loop (fx- i 1)) )
5382			     (loop i) ) )
5383		  ((#\#) (loop (if (eq? #\| (##sys#read-char-0 port))
5384				   (fx+ i 1)
5385				   i) ) )
5386		  (else (if (eof-object? c)
5387			    (##sys#read-error port "unterminated block-comment")
5388			    (loop i) ) ) ) ) ) )
5389
5390	  (define (r-ext-symbol)
5391	    (let ((tok (r-token)))
5392	      (build-symbol (string-append "##" tok))))
5393
5394	  (define (r-quote q)
5395	    (let ((ln (##sys#port-line port)))
5396	      (info 'list-info (list q (readrec)) ln)))
5397
5398	  (define (build-symbol tok)
5399	    (##sys#string->symbol tok) )
5400
5401	  (define (build-keyword tok)
5402	    (##sys#intern-keyword (##sys#string->symbol-name tok)))
5403
5404          ;; now have the state to make a decision.
5405          (set! reserved-characters
5406                (append (if (not psp) '(#\[ #\] #\{ #\}) '())
5407                        (if (not sep) '(#\|) '())))
5408	  (r-spaces)
5409	  (let* ((c (##sys#peek-char-0 port))
5410		 (srst (##sys#slot crt 1))
5411		 (h (and (not (eof-object? c))
5412			 (assq c srst))))
5413	    (if (and h (##sys#slot h 1))
5414                ;; then handled by read-table entry
5415		(##sys#call-with-values
5416		 (lambda () ((##sys#slot h 1) c port))
5417		 (lambda xs (if (null? xs) (readrec) (car xs))))
5418		;; otherwise chicken extended r5rs syntax
5419		(case c
5420		  ((#\')
5421		   (##sys#read-char-0 port)
5422		   (r-quote 'quote))
5423		  ((#\`)
5424		   (##sys#read-char-0 port)
5425		   (r-quote 'quasiquote))
5426		  ((#\,)
5427		   (##sys#read-char-0 port)
5428		   (cond ((eq? (##sys#peek-char-0 port) #\@)
5429			  (##sys#read-char-0 port)
5430			  (r-quote 'unquote-splicing))
5431			 (else (r-quote 'unquote))))
5432		  ((#\#)
5433		   (##sys#read-char-0 port)
5434		   (let ((dchar (##sys#peek-char-0 port)))
5435		     (cond
5436		      ((eof-object? dchar)
5437		       (##sys#read-error
5438			port "unexpected end of input after reading #-sign"))
5439		      ((char-numeric? dchar)
5440		       (let* ((n (string->number (r-digits)))
5441			      (dchar2 (##sys#peek-char-0 port))
5442			      (spdrst (##sys#slot crt 3)))
5443			 (cond ((eof-object? dchar2)
5444                                (##sys#read-error
5445                                 port "unexpected end of input after reading"
5446                                 c n))
5447                               ;; #<num>=...
5448                               ((eq? #\= dchar2)
5449                                (##sys#read-char-0 port)
5450                                (letrec ((datum (begin
5451                                                  (register-shared! n (lambda () datum))
5452                                                  (readrec))))
5453                                  datum))
5454                               ;; #<num>#
5455                               ((eq? #\# dchar2)
5456                                (##sys#read-char-0 port)
5457                                (cond ((assq n shared) => cdr)
5458                                      (else (##sys#read-error port "undefined datum" n))))
5459                           			 ;; #<num> handled by parameterized # read-table entry?
5460                               ((and (char? dchar2)
5461                                     (let ((a (assq dchar2 spdrst)))
5462                                       (and a (##sys#slot a 1) a))) =>
5463                                (lambda (h)
5464                                  (##sys#call-with-values
5465                                    (lambda () ((##sys#slot h 1) dchar2 port n))
5466                                    (lambda xs (if (null? xs) (readrec) (car xs))))))
5467                               ;; #<num>
5468			       ((or (eq? dchar2 #\)) (char-whitespace? dchar2))
5469				(##sys#sharp-number-hook port n))
5470			       (else (##sys#read-char-0 port) ; Consume it first
5471				     (##sys#read-error
5472				      port
5473				      "invalid parameterized read syntax"
5474				      c n dchar2) ) ) ))
5475		      (else (let* ((sdrst (##sys#slot crt 2))
5476				   (h (assq dchar sdrst)))
5477			      (if (and h (##sys#slot h 1))
5478                                  ;; then handled by # read-table entry
5479				  (##sys#call-with-values
5480				   (lambda () ((##sys#slot h 1) dchar port))
5481				   (lambda xs (if (null? xs) (readrec) (car xs))))
5482                                  ;; otherwise chicken extended R7RS syntax
5483				  (case (char-downcase dchar)
5484				    ((#\x) (##sys#read-char-0 port) (r-number-with-exactness 16))
5485				    ((#\d) (##sys#read-char-0 port) (r-number-with-exactness 10))
5486				    ((#\o) (##sys#read-char-0 port) (r-number-with-exactness 8))
5487				    ((#\b) (##sys#read-char-0 port) (r-number-with-exactness 2))
5488				    ((#\i) (##sys#read-char-0 port) (r-number-with-radix 'i))
5489				    ((#\e) (##sys#read-char-0 port) (r-number-with-radix 'e))
5490				    ((#\() (r-vector))
5491				    ((#\\) (##sys#read-char-0 port) (r-char))
5492				    ((#\|)
5493				     (##sys#read-char-0 port)
5494				     (r-comment) (readrec) )
5495				    ((#\#)
5496				     (##sys#read-char-0 port)
5497				     (r-ext-symbol) )
5498				    ((#\;)
5499				     (##sys#read-char-0 port)
5500				     (readrec) (readrec) )
5501				    ((#\`)
5502				     (##sys#read-char-0 port)
5503				     (r-quote 'quasisyntax))
5504				    ((#\$)
5505				     (##sys#read-char-0 port)
5506                                     ;; HACK: reuse r-quote to add line number info
5507				     (r-quote 'location))
5508				    ((#\:)
5509				     (##sys#read-char-0 port)
5510				     (let ((c (##sys#peek-char-0 port)))
5511				       (fluid-let ((ksp #f))
5512					 (r-xtoken
5513					  (lambda (str kw)
5514					    (if (and (eq? 0 (string-length str))
5515						     (not (char=? c #\|)))
5516						(##sys#read-error port "empty keyword")
5517						(build-keyword str)))))))
5518				    ((#\+)
5519				     (##sys#read-char-0 port)
5520				     (let* ((ln (##sys#port-line port))
5521					    (tst (readrec)))
5522				       (info 'list-info
5523					     (list 'cond-expand (list tst (readrec)) '(else))
5524					     ln)))
5525				    ((#\!)
5526				     (##sys#read-char-0 port)
5527				     (let ((c (##sys#peek-char-0 port)))
5528				       (cond ((and (char? c)
5529						   (or (char-whitespace? c) (char=? #\/ c)))
5530					      (skip-to-eol)
5531					      (readrec) )
5532					     (else
5533					      (let ([tok (r-token)])
5534						(cond ((string=? "eof" tok) #!eof)
5535						      ((string=? "bwp" tok) #!bwp)
5536                                                      ((string=? "fold-case" tok)
5537                                                       (set! csp #f)
5538                                                       (##sys#setislot port 13 csp)
5539                                                       (readrec))
5540                                                      ((string=? "no-fold-case" tok)
5541                                                       (set! csp #t)
5542                                                       (##sys#setislot port 13 csp)
5543                                                       (readrec))
5544						      ((member tok '("optional" "rest" "key"))
5545						       (build-symbol (##sys#string-append "#!" tok)) )
5546						      (else
5547						       (let ((a (assq (string->symbol tok) ##sys#read-marks)))
5548							 (if a
5549							     ((##sys#slot a 1) port)
5550							     (##sys#read-error
5551							      port
5552							      "invalid `#!' token" tok) ) ) ) ) ) ) ) ) )
5553				    (else
5554				     (##sys#call-with-values (lambda () (##sys#user-read-hook dchar port))
5555							     (lambda xs (if (null? xs) (readrec) (car xs)))) ) ) ) )) ) ) )
5556		  ((#\() (r-list #\( #\)))
5557		  ((#\)) (##sys#read-char-0 port) (container c))
5558		  ((#\") (##sys#read-char-0 port) (r-string #\"))
5559		  ((#\.) (r-number #f #f))
5560		  ((#\- #\+) (r-number #f #f))
5561		  (else
5562		   (cond [(eof-object? c) c]
5563			 [(char-numeric? c) (r-number #f #f)]
5564			 ((memq c reserved-characters)
5565			  (reserved-character c))
5566			 (else
5567			  (case c
5568			    ((#\[) (r-list #\[ #\]))
5569			    ((#\{) (r-list #\{ #\}))
5570			    ((#\] #\}) (##sys#read-char-0 port) (container c))
5571			    (else (r-symbol) ) ) ) ) ) ) ) ) )
5572
5573        (let ((x (readrec)))
5574          (when warn (##sys#read-warning port warn))
5575          (when (pair? shared)
5576            (unthunkify! x (lambda a (apply ##sys#read-error p a))))
5577          x)))))
5578
5579;;; Hooks for user-defined read-syntax:
5580;
5581; - Redefine this to handle new read-syntaxes. If 'char' doesn't match
5582;   your character then call the previous handler.
5583; - Don't forget to read 'char', it's only peeked at this point.
5584
5585(define (##sys#user-read-hook char port)
5586  (define (fail item) (##sys#read-error port "invalid sharp-sign read syntax" item))
5587  (case char
5588    ((#\f #\t #\u)
5589     (let ((sym (##sys#read port ##sys#default-read-info-hook)))
5590       (if (not (symbol? sym))
5591           (fail char)
5592           (case sym
5593             ((t true) #t)
5594             ((f false) #f)
5595             ((u8)
5596              ;; u8vectors, srfi-4 handles this already via read-hook but we reimplement it
5597              ;; here in case srfi-4 is not loaded
5598              (let ((d (##sys#read-numvector-data port)))
5599                (if (or (null? d) (pair? d))
5600                    (##sys#list->bytevector (##sys#canonicalize-number-list! d))
5601                    ;; reuse already created bytevector
5602                    (##core#inline "C_chop_bv" (##sys#slot d 0)))))
5603             (else (fail sym))))))
5604    (else (fail char))))
5605
5606;; returns a (potentially large) list of numbers (bytes) in
5607;; order. ignores whitespace.
5608(define (##sys#read-hex-literal port) ;; { 00ff11 ff } => #u8(0 255 17 255)
5609  (define (hex c)
5610    (cond ((and (char>=? c #\a) (char<=? c #\f)) (fx- (char->integer c) 87)) ;; (- (char->integer #\a) 10)
5611          ((and (char>=? c #\A) (char<=? c #\F)) (fx- (char->integer c) 55)) ;; (- (char->integer #\A) 10)
5612	  ((and (char>=? c #\0) (char<=? c #\9)) (fx- (char->integer c) 48)) ;; (char->integer #\0)
5613	  (else (##sys#read-error port "invalid hex-code in bytecode literal" c))))
5614
5615  (unless (eq? #\{ (##sys#read-char-0 port)) (##sys#read-error port "internal error"))
5616  (let ((first #f))
5617    (let loop ((h #f) (last #f))
5618      (let ((c (##sys#read-char-0 port)))
5619        (cond ((eof-object? c)
5620	       (##sys#read-error port "unexpected end of hex bytevector literal"))
5621	      ((char=? #\} c)
5622	       (if h
5623		   (##sys#read-error port "odd-numbered hex bytevector literal")
5624		   (or first '())))
5625	      ((char-whitespace? c)
5626	       (if h
5627		   (##sys#read-error port "odd-numbered hex bytevector literal")
5628		   (loop #f last)))
5629	      (h
5630               (let ((node (cons (fxior (fxshl h 4) (hex c)) '())))
5631                 (if first
5632                     (##sys#setslot last 1 node)
5633                     (set! first node))
5634                 (loop #f node)))
5635	      (else (loop (hex c) last)))))))
5636
5637(define (##sys#read-numvector-data port)
5638  (let ((c (##sys#peek-char-0 port)))
5639    (case c
5640      ((#\( #\") (##sys#read port ##sys#default-read-info-hook))
5641      ((#\{) (##sys#read-hex-literal port))
5642      (else (##sys#read-error port "invalid numeric vector syntax" c)))))
5643
5644(define (##sys#canonicalize-number-list! lst1)
5645  (let loop ((lst lst1) (prev #f))
5646    (if (and (##core#inline "C_blockp" lst)
5647             (##core#inline "C_pairp" lst))
5648        (let retry ((x (##sys#slot lst 0)))
5649          (cond ((char? x) (retry (string x)))
5650                ((null? x) 
5651                  (if prev 
5652                      (##sys#setslot prev 1 (##sys#slot lst 1))
5653                      (set! lst1 (##sys#slot lst 1)))
5654                  (loop (##sys#slot lst 1) prev))
5655                ((list? x) 
5656                  (let ((lst (##sys#append x (##sys#slot lst 1))))
5657                    (if prev
5658                        (##sys#setslot prev 1 lst)
5659                        (set! lst1 lst))
5660                    (loop lst prev)))
5661                ((string? x) (retry (chicken.bytevector#string->utf8 x)))
5662                ((and (##core#inline "C_blockp" x)
5663                      (##sys#bytevector? x))
5664                  (retry (##sys#bytevector->list x)))
5665                ((##sys#srfi-4-vector? x) (retry (##sys#slot x 1)))
5666                (else (loop (##sys#slot lst 1) lst))))
5667        lst1)))
5668
5669;;; Table for specially-handled read-syntax:
5670;
5671; - entries should be #f or a 256-element vector containing procedures
5672; - each procedure is called with two arguments, a char (peeked) and a
5673;   port, and should return an expression
5674
5675(define ##sys#read-marks '()) ; TODO move to read-syntax module
5676
5677
5678;;; Output:
5679
5680(define (##sys#write-char-0 c p)
5681  ((##sys#slot (##sys#slot p 2) 2) p c)
5682  (##sys#void))
5683
5684(define (##sys#write-char/port c port)
5685  (##sys#check-output-port port #t 'write-char)
5686  (##sys#check-char c 'write-char)
5687  (##sys#write-char-0 c port) )
5688
5689(set! scheme#write-char
5690  (lambda (c #!optional (port ##sys#standard-output))
5691    (##sys#check-char c 'write-char)
5692    (##sys#check-output-port port #t 'write-char)
5693    (##sys#write-char-0 c port) ))
5694
5695(set! scheme#newline
5696  (lambda (#!optional (port ##sys#standard-output))
5697    (##sys#write-char/port #\newline port) ))
5698
5699(set! scheme#write
5700  (lambda (x #!optional (port ##sys#standard-output))
5701    (##sys#check-output-port port #t 'write)
5702    (##sys#print x #t port) ))
5703
5704(set! scheme#display
5705  (lambda (x #!optional (port ##sys#standard-output))
5706    (##sys#check-output-port port #t 'display)
5707    (##sys#print x #f port) ))
5708
5709(define-inline (*print-each lst)
5710  (for-each (cut ##sys#print <> #f ##sys#standard-output) lst) )
5711
5712(set! chicken.base#print
5713  (lambda args
5714    (##sys#check-output-port ##sys#standard-output #t 'print)
5715    (*print-each args)
5716    (##sys#write-char-0 #\newline ##sys#standard-output)
5717    (void)))
5718
5719(set! chicken.base#print*
5720  (lambda args
5721    (##sys#check-output-port ##sys#standard-output #t 'print)
5722    (*print-each args)
5723    (##sys#flush-output ##sys#standard-output)
5724    (void)))
5725
5726(define ##sys#current-print-length (make-parameter 0))
5727(define ##sys#print-length-limit (make-parameter #f))
5728(define ##sys#print-exit (make-parameter #f))
5729
5730(define ##sys#print
5731  (let ((case-sensitive case-sensitive)
5732        (symbol-escape symbol-escape)
5733	(keyword-style keyword-style))
5734    (lambda (x readable port)
5735      (##sys#check-output-port port #t #f)
5736      (let ((csp (case-sensitive))
5737	    (ksp (keyword-style))
5738            (sep (symbol-escape))
5739	    (length-limit (##sys#print-length-limit))
5740	    (special-characters '(#\( #\) #\, #\[ #\] #\{ #\} #\' #\" #\; #\ #\` #\| #\\)) )
5741
5742	(define (outstr port str)
5743	  (if length-limit
5744	      (let* ((len (string-length str))
5745		     (cpp0 (##sys#current-print-length))
5746		     (cpl (fx+ cpp0 len)) )
5747		(if (fx> cpl length-limit)
5748		    (let ((n (fx- length-limit cpp0)))
5749		      (when (fx> n 0) (outstr0 port (##sys#substring str 0 n)))
5750		      (outstr0 port "...")
5751		      ((##sys#print-exit) (##sys#void)))
5752		    (outstr0 port str) )
5753		(##sys#current-print-length cpl) )
5754	      (outstr0 port str) ) )
5755
5756	(define (outstr0 port str)
5757          (let ((bv (##sys#slot str 0)))
5758  	    ((##sys#slot (##sys#slot port 2) 3) port bv 0 (fx- (##sys#size bv) 1)))) ; write-bytevector
5759
5760	(define (outchr port chr)
5761	  (when length-limit
5762	    (let ((cpp0 (##sys#current-print-length)))
5763	      (##sys#current-print-length (fx+ cpp0 1))
5764	      (when (fx> cpp0 length-limit)
5765		(outstr0 port "...")
5766		((##sys#print-exit) (##sys#void)))))
5767	  ((##sys#slot (##sys#slot port 2) 2) port chr))  ; write-char
5768
5769	(define (specialchar? chr)
5770	  (let ([c (char->integer chr)])
5771	    (or (fx<= c 32)
5772		(memq chr special-characters) ) ) )
5773
5774	(define (outsym port sym)
5775	  (let ((str (##sys#symbol->string/shared sym)))
5776	    (if (or (not sep) (not readable) (sym-is-readable? str))
5777		(outstr port str)
5778		(outreadablesym port str))))
5779
5780	(define (outreadablesym port str)
5781	  (let ((len (string-length str)))
5782	    (outchr port #\|)
5783	    (let loop ((i 0))
5784	      (if (fx>= i len)
5785		  (outchr port #\|)
5786		  (let ((c (string-ref str i)))
5787		    (cond ((or (char<? c #\space) (char>? c #\~))
5788			   (outstr port "\\x")
5789			   (let ((n (char->integer c)))
5790			     (outstr port (##sys#number->string n 16))
5791                             (outchr port #\;)
5792			     (loop (fx+ i 1))))
5793			  (else
5794			   (when (or (eq? c #\|) (eq? c #\\)) (outchr port #\\))
5795			   (outchr port c)
5796			   (loop (fx+ i 1)) ) ) ) ) )))
5797
5798	(define (sym-is-readable? str)
5799	  (let ((len (string-length str)))
5800	    (cond ((eq? len 0) #f)
5801		  ((eq? len 1)
5802		   (let ((c (string-ref str 0)))
5803		     (cond ((or (eq? #\# c) (eq? #\. c)) #f)
5804			   ((specialchar? c) #f)
5805			   ((char-numeric? c) #f)
5806			   (else #t))))
5807		  (else
5808		   (let loop ((i (fx- len 1)))
5809		     (if (eq? i 0)
5810			 (let ((c (string-ref str 0)))
5811			   (cond ((char-numeric? c) #f)
5812                                 ((or (eq? c #\+) (eq? c #\-))
5813				  (or (fx= len 1)
5814                                      (not (char-numeric? (string-ref str 1)))))
5815                                 ((eq? c #\.)
5816				  (and (fx> len 1)
5817                                       (not (char-numeric? (string-ref str 1)))))
5818				 ((eq? c #\:) #f)
5819				 ((and (eq? c #\#)
5820				       ;; Not a qualified symbol?
5821				       (not (and (fx> len 2)
5822						 (eq? (string-ref str 1) #\#)
5823						 (not (eq? (string-ref str 2) #\#)))))
5824				  (member str '("#!rest" "#!key" "#!optional"
5825                                                "#!fold-case" "#!no-fold-case")))
5826				 ((specialchar? c) #f)
5827				 (else #t) ) )
5828			 (let ((c (string-ref str i)))
5829			   (and (or csp (not (char-upper-case? c)))
5830				(not (specialchar? c))
5831				(or (not (eq? c #\:))
5832				    (fx< i (fx- len 1)))
5833				(loop (fx- i 1)) ) ) ) ) ) ) ) )
5834
5835	(let out ([x x])
5836	  (cond ((eq? x '()) (outstr port "()"))
5837		((eq? x #t) (outstr port "#t"))
5838		((eq? x #f) (outstr port "#f"))
5839		((##core#inline "C_eofp" x) (outstr port "#!eof"))
5840		((##core#inline "C_undefinedp" x) (outstr port "#<unspecified>"))
5841		((##core#inline "C_bwpp" x) (outstr port "#!bwp"))
5842		((##core#inline "C_charp" x)
5843		 (cond [readable
5844			(outstr port "#\\")
5845			(let ([code (char->integer x)])
5846			  (cond [(char-name x)
5847				 => (lambda (cn)
5848				      (outstr port (##sys#symbol->string/shared cn)) ) ]
5849				[(or (fx< code 32) (fx> code #x1ffff))
5850				 (outchr port #\x)
5851				 (outstr port (##sys#number->string code 16)) ]
5852				[else (outchr port x)] ) ) ]
5853		       [else (outchr port x)] ) )
5854		((##core#inline "C_fixnump" x) (outstr port (##sys#number->string x)))
5855		((##core#inline "C_unboundvaluep" x) (outstr port "#<unbound value>"))
5856		((not (##core#inline "C_blockp" x)) (outstr port "#<invalid immediate object>"))
5857		((##core#inline "C_forwardedp" x) (outstr port "#<invalid forwarded object>"))
5858		((##core#inline "C_i_keywordp" x)
5859                 ;; Force portable #: style for readable output
5860		 (case (and (not readable) ksp)
5861                   ((#:prefix)
5862                    (outchr port #\:)
5863                    (outsym port x))
5864                   ((#:suffix)
5865                    (outsym port x)
5866                    (outchr port #\:))
5867                   (else
5868                    (outstr port "#:")
5869                    (outsym port x))))
5870		((##core#inline "C_i_symbolp" x) (outsym port x))
5871		((number? x) (outstr port (##sys#number->string x)))
5872		((##core#inline "C_anypointerp" x) (outstr port (##sys#pointer->string x)))
5873		((##core#inline "C_stringp" x)
5874		 (cond (readable
5875			(outchr port #\")
5876			(do ((i 0 (fx+ i 1))
5877			     (c (string-length x) (fx- c 1)) )
5878			    ((eq? c 0)
5879			     (outchr port #\") )
5880			  (let ((chr (char->integer (string-ref x i))))
5881			    (case chr
5882			      ((34) (outstr port "\\\""))
5883			      ((92) (outstr port "\\\\"))
5884			      (else
5885			       (cond ((or (fx< chr 32)
5886					  (fx= chr #x1ffff))
5887				      (outchr port #\\)
5888				      (case chr
5889                                        ((7) (outchr port #\a))
5890					((8) (outchr port #\b))
5891					((9) (outchr port #\t))
5892					((10) (outchr port #\n))
5893					((11) (outchr port #\v))
5894					((12) (outchr port #\f))
5895					((13) (outchr port #\r))
5896					(else
5897					 (outchr port #\x)
5898					 (when (fx< chr 16) (outchr port #\0))
5899					 (outstr port (##sys#number->string chr 16))
5900					 (outchr port #\;) ) ) )
5901				     (else (outchr port (##core#inline "C_fix_to_char" chr)) ) ) ) ) ) ) )
5902		       (else (outstr port x)) ) )
5903		((##core#inline "C_pairp" x)
5904		 (outchr port #\()
5905		 (out (##sys#slot x 0))
5906		 (do ((x (##sys#slot x 1) (##sys#slot x 1)))
5907		     ((or (not (##core#inline "C_blockp" x)) (not (##core#inline "C_pairp" x)))
5908		      (if (not (eq? x '()))
5909			  (begin
5910			    (outstr port " . ")
5911			    (out x) ) )
5912		      (outchr port #\)) )
5913		   (outchr port #\space)
5914		   (out (##sys#slot x 0)) ) )
5915		((##core#inline "C_bytevectorp" x)
5916		 (outstr port "#u8")
5917                 (out (##sys#bytevector->list x)))
5918		((##core#inline "C_structurep" x) (##sys#user-print-hook x readable port))
5919		((##core#inline "C_closurep" x) (outstr port (##sys#procedure->string x)))
5920		((##core#inline "C_locativep" x) (outstr port "#<locative>"))
5921		((##core#inline "C_lambdainfop" x)
5922		 (outstr port "#<lambda info ")
5923		 (outstr port (##sys#lambda-info->string x))
5924		 (outchr port #\>) )
5925		((##core#inline "C_portp" x)
5926		 (case (##sys#slot x 1)
5927		   ((1)  (outstr port "#<input port \""))
5928		   ((2)  (outstr port "#<output port \""))
5929		   (else (outstr port "#<port \"")))
5930		 (outstr port (##sys#slot x 3))
5931		 (outstr port "\">") )
5932		((##core#inline "C_vectorp" x)
5933		 (let ((n (##sys#size x)))
5934		   (cond ((eq? 0 n)
5935			  (outstr port "#()") )
5936			 (else
5937			  (outstr port "#(")
5938			  (out (##sys#slot x 0))
5939			  (do ((i 1 (fx+ i 1))
5940			       (c (fx- n 1) (fx- c 1)) )
5941			      ((eq? c 0)
5942			       (outchr port #\)) )
5943			    (outchr port #\space)
5944			    (out (##sys#slot x i)) ) ) ) ) )
5945		(else (##sys#error "unprintable block object encountered")))))
5946      (##sys#void))))
5947
5948(define ##sys#procedure->string
5949  (let ((string-append string-append))
5950    (lambda (x)
5951      (let ((info (##sys#lambda-info x)))
5952	(if info
5953	    (string-append "#<procedure " (##sys#lambda-info->string info) ">")
5954	    "#<procedure>") ) ) ) )
5955
5956(define ##sys#record-printers '())
5957
5958(set! chicken.base#record-printer
5959  (lambda (type)
5960    (let ((a (assq type ##sys#record-printers)))
5961      (and a (cdr a)))))
5962
5963(set! chicken.base#set-record-printer!
5964  (lambda (type proc)
5965    (##sys#check-closure proc 'set-record-printer!)
5966    (let ((a (assq type ##sys#record-printers)))
5967      (if a
5968	  (##sys#setslot a 1 proc)
5969	  (set! ##sys#record-printers (cons (cons type proc) ##sys#record-printers)))
5970      (##core#undefined))))
5971
5972;; OBSOLETE can be removed after bootstrapping
5973(set! ##sys#register-record-printer chicken.base#set-record-printer!)
5974
5975(set! chicken.base#record-printer
5976  (getter-with-setter record-printer set-record-printer!))
5977
5978(define (##sys#user-print-hook x readable port)
5979  (let* ((type (##sys#slot x 0))
5980	 (a (assq type ##sys#record-printers))
5981         (name (if (vector? type) (##sys#slot type 0) type)))
5982    (cond (a (handle-exceptions ex
5983		(begin
5984		  (##sys#print "#<Error in printer of record type `" #f port)
5985		  (##sys#print name #f port)
5986		  (if (##sys#structure? ex 'condition)
5987		      (and-let* ((a (member '(exn . message) (##sys#slot ex 2))))
5988			(##sys#print "': " #f port)
5989			(##sys#print (cadr a) #f port)
5990			(##sys#write-char-0 #\> port))
5991		      (##sys#print "'>" #f port)))
5992	       ((##sys#slot a 1) x port)))
5993	  (else
5994	   (##sys#print "#<" #f port)
5995	   (##sys#print name #f port)
5996	   (case type
5997	     ((condition)
5998	      (##sys#print ": " #f port)
5999	      (##sys#print (##sys#slot x 1) #f port) )
6000	     ((thread)
6001	      (##sys#print ": " #f port)
6002	      (##sys#print (##sys#slot x 6) #f port) ) )
6003	   (##sys#write-char-0 #\> port) ) ) ) )
6004
6005(define ##sys#with-print-length-limit
6006  (let ([call-with-current-continuation call-with-current-continuation])
6007    (lambda (limit thunk)
6008      (call-with-current-continuation
6009       (lambda (return)
6010	 (parameterize ((##sys#print-length-limit limit)
6011			(##sys#print-exit return)
6012			(##sys#current-print-length 0))
6013	   (thunk)))))))
6014
6015
6016;;; String ports:
6017;
6018; - Port-slots:
6019;
6020;   Input:
6021;
6022;   10: position (in bytes)
6023;   11: len
6024;   12: input bytevector
6025;
6026;   Output:
6027;
6028;   10: position (in bytes)
6029;   11: limit
6030;   12: output bytevector
6031
6032(define ##sys#string-port-class
6033  (letrec ((check
6034	    (lambda (p n)
6035	      (let* ((position (##sys#slot p 10))
6036		     (limit (##sys#slot p 11))
6037		     (output (##sys#slot p 12))
6038		     (limit2 (fx+ position n)))
6039		(when (fx>= limit2 limit)
6040		  (when (fx>= limit2 maximal-string-length)
6041		    (##sys#error "string buffer full" p) )
6042		  (let* ([limit3 (fxmin maximal-string-length (fx+ limit limit))]
6043			 [buf (##sys#make-bytevector limit3)] )
6044		    (##core#inline "C_copy_memory_with_offset" buf output 0 0 position)
6045		    (##sys#setslot p 12 buf)
6046		    (##sys#setislot p 11 limit3)
6047		    (check p n) ) ) ) ) ) )
6048    (vector
6049     (lambda (p)			; read-char
6050       (let ((position (##sys#slot p 10))
6051             (input (##sys#slot p 12))
6052             (len (##sys#slot p 11)))
6053         (if (fx>= position len)
6054             #!eof
6055             (let ((c (##core#inline "C_utf_decode" input position)))
6056               (##sys#setislot p 10
6057                               (##core#inline "C_utf_advance" input position))
6058               c))))
6059     (lambda (p)			; peek-char
6060       (let ((position (##sys#slot p 10))
6061             (input (##sys#slot p 12))
6062             (len (##sys#slot p 11)))
6063         (if (fx>= position len)
6064             #!eof
6065             (##core#inline "C_utf_decode" input position))))
6066     (lambda (p c)			; write-char
6067       (check p 1)
6068       (let ([position (##sys#slot p 10)]
6069	     [output (##sys#slot p 12)] )
6070         (##sys#setislot p 10 (##core#inline "C_utf_insert" output position c))))
6071     (lambda (p bv from to)			; write-bytevector
6072       (let ((len (fx- to from)))
6073	 (check p len)
6074	 (let* ((position (##sys#slot p 10))
6075	        (output (##sys#slot p 12)))
6076	   (##core#inline "C_copy_memory_with_offset" output bv position from len)
6077	   (##sys#setislot p 10 (fx+ position len)) ) ) )
6078     void ; close
6079     (lambda (p) #f)			; flush-output
6080     (lambda (p) #t)			; u8-ready?
6081     (lambda (p n dest start)		; read-bytevector!
6082       (let* ((pos (##sys#slot p 10))
6083              (input (##sys#slot p 12))
6084	      (n2 (fx- (##sys#slot p 11) pos)))
6085	 (when (or (not n) (fx> n n2)) (set! n n2))
6086	 (##core#inline "C_copy_memory_with_offset" dest input start pos n)
6087	 (##sys#setislot p 10 (fx+ pos n))
6088	 n))
6089     (lambda (p limit)			; read-line
6090       (let* ((pos (##sys#slot p 10))
6091	      (size (##sys#slot p 11))
6092	      (buf (##sys#slot p 12))
6093	      (end (if limit (fx+ pos limit) size)))
6094	 (if (fx>= pos size)
6095	     #!eof
6096	     (receive (next line full-line?)
6097		 (##sys#scan-buffer-line
6098		  buf (if (fx> end size) size end) pos
6099		  (lambda (pos) (values #f pos #f) ) )
6100	       ;; Update row & column position
6101	       (if full-line?
6102		   (begin
6103		     (##sys#setislot p 4 (fx+ (##sys#slot p 4) 1))
6104		     (##sys#setislot p 5 0))
6105		   (##sys#setislot p 5 (fx+ (##sys#slot p 5) (string-length line))))
6106	       (##sys#setislot p 10 next)
6107	       line) ) ) )
6108     (lambda (p)			; read-buffered
6109       (let ((pos (##sys#slot p 10))
6110	     (buf (##sys#slot p 12))
6111	     (len (##sys#slot p 11)) )
6112	 (if (fx>= pos len)
6113	     ""
6114	     (let* ((rest (fx- len pos))
6115                    (buffered (##sys#buffer->string buf pos rest)))
6116	       (##sys#setislot p 10 len)
6117	       buffered))))
6118     (lambda (p) #t)			; char-ready?
6119     )))
6120
6121;; Invokes the eos handler when EOS is reached to get more data.
6122;; The eos-handler is responsible for stopping, either when EOF is hit or
6123;; a user-supplied limit is reached (ie, it's indistinguishable from EOF)
6124(define (##sys#scan-buffer-line buf limit start-pos eos-handler #!optional enc)
6125  (let* ((hold 1024)
6126         (dpos 0)
6127         (line (##sys#make-bytevector hold)))
6128    (define (grow)
6129      (let* ((h2 (fx* hold 2))
6130             (l2 (##sys#make-bytevector h2)))
6131        (##core#inline "C_copy_memory" l2 line dpos)
6132        (set! line l2)
6133        (set! hold h2)))
6134    (define (conc buf from to)
6135      (let ((len (fx- to from)))
6136        (when (fx>= (fx+ dpos len) hold) (grow))
6137        (##core#inline "C_copy_memory_with_offset" line buf dpos from len)
6138        (set! dpos (fx+ dpos len))))
6139    (define (conc1 b)
6140      (when (fx>= (fx+ dpos 1) hold) (grow))
6141      (##core#inline "C_setsubbyte" line dpos b)
6142      (set! dpos (fx+ dpos 1)))
6143    (define (getline)
6144      (if enc
6145          (##sys#buffer->string/encoding line 0 dpos enc)
6146          (##sys#buffer->string line 0 dpos)))
6147    (let loop ((buf buf)
6148               (offset start-pos)
6149               (pos start-pos)
6150               (limit limit))
6151      (cond ((fx= pos limit)
6152             (conc buf offset pos)
6153             (receive (buf offset limit) (eos-handler pos)
6154               (if buf
6155                   (loop buf offset offset limit)
6156                   (values offset (getline) #f))))
6157            (else
6158              (let ((c (##core#inline "C_subbyte" buf pos)))
6159                (cond ((eq? c 10)
6160                       (conc buf offset pos)
6161                       (values (fx+ pos 1) (getline) #t))
6162                      ((and (eq? c 13)	; \r\n -> drop \r from string
6163                            (fx> limit (fx+ pos 1))
6164                            (eq? (##core#inline "C_subbyte" buf (fx+ pos 1)) 10))
6165                       (conc buf offset pos)
6166                       (values (fx+ pos 2) (getline) #t))
6167                      ((and (eq? c 13)	; Edge case (#568): \r{read}[\n|xyz]
6168                            (fx= limit (fx+ pos 1)))
6169                       (conc buf offset pos)
6170                       (receive (buf offset limit) (eos-handler pos)
6171                         (if buf
6172                             (if (eq? (##core#inline "C_subbyte" buf offset) 10)
6173                                 (values (fx+ offset 1) (getline) #t)
6174                                 ;; "Restore" \r we didn't copy, loop w/ new string
6175                                 (begin
6176                                   (conc1 13)
6177                                   (loop buf offset offset limit)))
6178                             (values (fx+ offset 1) (getline) #t))))
6179                      ((eq? c 13)
6180                       (conc buf offset pos)
6181                       (values (fx+ pos 1) (getline) #t))
6182                      (else (loop buf offset (fx+ pos 1) limit)) ) ) ) ) )))
6183
6184(define ##sys#print-to-string
6185  (let ([get-output-string get-output-string]
6186	[open-output-string open-output-string] )
6187    (lambda (xs)
6188      (let ([out (open-output-string)])
6189	(for-each (lambda (x) (##sys#print x #f out)) xs)
6190	(get-output-string out) ) ) ) )
6191
6192(define ##sys#pointer->string
6193  (let ((string-append string-append))
6194    (lambda (x)
6195      (if (##core#inline "C_taggedpointerp" x)
6196	  (string-append
6197	   "#<tagged pointer "
6198	   (##sys#print-to-string
6199	    (let ((tag (##sys#slot x 1)))
6200	      (list (if (pair? tag) (car tag) tag) ) ) )
6201	   " "
6202	   (##sys#number->string (##sys#pointer->address x) 16)
6203	   ">")
6204	  (string-append "#<pointer 0x" (##sys#number->string (##sys#pointer->address x) 16) ">") ) ) ) )
6205
6206
6207;;; Access backtrace:
6208
6209(define-constant +trace-buffer-entry-slot-count+ 5)
6210
6211(set! chicken.base#get-call-chain
6212  (let ((extract
6213	 (foreign-lambda* nonnull-c-string ((scheme-object x)) "C_return((C_char *)x);")))
6214    (lambda (#!optional (start 0) (thread ##sys#current-thread))
6215      (let* ((tbl (foreign-value "C_trace_buffer_size" int))
6216	     ;; 5 slots: "raw" location (for compiled code), "cooked" location (for interpreted code), cooked1, cooked2, thread
6217	     (c +trace-buffer-entry-slot-count+)
6218	     (vec (##sys#make-vector (fx* c tbl) #f))
6219	     (r (##core#inline "C_fetch_trace" start vec))
6220	     (n (if (fixnum? r) r (fx* c tbl)))
6221             (t-id (and thread (##sys#slot thread 14))))
6222	(let loop ((i 0))
6223	  (if (fx>= i n)
6224	      '()
6225	      (let ((t (##sys#slot vec (fx+ i 4)))) ; thread id
6226		(if (or (not t) (not thread) (eq? t-id t))
6227		    (cons (vector
6228			   (or (##sys#slot vec (fx+ i 1)) ; cooked_location
6229			       (extract (##sys#slot vec i))) ; raw_location
6230			   (##sys#slot vec (fx+ i 2))   ; cooked1
6231			   (##sys#slot vec (fx+ i 3)))  ; cooked2
6232			  (loop (fx+ i c)))
6233		    (loop (fx+ i c))))))))))
6234
6235(define (##sys#really-print-call-chain port chain header)
6236  (when (pair? chain)
6237    (##sys#print header #f port)
6238    (for-each
6239     (lambda (info)
6240       (let* ((more1 (##sys#slot info 1)) ; cooked1 (expr/form)
6241	      (more2 (##sys#slot info 2)) ; cooked2 (cntr/frameinfo)
6242	      (fi (##sys#structure? more2 'frameinfo)))
6243	 (##sys#print "\n\t" #f port)
6244	 (##sys#print (##sys#slot info 0) #f port) ; raw (mode)
6245	 (##sys#print "\t  " #f port)
6246	 (when (and more2 (if fi (##sys#slot more2 1)))
6247	   (##sys#write-char-0 #\[ port)
6248	   (##sys#print
6249	    (if fi
6250		(##sys#slot more2 1)	; cntr
6251		more2)
6252	    #f port)
6253	   (##sys#print "] " #f port))
6254	 (when more1
6255	   (##sys#with-print-length-limit
6256	    100
6257	    (lambda ()
6258	      (##sys#print more1 #t port))))))
6259     chain)
6260    (##sys#print "\t<--\n" #f port)))
6261
6262(set! chicken.base#print-call-chain
6263  (lambda (#!optional (port ##sys#standard-output) (start 0)
6264		      (thread ##sys#current-thread)
6265		      (header "\n\tCall history:\n"))
6266    (##sys#check-output-port port #t 'print-call-chain)
6267    (##sys#check-fixnum start 'print-call-chain)
6268    (##sys#check-string header 'print-call-chain)
6269    (##sys#really-print-call-chain port (get-call-chain start thread) header)))
6270
6271
6272;;; Interrupt handling:
6273
6274(define (##sys#user-interrupt-hook)
6275  (define (break) (##sys#signal-hook #:user-interrupt #f))
6276  (if (eq? ##sys#current-thread ##sys#primordial-thread)
6277      (break)
6278      (##sys#setslot ##sys#primordial-thread 1 break) ) )
6279
6280
6281;;; Default handlers
6282
6283(define-foreign-variable _ex_software int "EX_SOFTWARE")
6284
6285(define exit-in-progress #f)
6286
6287(define (cleanup-before-exit)
6288  (set! exit-in-progress #t)
6289  (##core#inline "C_flush_all_files" #f)
6290  (when (##core#inline "C_i_dump_heap_on_exitp")
6291    (##sys#print "\n" #f ##sys#standard-error)
6292    (##sys#dump-heap-state))
6293  (when (##core#inline "C_i_profilingp")
6294    (##core#inline "C_i_dump_statistical_profile"))
6295  (let loop ()
6296    (let ((tasks chicken.base#cleanup-tasks))
6297      (set! chicken.base#cleanup-tasks '())
6298      (unless (null? tasks)
6299	(for-each (lambda (t) (t)) tasks)
6300	(loop))))
6301  (when (fx> (##sys#slot ##sys#pending-finalizers 0) 0)
6302    (##sys#run-pending-finalizers #f))
6303  (when (fx> (##core#inline "C_i_live_finalizer_count") 0)
6304    (when (##sys#debug-mode?)
6305      (##sys#print "[debug] forcing finalizers...\n" #f ##sys#standard-error))
6306    (when (chicken.gc#force-finalizers)
6307      (##sys#force-finalizers))))
6308
6309(set! chicken.base#exit-handler
6310  (make-parameter
6311   (lambda (#!optional (code 0))
6312     (##sys#check-fixnum code)
6313     (cond (exit-in-progress
6314	    (##sys#warn "\"exit\" called while processing on-exit tasks"))
6315	   (else
6316	    (cleanup-before-exit)
6317	    (##core#inline "C_exit_runtime" code))))))
6318
6319(set! chicken.base#implicit-exit-handler
6320  (make-parameter
6321   (lambda ()
6322     (cleanup-before-exit))))
6323
6324(define ##sys#reset-handler ; Exposed by chicken.repl
6325  (make-parameter
6326   (lambda ()
6327     ((exit-handler) _ex_software))))
6328
6329(define (##sys#dbg-hook . args)
6330  (##core#inline "C_dbg_hook" #f)
6331  (##core#undefined))
6332
6333
6334;;; Condition handling:
6335
6336(module chicken.condition
6337    ;; NOTE: We don't emit the import lib.  Due to syntax exports, it
6338    ;; has to be a hardcoded primitive module.
6339    (abort signal current-exception-handler
6340     print-error-message with-exception-handler
6341
6342     ;; [syntax] condition-case handle-exceptions
6343
6344     ;; Condition object manipulation
6345     make-property-condition make-composite-condition
6346     condition condition? condition->list condition-predicate
6347     condition-property-accessor get-condition-property)
6348
6349(import scheme chicken.base chicken.fixnum chicken.foreign)
6350(import chicken.internal.syntax)
6351(import (only (scheme base) make-parameter open-output-string get-output-string))
6352
6353(define (##sys#signal-hook/errno mode errno msg . args)
6354  (##core#inline "C_dbg_hook" #f)
6355  (##core#inline "signal_debug_event" mode msg args)
6356  (case mode
6357    [(#:user-interrupt)
6358     (abort
6359      (##sys#make-structure
6360       'condition
6361       '(user-interrupt)
6362       '() ) ) ]
6363    [(#:warning #:notice)
6364     (##sys#print
6365      (if (eq? mode #:warning) "\nWarning: " "\nNote: ")
6366      #f ##sys#standard-error)
6367     (##sys#print msg #f ##sys#standard-error)
6368     (if (or (null? args) (fx> (length args) 1))
6369	 (##sys#write-char-0 #\newline ##sys#standard-error)
6370	 (##sys#print ": " #f ##sys#standard-error))
6371     (for-each
6372      (lambda (x)
6373	(##sys#with-print-length-limit
6374	 400
6375	 (lambda ()
6376	   (##sys#print x #t ##sys#standard-error)
6377	   (##sys#write-char-0 #\newline ##sys#standard-error))))
6378      args)
6379     (##sys#flush-output ##sys#standard-error)]
6380    (else
6381     (when (and (symbol? msg) (null? args))
6382       (set! msg (symbol->string msg)))
6383     (let* ([hasloc (and (or (not msg) (symbol? msg)) (pair? args))]
6384	    [loc (and hasloc msg)]
6385	    [msg (if hasloc (##sys#slot args 0) msg)]
6386	    [args (if hasloc (##sys#slot args 1) args)] )
6387       (abort
6388	(##sys#make-structure
6389	 'condition
6390	 (case mode
6391	   [(#:type-error)		'(exn type)]
6392	   [(#:syntax-error)		'(exn syntax)]
6393	   [(#:bounds-error)		'(exn bounds)]
6394	   [(#:arithmetic-error)	'(exn arithmetic)]
6395	   [(#:file-error)		'(exn i/o file)]
6396	   [(#:runtime-error)		'(exn runtime)]
6397	   [(#:process-error)		'(exn process)]
6398	   [(#:network-error)		'(exn i/o net)]
6399	   [(#:network-timeout-error)   '(exn i/o net timeout)]
6400	   [(#:limit-error)		'(exn runtime limit)]
6401	   [(#:arity-error)		'(exn arity)]
6402	   [(#:access-error)		'(exn access)]
6403	   [(#:domain-error)		'(exn domain)]
6404	   ((#:memory-error)            '(exn memory))
6405	   [else			'(exn)] )
6406         (let ((props
6407                (list '(exn . message) msg
6408                      '(exn . arguments) args
6409                      '(exn . call-chain) (get-call-chain)
6410                      '(exn . location) loc)))
6411           (if errno
6412               (cons '(exn . errno) (cons errno props))
6413               props))))))))
6414
6415(define (##sys#signal-hook mode msg . args)
6416  (if (pair? args)
6417      (apply ##sys#signal-hook/errno mode #f msg args)
6418      (##sys#signal-hook/errno mode #f msg)))
6419
6420(define (abort x)
6421  (##sys#current-exception-handler x)
6422  (abort
6423   (##sys#make-structure
6424    'condition
6425    '(exn)
6426    (list '(exn . message) "exception handler returned"
6427	  '(exn . arguments) '()
6428	  '(exn . location) #f) ) ) )
6429
6430(define (signal x)
6431  (##sys#current-exception-handler x) )
6432
6433(define ##sys#error-handler
6434  (make-parameter
6435   (let ([string-append string-append])
6436     (lambda (msg . args)
6437       (##sys#error-handler (lambda args (##core#inline "C_halt" "error in error")))
6438       (cond ((not (foreign-value "C_gui_mode" bool))
6439	      (##sys#print "\nError" #f ##sys#standard-error)
6440	      (when msg
6441		(##sys#print ": " #f ##sys#standard-error)
6442		(##sys#print msg #f ##sys#standard-error))
6443	      (##sys#with-print-length-limit
6444	       400
6445	       (lambda ()
6446		 (cond [(fx= 1 (length args))
6447			(##sys#print ": " #f ##sys#standard-error)
6448			(##sys#print (##sys#slot args 0) #t ##sys#standard-error)]
6449		       [else
6450			(##sys#for-each
6451			 (lambda (x)
6452			   (##sys#print #\newline #f ##sys#standard-error)
6453			   (##sys#print x #t ##sys#standard-error))
6454			 args)])))
6455	      (##sys#print #\newline #f ##sys#standard-error)
6456	      (print-call-chain ##sys#standard-error)
6457	      (##core#inline "C_halt" #f))
6458	     (else
6459	      (let ((out (open-output-string)))
6460		(when msg (##sys#print msg #f out))
6461		(##sys#print #\newline #f out)
6462		(##sys#for-each (lambda (x) (##sys#print x #t out) (##sys#print #\newline #f out)) args)
6463		(##core#inline "C_halt" (get-output-string out)))))))))
6464
6465
6466(define ##sys#last-exception #f)	; used in csi for ,exn command
6467
6468(define ##sys#current-exception-handler
6469  ;; Exception-handler for the primordial thread:
6470  (let ((string-append string-append))
6471    (lambda (c)
6472      (when (##sys#structure? c 'condition)
6473	(set! ##sys#last-exception c)
6474	(let ((kinds (##sys#slot c 1)))
6475	  (cond ((memq 'exn kinds)
6476		 (let* ((props (##sys#slot c 2))
6477			(msga (member '(exn . message) props))
6478			(argsa (member '(exn . arguments) props))
6479			(loca (member '(exn . location) props)) )
6480		   (apply
6481		    (##sys#error-handler)
6482		    (if msga
6483			(let ((msg (cadr msga))
6484			      (loc (and loca (cadr loca))) )
6485			  (if (and loc (symbol? loc))
6486			      (string-append
6487			       "(" (##sys#symbol->string/shared loc) ") "
6488			       (cond ((symbol? msg) (##sys#slot msg 1))
6489				     ((string? msg) msg)
6490				     (else "") ) ) ; Hm...
6491			      msg) )
6492			"<exn: has no `message' property>")
6493		    (if argsa
6494			(cadr argsa)
6495			'() ) )
6496		   ;; in case error-handler returns, which shouldn't happen:
6497		   ((##sys#reset-handler)) ) )
6498		((eq? 'user-interrupt (##sys#slot kinds 0))
6499		 (##sys#print "\n*** user interrupt ***\n" #f ##sys#standard-error)
6500		 ((##sys#reset-handler)) )
6501		((eq? 'uncaught-exception (##sys#slot kinds 0))
6502		 ((##sys#error-handler)
6503		  "uncaught exception"
6504		  (cadr (member '(uncaught-exception . reason) (##sys#slot c 2))) )
6505		 ((##sys#reset-handler)) ) ) ) )
6506      (abort
6507       (##sys#make-structure
6508	'condition
6509	'(uncaught-exception)
6510	(list '(uncaught-exception . reason) c)) ) ) ) )
6511
6512(define (with-exception-handler handler thunk)
6513  (let ([oldh ##sys#current-exception-handler])
6514    (##sys#dynamic-wind
6515      (lambda () (set! ##sys#current-exception-handler handler))
6516      thunk
6517      (lambda () (set! ##sys#current-exception-handler oldh)) ) ) )
6518
6519;; TODO: Make this a proper parameter
6520(define (current-exception-handler . args)
6521  (if (null? args)
6522      ##sys#current-exception-handler
6523      (let ((proc (car args)))
6524	(##sys#check-closure proc 'current-exception-handler)
6525	(let-optionals (cdr args) ((convert? #t) (set? #t))
6526	  (when set? (set! ##sys#current-exception-handler proc)))
6527	proc)))
6528
6529;;; Condition object manipulation
6530
6531(define (prop-list->kind-prefixed-prop-list loc kind plist)
6532  (let loop ((props plist))
6533    (cond ((null? props) '())
6534	  ((or (not (pair? props)) (not (pair? (cdr props))))
6535	   (##sys#signal-hook
6536	    #:type-error loc "argument is not an even property list" plist))
6537	  (else (cons (cons kind (car props))
6538		      (cons (cadr props)
6539			    (loop (cddr props))))))))
6540
6541(define (make-property-condition kind . props)
6542  (##sys#make-structure
6543   'condition (list kind)
6544   (prop-list->kind-prefixed-prop-list
6545    'make-property-condition kind props)))
6546
6547(define (make-composite-condition c1 . conds)
6548  (let ([conds (cons c1 conds)])
6549    (for-each (lambda (c) (##sys#check-structure c 'condition 'make-composite-condition)) conds)
6550    (##sys#make-structure
6551     'condition
6552     (apply ##sys#append (map (lambda (c) (##sys#slot c 1)) conds))
6553     (apply ##sys#append (map (lambda (c) (##sys#slot c 2)) conds)) ) ) )
6554
6555(define (condition arg1 . args)
6556  (let* ((args (cons arg1 args))
6557	 (keys (apply ##sys#append
6558		      (map (lambda (c)
6559			     (prop-list->kind-prefixed-prop-list
6560			      'condition (car c) (cdr c)))
6561			     args))))
6562    (##sys#make-structure 'condition (map car args) keys)))
6563
6564(define (condition? x) (##sys#structure? x 'condition))
6565
6566(define (condition->list x)
6567  (unless (condition? x)
6568    (##sys#signal-hook
6569     #:type-error 'condition->list
6570     "argument is not a condition object" x))
6571  (map (lambda (k)
6572	 (cons k (let loop ((props (##sys#slot x 2)))
6573		   (cond ((null? props) '())
6574			 ((eq? (caar props) k)
6575			  (cons (cdar props)
6576				(cons (cadr props)
6577				      (loop (cddr props)))))
6578			 (else
6579			  (loop (cddr props)))))))
6580       (##sys#slot x 1)))
6581
6582(define (condition-predicate kind)
6583  (lambda (c)
6584    (and (condition? c)
6585         (if (memv kind (##sys#slot c 1)) #t #f)) ) )
6586
6587(define (condition-property-accessor kind prop . err-def)
6588  (let ((err? (null? err-def))
6589	(k+p (cons kind prop)) )
6590    (lambda (c)
6591      (##sys#check-structure c 'condition)
6592      (and (memv kind (##sys#slot c 1))
6593	   (let ([a (member k+p (##sys#slot c 2))])
6594	     (cond [a (cadr a)]
6595		   [err? (##sys#signal-hook
6596			  #:type-error 'condition-property-accessor
6597			  "condition has no such property" prop) ]
6598		   [else (car err-def)] ) ) ) ) ) )
6599
6600(define get-condition-property
6601  (lambda (c kind prop . err-def)
6602    ((apply condition-property-accessor kind prop err-def) c)))
6603
6604
6605;;; Convenient error printing:
6606
6607(define print-error-message
6608  (let* ((display display)
6609	 (newline newline)
6610	 (write write)
6611	 (string-append string-append)
6612	 (errmsg (condition-property-accessor 'exn 'message #f))
6613	 (errloc (condition-property-accessor 'exn 'location #f))
6614	 (errargs (condition-property-accessor 'exn 'arguments #f))
6615	 (writeargs
6616	  (lambda (args port)
6617	    (##sys#for-each
6618	     (lambda (x)
6619	       (##sys#with-print-length-limit 80 (lambda () (write x port)))
6620	       (newline port) )
6621	     args) ) ) )
6622    (lambda (ex . args)
6623      (let-optionals args ((port ##sys#standard-output)
6624			   (header "Error"))
6625	(##sys#check-output-port port #t 'print-error-message)
6626	(newline port)
6627	(display header port)
6628	(cond ((and (not (##sys#immediate? ex)) (eq? 'condition (##sys#slot ex 0)))
6629	       (cond ((errmsg ex) =>
6630		      (lambda (msg)
6631			(display ": " port)
6632			(let ((loc (errloc ex)))
6633			  (when (and loc (symbol? loc))
6634			    (display (string-append "(" (##sys#symbol->string/shared loc) ") ") port) ) )
6635			(display msg port) ) )
6636		     (else
6637		      (let ((kinds (##sys#slot ex 1)))
6638			(if (equal? '(user-interrupt) kinds)
6639			    (display ": *** user interrupt ***" port)
6640			    (begin
6641			      (display ": <condition> " port)
6642			      (display (##sys#slot ex 1) port) ) ) ) ) )
6643	       (let ((args (errargs ex)))
6644		 (cond
6645		   ((not args))
6646		   ((fx= 1 (length args))
6647		    (display ": " port)
6648		    (writeargs args port))
6649		   (else
6650		    (newline port)
6651		    (writeargs args port)))))
6652	      ((string? ex)
6653	       (display ": " port)
6654	       (display ex port)
6655	       (newline port))
6656	      (else
6657	       (display ": uncaught exception: " port)
6658	       (writeargs (list ex) port) ) ) ) ) ) )
6659
6660
6661;;; Show exception message and backtrace as warning
6662;;; (used for threads and finalizers)
6663
6664(define ##sys#show-exception-warning
6665  (let ((print-error-message print-error-message)
6666	(display display)
6667	(write-char write-char)
6668	(print-call-chain print-call-chain)
6669	(open-output-string open-output-string)
6670	(get-output-string get-output-string) )
6671    (lambda (exn cause #!optional (thread ##sys#current-thread))
6672      (when ##sys#warnings-enabled
6673	(let ((o (open-output-string)))
6674	  (display "Warning" o)
6675	  (when thread
6676	    (display " (" o)
6677	    (display thread o)
6678	    (write-char #\) o))
6679	  (display ": " o)
6680	  (display cause o)
6681	  (print-error-message exn ##sys#standard-error (get-output-string o))
6682	  (print-call-chain ##sys#standard-error 0 thread) ) ))))
6683
6684
6685;;; Error hook (called by runtime-system):
6686
6687(define ##sys#error-hook
6688  (let ([string-append string-append])
6689    (lambda (code loc . args)
6690      (case code
6691	((1) (let ([c (car args)]
6692		   [n (cadr args)]
6693		   [fn (caddr args)] )
6694	       (apply
6695		##sys#signal-hook
6696		#:arity-error loc
6697		(string-append "bad argument count - received " (##sys#number->string n) " but expected "
6698			       (##sys#number->string c) )
6699		(if fn (list fn) '())) ) )
6700	((2) (let ([c (car args)]
6701		   [n (cadr args)]
6702		   [fn (caddr args)] )
6703	       (apply
6704		##sys#signal-hook
6705		#:arity-error loc
6706		(string-append "too few arguments - received " (##sys#number->string n) " but expected "
6707			       (##sys#number->string c) )
6708		(if fn (list fn) '()))))
6709	((3) (apply ##sys#signal-hook #:type-error loc "bad argument type" args))
6710	((4) (apply ##sys#signal-hook #:runtime-error loc "unbound variable" args))
6711	((5) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a keyword" args))
6712	((6) (apply ##sys#signal-hook #:limit-error loc "out of memory" args))
6713	((7) (apply ##sys#signal-hook #:arithmetic-error loc "division by zero" args))
6714	((8) (apply ##sys#signal-hook #:bounds-error loc "out of range" args))
6715	((9) (apply ##sys#signal-hook #:type-error loc "call of non-procedure" args))
6716	((10) (apply ##sys#signal-hook #:arity-error loc "continuation cannot receive multiple values" args))
6717	((11) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a non-cyclic list" args))
6718	((12) (apply ##sys#signal-hook #:limit-error loc "recursion too deep" args))
6719	((13) (apply ##sys#signal-hook #:type-error loc "inexact number cannot be represented as an exact number" args))
6720	((14) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a proper list" args))
6721	((15) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a fixnum" args))
6722	((16) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a number" args))
6723	((17) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a string" args))
6724	((18) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a pair" args))
6725	((19) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a list" args))
6726	((20) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a character" args))
6727	((21) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a vector" args))
6728	((22) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a symbol" args))
6729	((23) (apply ##sys#signal-hook #:limit-error loc "stack overflow" args))
6730	((24) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a structure of the required type" args))
6731	((25) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a bytevector" args))
6732	((26) (apply ##sys#signal-hook #:type-error loc "locative refers to reclaimed object" args))
6733	((27) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a block object" args))
6734	((28) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a number vector" args))
6735	((29) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an integer" args))
6736	((30) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an unsigned integer" args))
6737	((31) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a pointer" args))
6738	((32) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a tagged pointer" args))
6739	((33) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a flonum" args))
6740	((34) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a procedure" args))
6741	((35) (apply ##sys#signal-hook #:type-error loc "bad argument type - invalid base" args))
6742	((36) (apply ##sys#signal-hook #:limit-error loc "recursion too deep or circular data encountered" args))
6743	((37) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a boolean" args))
6744	((38) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a locative" args))
6745	((39) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a port" args))
6746	((40) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a port of the correct type" args))
6747	((41) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an input-port" args))
6748	((42) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an output-port" args))
6749	((43) (apply ##sys#signal-hook #:file-error loc "port already closed" args))
6750	((44) (apply ##sys#signal-hook #:type-error loc "cannot represent string with NUL bytes as C string" args))
6751	((45) (apply ##sys#signal-hook #:memory-error loc "segmentation violation" args))
6752	((46) (apply ##sys#signal-hook #:arithmetic-error loc "floating-point exception" args))
6753	((47) (apply ##sys#signal-hook #:runtime-error loc "illegal instruction" args))
6754	((48) (apply ##sys#signal-hook #:memory-error loc "bus error" args))
6755	((49) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an exact number" args))
6756	((50) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an inexact number" args))
6757	((51) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a real" args))
6758	((52) (apply ##sys#signal-hook #:type-error loc "bad argument type - complex number has no ordering" args))
6759	((53) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an exact integer" args))
6760	((54) (apply ##sys#signal-hook #:type-error loc "number does not fit in foreign type" args))
6761	((55) (apply ##sys#signal-hook #:type-error loc "cannot compute absolute value of complex number" args))
6762	((56) (let ((c (car args))
6763		    (n (cadr args))
6764		    (fn (caddr args)))
6765	        (apply
6766		 ##sys#signal-hook
6767		 #:bounds-error loc
6768		 (string-append "attempted rest argument access at index " (##sys#number->string n)
6769                                " but rest list length is " (##sys#number->string c) )
6770		 (if fn (list fn) '()))))
6771        ((57) (apply ##sys#signal-hook #:type-error loc "string contains invalid UTF-8 sequence" args))
6772        ((58) (apply ##sys#signal-hook #:type-error loc "bad argument type - numeric value exceeds range" args))
6773	(else (apply ##sys#signal-hook #:runtime-error loc "unknown internal error" args)) ) ) ) )
6774
6775) ; chicken.condition
6776
6777(import chicken.condition)
6778
6779;;; R7RS exceptions
6780
6781(define ##sys#r7rs-exn-handlers
6782  (make-parameter
6783    (let ((lst (list ##sys#current-exception-handler)))
6784      (set-cdr! lst lst)
6785      lst)))
6786
6787(define scheme#with-exception-handler
6788  (let ((eh ##sys#r7rs-exn-handlers))
6789    (lambda (handler thunk)
6790      (dynamic-wind
6791       (lambda ()
6792         ;; We might be interoperating with srfi-12 handlers set by intermediate
6793         ;; non-R7RS code, so check if a new handler was set in the meanwhile.
6794         (unless (eq? (car (eh)) ##sys#current-exception-handler)
6795           (eh (cons ##sys#current-exception-handler (eh))))
6796         (eh (cons handler (eh)))
6797         (set! ##sys#current-exception-handler handler))
6798       thunk
6799       (lambda ()
6800         (eh (cdr (eh)))
6801         (set! ##sys#current-exception-handler (car (eh))))))))
6802
6803(define scheme#raise
6804  (let ((eh ##sys#r7rs-exn-handlers))
6805    (lambda (obj)
6806      (scheme#with-exception-handler
6807        (cadr (eh))
6808        (lambda ()
6809          ((cadr (eh)) obj)
6810          ((car (eh))
6811           (make-property-condition
6812            'exn
6813            'message "exception handler returned"
6814            'arguments '()
6815            'location #f)))))))
6816
6817(define scheme#raise-continuable
6818  (let ((eh ##sys#r7rs-exn-handlers))
6819     (lambda (obj)
6820       (scheme#with-exception-handler
6821        (cadr (eh))
6822        (lambda ()
6823          ((cadr (eh)) obj))))))
6824
6825(define scheme#error-object? condition?)
6826(define scheme#error-object-message (condition-property-accessor 'exn 'message))
6827(define scheme#error-object-irritants (condition-property-accessor 'exn 'arguments))
6828
6829(define scheme#read-error?)
6830(define scheme#file-error?)
6831
6832(let ((exn?    (condition-predicate 'exn))
6833      (i/o?    (condition-predicate 'i/o))
6834      (file?   (condition-predicate 'file))
6835      (syntax? (condition-predicate 'syntax)))
6836  (set! scheme#read-error?
6837    (lambda (obj)
6838      (and (exn? obj)
6839           (or (i/o? obj) ; XXX Not fine-grained enough.
6840               (syntax? obj)))))
6841  (set! scheme#file-error?
6842    (lambda (obj)
6843      (and (exn? obj)
6844           (file? obj)))))
6845
6846
6847;;; Miscellaneous low-level routines:
6848
6849(define (##sys#structure? x s) (##core#inline "C_i_structurep" x s))
6850(define (##sys#generic-structure? x) (##core#inline "C_structurep" x))
6851(define (##sys#slot x i) (##core#inline "C_slot" x i))
6852(define (##sys#size x) (##core#inline "C_block_size" x))
6853(define ##sys#make-pointer (##core#primitive "C_make_pointer"))
6854(define ##sys#make-tagged-pointer (##core#primitive "C_make_tagged_pointer"))
6855(define (##sys#pointer? x) (##core#inline "C_anypointerp" x))
6856(define (##sys#set-pointer-address! ptr addr) (##core#inline "C_update_pointer" addr ptr))
6857(define (##sys#bytevector? x) (##core#inline "C_i_bytevectorp" x))
6858(define (##sys#string->pbytevector s) (##core#inline "C_string_to_pbytevector" s))
6859(define (##sys#permanent? x) (##core#inline "C_permanentp" x))
6860(define (##sys#block-address x) (##core#inline_allocate ("C_block_address" 6) x))
6861(define (##sys#locative? x) (##core#inline "C_locativep" x))
6862
6863(define (##sys#srfi-4-vector? x)
6864  (or (##core#inline "C_i_srfi_4_vectorp" x)
6865      (and (##core#inline "C_blockp" x)
6866           (##core#inline "C_structurep" x)
6867           (let ((t (##sys#slot x 0)))
6868             (or (eq? t 'c64vector) (eq? t 'c128vector))))))
6869
6870(define (##sys#null-pointer)
6871  (let ([ptr (##sys#make-pointer)])
6872    (##core#inline "C_update_pointer" 0 ptr)
6873    ptr) )
6874
6875(define (##sys#null-pointer? x)
6876  (eq? 0 (##sys#pointer->address x)) )
6877
6878(define (##sys#address->pointer addr)
6879  (let ([ptr (##sys#make-pointer)])
6880    (##core#inline "C_update_pointer" addr ptr)
6881    ptr) )
6882
6883(define (##sys#pointer->address ptr)
6884  ;;XXX '6' is platform dependent!
6885  (##core#inline_allocate ("C_a_unsigned_int_to_num" 6) (##sys#slot ptr 0)) )
6886
6887(define (##sys#make-c-string str #!optional loc)
6888  (let ((bv (##sys#slot str 0)))
6889    (if (fx= (##core#inline "C_asciiz_strlen" bv) (fx- (##sys#size bv) 1))
6890        bv
6891        (##sys#error-hook (foreign-value "C_ASCIIZ_REPRESENTATION_ERROR" int)
6892                          loc str))) )
6893
6894(define ##sys#peek-signed-integer (##core#primitive "C_peek_signed_integer"))
6895(define ##sys#peek-unsigned-integer (##core#primitive "C_peek_unsigned_integer"))
6896(define (##sys#peek-fixnum b i) (##core#inline "C_peek_fixnum" b i))
6897(define (##sys#peek-byte ptr i) (##core#inline "C_peek_byte" ptr i))
6898
6899(define (##sys#vector->structure! vec) (##core#inline "C_vector_to_structure" vec))
6900
6901(define (##sys#peek-double b i)
6902  (##core#inline_allocate ("C_a_f64peek" 4) b i))
6903
6904(define (##sys#peek-c-string b i)
6905  (and (not (##sys#null-pointer? b))
6906       (##sys#peek-nonnull-c-string b i)))
6907
6908(define (##sys#peek-nonnull-c-string b i)
6909  (let* ([len (##core#inline "C_fetch_c_strlen" b i)]
6910	 [bv (##sys#make-bytevector (fx+ len 1) 0)] )
6911    (##core#inline "C_peek_c_string" b i bv len)
6912    (##sys#buffer->string! bv len)))
6913
6914(define (##sys#peek-and-free-c-string b i)
6915  (let ((str (##sys#peek-c-string b i)))
6916    (##core#inline "C_free_mptr" b i)
6917    str))
6918
6919(define (##sys#peek-and-free-nonnull-c-string b i)
6920  (let ((str (##sys#peek-nonnull-c-string b i)))
6921    (##core#inline "C_free_mptr" b i)
6922    str))
6923
6924(define (##sys#poke-c-string b i s)
6925  (##core#inline "C_poke_c_string" b i (##sys#make-c-string s) s) )
6926
6927(define (##sys#poke-integer b i n) (##core#inline "C_poke_integer" b i n))
6928(define (##sys#poke-double b i n) (##core#inline "C_poke_double" b i n))
6929
6930(define ##sys#peek-c-string-list
6931  (let ((fetch (foreign-lambda c-string "C_peek_c_string_at" c-pointer int)))
6932    (lambda (ptr n)
6933      (let loop ((i 0))
6934	(if (and n (fx>= i n))
6935	    '()
6936	    (let ((s (fetch ptr i)))
6937	      (if s
6938		  (cons s (loop (fx+ i 1)))
6939		  '() ) ) ) ) ) ) )
6940
6941(define ##sys#peek-and-free-c-string-list
6942  (let ((fetch (foreign-lambda c-string "C_peek_c_string_at" c-pointer int))
6943	(free (foreign-lambda void "C_free" c-pointer)))
6944    (lambda (ptr n)
6945      (let ((lst (let loop ((i 0))
6946		   (if (and n (fx>= i n))
6947		       '()
6948		       (let ((s (fetch ptr i)))
6949			 (cond (s
6950				(##core#inline "C_free_sptr" ptr i)
6951				(cons s (loop (fx+ i 1))) )
6952			       (else '() ) ) ) ) ) ) )
6953	(free ptr)
6954	lst) ) ) )
6955
6956(define (##sys#vector->closure! vec addr)
6957  (##core#inline "C_vector_to_closure" vec)
6958  (##core#inline "C_update_pointer" addr vec) )
6959
6960(define (##sys#symbol-has-toplevel-binding? s)
6961  (##core#inline "C_boundp" s))
6962
6963(define (##sys#block-pointer x)
6964  (let ([ptr (##sys#make-pointer)])
6965    (##core#inline "C_pointer_to_block" ptr x)
6966    ptr) )
6967
6968
6969;;; Support routines for foreign-function calling:
6970
6971(define (##sys#foreign-char-argument x) (##core#inline "C_i_foreign_char_argumentp" x))
6972(define (##sys#foreign-fixnum-argument x) (##core#inline "C_i_foreign_fixnum_argumentp" x))
6973(define (##sys#foreign-flonum-argument x) (##core#inline "C_i_foreign_flonum_argumentp" x))
6974(define (##sys#foreign-block-argument x) (##core#inline "C_i_foreign_block_argumentp" x))
6975
6976(define (##sys#foreign-cplxnum-argument x)
6977  (if (##core#inline "C_i_numberp" x)
6978	  (##core#inline_allocate ("C_a_i_exact_to_inexact" 12) x)
6979   	  (##sys#signal-hook
6980    	#:type-error #f "bad argument type - not a complex number"
6981	    x)))
6982
6983(define (##sys#foreign-struct-wrapper-argument t x)
6984  (##core#inline "C_i_foreign_struct_wrapper_argumentp" t x))
6985
6986(define (##sys#foreign-string-argument x) (##core#inline "C_i_foreign_string_argumentp" x))
6987(define (##sys#foreign-symbol-argument x) (##core#inline "C_i_foreign_symbol_argumentp" x))
6988(define (##sys#foreign-pointer-argument x) (##core#inline "C_i_foreign_pointer_argumentp" x))
6989(define (##sys#foreign-tagged-pointer-argument x tx) (##core#inline "C_i_foreign_tagged_pointer_argumentp" x tx))
6990
6991(define (##sys#foreign-ranged-integer-argument obj size)
6992  (##core#inline "C_i_foreign_ranged_integer_argumentp" obj size))
6993(define (##sys#foreign-unsigned-ranged-integer-argument obj size)
6994  (##core#inline "C_i_foreign_unsigned_ranged_integer_argumentp" obj size))
6995
6996(define (##sys#wrap-struct type rec)
6997  (##sys#setslot rec 0 type)
6998  rec)
6999
7000;;; Low-level threading interface:
7001
7002(define ##sys#default-thread-quantum 10000)
7003
7004(define (##sys#default-exception-handler arg)
7005  (##core#inline "C_halt" "internal error: default exception handler shouldn't be called!") )
7006
7007(define (##sys#make-thread thunk state name q)
7008  (##sys#make-structure
7009   'thread
7010   thunk				; #1 thunk
7011   #f					; #2 result list
7012   state				; #3 state
7013   #f					; #4 block-timeout
7014   (vector				; #5 state buffer
7015    ##sys#dynamic-winds
7016    ##sys#standard-input
7017    ##sys#standard-output
7018    ##sys#standard-error
7019    ##sys#default-exception-handler
7020    (##sys#vector-resize ##sys#current-parameter-vector
7021			 (##sys#size ##sys#current-parameter-vector) #f) )
7022   name					; #6 name
7023   (##core#undefined)			; #7 end-exception
7024   '()					; #8 owned mutexes
7025   q					; #9 quantum
7026   (##core#undefined)			; #10 specific
7027   #f					; #11 block object (type depends on blocking type)
7028   '()					; #12 recipients
7029   #f					; #13 unblocked by timeout?
7030   (cons #f #f)))            		; #14 ID (just needs to be unique)
7031
7032(define ##sys#primordial-thread
7033  (##sys#make-thread #f 'running 'primordial ##sys#default-thread-quantum))
7034
7035(define ##sys#current-thread ##sys#primordial-thread)
7036
7037(define (##sys#make-mutex id owner)
7038  (##sys#make-structure
7039   'mutex
7040   id					; #1 name
7041   owner				; #2 thread or #f
7042   '()					; #3 list of waiting threads
7043   #f					; #4 abandoned
7044   #f					; #5 locked
7045   (##core#undefined) ) )		; #6 specific
7046
7047(define (##sys#schedule) ((##sys#slot ##sys#current-thread 1)))
7048
7049(define (##sys#thread-yield!)
7050  (##sys#call-with-current-continuation
7051   (lambda (return)
7052     (let ((ct ##sys#current-thread))
7053       (##sys#setslot ct 1 (lambda () (return (##core#undefined))))
7054       (##sys#schedule) ) ) ) )
7055
7056(define (##sys#kill-other-threads thunk)
7057  (thunk))	     ; does nothing, will be modified by scheduler.scm
7058
7059;; these two procedures should redefined in thread APIs (e.g. srfi-18):
7060(define (##sys#resume-thread-on-event t) #f)
7061
7062(define (##sys#suspend-thread-on-event t)
7063  ;; wait until signal handler fires. If we are only waiting for a finalizer,
7064  ;; then this will wait forever:
7065  (##sys#sleep-until-interrupt))
7066
7067(define (##sys#sleep-until-interrupt)
7068  (##core#inline "C_i_sleep_until_interrupt" 100)
7069  (##sys#dispatch-interrupt (lambda _ #f)))
7070
7071
7072;;; event queues (for signals and finalizers)
7073
7074(define (##sys#make-event-queue)
7075  (##sys#make-structure 'event-queue
7076                        '() ; head
7077                        '() ; tail
7078                        #f)) ; suspended thread
7079
7080(define (##sys#add-event-to-queue! q e)
7081  (let ((h (##sys#slot q 1))
7082        (t (##sys#slot q 2))
7083        (item (cons e '())))
7084    (if (null? h)
7085        (##sys#setslot q 1 item)
7086        (##sys#setslot t 1 item))
7087    (##sys#setslot q 2 item)
7088    (let ((st (##sys#slot q 3))) ; thread suspended?
7089      (when st
7090        (##sys#setslot q 3 #f)
7091        (##sys#resume-thread-on-event st)))))
7092
7093(define (##sys#get-next-event q)
7094  (let ((st (##sys#slot q 3)))
7095    (and (not st)
7096         (let ((h (##sys#slot q 1)))
7097           (and (not (null? h))
7098                (let ((x (##sys#slot h 0))
7099                      (n (##sys#slot h 1)))
7100                  (##sys#setslot q 1 n)
7101                  (when (null? n) (##sys#setslot q 2 '()))
7102                  x))))))
7103
7104(define (##sys#wait-for-next-event q)
7105  (let ((st (##sys#slot q 3)))
7106    (when st
7107      (##sys#signal-hook #:runtime-error #f "event queue blocked" q))
7108    (let again ()
7109      (let ((h (##sys#slot q 1)))
7110        (cond ((null? h)
7111               (##sys#setslot q 3 ##sys#current-thread)
7112               (##sys#suspend-thread-on-event ##sys#current-thread)
7113               (again))
7114              (else
7115                (let ((x (##sys#slot h 0))
7116                      (n (##sys#slot h 1)))
7117                  (##sys#setslot q 1 n)
7118                  (when (null? n) (##sys#setslot q 2 '()))
7119                  x)))))))
7120
7121
7122;;; Sleeping:
7123
7124(define (chicken.base#sleep-hook n) ; modified by scheduler.scm
7125  (##core#inline "C_i_process_sleep" n))
7126
7127(set! chicken.base#sleep
7128  (lambda (n)
7129    (##sys#check-fixnum n 'sleep)
7130    (chicken.base#sleep-hook n)
7131    (##core#undefined)))
7132
7133
7134;;; Interrupt-handling:
7135
7136(define ##sys#context-switch (##core#primitive "C_context_switch"))
7137
7138(define ##sys#signal-vector (make-vector 256 #f))
7139
7140(define (##sys#interrupt-hook reason state)
7141  (let loop ((reason reason))
7142    (when reason
7143      (let ((handler (##sys#slot ##sys#signal-vector reason)))
7144	(when handler
7145	  (handler reason))
7146	(loop (##core#inline "C_i_pending_interrupt" #f)))))
7147    (cond ((fx> (##sys#slot ##sys#pending-finalizers 0) 0)
7148	   (##sys#run-pending-finalizers state) )
7149	  ((procedure? state) (state))
7150	  (else (##sys#context-switch state) ) ) )
7151
7152(define (##sys#dispatch-interrupt k)
7153  (##sys#interrupt-hook
7154   (##core#inline "C_i_pending_interrupt" #f)
7155   k))
7156
7157
7158;;; Accessing "errno":
7159
7160(define-foreign-variable _errno int "errno")
7161
7162(define ##sys#update-errno)
7163(define ##sys#errno)
7164
7165(let ((n 0))
7166  (set! ##sys#update-errno (lambda () (set! n _errno) n))
7167  (set! ##sys#errno (lambda () n)))
7168
7169
7170;;; Format error string for unterminated here-docs:
7171
7172(define (##sys#format-here-doc-warning end)
7173  (##sys#print-to-string `("unterminated here-doc string literal `" ,end "'")))
7174
7175;;; Special string quoting syntax:
7176
7177(set! ##sys#user-read-hook
7178  (let ([old ##sys#user-read-hook]
7179	[read read]
7180	[display display] )
7181    (define (readln port)
7182      (let ([ln (open-output-string)])
7183	(do ([c (##sys#read-char-0 port) (##sys#read-char-0 port)])
7184	    ((or (eof-object? c) (char=? #\newline c))
7185	     (if (eof-object? c) c (get-output-string ln)))
7186	  (##sys#write-char-0 c ln) ) ) )
7187    (define (read-escaped-sexp port skip-brace?)
7188      (when skip-brace? (##sys#read-char-0 port))
7189      (let* ((form (read port)))
7190	(when skip-brace?
7191	      (let loop ()
7192		;; Skips all characters until #\}
7193		(let ([c (##sys#read-char-0 port)])
7194		  (cond [(eof-object? c)
7195			 (##sys#read-error port "unexpected end of file - unterminated `#{...}' item in `here' string literal") ]
7196			[(not (char=? #\} c)) (loop)] ) ) ) )
7197	form))
7198    (lambda (char port)
7199      (cond [(not (char=? #\< char)) (old char port)]
7200	    [else
7201	     (read-char port)
7202	     (case (##sys#peek-char-0 port)
7203	       [(#\<)
7204		(##sys#read-char-0 port)
7205		(let ([str (open-output-string)]
7206		      [end (readln port)]
7207		      [f #f] )
7208		  (let ((endlen (if (eof-object? end) 0 (string-length end))))
7209		    (cond
7210		     ((fx= endlen 0)
7211		      (##sys#read-warning
7212		       port "Missing tag after #<< here-doc token"))
7213		     ((or (char=? (string-ref end (fx- endlen 1)) #\space)
7214			  (char=? (string-ref end (fx- endlen 1)) #\tab))
7215		      (##sys#read-warning
7216		       port "Whitespace after #<< here-doc tag"))
7217		     ))
7218		  (do ([ln (readln port) (readln port)])
7219		      ((or (eof-object? ln) (string=? end ln))
7220		       (when (eof-object? ln)
7221			 (##sys#read-warning port
7222			  (##sys#format-here-doc-warning end)))
7223		       (get-output-string str) )
7224		    (if f
7225			(##sys#write-char-0 #\newline str)
7226			(set! f #t) )
7227		    (display ln str) ) ) ]
7228	       [(#\#)
7229		(##sys#read-char-0 port)
7230		(let ([end (readln port)]
7231		      [str (open-output-string)] )
7232		  (define (get/clear-str)
7233		    (let ((s (get-output-string str)))
7234		      (set! str (open-output-string))
7235		      s))
7236
7237		  (let ((endlen (if (eof-object? end) 0 (string-length end))))
7238		    (cond
7239		     ((fx= endlen 0)
7240		      (##sys#read-warning
7241		       port "Missing tag after #<# here-doc token"))
7242		     ((or (char=? (string-ref end (fx- endlen 1)) #\space)
7243			  (char=? (string-ref end (fx- endlen 1)) #\tab))
7244		      (##sys#read-warning
7245		       port "Whitespace after #<# here-doc tag"))
7246		     ))
7247
7248		  (let loop [(lst '())]
7249		    (let ([c (##sys#read-char-0 port)])
7250		      (case c
7251			[(#\newline #!eof)
7252			 (let ([s (get/clear-str)])
7253			   (cond [(or (eof-object? c) (string=? end s))
7254				  (when (eof-object? c)
7255				    (##sys#read-warning
7256				     port (##sys#format-here-doc-warning end)))
7257				  `(##sys#print-to-string
7258				    ;;Can't just use `(list ,@lst) because of 126 argument apply limit
7259				    ,(let loop2 ((lst (cdr lst)) (next-string '()) (acc ''())) ; drop last newline
7260				       (cond ((null? lst)
7261					      `(cons ,(##sys#print-to-string next-string) ,acc))
7262					     ((or (string? (car lst)) (char? (car lst)))
7263					      (loop2 (cdr lst) (cons (car lst) next-string) acc))
7264					     (else
7265					      (loop2 (cdr lst)
7266						     '()
7267						     `(cons ,(car lst)
7268							    (cons ,(##sys#print-to-string next-string) ,acc))))))) ]
7269				 [else (loop (cons #\newline (cons s lst)))] ) ) ]
7270			[(#\#)
7271			 (let ([c (##sys#peek-char-0 port)])
7272			   (case c
7273			     [(#\#)
7274			      (##sys#write-char-0 (##sys#read-char-0 port) str)
7275			      (loop lst) ]
7276			     [(#\{) (loop (cons (read-escaped-sexp port #t)
7277						(cons (get/clear-str) lst) ) ) ]
7278			     [else  (loop (cons (read-escaped-sexp port #f)
7279						(cons (get/clear-str) lst) ) ) ] ) ) ]
7280			[else
7281			 (##sys#write-char-0 c str)
7282			 (loop lst) ] ) ) ) ) ]
7283	       [else (##sys#read-error port "unreadable object")] ) ] ) ) ) )
7284
7285
7286;;; Accessing process information (cwd, environ, etc.)
7287
7288#>
7289#if defined(_WIN32) && !defined(__CYGWIN__)
7290#include <direct.h>
7291
7292static C_word C_chdir(C_word str) {
7293	return C_fix(_wchdir(C_utf16(str, 0)));
7294}
7295
7296static C_word C_curdir(C_word buf, C_word size) {
7297	C_WCHAR *cwd = _wgetcwd((C_WCHAR *)C_c_string(buf), C_unfix(size));
7298        if(cwd == NULL) return C_SCHEME_FALSE;
7299	C_char *up = C_utf8(cwd);
7300	C_char *p = up;
7301	while(*p) {
7302		*p = *p == '\\' ? '/' : *p;
7303		++p;
7304	}
7305	int len = C_strlen(up);
7306	C_memcpy(cwd, up, len + 1);
7307        return C_fix(len);
7308}
7309#else
7310# define C_chdir(str) C_fix(chdir(C_c_string(str)))
7311# define C_curdir(buf, size) (getcwd(C_c_string(buf), size) ? C_fix(strlen(C_c_string(buf))) : C_SCHEME_FALSE)
7312#endif
7313
7314<#
7315
7316(module chicken.process-context
7317  (argv argc+argv command-line-arguments
7318   program-name executable-pathname
7319   change-directory current-directory
7320   get-environment-variable get-environment-variables
7321   set-environment-variable! unset-environment-variable!)
7322
7323(import scheme)
7324(import chicken.base chicken.fixnum chicken.foreign)
7325(import chicken.internal.syntax)
7326(import (only (scheme base) make-parameter))
7327
7328;;; Current directory access:
7329
7330(define (change-directory name)
7331  (##sys#check-string name 'change-directory)
7332  (let ((sname (##sys#make-c-string name 'change-directory)))
7333    (unless (fx= (##core#inline "C_chdir" sname) 0)
7334      (##sys#signal-hook/errno #:file-error (##sys#update-errno) 'change-directory
7335       (string-append "cannot change current directory - " strerror) name))
7336    name))
7337
7338(define (##sys#change-directory-hook dir) ; set! by posix for fd support
7339  (change-directory dir))
7340
7341(define current-directory
7342  (getter-with-setter
7343    (lambda ()
7344      (let* ((buffer-size (foreign-value "C_MAX_PATH" size_t))
7345             (buffer (##sys#make-bytevector buffer-size))
7346             (len (##core#inline "C_curdir" buffer buffer-size)))
7347        (unless ##sys#windows-platform ; FIXME need `cond-expand' here
7348          (##sys#update-errno))
7349        (if len
7350            (##sys#buffer->string buffer 0 len)
7351            (##sys#signal-hook/errno
7352             #:file-error
7353             (##sys#errno)
7354             'current-directory "cannot retrieve current directory"))))
7355    (lambda (dir)
7356      (##sys#change-directory-hook dir))
7357    "(chicken.process-context#current-directory)"))
7358
7359
7360;;; Environment access:
7361
7362(define _getenv
7363  (foreign-lambda c-string "C_getenv" scheme-object))
7364
7365(define (get-environment-variable var)
7366  (_getenv (##sys#make-c-string var 'get-environment-variable)))
7367
7368(define get-environment-entry
7369  (foreign-lambda c-string* "C_getenventry" int))
7370
7371(define (set-environment-variable! var val)
7372  (##sys#check-string var 'set-environment-variable!)
7373  (##core#inline "C_i_setenv"
7374   (##sys#make-c-string var 'set-environment-variable!)
7375   (and val
7376        (begin
7377          (##sys#check-string val 'set-environment-variable!)
7378          (##sys#make-c-string val 'set-environment-variable!))))
7379  (##core#undefined))
7380
7381(define (unset-environment-variable! var)
7382  (##sys#check-string var 'unset-environment-variable!)
7383  (##core#inline "C_i_setenv"
7384   (##sys#make-c-string var 'unset-environment-variable!)
7385   #f)
7386  (##core#undefined))
7387
7388(define get-environment-variables
7389   (lambda ()
7390      (let loop ((i 0))
7391        (let ((entry (get-environment-entry i)))
7392          (if entry
7393              (let scan ((j 0))
7394                (if (char=? #\= (string-ref entry j))
7395                    (cons (cons (##sys#substring entry 0 j)
7396                                (##sys#substring entry (fx+ j 1) (string-length entry)))
7397                          (loop (fx+ i 1)))
7398                    (scan (fx+ j 1))))
7399              '())))))
7400
7401
7402;;; Command line handling
7403
7404(define-foreign-variable main_argc int "C_main_argc")
7405(define-foreign-variable main_argv c-pointer "C_main_argv")
7406
7407(define executable-pathname
7408  (foreign-lambda c-string* "C_executable_pathname"))
7409
7410(define (argc+argv)
7411  (##sys#values main_argc main_argv))
7412
7413(define argv				; includes program name
7414  (let ((cache #f)
7415        (fetch-arg (foreign-lambda* c-string ((scheme-object i))
7416                     "C_return(C_main_argv[C_unfix(i)]);")))
7417    (lambda ()
7418      (unless cache
7419        (set! cache (do ((i (fx- main_argc 1) (fx- i 1))
7420                         (v '() (cons (fetch-arg i) v)))
7421                        ((fx< i 0) v))))
7422      cache)))
7423
7424(define program-name
7425  (make-parameter
7426   (if (null? (argv))
7427       "<unknown>" ; may happen if embedded in C application
7428       (car (argv)))
7429   (lambda (x)
7430     (##sys#check-string x 'program-name)
7431     x) ) )
7432
7433(define command-line-arguments
7434  (make-parameter
7435   (let ((args (argv)))
7436     (if (pair? args)
7437	 (let loop ((args (##sys#slot args 1)))	; Skip over program name (argv[0])
7438	   (if (null? args)
7439	       '()
7440	       (let ((arg (##sys#slot args 0))
7441		     (rest (##sys#slot args 1)) )
7442		 (cond
7443		  ((string=? "-:" arg)	; Consume first "empty" runtime options list, return rest
7444		   rest)
7445
7446		  ((and (fx>= (string-length arg) 3)
7447			(string=? "-:" (##sys#substring arg 0 2)))
7448		   (loop rest))
7449
7450		  ;; First non-runtime option and everything following it is returned as-is
7451		  (else args) ) ) ) )
7452	 args) )
7453   (lambda (x)
7454     (##sys#check-list x 'command-line-arguments)
7455     x) ) )
7456
7457) ; chicken.process-context
7458
7459
7460(module chicken.gc
7461    (current-gc-milliseconds gc memory-statistics
7462     set-finalizer! make-finalizer add-to-finalizer
7463     set-gc-report! force-finalizers)
7464
7465(import scheme)
7466(import chicken.base chicken.fixnum chicken.foreign)
7467(import chicken.internal.syntax)
7468(import (only (scheme base) make-parameter))
7469
7470;;; GC info:
7471
7472(define (current-gc-milliseconds)
7473  (##core#inline "C_i_accumulated_gc_time"))
7474
7475(define (set-gc-report! flag)
7476  (##core#inline "C_set_gc_report" flag))
7477
7478;;; Memory info:
7479
7480(define (memory-statistics)
7481  (let* ((free (##sys#gc #t))
7482	 (info (##sys#memory-info))
7483	 (half-size (fx/ (##sys#slot info 0) 2)))
7484    (vector half-size (fx- half-size free) (##sys#slot info 1))))
7485
7486;;; Finalization:
7487
7488(define-foreign-variable _max_pending_finalizers int "C_max_pending_finalizers")
7489
7490(define ##sys#pending-finalizers
7491  (##sys#make-vector (fx+ (fx* 2 _max_pending_finalizers) 1) (##core#undefined)) )
7492
7493(##sys#setislot ##sys#pending-finalizers 0 0)
7494
7495(define ##sys#set-finalizer! (##core#primitive "C_register_finalizer"))
7496
7497(define ##sys#init-finalizer
7498  (let ((string-append string-append))
7499    (lambda (x y)
7500      (when (fx>= (##core#inline "C_i_live_finalizer_count") _max_pending_finalizers)
7501	(cond ((##core#inline "C_resize_pending_finalizers" (fx* 2 _max_pending_finalizers))
7502	       (set! ##sys#pending-finalizers
7503		 (##sys#vector-resize ##sys#pending-finalizers
7504				      (fx+ (fx* 2 _max_pending_finalizers) 1)
7505				      (##core#undefined)))
7506	       (when (##sys#debug-mode?)
7507		 (##sys#print
7508		  (string-append
7509		   "[debug] too many finalizers ("
7510		   (##sys#number->string
7511		    (##core#inline "C_i_live_finalizer_count"))
7512		   "), resized max finalizers to "
7513		   (##sys#number->string _max_pending_finalizers)
7514		   "\n")
7515		  #f ##sys#standard-error)))
7516	      (else
7517	       (when (##sys#debug-mode?)
7518		 (##sys#print
7519		  (string-append
7520		   "[debug] too many finalizers ("
7521		   (##core#inline "C_i_live_finalizer_count")
7522		   "), forcing ...\n")
7523		  #f ##sys#standard-error))
7524	       (##sys#force-finalizers) ) ) )
7525      (##sys#set-finalizer! x y) ) ) )
7526
7527(define set-finalizer! ##sys#init-finalizer)
7528
7529(define finalizer-tag (vector 'finalizer))
7530
7531(define (finalizer? x)
7532  (and (pair? x) (eq? finalizer-tag (##sys#slot x 0))) )
7533
7534(define (make-finalizer . objects)
7535  (let ((q (##sys#make-event-queue)))
7536    (define (handler o) (##sys#add-event-to-queue! q o))
7537    (define (handle o) (##sys#init-finalizer o handler))
7538    (for-each handle objects)
7539    (##sys#decorate-lambda
7540       (lambda (#!optional mode)
7541         (if mode
7542             (##sys#wait-for-next-event q)
7543             (##sys#get-next-event q)))
7544       finalizer?
7545       (lambda (proc i)
7546         (##sys#setslot proc i (cons finalizer-tag handle))
7547         proc))))
7548
7549(define (add-to-finalizer f . objects)
7550  (let ((af (and (procedure? f)
7551                 (##sys#lambda-decoration f finalizer?))))
7552    (unless af
7553      (error 'add-to-finalizer "bad argument type - not a finalizer procedure"
7554             f))
7555    (for-each (cdr af) objects)))
7556
7557(define ##sys#run-pending-finalizers
7558  (let ((vector-fill! vector-fill!)
7559	(string-append string-append)
7560	(working-thread #f) )
7561    (lambda (state)
7562      (cond
7563       ((not working-thread)
7564	(set! working-thread ##sys#current-thread)
7565	(let* ((c (##sys#slot ##sys#pending-finalizers 0)) )
7566	  (when (##sys#debug-mode?)
7567	    (##sys#print
7568	     (string-append "[debug] running " (##sys#number->string c)
7569			    " finalizer(s) ("
7570			    (##sys#number->string
7571			     (##core#inline "C_i_live_finalizer_count"))
7572			    " live, "
7573			    (##sys#number->string
7574			     (##core#inline "C_i_allocated_finalizer_count"))
7575			    " allocated) ...\n")
7576	     #f ##sys#standard-error))
7577	  (do ([i 0 (fx+ i 1)])
7578	      ((fx>= i c))
7579	    (let ([i2 (fx+ 1 (fx* i 2))])
7580	      (handle-exceptions ex
7581		  (##sys#show-exception-warning ex "in finalizer" #f)
7582		((##sys#slot ##sys#pending-finalizers (fx+ i2 1))
7583		 (##sys#slot ##sys#pending-finalizers i2)) ) ))
7584	  (vector-fill! ##sys#pending-finalizers (##core#undefined))
7585	  (##sys#setislot ##sys#pending-finalizers 0 0)
7586	  (set! working-thread #f)))
7587       (state)         ; Got here due to interrupt; continue w/o error
7588       ((eq? working-thread ##sys#current-thread)
7589	 (##sys#signal-hook
7590	  #:error '##sys#run-pending-finalizers
7591	  "re-entry from finalizer thread (maybe (gc #t) was called from a finalizer)"))
7592       (else
7593	;; Give finalizer thread a change to run
7594	(##sys#thread-yield!)))
7595      (cond ((not state))
7596	    ((procedure? state) (state))
7597	    (state (##sys#context-switch state) ) ) ) ))
7598
7599(define force-finalizers (make-parameter #t))
7600
7601(define (##sys#force-finalizers)
7602  (let loop ()
7603    (let ([n (##sys#gc)])
7604      (cond ((fx> (##sys#slot ##sys#pending-finalizers 0) 0)
7605	     (##sys#run-pending-finalizers #f)
7606	     (loop) )
7607	    (else n) ) ) ))
7608
7609(define (gc . arg)
7610  (let ((a (and (pair? arg) (car arg))))
7611    (if a
7612	(##sys#force-finalizers)
7613	(##sys#gc a)))))
7614
7615;;; Auxilliary definitions for safe use in quasiquoted forms and evaluated code:
7616
7617(define ##sys#list->vector list->vector)
7618(define ##sys#list list)
7619(define ##sys#length length)
7620(define ##sys#cons cons)
7621(define ##sys#append append)
7622(define ##sys#vector vector)
7623(define ##sys#apply apply)
7624(define ##sys#values values)
7625(define ##sys#equal? equal?)
7626(define ##sys#car car)
7627(define ##sys#cdr cdr)
7628(define ##sys#pair? pair?)
7629(define ##sys#vector? vector?)
7630(define ##sys#vector->list vector->list)
7631(define ##sys#vector-length vector-length)
7632(define ##sys#vector-ref vector-ref)
7633(define ##sys#>= >=)
7634(define ##sys#= =)
7635(define ##sys#+ +)
7636(define ##sys#eq? eq?)
7637(define ##sys#eqv? eqv?)
7638(define ##sys#list? list?)
7639(define ##sys#null? null?)
7640(define ##sys#map-n map)
7641
7642;;; We need this here so `location' works:
7643
7644(define (##sys#make-locative obj index weak? loc)
7645  (cond [(##sys#immediate? obj)
7646	 (##sys#signal-hook #:type-error loc "locative cannot refer to immediate object" obj) ]
7647	[(or (vector? obj) (pair? obj))
7648	 (##sys#check-range index 0 (##sys#size obj) loc)
7649	 (##core#inline_allocate ("C_a_i_make_locative" 5) 0 obj index weak?) ]
7650	[(and (##core#inline "C_blockp" obj)
7651	      (##core#inline "C_bytevectorp" obj) )
7652	 (##sys#check-range index 0 (##sys#size obj) loc)
7653	 (##core#inline_allocate ("C_a_i_make_locative" 5) 2 obj index weak?) ]
7654	[(##sys#generic-structure? obj)
7655	 (case (##sys#slot obj 0)
7656	   ((u8vector)
7657	    (let ([v (##sys#slot obj 1)])
7658	      (##sys#check-range index 0 (##sys#size v) loc)
7659	      (##core#inline_allocate ("C_a_i_make_locative" 5) 2 v index weak?))  )
7660	   ((s8vector)
7661	    (let ([v (##sys#slot obj 1)])
7662	      (##sys#check-range index 0 (##sys#size v) loc)
7663	      (##core#inline_allocate ("C_a_i_make_locative" 5) 3 v index weak?) ) )
7664	   ((u16vector)
7665	    (let ([v (##sys#slot obj 1)])
7666	      (##sys#check-range index 0 (##sys#size v) loc)
7667	      (##core#inline_allocate ("C_a_i_make_locative" 5) 4 v index weak?) ) )
7668	   ((s16vector)
7669	    (let ([v (##sys#slot obj 1)])
7670	      (##sys#check-range index 0 (##sys#size v) loc)
7671	      (##core#inline_allocate ("C_a_i_make_locative" 5) 5 v index weak?) ) )
7672	   ((u32vector)
7673	    (let ([v (##sys#slot obj 1)])
7674	      (##sys#check-range index 0 (##sys#size v) loc)
7675	      (##core#inline_allocate ("C_a_i_make_locative" 5) 6 v index weak?) ) )
7676	   ((s32vector)
7677	    (let ([v (##sys#slot obj 1)])
7678	      (##sys#check-range index 0 (##sys#size v) loc)
7679	      (##core#inline_allocate ("C_a_i_make_locative" 5) 7 v index weak?) ) )
7680	   ((u64vector)
7681	    (let ([v (##sys#slot obj 1)])
7682	      (##sys#check-range index 0 (##sys#size v) loc)
7683	      (##core#inline_allocate ("C_a_i_make_locative" 5) 8 v index weak?) ) )
7684	   ((s64vector)
7685	    (let ([v (##sys#slot obj 1)])
7686	      (##sys#check-range index 0 (##sys#size v) loc)
7687	      (##core#inline_allocate ("C_a_i_make_locative" 5) 9 v index weak?) ) )
7688	   ((f32vector)
7689	    (let ([v (##sys#slot obj 1)])
7690	      (##sys#check-range index 0 (##sys#size v) loc)
7691	      (##core#inline_allocate ("C_a_i_make_locative" 5) 10 v index weak?) ) )
7692	   ((f64vector)
7693	    (let ([v (##sys#slot obj 1)])
7694	      (##sys#check-range index 0 (##sys#size v) loc)
7695	      (##core#inline_allocate ("C_a_i_make_locative" 5) 11 v index weak?) ) )
7696	   ;;XXX pointer-vector currently not supported
7697	   (else
7698	    (##sys#check-range index 0 (fx- (##sys#size obj) 1) loc)
7699	    (##core#inline_allocate ("C_a_i_make_locative" 5) 0 obj (fx+ index 1) weak?) ) ) ]
7700	((string? obj)
7701	 (let ((bv (##sys#slot obj 0))
7702               (p (##core#inline "C_utf_position" obj index)))
7703           (##sys#check-range index 0 (##sys#slot obj 1) loc)
7704  	   (##core#inline_allocate ("C_a_i_make_locative" 5) 1 bv p weak?) ) )
7705	[else
7706	 (##sys#signal-hook
7707	  #:type-error loc
7708	  "bad argument type - locative cannot refer to objects of this type"
7709	  obj) ] ) )
7710
7711
7712;;; Property lists
7713
7714(module chicken.plist
7715  (get get-properties put! remprop! symbol-plist)
7716
7717(import scheme)
7718(import (only chicken.base getter-with-setter))
7719(import chicken.internal.syntax)
7720
7721(define (put! sym prop val)
7722  (##sys#check-symbol sym 'put!)
7723  (##core#inline_allocate ("C_a_i_putprop" 8) sym prop val) )
7724
7725(define (get sym prop #!optional default)
7726  (##sys#check-symbol sym 'get)
7727  (##core#inline "C_i_getprop" sym prop default))
7728
7729(define ##sys#put! put!)
7730(define ##sys#get get)
7731
7732(set! get (getter-with-setter get put!))
7733
7734(define (remprop! sym prop)
7735  (##sys#check-symbol sym 'remprop!)
7736  (let loop ((plist (##sys#slot sym 2)) (ptl #f))
7737    (and (not (null? plist))
7738	 (let* ((tl (##sys#slot plist 1))
7739		(nxt (##sys#slot tl 1)))
7740	   (or (and (eq? (##sys#slot plist 0) prop)
7741		    (begin
7742		      (if ptl
7743			  (##sys#setslot ptl 1 nxt)
7744			  (##sys#setslot sym 2 nxt) )
7745		      #t ) )
7746	       (loop nxt tl) ) ) ) )
7747  (when (null? (##sys#slot sym 2))
7748    ;; This will only unpersist if symbol is also unbound
7749    (##core#inline "C_i_unpersist_symbol" sym) ) )
7750
7751(define symbol-plist
7752  (getter-with-setter
7753   (lambda (sym)
7754     (##sys#check-symbol sym 'symbol-plist)
7755     (##sys#slot sym 2) )
7756   (lambda (sym lst)
7757     (##sys#check-symbol sym 'symbol-plist)
7758     (##sys#check-list lst 'symbol-plist/setter)
7759     (if (##core#inline "C_i_fixnumevenp" (##core#inline "C_i_length" lst))
7760	 (##sys#setslot sym 2 lst)
7761	 (##sys#signal-hook
7762	  #:type-error "property-list must be of even length"
7763	  lst sym))
7764     (if (null? lst)
7765	 (##core#inline "C_i_unpersist_symbol" sym)
7766	 (##core#inline "C_i_persist_symbol" sym)))
7767   "(chicken.plist#symbol-plist sym)"))
7768
7769(define (get-properties sym props)
7770  (##sys#check-symbol sym 'get-properties)
7771  (unless (pair? props)
7772    (set! props (list props)) )
7773  (let loop ((plist (##sys#slot sym 2)))
7774    (if (null? plist)
7775	(values #f #f #f)
7776	(let* ((prop (##sys#slot plist 0))
7777	       (tl (##sys#slot plist 1))
7778	       (nxt (##sys#slot tl 1)))
7779	  (if (memq prop props)
7780	      (values prop (##sys#slot tl 0) nxt)
7781	      (loop nxt) ) ) ) ) )
7782
7783) ; chicken.plist
7784
7785
7786;;; Print timing information (support for "time" macro):
7787
7788(define (##sys#display-times info)
7789  (define (pstr str) (##sys#print str #f ##sys#standard-error))
7790  (define (pchr chr) (##sys#write-char-0 chr ##sys#standard-error))
7791  (define (pnum num)
7792    (##sys#print (if (zero? num) "0" (##sys#number->string num)) #f ##sys#standard-error))
7793  (define (round-to x y) ; Convert to fp with y digits after the point
7794    (/ (round (* x (expt 10 y))) (expt 10.0 y)))
7795  (define (pmem bytes)
7796    (cond ((> bytes (expt 1024 3))
7797	   (pnum (round-to (/ bytes (expt 1024 3)) 2)) (pstr " GiB"))
7798	  ((> bytes (expt 1024 2))
7799	   (pnum (round-to (/ bytes (expt 1024 2)) 2)) (pstr " MiB"))
7800	  ((> bytes 1024)
7801	   (pnum (round-to (/ bytes 1024) 2)) (pstr " KiB"))
7802	  (else (pnum bytes) (pstr " bytes"))))
7803  (##sys#flush-output ##sys#standard-output)
7804  (pnum (##sys#slot info 0))
7805  (pstr "s CPU time")
7806  (let ((gctime (##sys#slot info 1)))
7807    (when (> gctime 0)
7808      (pstr ", ")
7809      (pnum gctime)
7810      (pstr "s GC time (major)")))
7811  (let ((mut (##sys#slot info 2))
7812	(umut (##sys#slot info 3)))
7813    (when (fx> mut 0)
7814      (pstr ", ")
7815      (pnum mut)
7816      (pchr #\/)
7817      (pnum umut)
7818      (pstr " mutations (total/tracked)")))
7819  (let ((minor (##sys#slot info 4))
7820	(major (##sys#slot info 5)))
7821    (when (or (fx> minor 0) (fx> major 0))
7822      (pstr ", ")
7823      (pnum major)
7824      (pchr #\/)
7825      (pnum minor)
7826      (pstr " GCs (major/minor)")))
7827  (let ((maximum-heap-usage (##sys#slot info 6)))
7828    (pstr ", maximum live heap: ")
7829    (pmem maximum-heap-usage))
7830  (##sys#write-char-0 #\newline ##sys#standard-error)
7831  (##sys#flush-output ##sys#standard-error))
7832
7833
7834;;; Dump heap state to stderr:
7835
7836(define ##sys#dump-heap-state (##core#primitive "C_dump_heap_state"))
7837(define ##sys#filter-heap-objects (##core#primitive "C_filter_heap_objects"))
7838
7839
7840;;; Platform configuration inquiry:
7841
7842(module chicken.platform
7843    (build-platform chicken-version 
7844     feature? machine-byte-order machine-type
7845     repository-path installation-repository
7846     register-feature! unregister-feature! include-path
7847     software-type software-version return-to-host
7848     system-config-directory system-cache-directory
7849     )
7850
7851(import scheme)
7852(import chicken.fixnum chicken.foreign chicken.keyword chicken.process-context)
7853(import chicken.internal.syntax)
7854(import (only (scheme base) make-parameter))
7855
7856(define software-type
7857  (let ((sym (string->symbol ((##core#primitive "C_software_type")))))
7858    (lambda () sym)))
7859
7860(define machine-type
7861  (let ((sym (string->symbol ((##core#primitive "C_machine_type")))))
7862    (lambda () sym)))
7863
7864(define machine-byte-order
7865  (let ((sym (string->symbol ((##core#primitive "C_machine_byte_order")))))
7866    (lambda () sym)))
7867
7868(define software-version
7869  (let ((sym (string->symbol ((##core#primitive "C_software_version")))))
7870    (lambda () sym)))
7871
7872(define build-platform
7873  (let ((sym (string->symbol ((##core#primitive "C_build_platform")))))
7874    (lambda () sym)))
7875
7876(define ##sys#windows-platform
7877  (and (eq? 'windows (software-type))
7878       ;; Still windows even if 'Linux-like'
7879       (not (eq? 'cygwin (software-version)))))
7880
7881(define (chicken-version #!optional full)
7882  (define (get-config)
7883    (let ((bp (build-platform))
7884	  (st (software-type))
7885	  (sv (software-version))
7886	  (mt (machine-type)))
7887      (define (str x)
7888	(if (eq? 'unknown x)
7889	    ""
7890	    (string-append (symbol->string x) "-")))
7891      (string-append (str sv) (str st) (str bp) (##sys#symbol->string/shared mt))))
7892  (if full
7893      (let ((spec (string-append
7894		   " " (number->string (foreign-value "C_WORD_SIZE" int)) "bit"
7895		   (if (feature? #:dload) " dload" "")
7896		   (if (feature? #:ptables) " ptables" "")
7897		   (if (feature? #:gchooks) " gchooks" "")
7898		   (if (feature? #:cross-chicken) " cross" ""))))
7899	(string-append
7900	 "Version " ##sys#build-version
7901	 (if ##sys#build-branch (string-append " (" ##sys#build-branch ")") "")
7902	 (if ##sys#build-id (string-append " (rev " ##sys#build-id ")") "")
7903	 "\n"
7904	 (get-config)
7905	 (if (zero? (string-length spec))
7906	     ""
7907	     (string-append " [" spec " ]"))))
7908      ##sys#build-version))
7909
7910;;; Installation locations
7911
7912(define-foreign-variable binary-version int "C_BINARY_VERSION")
7913(define-foreign-variable installation-home c-string "C_INSTALL_SHARE_HOME")
7914(define-foreign-variable install-egg-home c-string "C_INSTALL_EGG_HOME")
7915
7916(define (include-path #!optional new)
7917  (when new
7918    (##sys#check-list new 'include-path)
7919    (set! ##sys#include-pathnames new))
7920  ##include-pathnames)
7921
7922(define path-list-separator
7923  (if ##sys#windows-platform #\; #\:))
7924
7925(define ##sys#split-path
7926  (let ((cache '(#f)))
7927    (lambda (path)
7928      (cond ((not path) '())
7929            ((equal? path (car cache))
7930             (cdr cache))
7931            (else
7932              (let* ((len (string-length path))
7933                     (lst (let loop ((start 0) (pos 0))
7934                            (cond ((fx>= pos len)
7935                                   (if (fx= pos start)
7936                                       '()
7937                                       (list (substring path start pos))))
7938                                  ((char=? (string-ref path pos)
7939                                           path-list-separator)
7940                                   (cons (substring path start pos)
7941                                         (loop (fx+ pos 1)
7942                                               (fx+ pos 1))))
7943                                  (else
7944                                    (loop start (fx+ pos 1)))))))
7945                (set! cache (cons path lst))
7946                lst))))))
7947
7948(define repository-path
7949  (make-parameter
7950   (cond ((foreign-value "C_private_repository_path()" c-string)
7951           => list)
7952         ((get-environment-variable "CHICKEN_REPOSITORY_PATH")
7953           => ##sys#split-path)
7954         (install-egg-home
7955           => list)
7956         (else #f))
7957   (lambda (new)
7958     (and new
7959          (begin
7960            (##sys#check-list new 'repository-path)
7961            (for-each (lambda (p) (##sys#check-string p 'repository-path)) new)
7962            new)))))
7963
7964(define installation-repository
7965  (make-parameter
7966   (or (foreign-value "C_private_repository_path()" c-string)
7967       (get-environment-variable "CHICKEN_INSTALL_REPOSITORY")
7968       install-egg-home)))
7969
7970(define (chop-separator str)
7971  (let ((len (fx- (string-length str) 1)))
7972    (if (and (> len 0)
7973             (memq (string-ref str len) '(#\\ #\/)))
7974        (substring str 0 len)
7975        str) ) )
7976
7977(define ##sys#include-pathnames
7978  (cond ((get-environment-variable "CHICKEN_INCLUDE_PATH")
7979         => (lambda (p)
7980              (map chop-separator (##sys#split-path p))))
7981        (else (list installation-home))))
7982
7983(define (include-path) ##sys#include-pathnames)
7984
7985
7986;;; Feature identifiers:
7987
7988(define ->feature-id ; TODO: export this?  It might be useful..
7989  (let ()
7990    (define (err . args)
7991      (apply ##sys#signal-hook #:type-error "bad argument type - not a valid feature identifer" args))
7992    (define (prefix s)
7993      (if s (##sys#string-append s "-") ""))
7994    (lambda (x)
7995      (cond ((keyword? x) x)
7996	    ((string? x) (string->keyword x))
7997	    ((symbol? x) (string->keyword (##sys#symbol->string/shared x)))
7998	    (else (err x))))))
7999
8000(define ##sys#features
8001  '(#:chicken
8002    #:srfi-6 #:srfi-12 #:srfi-17 #:srfi-23 #:srfi-30
8003    #:exact-complex #:srfi-39 #:srfi-62 #:srfi-88 #:full-numeric-tower #:full-unicode))
8004
8005;; Add system features:
8006
8007;; all platforms we support have this
8008(set! ##sys#features `(#:posix #:r7rs #:ieee-float #:ratios ,@##sys#features))
8009
8010(let ((check (lambda (f)
8011	       (unless (eq? 'unknown f)
8012		 (set! ##sys#features (cons (->feature-id f) ##sys#features))))))
8013  (check (software-type))
8014  (check (software-version))
8015  (check (build-platform))
8016  (check (machine-type))
8017  (check (machine-byte-order)))
8018
8019(when (foreign-value "HAVE_DLOAD" bool)
8020  (set! ##sys#features (cons #:dload ##sys#features)))
8021(when (foreign-value "HAVE_PTABLES" bool)
8022  (set! ##sys#features (cons #:ptables ##sys#features)))
8023(when (foreign-value "HAVE_GCHOOKS" bool)
8024  (set! ##sys#features (cons #:gchooks ##sys#features)))
8025(when (foreign-value "IS_CROSS_CHICKEN" bool)
8026  (set! ##sys#features (cons #:cross-chicken ##sys#features)))
8027
8028;; Register a feature to represent the word size (e.g., 32bit, 64bit)
8029(set! ##sys#features
8030      (cons (string->keyword
8031             (string-append
8032              (number->string (foreign-value "C_WORD_SIZE" int))
8033              "bit"))
8034            ##sys#features))
8035
8036(set! ##sys#features
8037  (let ((major (##sys#number->string (foreign-value "C_MAJOR_VERSION" int)))
8038	(minor (##sys#number->string (foreign-value "C_MINOR_VERSION" int))))
8039    (cons (->feature-id (string-append "chicken-" major))
8040	  (cons (->feature-id (string-append "chicken-" major "." minor))
8041		##sys#features))))
8042
8043(define (register-feature! . fs)
8044  (for-each
8045   (lambda (f)
8046     (let ((id (->feature-id f)))
8047       (unless (memq id ##sys#features) (set! ##sys#features (cons id ##sys#features)))))
8048   fs)
8049  (##core#undefined))
8050
8051(define (unregister-feature! . fs)
8052  (let ((fs (map ->feature-id fs)))
8053    (set! ##sys#features
8054      (let loop ((ffs ##sys#features))
8055	(if (null? ffs)
8056	    '()
8057	    (let ((f (##sys#slot ffs 0))
8058		  (r (##sys#slot ffs 1)))
8059	      (if (memq f fs)
8060		  (loop r)
8061		  (cons f (loop r)))))))
8062    (##core#undefined)))
8063
8064(define (feature? . ids)
8065  (let loop ((ids ids))
8066    (or (null? ids)
8067	(and (memq (->feature-id (##sys#slot ids 0)) ##sys#features)
8068	     (loop (##sys#slot ids 1))))))
8069
8070(define return-to-host
8071  (##core#primitive "C_return_to_host"))
8072
8073(define (system-config-directory)
8074  (or (get-environment-variable "XDG_CONFIG_HOME")
8075      (if ##sys#windows-platform
8076          (get-environment-variable "APPDATA")
8077          (let ((home (get-environment-variable "HOME")))
8078            (and home (string-append home "/.config"))))))
8079
8080(define (system-cache-directory)
8081  (or (get-environment-variable "XDG_CACHE_HOME")
8082      (if ##sys#windows-platform
8083          (or (get-environment-variable "LOCALAPPDATA")
8084              (get-environment-variable "APPDATA"))
8085          (let ((home (get-environment-variable "HOME")))
8086            (and home (string-append home "/.cache"))))))
8087
8088) ; chicken.platform
8089
8090(set! scheme#features
8091  (lambda ()
8092    (map (lambda (s)
8093         (##sys#string->symbol (##sys#symbol->string s)))
8094       ##sys#features)))
8095
8096(set! scheme#make-list
8097 (lambda (n #!optional fill)
8098  (##sys#check-integer n 'make-list)
8099  (unless (fx>= n 0)
8100    (error 'make-list "not a positive integer" n))
8101  (do ((i n (fx- i 1))
8102       (result '() (cons fill result)))
8103      ((eq? i 0) result))))
8104
8105(set! scheme#list-set!
8106 (lambda (l n obj)
8107  (##sys#check-integer n 'list-set!)
8108  (unless (fx>= n 0)
8109    (error 'list-set! "not a positive integer" n))
8110  (do ((i n (fx- i 1))
8111       (l l (cdr l)))
8112      ((fx= i 0) (set-car! l obj))
8113    (when (null? l)
8114      (error 'list-set! "out of range")))))
8115
8116;; TODO: Test if this is the quickest way to do this, or whether we
8117;; should just cons recursively like our SRFI-1 implementation does.
8118(set! scheme#list-copy
8119 (lambda (lst)
8120  (cond ((pair? lst)
8121         (let lp ((res '())
8122                  (lst lst))
8123           (if (pair? lst)
8124               (lp (cons (car lst) res) (cdr lst))
8125               (append (##sys#fast-reverse res) lst))))
8126        (else lst))))
8127
8128(set! scheme#string->vector
8129 (lambda (s #!optional start end)
8130  (##sys#check-string s 'string->vector)
8131  (let ((s->v (lambda (s start end)
8132                (let* ((len (##sys#slot s 1)))
8133                  (##sys#check-range/including start 0 end 'string->vector)
8134                  (##sys#check-range/including end start len 'string->vector)
8135                  (let ((v (##sys#make-vector (fx- end start))))
8136                    (do ((ti 0 (fx+ ti 1))
8137                         (fi start (fx+ fi 1)))
8138                        ((fx= fi end) v)
8139                      (##sys#setslot v ti (##core#inline "C_utf_subchar" s fi))))))))
8140    (if end
8141        (s->v s start end)
8142        (s->v s (or start 0) (string-length s))))))
8143
8144(set! scheme#vector->string
8145  (lambda (v #!optional start end)
8146    (##sys#check-vector v 'vector->string)
8147    (let ((v->s (lambda (v start end)
8148                  (let ((len (##sys#size v)))
8149                    (##sys#check-range/including start 0 end 'vector->string)
8150                    (##sys#check-range/including end start len 'vector->string)
8151                    (let ((bv (##sys#make-bytevector (fx* (fx- end start) 4))))
8152                      (let loop ((i 0)
8153                                 (p start))
8154                        (if (fx= p end)
8155                            (##sys#buffer->string! bv i)
8156                            (let ((c (##sys#slot v p)))
8157                              (##sys#check-char c 'vector->string)
8158                              (loop (##core#inline "C_utf_insert" bv i c)
8159                                    (fx+ p 1))))))))))
8160      (if end
8161          (v->s v start end)
8162          (v->s v (or start 0) (##sys#size v))))))
8163
8164(set! scheme#string-map
8165  (lambda (proc str . more)
8166    (define (%string-map proc s)
8167      (let* ((len (string-length s))
8168             (ans (##sys#make-bytevector (fx* 4 len))))
8169        (let loop ((i 0)
8170                   (j 0))
8171          (if (fx>= j len)
8172              (##sys#buffer->string! ans i)
8173              (let ((r (proc (string-ref s j))))
8174                (##sys#check-char r 'string-map)
8175                (loop (##core#inline "C_utf_insert" ans i r)
8176                      (fx+ j 1)))))))
8177    (if (null? more)
8178        (%string-map proc str)
8179        (let ((strs (cons str more)))
8180          (##sys#check-closure proc 'string-map)
8181          (##sys#for-each (cut ##sys#check-string <> 'string-map) strs)
8182          (let* ((len (foldl fxmin most-positive-fixnum (map string-length strs)))
8183                 (str (##sys#make-string len)))
8184            (do ((i 0 (fx+ i 1)))
8185                ((fx= i len) str)
8186                (string-set! str i (apply proc (map (cut string-ref <> i) strs)))))))))
8187
8188(set! scheme#string-for-each
8189  (lambda (proc str . more)
8190    (define (%string-for-each proc s)
8191      (let ((len (string-length s)))
8192        (let lp ((i 0))
8193          (if (fx< i len)
8194              (begin (proc (string-ref s i))
8195                (lp (fx+ i 1)))))))
8196    (if (null? more)
8197        (%string-for-each proc str)
8198        (let ((strs (cons str more)))
8199          (##sys#check-closure proc 'string-for-each)
8200          (##sys#for-each (cut ##sys#check-string <> 'string-for-each) strs)
8201          (let* ((len (foldl fxmin most-positive-fixnum (map string-length strs)))
8202                 (str (##sys#make-string len)))
8203            (do ((i 0 (fx+ i 1)))
8204                ((fx= i len))
8205                (apply proc (map (cut string-ref <> i) strs))))))))
8206
8207(set! scheme#vector-map
8208 (lambda (proc v . more)
8209  (cond ((null? more)
8210         (##sys#check-closure proc 'vector-map)
8211         (##sys#check-vector v 'vector-map)
8212         (let* ((len (##sys#size v))
8213                (vec (##sys#make-vector len)))
8214           (do ((i 0 (fx+ i 1)))
8215               ((fx= i len) vec)
8216               (##sys#setslot vec i (proc (##sys#slot v i))))))
8217        (else
8218          (let ((vs (cons v more)))
8219            (##sys#check-closure proc 'vector-map)
8220            (##sys#for-each (cut ##sys#check-vector <> 'vector-map) vs)
8221            (let* ((len (foldl fxmin most-positive-fixnum (map ##sys#size vs)))
8222                   (vec (##sys#make-vector len)))
8223              (do ((i 0 (fx+ i 1)))
8224                  ((fx= i len) vec)
8225                  (##sys#setslot vec i (apply proc (map (cut vector-ref <> i) vs))))))))))
8226
8227(set! scheme#vector-for-each
8228 (lambda (proc v . more)
8229  (cond ((null? more)
8230         (##sys#check-closure proc 'vector-for-each)
8231         (##sys#check-vector v 'vector-for-each)
8232         (let ((len (##sys#size v)))
8233           (do ((i 0 (fx+ i 1)))
8234               ((fx= i len))
8235               (proc (##sys#slot v i)))))
8236        (else
8237          (let ((vs (cons v more)))
8238            (##sys#check-closure proc 'vector-for-each)
8239            (##sys#for-each (cut ##sys#check-vector <> 'vector-for-each) vs)
8240            (let* ((len (foldl fxmin most-positive-fixnum (map ##sys#size vs)))
8241                   (vec (##sys#make-vector len)))
8242              (do ((i 0 (fx+ i 1)))
8243                  ((fx= i len) vec)
8244                  (apply proc (map (cut vector-ref <> i) vs)))))))))
8245
8246(set! scheme#close-port
8247 (lambda (port)
8248  (##sys#check-port port 'close-port)
8249  (when (##core#inline "C_port_openp" port 1)
8250    ((##sys#slot (##sys#slot port 2) 4) port 1))
8251  (when (##core#inline "C_port_openp" port 2)
8252    ((##sys#slot (##sys#slot port 2) 4) port 2))
8253  (##sys#setislot port 8 0)))
8254
8255(set! scheme#call-with-port
8256 (lambda (port proc)
8257  (receive ret
8258      (proc port)
8259    (scheme#close-port port)
8260    (apply values ret))))
8261
8262(set! scheme#eof-object (lambda () #!eof))
8263
8264(set! scheme#peek-u8
8265  (lambda (#!optional (port ##sys#standard-input))
8266    (let ((c (peek-char port)))
8267      (if (eof-object? c)
8268          c
8269          (let ((d (char->integer c)))
8270            (if (fx< d 256) 
8271                d
8272                (let ((bv (##sys#make-bytevector 4)))
8273                  (##sys#encode-char c bv (##sys#slot port 15))
8274                  (##core#inline "C_subbyte" bv 0))))))))
8275
8276(set! scheme#write-string
8277  (lambda (s #!optional (port ##sys#standard-output) start end)
8278    (##sys#check-string s 'write-string)
8279    (##sys#check-output-port port #t 'write-string)
8280    (if start
8281        (##sys#check-fixnum start 'write-string)
8282        (set! start 0))
8283    (if end
8284        (##sys#check-fixnum end 'write-string)
8285        (set! end (string-length s)))
8286    (let* ((part (if start (substring s start end) s))
8287           (bv (##sys#slot part 0))
8288           (len (fx- (##sys#size bv) 1)))
8289      ((##sys#slot (##sys#slot port 2) 3) ; write-bytevector
8290       port bv 0 len))))
8291
8292
8293;; I/O
8294
8295(module chicken.io
8296  (read-list read-buffered read-byte read-line
8297   read-lines read-string read-string! read-token
8298   write-byte write-line write-bytevector read-bytevector
8299   read-bytevector!)
8300
8301(import scheme chicken.base chicken.fixnum)
8302(import chicken.internal.syntax)
8303(import (only (scheme base) open-output-string get-output-string))
8304
8305
8306;;; Read expressions from file:
8307
8308(define read-list
8309  (let ((read read))
8310    (lambda (#!optional (port ##sys#standard-input) (reader read) max)
8311      (##sys#check-input-port port #t 'read-list)
8312      (do ((x (reader port) (reader port))
8313	   (i 0 (fx+ i 1))
8314	   (xs '() (cons x xs)))
8315	  ((or (eof-object? x) (and max (fx>= i max)))
8316	   (##sys#fast-reverse xs))))))
8317
8318
8319;;; Line I/O:
8320
8321(define read-line
8322  (let ()
8323    (lambda args
8324      (let* ([parg (pair? args)]
8325	     [p (if parg (car args) ##sys#standard-input)]
8326	     [limit (and parg (pair? (cdr args)) (cadr args))])
8327	(##sys#check-input-port p #t 'read-line)
8328	(cond ((##sys#slot (##sys#slot p 2) 8) => (lambda (rl) (rl p limit)))
8329	      (else
8330	       (let* ((buffer-len (if limit limit 256))
8331		      (buffer (##sys#make-string buffer-len)))
8332		 (let loop ([i 0])
8333		   (if (and limit (fx>= i limit))
8334		       (##sys#substring buffer 0 i)
8335		       (let ([c (##sys#read-char-0 p)])
8336			 (if (eof-object? c)
8337			     (if (fx= i 0)
8338				 c
8339				 (##sys#substring buffer 0 i) )
8340			     (case c
8341			       [(#\newline) (##sys#substring buffer 0 i)]
8342			       [(#\return)
8343				(let ([c (peek-char p)])
8344				  (if (char=? c #\newline)
8345				      (begin (##sys#read-char-0 p)
8346					     (##sys#substring buffer 0 i))
8347				      (##sys#substring buffer 0 i) ) ) ]
8348			       [else
8349				(when (fx>= i buffer-len)
8350				  (set! buffer
8351				    (##sys#string-append buffer (make-string buffer-len)))
8352				  (set! buffer-len (fx+ buffer-len buffer-len)) )
8353				(string-set! buffer i c)
8354				(loop (fx+ i 1)) ] ) ) ) ) ) ) ) ) ) ) ) )
8355
8356(define read-lines
8357  (lambda (#!optional (port ##sys#standard-input) max)
8358    (##sys#check-input-port port #t 'read-lines)
8359    (when max (##sys#check-fixnum max 'read-lines))
8360    (let loop ((lns '())
8361	       (n (or max most-positive-fixnum)))
8362      (if (eq? n 0)
8363	  (##sys#fast-reverse lns)
8364	  (let ((ln (read-line port)))
8365	    (if (eof-object? ln)
8366		(##sys#fast-reverse lns)
8367		(loop (cons ln lns) (fx- n 1))))))))
8368
8369(define write-line
8370  (lambda (str . port)
8371    (let* ((p (if (##core#inline "C_eqp" port '())
8372                  ##sys#standard-output
8373                  (##sys#slot port 0) ) ))
8374      (##sys#check-output-port p #t 'write-line)
8375      (##sys#check-string str 'write-line)
8376      (let ((bv (##sys#slot str 0)))
8377        ((##sys#slot (##sys#slot p 2) 3)  ; write-bytevector
8378         p
8379         bv
8380         0
8381         (fx- (##sys#size bv) 1)))
8382      (##sys#write-char-0 #\newline p))))
8383
8384
8385;;; Extended I/O
8386
8387(define (read-bytevector!/port n dest port start)
8388  (if (eq? n 0)
8389      0
8390      (let ((rdbvec (##sys#slot (##sys#slot port 2) 7))) ; read-bytevector!
8391        (let loop ((start start) (n n) (m 0))
8392          (let ((n2 (rdbvec port n dest start)))
8393            (##sys#setislot port 5 ; update port-position
8394                            (fx+ (##sys#slot port 5) n2))
8395            (cond ((eq? n2 0) m)
8396                  ((or (not n) (fx< n2 n))
8397                   (loop (fx+ start n2) (and n (fx- n n2)) (fx+ m n2)))
8398                  (else (fx+ n2 m))))))))
8399
8400(define (read-string!/port n dest port start)
8401  (let ((buf (##sys#make-bytevector (fx* n 4)))
8402        (enc (##sys#slot port 15)))
8403    (##sys#encoding-hook
8404     enc
8405     (lambda (decoder _ _)
8406       (define (readb n buf port p)
8407         (let ((bytes (read-bytevector!/port n buf port p)))
8408           (if (eq? enc 'utf-8) ; fast path, avoid copying
8409               bytes
8410               (decoder buf p bytes
8411                        (lambda (dbuf start len)
8412                          (##core#inline "C_copy_memory_with_offset" buf dbuf p start len)
8413                          len)))))
8414       (define (finish un bytes)
8415         (##core#inline "C_utf_overwrite" dest start un buf bytes)
8416         un)
8417       (let loop ((p 0) (n n) (un 0) (bn 0))    ; pos, count, codepoints, rest bytes
8418         (let ((bytes (readb n buf port p)))
8419           (cond ((eq? bytes 0) (finish un bn))
8420                 ((eq? enc 'utf-8)
8421                  ;; read incomplete fragments
8422                  ;; FIXME: hardcoded, should be encoding-specific!
8423                  (let recount ((bytes bytes))
8424                    (let* ((fc (##core#inline "C_utf_fragment_counts" buf p bytes))
8425                           (full (fxshr fc 4))
8426                           (left (fxand fc 15))
8427                           (total (fx+ un full))
8428                           (tbytes (fx+ bn bytes))
8429                           (remain (fx- n full)))
8430                      (cond ((fx> left 0)
8431                             (let ((b2 (readb left buf port (fx+ p bytes))))
8432                               (if (fx< b2 left)
8433                                   (finish total tbytes)
8434                                   (recount (fx+ bytes b2)))))
8435                            ((eq? remain 0) (finish total tbytes))
8436                            (else (loop (fx+ p bytes) remain total
8437                                        tbytes))))))
8438                 (else
8439                  (loop (fx+ p bytes) (fx- n bytes)
8440                        (fx+ un bytes) (fx+ bn bytes))))))))))
8441
8442(define (read-string! n dest #!optional (port ##sys#standard-input) (start 0))
8443  (##sys#check-input-port port #t 'read-string!)
8444  (##sys#check-string dest 'read-string!)
8445  (when n (##sys#check-fixnum n 'read-string!))
8446  (let ((dest-size (string-length dest)))
8447    (unless (and n (fx<= (fx+ start n) dest-size))
8448      (set! n (fx- dest-size start))))
8449  (##sys#check-fixnum start 'read-string!)
8450  (read-string!/port n dest port start))
8451
8452(define (read-bytevector! dest #!optional (port ##sys#standard-input) (start 0) end)
8453  (##sys#check-input-port port #t 'read-bytevector!)
8454  (##sys#check-bytevector dest 'read-bytevector!)
8455  (##sys#check-fixnum start 'read-bytevector!)
8456  (when end (##sys#check-fixnum end 'read-bytevector!))
8457  (let* ((size (##sys#size dest))
8458         (n (fx- (or end size) start)))
8459    (read-bytevector!/port n dest port start)))
8460
8461(define read-string/port
8462  (lambda (n p)
8463    (cond ((eq? n 0) "") ; Don't attempt to peek (fd might not be ready)
8464          ((eof-object? (##sys#peek-char-0 p)) #!eof)
8465          (n (let* ((str (##sys#make-string n))
8466                    (n2 (read-string!/port n str p 0)))
8467               (if (eq? n n2)
8468                   str
8469                   (##sys#substring str 0 n2))))
8470          (else
8471            (##sys#read-remaining
8472              p
8473              (lambda (buf len)
8474                (##sys#buffer->string/encoding buf 0 len
8475                                               (##sys#slot p 15))))))))
8476
8477(define (##sys#read-remaining p k)
8478  (let ((len 1024))
8479    (let loop ((buf (##sys#make-bytevector len))
8480               (bsize len)
8481               (pos 0))
8482      (let* ((nr (fx- (##sys#size buf) pos))
8483             (n (read-bytevector!/port nr buf p pos)))
8484        (cond ((eq? n nr)
8485               (let* ((bsize2 (fx* bsize 2))
8486                      (buf2 (##sys#make-bytevector bsize2)))
8487                 (##core#inline "C_copy_memory" buf2 buf bsize)
8488                 (loop buf2 bsize2 (fx+ pos n))))
8489              (else (k buf (fx+ n pos))))))))
8490
8491(define read-bytevector/port
8492  (lambda (n p)
8493    (let* ((bv (##sys#make-bytevector n))
8494           (n2 (read-bytevector!/port n bv p 0)))
8495      (if (eq? n n2)
8496          bv
8497          (let ((bv2 (##sys#make-bytevector n2)))
8498            (##core#inline "C_copy_memory" bv2 bv n2)
8499            bv2)))))
8500
8501(define (read-string #!optional n (port ##sys#standard-input))
8502  (##sys#check-input-port port #t 'read-string)
8503  (when n (##sys#check-fixnum n 'read-string))
8504  (read-string/port n port))
8505
8506(define (read-bytevector #!optional n (port ##sys#standard-input))
8507  (##sys#check-input-port port #t 'read-bytevector)
8508  (cond (n (##sys#check-fixnum n 'read-bytevector)
8509           (let ((r (read-bytevector/port n port)))
8510             (if (eq? (##sys#size r) 0)
8511                 #!eof
8512                 r)))
8513        (else
8514          (##sys#read-remaining
8515            port
8516            (lambda (buf len)
8517              (if (eq? len 0)
8518                  #!eof
8519                  (let ((r (##sys#make-bytevector len)))
8520                    (##core#inline "C_copy_memory" r buf len)
8521                    r)))))))
8522
8523
8524;; Make internal reader procedures available for use in srfi-4.scm:
8525
8526(define chicken.io#read-string/port read-string/port)
8527(define chicken.io#read-string!/port read-string!/port)
8528(define chicken.io#read-bytevector/port read-bytevector/port)
8529(define chicken.io#read-bytevector!/port read-bytevector!/port)
8530
8531(define (read-buffered #!optional (port ##sys#standard-input))  ; DEPRECATED
8532  (##sys#check-input-port port #t 'read-buffered)
8533  (let ((rb (##sys#slot (##sys#slot port 2) 9))) ; read-buffered method
8534    (if rb
8535	(rb port)
8536	"")))
8537
8538
8539;;; read token of characters that satisfy a predicate
8540
8541(define read-token
8542  (lambda (pred . port)
8543    (let ([port (optional port ##sys#standard-input)])
8544      (##sys#check-input-port port #t 'read-token)
8545      (let ([out (open-output-string)])
8546	(let loop ()
8547	  (let ([c (##sys#peek-char-0 port)])
8548	    (if (and (not (eof-object? c)) (pred c))
8549		(begin
8550		  (##sys#write-char-0 (##sys#read-char-0 port) out)
8551		  (loop) )
8552		(get-output-string out) ) ) ) ) ) ) )
8553
8554
8555;;; Binary I/O
8556
8557(define (read-byte #!optional (port ##sys#standard-input))
8558  (##sys#check-input-port port #t 'read-byte)
8559  (let* ((bv (##sys#make-bytevector 1))
8560         (n (read-bytevector!/port 1 bv port 0)))
8561    (if (fx< n 1)
8562        #!eof
8563        (##core#inline "C_subbyte" bv 0))))
8564
8565(define (write-byte byte #!optional (port ##sys#standard-output))
8566  (##sys#check-fixnum byte 'write-byte)
8567  (##sys#check-output-port port #t 'write-byte)
8568  (let ((bv (##sys#make-bytevector 1 byte)))
8569    ((##sys#slot (##sys#slot port 2) 3) ; write-bytevector
8570     port bv 0 1)))
8571
8572(define (write-bytevector bv #!optional (port ##sys#standard-output) (start 0)
8573                          end)
8574  (##sys#check-bytevector bv 'write-bytevector)
8575  (##sys#check-output-port port #t 'write-bytevector)
8576  (##sys#check-fixnum start 'write-bytevector)
8577  (let ((len (##sys#size bv)))
8578    (##sys#check-range/including start 0 len 'write-bytevector)
8579    (when end (##sys#check-range/including end 0 len 'write-bytevector))
8580    (let ((end (if end (fxmin end len) len)))
8581      ((##sys#slot (##sys#slot port 2) 3) ; write-bytevector
8582       port bv start end))))
8583
8584) ; module chicken.io
Trap