~ 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	current-print-length 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 round-quotient
  41	##sys#string->compnum ##sys#internal-gcd)
  42  (not inline chicken.base#sleep-hook ##sys#change-directory-hook
  43       ##sys#user-read-hook ##sys#error-hook ##sys#signal-hook ##sys#signal-hook/errno
  44       ##sys#default-read-info-hook ##sys#infix-list-hook
  45       ##sys#sharp-number-hook ##sys#user-print-hook
  46       ##sys#user-interrupt-hook ##sys#windows-platform
  47       ##sys#resume-thread-on-event ##sys#suspend-thread-on-event
  48       ##sys#schedule ##sys#features)
  49  (foreign-declare #<<EOF
  50#include <errno.h>
  51#include <float.h>
  52
  53#ifdef HAVE_SYSEXITS_H
  54# include <sysexits.h>
  55#endif
  56
  57#ifndef EX_SOFTWARE
  58# define EX_SOFTWARE	70
  59#endif
  60
  61#define C_close_file(p)	      (C_fclose((C_FILEPTR)(C_port_file(p))), C_SCHEME_UNDEFINED)
  62#define C_a_f64peek(ptr, c, b, i)  C_flonum(ptr, ((double *)C_data_pointer(b))[ C_unfix(i) ])
  63#define C_fetch_c_strlen(b, i) C_fix(strlen((C_char *)C_block_item(b, C_unfix(i))))
  64#define C_asciiz_strlen(str) C_fix(strlen(C_c_string(str)))
  65#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)
  66#define C_free_mptr(p, i)     (C_free((void *)C_block_item(p, C_unfix(i))), C_SCHEME_UNDEFINED)
  67#define C_free_sptr(p, i)     (C_free((void *)(((C_char **)C_block_item(p, 0))[ C_unfix(i) ])), C_SCHEME_UNDEFINED)
  68
  69#define C_a_get_current_seconds(ptr, c, dummy)  C_int64_to_num(ptr, time(NULL))
  70#define C_peek_c_string_at(ptr, i)    ((C_char *)(((C_char **)ptr)[ i ]))
  71
  72#define C_flush_all_files(dummy)    (C_fflush(NULL), C_SCHEME_UNDEFINED)
  73
  74static C_word
  75fast_read_line_from_file(C_word str, C_word port, C_word size) {
  76  int n = C_unfix(size);
  77  int i;
  78  int c;
  79  char *buf = C_c_string(str);
  80  C_FILEPTR fp = C_port_file(port);
  81
  82  if ((c = C_getc(fp)) == EOF) {
  83    if (ferror(fp)) {
  84      clearerr(fp);
  85      return C_fix(-1);
  86    } else { /* feof (fp) */
  87      return C_SCHEME_END_OF_FILE;
  88    }
  89  }
  90
  91  C_ungetc(c, fp);
  92
  93  for (i = 0; i < n; i++) {
  94    c = C_getc(fp);
  95
  96    if(c == EOF && ferror(fp)) {
  97      clearerr(fp);
  98      return C_fix(-(i + 1));
  99    }
 100
 101    switch (c) {
 102    case '\r':	if ((c = C_getc(fp)) != '\n') C_ungetc(c, fp);
 103    case EOF:	clearerr(fp);
 104    case '\n':	return C_fix(i);
 105    }
 106    buf[i] = c;
 107  }
 108  return C_SCHEME_FALSE;
 109}
 110
 111static C_word
 112fast_read_string_from_file(C_word dest, C_word port, C_word len, C_word pos)
 113{
 114  size_t m;
 115  int n = C_unfix (len);
 116  C_char * buf = C_c_string(dest) + C_unfix(pos);
 117  C_FILEPTR fp = C_port_file (port);
 118
 119  if(feof(fp)) return C_SCHEME_END_OF_FILE;
 120
 121  m = fread (buf, sizeof (char), n, fp);
 122
 123  if (m < n) {
 124    if (ferror(fp)) /* Report to Scheme, which may retry, so clear errors */
 125      clearerr(fp);
 126    else if (feof(fp) && 0 == m) /* eof but m > 0? Return data first, below */
 127      return C_SCHEME_END_OF_FILE; /* Calling again will get us here */
 128  }
 129
 130  return C_fix (m);
 131}
 132
 133static C_word
 134shallow_equal(C_word x, C_word y)
 135{
 136  /* assumes x and y are non-immediate */
 137  int i, len = C_header_size(x);
 138
 139  if(C_header_size(y) != len) return C_SCHEME_FALSE;
 140  else return C_mk_bool(!C_memcmp((void *)x, (void *)y, len * sizeof(C_word)));
 141}
 142
 143static C_word
 144signal_debug_event(C_word mode, C_word msg, C_word args)
 145{
 146  C_DEBUG_INFO cell;
 147  C_word av[ 3 ];
 148  cell.enabled = 1;
 149  cell.event = C_DEBUG_SIGNAL;
 150  cell.loc = "";
 151  cell.val = "";
 152  av[ 0 ] = mode;
 153  av[ 1 ] = msg;
 154  av[ 2 ] = args;
 155  C_debugger(&cell, 3, av);
 156  return C_SCHEME_UNDEFINED;
 157}
 158
 159static C_word C_i_sleep_until_interrupt(C_word secs)
 160{
 161   while(C_i_process_sleep(secs) == C_fix(-1) && errno == EINTR);
 162   return C_SCHEME_UNDEFINED;
 163}
 164
 165#ifdef NO_DLOAD2
 166# define HAVE_DLOAD 0
 167#else
 168# define HAVE_DLOAD 1
 169#endif
 170
 171#ifdef C_ENABLE_PTABLES
 172# define HAVE_PTABLES 1
 173#else
 174# define HAVE_PTABLES 0
 175#endif
 176
 177#ifdef C_GC_HOOKS
 178# define HAVE_GCHOOKS 1
 179#else
 180# define HAVE_GCHOOKS 0
 181#endif
 182
 183#if defined(C_CROSS_CHICKEN) && C_CROSS_CHICKEN
 184# define IS_CROSS_CHICKEN 1
 185#else
 186# define IS_CROSS_CHICKEN 0
 187#endif
 188EOF
 189) )
 190
 191;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 192;; NOTE: Modules defined here will typically exclude syntax
 193;; definitions, those are handled by expand.scm or modules.scm.
 194;; Handwritten import libraries (or a special-case module in
 195;; modules.scm for scheme) contain the value exports merged with
 196;; syntactic exports.  The upshot of this is that any module that
 197;; refers to another module defined *earlier* in this file cannot use
 198;; macros from the earlier module!
 199;;
 200;; We get around this problem by using the "chicken.internal.syntax"
 201;; module, which is baked in and exports *every* available core macro.
 202;; See modules.scm, expand.scm and chicken-syntax.scm for details.
 203;;
 204;; NOTE #2: The module "scheme" is a legacy artifact, with CHICKEN
 205;; 6 "scheme" being just an alias for "scheme.r5rs", and "scheme.base"
 206;; is what used to be the standard Scheme module. We use it only
 207;; to provide a prefix ("scheme#") for the exported toplevel
 208;; identifiers, which now represent what is in the "scheme.base"
 209;; standard module. Yes, this is somewhat confusing, but changing
 210;; all prefixes to use the "proper" name would cause too many
 211;; bootstrapping problems.
 212;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 213
 214;; Pre-declaration of scheme, so it can be used later on.  We only use
 215;; scheme macros and core language forms in here, to avoid a cyclic
 216;; dependency on itself.  All actual definitions are set! below.
 217;; Also, this declaration is incomplete: the module itself is defined
 218;; as a primitive module due to syntax exports, which are missing
 219;; here.  See modules.scm for the full definition.
 220(module scheme
 221    (;; [syntax]
 222     ;; We are reexporting these because otherwise the module here
 223     ;; will be inconsistent with the built-in one, and be void of
 224     ;; syntax definitions, causing problems below.
 225     begin and case cond define define-syntax delay do lambda
 226     if let let* let-syntax letrec letrec-syntax or
 227     quasiquote quote set! syntax-rules
 228
 229     not boolean? eq? eqv? equal? pair? boolean=? symbol=?
 230     cons car cdr caar cadr cdar cddr caaar caadr cadar caddr cdaar
 231     cdadr cddar cdddr caaaar caaadr caadar caaddr cadaar cadadr
 232     caddar cadddr cdaaar cdaadr cdadar cdaddr cddaar cddadr cdddar
 233     cddddr set-car! set-cdr!
 234     null? list? list length list-tail list-ref append reverse memq memv
 235     member assq assv assoc symbol? symbol->string string->symbol number?
 236     integer? exact? real? complex? inexact? rational? zero? odd? even?
 237     positive? negative?  max min + - * / = > < >= <= quotient remainder
 238     exact-integer?
 239     modulo gcd lcm abs floor ceiling truncate round rationalize
 240     exact->inexact inexact->exact exp log expt sqrt
 241     sin cos tan asin acos atan
 242     number->string string->number char? char=? char>? char<? char>=?
 243     char<=? char-ci=? char-ci<? char-ci>?  char-ci>=? char-ci<=?
 244     char-alphabetic? char-whitespace? char-numeric? char-upper-case?
 245     char-lower-case? char-upcase char-downcase
 246     char->integer integer->char
 247     string? string=?  string>? string<? string>=? string<=? string-ci=?
 248     string-ci<? string-ci>? string-ci>=? string-ci<=?  make-string
 249     string-length string-ref string-set! string-append string-copy string-copy!
 250     string->list list->string substring string-fill! vector? make-vector
 251     vector-ref vector-set! string vector vector-length vector->list
 252     list->vector vector-fill! procedure? map for-each apply force
 253     call-with-current-continuation call/cc input-port? output-port?
 254     current-input-port current-output-port call-with-input-file
 255     call-with-output-file open-input-file open-output-file
 256     close-input-port close-output-port
 257     read read-char peek-char write display write-char newline
 258     eof-object? with-input-from-file with-output-to-file
 259     char-ready? imag-part real-part make-rectangular make-polar angle
 260     magnitude numerator denominator values call-with-values dynamic-wind
 261
 262     open-input-string open-output-string open-input-bytevector
 263     open-output-bytevector get-output-string get-output-bytevector
 264     features make-list port? call-with-port peek-u8 make-parameter
 265     string-map vector-map string-for-each vector-for-each u8-ready?
 266     make-list list-set! write-string eof-object list-copy
 267     string->vector vector->string textual-port? binary-port?
 268     input-port-open? output-port-open? floor/ truncate/
 269     exact inexact floor-remainder floor-quotient close-port
 270     
 271     char-foldcase string-foldcase string-upcase string-downcase
 272
 273     ;; The following procedures are overwritten in eval.scm:
 274     eval interaction-environment null-environment
 275     scheme-report-environment load)
 276
 277(import chicken.internal.syntax) ;; See note above
 278
 279;;; Operations on booleans:
 280
 281(define (not x) (##core#inline "C_i_not" x))
 282(define (boolean? x) (##core#inline "C_booleanp" x))
 283
 284
 285;;; Equivalence predicates:
 286
 287(define (eq? x y) (##core#inline "C_eqp" x y))
 288(define (eqv? x y) (##core#inline "C_i_eqvp" x y))
 289(define (equal? x y) (##core#inline "C_i_equalp" x y))
 290
 291(define (boolean=? x y . more)
 292  (##sys#check-boolean x 'boolean=?)
 293  (##sys#check-boolean y 'boolean=?)
 294  (let loop ((bs more) (f (eq? x y)))
 295    (if (null? bs)
 296        f
 297        (let ((b (##sys#slot bs 0)))
 298          (##sys#check-boolean b 'boolean=?)
 299          (loop (##sys#slot bs 1)
 300                (and f (eq? b y)))))))
 301
 302(define (symbol=? x y . more)
 303  (##sys#check-symbol x 'symbol=?)
 304  (##sys#check-symbol y 'symbol=?)
 305  (let loop ((bs more) (f (eq? x y)))
 306    (if (null? bs)
 307        f
 308        (let ((b (##sys#slot bs 0)))
 309          (##sys#check-symbol b 'symbol=?)
 310          (loop (##sys#slot bs 1)
 311                (and f (eq? b y)))))))
 312
 313
 314;;; Pairs and lists:
 315
 316(define (pair? x) (##core#inline "C_i_pairp" x))
 317(define (cons x y) (##core#inline_allocate ("C_a_i_cons" 3) x y))
 318(define (car x) (##core#inline "C_i_car" x))
 319(define (cdr x) (##core#inline "C_i_cdr" x))
 320
 321(define (set-car! x y) (##core#inline "C_i_set_car" x y))
 322(define (set-cdr! x y) (##core#inline "C_i_set_cdr" x y))
 323(define (cadr x) (##core#inline "C_i_cadr" x))
 324(define (caddr x) (##core#inline "C_i_caddr" x))
 325(define (cadddr x) (##core#inline "C_i_cadddr" x))
 326(define (cddddr x) (##core#inline "C_i_cddddr" x))
 327
 328(define (caar x) (##core#inline "C_i_caar" x))
 329(define (cdar x) (##core#inline "C_i_cdar" x))
 330(define (cddr x) (##core#inline "C_i_cddr" x))
 331(define (caaar x) (car (car (car x))))
 332(define (caadr x) (car (##core#inline "C_i_cadr" x)))
 333(define (cadar x) (##core#inline "C_i_cadr" (car x)))
 334(define (cdaar x) (cdr (car (car x))))
 335(define (cdadr x) (cdr (##core#inline "C_i_cadr" x)))
 336(define (cddar x) (cdr (cdr (car x))))
 337(define (cdddr x) (cdr (cdr (cdr x))))
 338(define (caaaar x) (car (car (car (car x)))))
 339(define (caaadr x) (car (car (##core#inline "C_i_cadr" x))))
 340(define (caadar x) (car (##core#inline "C_i_cadr" (car x))))
 341(define (caaddr x) (car (##core#inline "C_i_caddr" x)))
 342(define (cadaar x) (##core#inline "C_i_cadr" (car (car x))))
 343(define (cadadr x) (##core#inline "C_i_cadr" (##core#inline "C_i_cadr" x)))
 344(define (caddar x) (##core#inline "C_i_caddr" (car x)))
 345(define (cdaaar x) (cdr (car (car (car x)))))
 346(define (cdaadr x) (cdr (car (##core#inline "C_i_cadr" x))))
 347(define (cdadar x) (cdr (##core#inline "C_i_cadr" (car x))))
 348(define (cdaddr x) (cdr (##core#inline "C_i_caddr" x)))
 349(define (cddaar x) (cdr (cdr (car (car x)))))
 350(define (cddadr x) (cdr (cdr (##core#inline "C_i_cadr" x))))
 351(define (cdddar x) (cdr (cdr (cdr (car x)))))
 352
 353(define (null? x) (eq? x '()))
 354(define (list . lst) lst)
 355(define (length lst) (##core#inline "C_i_length" lst))
 356(define (list-tail lst i) (##core#inline "C_i_list_tail" lst i))
 357(define (list-ref lst i) (##core#inline "C_i_list_ref" lst i))
 358
 359(define append)
 360
 361(define (reverse lst0)
 362  (let loop ((lst lst0) (rest '()))
 363    (cond ((eq? lst '()) rest)
 364	  ((pair? lst)
 365	   (loop (##sys#slot lst 1) (cons (##sys#slot lst 0) rest)) )
 366	  (else (##sys#error-not-a-proper-list lst0 'reverse)) ) ))
 367
 368(define (memq x lst) (##core#inline "C_i_memq" x lst))
 369(define (memv x lst) (##core#inline "C_i_memv" x lst))
 370
 371(define (member x lst #!optional eq)
 372  (if eq
 373      (let loop ((lst lst))
 374        (and (pair? lst)
 375             (if (eq x (##sys#slot lst 0))
 376                 lst
 377                 (loop (##sys#slot lst 1)))))
 378      (##core#inline "C_i_member" x lst)))
 379
 380(define (assq x lst) (##core#inline "C_i_assq" x lst))
 381(define (assv x lst) (##core#inline "C_i_assv" x lst))
 382
 383(define (assoc x lst #!optional eq)
 384  (if eq
 385      (let loop ((lst lst))
 386        (and (pair? lst)
 387             (if (eq x (car (##sys#slot lst 0)))
 388                 (car lst)
 389                 (loop (##sys#slot lst 1)))))
 390      (##core#inline "C_i_assoc" x lst)))
 391
 392(define (list? x) (##core#inline "C_i_listp" x))
 393
 394;;; Strings:
 395
 396(define make-string)
 397
 398(define (string? x) (##core#inline "C_i_stringp" x))
 399(define (string-length s) (##core#inline "C_i_string_length" s))
 400(define (string-ref s i) (##core#inline "C_i_string_ref" s i))
 401(define (string-set! s i c) (##core#inline "C_i_string_set" s i c))
 402
 403(define (string=? x y . more)
 404  (let loop ((s y) (ss more) (f (##core#inline "C_i_string_equal_p" x y)))
 405    (if (null? ss)
 406        f
 407        (let ((s2 (##sys#slot ss 0)))
 408          (##sys#check-string s2 'string=?)
 409          (loop s2 (##sys#slot ss 1)
 410                (and f (##core#inline "C_i_string_equal_p" s s2)))))))
 411
 412(define (string-ci=? x y . more)
 413  (let loop ((s y) (ss more) (f (##core#inline "C_i_string_ci_equal_p" x y)))
 414    (if (null? ss)
 415        f
 416        (let ((s2 (##sys#slot ss 0)))
 417          (##sys#check-string s2 'string-ci=?)
 418          (loop s2 (##sys#slot ss 1)
 419                (and f (##core#inline "C_i_string_ci_equal_p" s s2)))))))
 420
 421(define string->list)
 422(define list->string)
 423(define string-copy)
 424(define string-copy!)
 425(define substring)
 426(define string-fill!)
 427
 428(define string<?)
 429(define string>?)
 430(define string<=?)
 431(define string>=?)
 432
 433(define string-ci<?)
 434(define string-ci>?)
 435(define string-ci<=?)
 436(define string-ci>=?)
 437
 438(define string)
 439(define string-append)
 440
 441(define open-input-string)
 442(define open-output-string)
 443(define open-input-bytevector)
 444(define open-output-bytevector)
 445(define get-output-string)
 446(define get-output-bytevector)
 447(define features)
 448(define make-list)
 449(define port?)
 450(define call-with-port)
 451(define close-port)
 452(define peek-u8)
 453(define string-map)
 454(define vector-map)
 455(define string-for-each)
 456(define vector-for-each)
 457(define make-list)
 458(define list-set!)
 459(define write-string)
 460(define eof-object)
 461(define list-copy)
 462(define string->vector)
 463(define vector->string)
 464(define input-port-open?)
 465(define output-port-open?)
 466(define floor/)
 467(define truncate/)
 468(define exact)
 469(define inexact)
 470(define floor-remainder)
 471(define floor-quotient)
 472(define make-parameter)
 473
 474;; Complex numbers
 475(define make-rectangular)
 476(define make-polar)
 477(define real-part)
 478(define imag-part)
 479(define angle)
 480(define magnitude)
 481
 482;; Rational numbers
 483(define numerator)
 484(define denominator)
 485(define inexact->exact)
 486(define (exact->inexact x)
 487  (##core#inline_allocate ("C_a_i_exact_to_inexact" 12) x))
 488
 489;; Numerical operations
 490(define (abs x) (##core#inline_allocate ("C_s_a_i_abs" 7) x))
 491(define + (##core#primitive "C_plus"))
 492(define - (##core#primitive "C_minus"))
 493(define * (##core#primitive "C_times"))
 494(define /)
 495(define floor)
 496(define ceiling)
 497(define truncate)
 498(define round)
 499(define rationalize)
 500
 501(define (quotient a b) (##core#inline_allocate ("C_s_a_i_quotient" 5) a b))
 502(define (remainder a b) (##core#inline_allocate ("C_s_a_i_remainder" 5) a b))
 503(define (modulo a b) (##core#inline_allocate ("C_s_a_i_modulo" 5) a b))
 504
 505(define (even? n) (##core#inline "C_i_evenp" n))
 506(define (odd? n) (##core#inline "C_i_oddp" n))
 507
 508(define max)
 509(define min)
 510(define exp)
 511(define log)
 512(define sin)
 513(define cos)
 514(define tan)
 515(define asin)
 516(define acos)
 517(define atan)
 518
 519(define sqrt)
 520(define expt)
 521(define gcd)
 522(define lcm)
 523
 524(define = (##core#primitive "C_nequalp"))
 525(define > (##core#primitive "C_greaterp"))
 526(define < (##core#primitive "C_lessp"))
 527(define >= (##core#primitive "C_greater_or_equal_p"))
 528(define <= (##core#primitive "C_less_or_equal_p"))
 529(define (number? x) (##core#inline "C_i_numberp" x))
 530(define complex? number?)
 531(define (real? x) (##core#inline "C_i_realp" x))
 532(define (rational? n) (##core#inline "C_i_rationalp" n))
 533(define (integer? x) (##core#inline "C_i_integerp" x))
 534(define (exact? x) (##core#inline "C_i_exactp" x))
 535(define (inexact? x) (##core#inline "C_i_inexactp" x))
 536(define (zero? n) (##core#inline "C_i_zerop" n))
 537(define (positive? n) (##core#inline "C_i_positivep" n))
 538(define (negative? n) (##core#inline "C_i_negativep" n))
 539(define (exact-integer? x) (##core#inline "C_i_exact_integerp" x))
 540
 541(define number->string (##core#primitive "C_number_to_string"))
 542(define string->number)
 543
 544
 545;;; Symbols:
 546
 547(define (symbol? x) (##core#inline "C_i_symbolp" x))
 548(define symbol->string)
 549(define string->symbol)
 550
 551;;; Vectors:
 552
 553(define (vector? x) (##core#inline "C_i_vectorp" x))
 554(define (vector-length v) (##core#inline "C_i_vector_length" v))
 555(define (vector-ref v i) (##core#inline "C_i_vector_ref" v i))
 556(define (vector-set! v i x) (##core#inline "C_i_vector_set" v i x))
 557(define make-vector)
 558(define list->vector)
 559(define vector->list)
 560(define vector)
 561(define vector-fill!)
 562
 563;;; Characters:
 564
 565(define (char? x) (##core#inline "C_charp" x))
 566
 567(define (char->integer c)
 568  (##sys#check-char c 'char->integer)
 569  (##core#inline "C_fix" (##core#inline "C_character_code" c)) )
 570
 571(define (##sys#check-char-code n loc)
 572  (if (or (##core#inline "C_fixnum_lessp" n 0)
 573          (##core#inline "C_fixnum_greaterp" n #x10ffff))
 574    (##sys#signal-hook
 575      #:domain-error loc "character code is out of valid range" n)
 576    n))
 577
 578(define-inline (fast-i->c n)
 579  (##core#inline "C_make_character" (##core#inline "C_unfix" n)) )
 580
 581(define (integer->char n)
 582  (##sys#check-fixnum n 'integer->char)
 583  (##sys#check-char-code n 'integer->char)
 584  (fast-i->c n))
 585 
 586(define (char=? c1 c2 . more)
 587  (##sys#check-char c1 'char=?)
 588  (##sys#check-char c2 'char=?)
 589  (let loop ((c c2) (cs more)
 590             (f (##core#inline "C_u_i_char_equalp" c1 c2)))
 591    (if (null? cs)
 592        f
 593        (let ((c2 (##sys#slot cs 0)))
 594          (##sys#check-char c2 'char=?)
 595          (loop c2 (##sys#slot cs 1)
 596                (and f (##core#inline "C_u_i_char_equalp" c c2)))))))
 597
 598(define (char>? c1 c2 . more)
 599  (##sys#check-char c1 'char>?)
 600  (##sys#check-char c2 'char>?)
 601  (let loop ((c c2) (cs more)
 602             (f (##core#inline "C_u_i_char_greaterp" c1 c2)))
 603    (if (null? cs)
 604        f
 605        (let ((c2 (##sys#slot cs 0)))
 606          (##sys#check-char c2 'char>?)
 607          (loop c2 (##sys#slot cs 1)
 608                (and f (##core#inline "C_u_i_char_greaterp" c c2)))))))
 609
 610(define (char<? c1 c2 . more)
 611  (##sys#check-char c1 'char<?)
 612  (##sys#check-char c2 'char<?)
 613  (let loop ((c c2) (cs more)
 614             (f (##core#inline "C_u_i_char_lessp" c1 c2)))
 615    (if (null? cs)
 616        f
 617        (let ((c2 (##sys#slot cs 0)))
 618          (##sys#check-char c2 'char<?)
 619          (loop c2 (##sys#slot cs 1)
 620                (and f (##core#inline "C_u_i_char_lessp" c c2)))))))
 621
 622(define (char>=? c1 c2 . more)
 623  (##sys#check-char c1 'char>=?)
 624  (##sys#check-char c2 'char>=?)
 625  (let loop ((c c2) (cs more)
 626             (f (##core#inline "C_u_i_char_greater_or_equal_p" c1 c2)))
 627    (if (null? cs)
 628        f
 629        (let ((c2 (##sys#slot cs 0)))
 630          (##sys#check-char c2 'char>=?)
 631          (loop c2 (##sys#slot cs 1)
 632                (and f (##core#inline "C_u_i_char_greater_or_equal_p" c c2)))))))
 633
 634(define (char<=? c1 c2 . more)
 635  (##sys#check-char c1 'char<=?)
 636  (##sys#check-char c2 'char<=?)
 637  (let loop ((c c2) (cs more)
 638             (f (##core#inline "C_u_i_char_less_or_equal_p" c1 c2)))
 639    (if (null? cs)
 640        f
 641        (let ((c2 (##sys#slot cs 0)))
 642          (##sys#check-char c2 'char<=?)
 643          (loop c2 (##sys#slot cs 1)
 644                (and f (##core#inline "C_u_i_char_less_or_equal_p" c c2)))))))
 645
 646(define (char-upcase c)
 647  (##sys#check-char c 'char-upcase)
 648  (##core#inline "C_u_i_char_upcase" c))
 649
 650(define (char-downcase c)
 651  (##sys#check-char c 'char-downcase)
 652  (##core#inline "C_u_i_char_downcase" c))
 653
 654(define char-ci=?)
 655(define char-ci>?)
 656(define char-ci<?)
 657(define char-ci>=?)
 658(define char-ci<=?)
 659
 660(define (char-upper-case? c)
 661  (##sys#check-char c 'char-upper-case?)
 662  (##core#inline "C_u_i_char_upper_casep" c) )
 663
 664(define (char-lower-case? c)
 665  (##sys#check-char c 'char-lower-case?)
 666  (##core#inline "C_u_i_char_lower_casep" c) )
 667
 668(define (char-numeric? c)
 669  (##sys#check-char c 'char-numeric?)
 670  (##core#inline "C_u_i_char_numericp" c) )
 671
 672(define (char-whitespace? c)
 673  (##sys#check-char c 'char-whitespace?)
 674  (##core#inline "C_u_i_char_whitespacep" c) )
 675
 676(define (char-alphabetic? c)
 677  (##sys#check-char c 'char-alphabetic?)
 678  (##core#inline "C_u_i_char_alphabeticp" c) )
 679
 680(define (scheme.char#digit-value c)
 681  (##sys#check-char c 'digit-value)
 682  (let ((n (##core#inline "C_u_i_digit_value" c)))
 683    (and (not (eq? n 0))
 684         (##core#inline "C_fixnum_difference" n 1))))
 685
 686;; case folding and conversion
 687
 688(define (char-foldcase c)
 689  (##sys#check-char c 'char-foldcase)
 690  (##core#inline "C_utf_char_foldcase" c))
 691
 692(define (string-foldcase str)
 693  (##sys#check-string str 'string-foldcase)
 694  (let* ((bv (##sys#slot str 0))
 695         (n (##core#inline "C_fixnum_difference" (##sys#size bv) 1))
 696         (buf (##sys#make-bytevector (##core#inline "C_fixnum_times" n 2)))
 697         (len (##core#inline "C_utf_string_foldcase" bv buf n)))
 698    (##sys#buffer->string! buf len)))
 699    
 700(define (string-downcase str)
 701  (##sys#check-string str 'string-downcase)
 702  (let* ((bv (##sys#slot str 0))
 703         (n (##core#inline "C_fixnum_difference" (##sys#size bv) 1))
 704         (buf (##sys#make-bytevector (##core#inline "C_fixnum_times" n 2)))
 705         (len (##core#inline "C_utf_string_downcase" bv buf n)))
 706    (##sys#buffer->string! buf len)))
 707
 708(define (string-upcase str)
 709  (##sys#check-string str 'string-upcase)
 710  (let* ((bv (##sys#slot str 0))
 711         (n (##core#inline "C_fixnum_difference" (##sys#size bv) 1))
 712         (buf (##sys#make-bytevector (##core#inline "C_fixnum_times" n 2)))
 713         (len (##core#inline "C_utf_string_upcase" bv buf n)))
 714    (##sys#buffer->string! buf len)))
 715
 716;;; Procedures:
 717
 718(define (procedure? x) (##core#inline "C_i_closurep" x))
 719(define apply (##core#primitive "C_apply"))
 720(define values (##core#primitive "C_values"))
 721(define call-with-values (##core#primitive "C_call_with_values"))
 722(define call-with-current-continuation)
 723(define call/cc)
 724
 725;;; Ports:
 726
 727(define (input-port? x)
 728  (and (##core#inline "C_blockp" x)
 729       (##core#inline "C_input_portp" x)))
 730
 731(define (output-port? x)
 732  (and (##core#inline "C_blockp" x)
 733       (##core#inline "C_output_portp" x)))
 734
 735(define (binary-port? port)
 736  (and (port? port)
 737       (eq? 'binary (##sys#slot port 14))))
 738
 739(define (textual-port? port)
 740  (and (port? port)
 741       (eq? 'textual (##sys#slot port 14))))
 742
 743(set! scheme#port?
 744  (lambda (x)
 745    (and (##core#inline "C_blockp" x)
 746         (##core#inline "C_portp" x))))
 747
 748(set! scheme#input-port-open?
 749  (lambda (p)
 750    (##sys#check-input-port p 'input-port-open?)
 751    (##core#inline "C_input_port_openp" p)))
 752
 753(set! scheme#output-port-open?
 754  (lambda (p)
 755    (##sys#check-output-port p 'output-port-open?)
 756    (##core#inline "C_output_port_openp" p)))
 757
 758(define current-input-port)
 759(define current-output-port)
 760(define open-input-file)
 761(define open-output-file)
 762(define close-input-port)
 763(define close-output-port)
 764(define call-with-input-file)
 765(define call-with-output-file)
 766(define with-input-from-file)
 767(define with-output-to-file)
 768
 769;;; Input:
 770
 771(define (eof-object? x) (##core#inline "C_eofp" x))
 772(define char-ready?)
 773(define u8-ready?)
 774(define read-char)
 775(define peek-char)
 776(define read)
 777
 778;;; Output:
 779
 780(define write-char)
 781(define newline)
 782(define write)
 783(define display)
 784
 785;;; Evaluation environments:
 786
 787;; All of the stuff below is overwritten with their "real"
 788;; implementations by chicken.eval (see eval.scm)
 789
 790(define (eval x . env)
 791  (##sys#error 'eval "`eval' is not defined - the `eval' unit was probably not linked with this executable"))
 792
 793(define (interaction-environment)
 794  (##sys#error 'interaction-environment "`interaction-environment' is not defined - the `eval' unit was probably not linked with this executable"))
 795
 796(define (scheme-report-environment n)
 797  (##sys#error 'scheme-report-environment "`scheme-report-environment' is not defined - the `eval' unit was probably not linked with this executable"))
 798
 799(define (null-environment)
 800  (##sys#error 'null-environment "`null-environment' is not defined - the `eval' unit was probably not linked with this executable"))
 801
 802(define (load filename . evaluator)
 803  (##sys#error 'load "`load' is not defined - the `eval' unit was probably not linked with this executable"))
 804
 805;; Other stuff:
 806
 807(define force)
 808(define for-each)
 809(define map)
 810(define dynamic-wind)
 811
 812) ; scheme
 813
 814(import scheme)
 815(import (only (scheme base) make-parameter open-output-string get-output-string))
 816
 817;; Pre-declaration of chicken.base, so it can be used later on.  Much
 818;; like the "scheme" module, most declarations will be set! further
 819;; down in this file, mostly to avoid a cyclic dependency on itself.
 820;; The full definition (with macros) is in its own import library.
 821(module chicken.base
 822  (;; [syntax] and-let* case-lambda cut cute declare define-constant
 823   ;; define-inline define-record define-record-type
 824   ;; define-values delay-force fluid-let include
 825   ;; include-relative let-optionals let-values let*-values letrec*
 826   ;; letrec-values nth-value optional parameterize rec receive
 827   ;; require-library require-extension set!-values syntax unless when
 828   bignum? flonum? fixnum? ratnum? cplxnum? finite? infinite? nan?
 829   exact-integer-sqrt exact-integer-nth-root
 830
 831   port-closed? flush-output
 832   get-call-chain print print* add1 sub1 sleep
 833   current-error-port error void gensym print-call-chain
 834   char-name enable-warnings
 835   equal=? finite? foldl foldr getter-with-setter
 836   notice procedure-information setter signum string->uninterned-symbol
 837   subvector symbol-append vector-resize
 838   warning quotient&remainder quotient&modulo
 839   record-printer set-record-printer!
 840   make-promise promise?
 841   alist-ref alist-update alist-update! rassoc atom? butlast chop
 842   compress flatten intersperse join list-of? tail? constantly
 843   complement compose conjoin disjoin each flip identity o
 844
 845   case-sensitive keyword-style parentheses-synonyms symbol-escape
 846
 847   on-exit exit exit-handler implicit-exit-handler emergency-exit
 848   bwp-object? weak-cons weak-pair?)
 849
 850(import scheme chicken.internal.syntax)
 851
 852(define (fixnum? x) (##core#inline "C_fixnump" x))
 853(define (flonum? x) (##core#inline "C_i_flonump" x))
 854(define (bignum? x) (##core#inline "C_i_bignump" x))
 855(define (ratnum? x) (##core#inline "C_i_ratnump" x))
 856(define (cplxnum? x) (##core#inline "C_i_cplxnump" x))
 857(define exact-integer-sqrt)
 858(define exact-integer-nth-root)
 859
 860(define quotient&remainder (##core#primitive "C_quotient_and_remainder"))
 861;; Modulo's sign follows y (whereas remainder's sign follows x)
 862;; Inlining this is not much use: quotient&remainder is primitive
 863(define (quotient&modulo x y)
 864  (call-with-values (lambda () (quotient&remainder x y))
 865    (lambda (div rem)
 866      (if (positive? y)
 867	  (if (negative? rem)
 868	      (values div (+ rem y))
 869	      (values div rem))
 870	  (if (positive? rem)
 871	      (values div (+ rem y))
 872	      (values div rem))))))
 873
 874
 875(define (finite? x) (##core#inline "C_i_finitep" x))
 876(define (infinite? x) (##core#inline "C_i_infinitep" x))
 877(define (nan? x) (##core#inline "C_i_nanp" x))
 878
 879(define signum (##core#primitive "C_signum"))
 880
 881(define equal=?)
 882(define get-call-chain)
 883(define print-call-chain)
 884(define print)
 885(define print*)
 886(define (add1 n) (+ n 1))
 887(define (sub1 n) (- n 1))
 888(define current-error-port)
 889
 890(define (error . args)
 891  (if (pair? args)
 892      (apply ##sys#signal-hook #:error args)
 893      (##sys#signal-hook #:error #f)))
 894
 895(define (void . _) (##core#undefined))
 896
 897(define sleep)
 898
 899(define char-name)
 900(define enable-warnings)
 901; (define enable-notices)???
 902(define getter-with-setter)
 903(define procedure-information)
 904(define setter)
 905(define string->uninterned-symbol)
 906(define record-printer)
 907(define set-record-printer!)
 908
 909(define gensym)
 910
 911(define subvector)
 912(define vector-resize)
 913
 914(define symbol-append)
 915(define warning)
 916(define notice)
 917
 918(define port-closed?)
 919(define flush-output)
 920
 921;;; Promises:
 922
 923(define (promise? x)
 924  (##sys#structure? x 'promise))
 925
 926(define (##sys#make-promise proc)
 927  (##sys#make-structure 'promise proc))
 928
 929(define (make-promise obj)
 930  (if (promise? obj) obj
 931      (##sys#make-promise (lambda () obj))))
 932
 933;;; fast folds with correct argument order
 934
 935(define (foldl f z lst)
 936  (##sys#check-list lst 'foldl)
 937  (let loop ((lst lst) (z z))
 938    (if (not (pair? lst))
 939	z
 940	(loop (##sys#slot lst 1) (f z (##sys#slot lst 0))))))
 941
 942(define (foldr f z lst)
 943  (##sys#check-list lst 'foldr)
 944  (let loop ((lst lst))
 945    (if (not (pair? lst))
 946	z
 947	(f (##sys#slot lst 0) (loop (##sys#slot lst 1))))))
 948
 949;;; Exit:
 950
 951(define implicit-exit-handler)
 952(define exit-handler)
 953
 954(define chicken.base#cleanup-tasks '())
 955
 956(define (on-exit thunk)
 957  (set! cleanup-tasks (cons thunk chicken.base#cleanup-tasks)))
 958
 959(define (exit #!optional (code 0))
 960  ((exit-handler) code))
 961
 962(define (emergency-exit #!optional (code 0))
 963  (##sys#check-fixnum code 'emergency-exit)
 964  (##core#inline "C_exit_runtime" code))
 965
 966;;; Parameters:
 967
 968(define case-sensitive)
 969(define keyword-style)
 970(define parentheses-synonyms)
 971(define symbol-escape)
 972
 973;;; Combinators:
 974
 975(define (identity x) x)
 976
 977(define (conjoin . preds)
 978  (lambda (x)
 979    (let loop ((preds preds))
 980      (or (null? preds)
 981	  (and ((##sys#slot preds 0) x)
 982	       (loop (##sys#slot preds 1)) ) ) ) ) )
 983
 984(define (disjoin . preds)
 985  (lambda (x)
 986    (let loop ((preds preds))
 987      (and (not (null? preds))
 988	   (or ((##sys#slot preds 0) x)
 989	       (loop (##sys#slot preds 1)) ) ) ) ) )
 990
 991(define (constantly . xs)
 992  (if (eq? 1 (length xs))
 993      (let ((x (car xs)))
 994	(lambda _ x) )
 995      (lambda _ (apply values xs)) ) )
 996
 997(define (flip proc) (lambda (x y) (proc y x)))
 998
 999(define complement
 1000  (lambda (p)
1001    (lambda args (not (apply p args))) ) )
1002
1003(define (compose . fns)
1004  (define (rec f0 . fns)
1005    (if (null? fns)
1006	f0
1007	(lambda args
1008	  (call-with-values
1009	      (lambda () (apply (apply rec fns) args))
1010	    f0) ) ) )
1011  (if (null? fns)
1012      values
1013      (apply rec fns) ) )
1014
1015(define (o . fns)
1016  (if (null? fns)
1017      identity
1018      (let loop ((fns fns))
1019	(let ((h (##sys#slot fns 0))
1020	      (t (##sys#slot fns 1)) )
1021	  (if (null? t)
1022	      h
1023	      (lambda (x) (h ((loop t) x))))))))
1024
1025(define (list-of? pred)
1026  (lambda (lst)
1027    (let loop ((lst lst))
1028      (cond ((null? lst) #t)
1029	    ((not (pair? lst)) #f)
1030	    ((pred (##sys#slot lst 0)) (loop (##sys#slot lst 1)))
1031	    (else #f) ) ) ) )
1032
1033(define (each . procs)
1034  (cond ((null? procs) (lambda _ (void)))
1035	((null? (##sys#slot procs 1)) (##sys#slot procs 0))
1036	(else
1037	 (lambda args
1038	   (let loop ((procs procs))
1039	     (let ((h (##sys#slot procs 0))
1040		   (t (##sys#slot procs 1)) )
1041	       (if (null? t)
1042		   (apply h args)
1043		   (begin
1044		     (apply h args)
1045		     (loop t) ) ) ) ) ) ) ) )
1046
1047
1048;;; Weak pairs:
1049(define (bwp-object? x) (##core#inline "C_bwpp" x))
1050(define (weak-cons x y) (##core#inline_allocate ("C_a_i_weak_cons" 3) x y))
1051(define (weak-pair? x) (##core#inline "C_i_weak_pairp" x))
1052
1053;;; List operators:
1054
1055(define (atom? x) (##core#inline "C_i_not_pair_p" x))
1056
1057(define (tail? x y)
1058  (##sys#check-list y 'tail?)
1059  (let loop ((y y))
1060    (cond ((##core#inline "C_eqp" x y) #t)
1061          ((and (##core#inline "C_blockp" y)
1062                (##core#inline "C_pairp" y))
1063           (loop (##sys#slot y 1)))
1064          (else #f))))
1065
1066(define intersperse
1067  (lambda (lst x)
1068    (let loop ((ns lst))
1069      (if (##core#inline "C_eqp" ns '())
1070	  ns
1071	  (let ((tail (cdr ns)))
1072	    (if (##core#inline "C_eqp" tail '())
1073		ns
1074		(cons (##sys#slot ns 0) (cons x (loop tail))) ) ) ) ) ) )
1075
1076(define (butlast lst)
1077  (##sys#check-pair lst 'butlast)
1078  (let loop ((lst lst))
1079    (let ((next (##sys#slot lst 1)))
1080      (if (and (##core#inline "C_blockp" next) (##core#inline "C_pairp" next))
1081	  (cons (##sys#slot lst 0) (loop next))
1082	  '() ) ) ) )
1083
1084(define (flatten . lists0)
1085  (let loop ((lists lists0) (rest '()))
1086    (cond ((null? lists) rest)
1087	  (else
1088	   (let ((head (##sys#slot lists 0))
1089		 (tail (##sys#slot lists 1)) )
1090	     (if (list? head)
1091		 (loop head (loop tail rest))
1092		 (cons head (loop tail rest)) ) ) ) ) ) )
1093
1094(define chop)
1095
1096(define (join lsts . lst)
1097  (let ((lst (if (pair? lst) (car lst) '())))
1098    (##sys#check-list lst 'join)
1099    (let loop ((lsts lsts))
1100      (cond ((null? lsts) '())
1101	    ((not (pair? lsts))
1102	     (##sys#error-not-a-proper-list lsts) )
1103	    (else
1104	     (let ((l (##sys#slot lsts 0))
1105		   (r (##sys#slot lsts 1)) )
1106	       (if (null? r)
1107		   l
1108		   (##sys#append l lst (loop r)) ) ) ) ) ) ) )
1109
1110(define compress
1111  (lambda (blst lst)
1112    (let ((msg "bad argument type - not a proper list"))
1113      (##sys#check-list lst 'compress)
1114      (let loop ((blst blst) (lst lst))
1115	(cond ((null? blst) '())
1116	      ((not (pair? blst))
1117	       (##sys#signal-hook #:type-error 'compress msg blst) )
1118	      ((not (pair? lst))
1119	       (##sys#signal-hook #:type-error 'compress msg lst) )
1120	      ((##sys#slot blst 0)
1121	       (cons (##sys#slot lst 0) (loop (##sys#slot blst 1) (##sys#slot lst 1))))
1122	      (else (loop (##sys#slot blst 1) (##sys#slot lst 1))) ) ) ) ) )
1123
1124
1125;;; Alists:
1126
1127(define (alist-update! x y lst #!optional (cmp eqv?))
1128  (let* ((aq (cond ((eq? eq? cmp) assq)
1129		   ((eq? eqv? cmp) assv)
1130		   ((eq? equal? cmp) assoc)
1131		   (else
1132		    (lambda (x lst)
1133		      (let loop ((lst lst))
1134			(and (pair? lst)
1135			     (let ((a (##sys#slot lst 0)))
1136			       (if (and (pair? a) (cmp x (##sys#slot a 0)))
1137				   a
1138				   (loop (##sys#slot lst 1)) ) ) ) ) ) ) ) )
1139	 (item (aq x lst)) )
1140    (if item
1141	(begin
1142	  (##sys#setslot item 1 y)
1143	  lst)
1144	(cons (cons x y) lst) ) ) )
1145
1146(define (alist-update k v lst #!optional (cmp eqv?))
1147  (let loop ((lst lst))
1148    (cond ((null? lst)
1149           (list (cons k v)))
1150          ((not (pair? lst))
1151           (error 'alist-update "bad argument type" lst))
1152          (else
1153           (let ((a (##sys#slot lst 0)))
1154             (cond ((not (pair? a))
1155                    (error 'alist-update "bad argument type" a))
1156                   ((cmp k (##sys#slot a 0))
1157                    (cons (cons k v) (##sys#slot lst 1)))
1158                   (else
1159                    (cons (cons (##sys#slot a 0) (##sys#slot a 1))
1160                          (loop (##sys#slot lst 1))))))))))
1161
1162(define (alist-ref x lst #!optional (cmp eqv?) (default #f))
1163  (let* ((aq (cond ((eq? eq? cmp) assq)
1164		   ((eq? eqv? cmp) assv)
1165		   ((eq? equal? cmp) assoc)
1166		   (else
1167		    (lambda (x lst)
1168		      (let loop ((lst lst))
1169			(cond
1170			 ((null? lst) #f)
1171			 ((pair? lst)
1172			  (let ((a (##sys#slot lst 0)))
1173			    (##sys#check-pair a 'alist-ref)
1174			    (if (cmp x (##sys#slot a 0))
1175				a
1176				(loop (##sys#slot lst 1)) ) ))
1177			 (else (error 'alist-ref "bad argument type" lst)) )  ) ) ) ) )
1178	 (item (aq x lst)) )
1179    (if item
1180	(##sys#slot item 1)
1181	default) ) )
1182
1183;; TODO: Make inlineable in C without "tst", to be more like assoc?
1184(define (rassoc x lst . tst)
1185  (##sys#check-list lst 'rassoc)
1186  (let ((tst (if (pair? tst) (car tst) eqv?)))
1187    (let loop ((l lst))
1188      (and (pair? l)
1189	   (let ((a (##sys#slot l 0)))
1190	     (##sys#check-pair a 'rassoc)
1191	     (if (tst x (##sys#slot a 1))
1192		 a
1193		 (loop (##sys#slot l 1)) ) ) ) ) ) )
1194
1195) ; chicken.base
1196
1197(import chicken.base)
1198
1199(define-constant output-string-initial-size 256)
1200
1201(set! scheme#open-input-string
1202  (lambda (string)
1203    (##sys#check-string string 'open-input-string)
1204    (let* ((port (##sys#make-port 1 ##sys#string-port-class "(string)" 'string))
1205           (bv (##sys#slot string 0))
1206           (len (##core#inline "C_fixnum_difference" (##sys#size bv) 1))
1207           (bv2 (##sys#make-bytevector len)))
1208      (##core#inline "C_copy_memory" bv2 bv len)
1209      (##sys#setislot port 10 0)
1210      (##sys#setislot port 11 len)
1211      (##sys#setslot port 12 bv2)
1212      port)))
1213
1214(set! scheme#open-output-string
1215  (lambda ()
1216    (let ((port (##sys#make-port 2 ##sys#string-port-class "(string)" 'string)))
1217      (##sys#setislot port 10 0)
1218      (##sys#setislot port 11 output-string-initial-size)
1219      (##sys#setslot port 12 (##sys#make-bytevector output-string-initial-size))
1220      port)))
1221
1222(set! scheme#get-output-string
1223  (lambda (port)
1224    (##sys#check-output-port port #f 'get-output-string)
1225    (if (not (eq? 'string (##sys#slot port 7)))
1226        (##sys#signal-hook
1227         #:type-error 'get-output-string "argument is not a string-output-port" port)
1228        (##sys#buffer->string (##sys#slot port 12) 0 (##sys#slot port 10)))))
1229
1230(set! scheme#open-input-bytevector
1231 (lambda (bv)
1232  (let ((port (##sys#make-port 1 #f "(bytevector)" 'custom)))
1233    (##sys#check-bytevector bv 'open-input-bytevector)
1234    (##sys#setslot port 14 'binary)
1235    (##sys#setslot
1236     port
1237     2
1238     (let ((index 0)
1239           (bv-len (##sys#size bv)))
1240       (vector (lambda (_) ; read-char
1241                 (if (eq? index bv-len)
1242                     #!eof
1243                     (let ((c (##core#inline "C_i_bytevector_ref" bv index)))
1244                       (set! index (##core#inline "C_fixnum_plus" index 1))
1245                       (fast-i->c c))))
1246               (lambda (_) ; peek-char
1247                 (if (eq? index bv-len)
1248                     #!eof
1249                     (##core#inline "C_i_bytevector_ref" bv index)))
1250               #f    ; write-char
1251               #f    ; write-bytevector
1252               (lambda (_ _) ; close
1253                 (##sys#setislot port 8 #t))
1254               #f    ; flush-output
1255               (lambda (_) ; char-ready?
1256                 (not (eq? index bv-len)))
1257               (lambda (p n dest start)    ; read-bytevector!
1258                 (let ((n2 (min n (##core#inline "C_fixnum_difference" bv-len index))))
1259                   (##core#inline "C_copy_memory_with_offset" dest bv start index n2)
1260                   (set! index (##core#inline "C_fixnum_plus" index n2))
1261                   n2))
1262               #f    ; read-line
1263               #f))) ; read-buffered
1264     port)))
1265
1266(set! scheme#open-output-bytevector
1267 (lambda ()
1268  (let ((port (##sys#make-port 2 #f "(bytevector)" 'custom))
1269        (buffer (##sys#make-bytevector 256))
1270        (index 0)
1271        (size 256))
1272    (define (add bv start end)
1273      (let* ((len (##core#inline "C_fixnum_difference" end start))
1274             (i2 (##core#inline "C_fixnum_plus" index len)))
1275        (when (##core#inline "C_fixnum_greaterp" i2 size)
1276          (let* ((sz2 (##core#inline "C_fixnum_times" size 2))
1277                 (bv2 (##sys#make-bytevector sz2)))
1278            (##core#inline "C_copy_memory_with_offset" bv2 buffer 0 0 index)
1279            (set! size sz2)
1280            (set! buffer bv2)))
1281        (##core#inline "C_copy_memory_with_offset" buffer bv index start len)
1282        (set! index i2)))
1283    (define (getter)
1284      (let ((bv (##sys#make-bytevector index)))
1285        (##core#inline "C_copy_memory_with_offset" bv buffer 0 0 index)
1286        bv))
1287    (##sys#setslot port 9 getter)
1288    (##sys#setslot port 14 'binary)
1289    (##sys#setslot
1290     port
1291     2
1292     (vector #f ; read-char
1293             #f ; peek-char
1294             (lambda (p c)    ; write-char
1295               (let* ((s (string c))
1296                      (bv (##sys#slot s 0)))
1297                 (add bv 0 (##core#inline "C_fixnum_difference" (##sys#size bv) 1))))
1298             (lambda (p bv start end)    ; write-bytevector
1299               (add bv start end))
1300             (lambda (_ _) ; close
1301               (##sys#setislot port 8 #t))
1302             #f    ; flush-output
1303             #f ; char-ready?
1304             #f  ; read-bytevector!
1305             #f    ; read-line
1306             #f)) ; read-buffered
1307     port)))
1308
1309(set! scheme#get-output-bytevector
1310 (lambda (p)
1311  (define (fail) (error 'get-output-bytevector "not an output-bytevector" p))
1312  (##sys#check-port p 'get-output-bytevector)
1313  (if (eq? (##sys#slot p 7) 'custom)
1314      (let ((getter (##sys#slot p 9)))
1315        (if (procedure? getter)
1316            (getter)
1317            (fail)))
1318      (fail))))
1319
1320(define-constant char-name-table-size 37)
1321(define-constant read-line-buffer-initial-size 1024)
1322(define-constant default-parameter-vector-size 16)
1323(define maximal-string-length (- (foreign-value "C_HEADER_SIZE_MASK" unsigned-long) 1))
1324
1325;;; Fixnum arithmetic:
1326
1327(module chicken.fixnum *
1328(import scheme)
1329(import chicken.foreign)
1330
1331(define most-positive-fixnum (foreign-value "C_MOST_POSITIVE_FIXNUM" int))
1332(define most-negative-fixnum (foreign-value "C_MOST_NEGATIVE_FIXNUM" int))
1333(define fixnum-bits (foreign-value "(C_WORD_SIZE - 1)" int))
1334(define fixnum-precision (foreign-value "(C_WORD_SIZE - (1 + 1))" int))
1335
1336(define (fx+ x y) (##core#inline "C_fixnum_plus" x y))
1337(define (fx- x y) (##core#inline "C_fixnum_difference" x y))
1338(define (fx* x y) (##core#inline "C_fixnum_times" x y))
1339(define (fx= x y) (eq? x y))
1340(define (fx> x y) (##core#inline "C_fixnum_greaterp" x y))
1341(define (fx< x y) (##core#inline "C_fixnum_lessp" x y))
1342(define (fx>= x y) (##core#inline "C_fixnum_greater_or_equal_p" x y))
1343(define (fx<= x y) (##core#inline "C_fixnum_less_or_equal_p" x y))
1344(define (fxmin x y) (##core#inline "C_i_fixnum_min" x y))
1345(define (fxmax x y) (##core#inline "C_i_fixnum_max" x y))
1346(define (fxneg x) (##core#inline "C_fixnum_negate" x))
1347(define (fxand x y) (##core#inline "C_fixnum_and" x y))
1348(define (fxior x y) (##core#inline "C_fixnum_or" x y))
1349(define (fxxor x y) (##core#inline "C_fixnum_xor" x y))
1350(define (fxnot x) (##core#inline "C_fixnum_not" x))
1351(define (fxshl x y) (##core#inline "C_fixnum_shift_left" x y))
1352(define (fxshr x y) (##core#inline "C_fixnum_shift_right" x y))
1353(define (fxodd? x) (##core#inline "C_i_fixnumoddp" x))
1354(define (fxeven? x) (##core#inline "C_i_fixnumevenp" x))
1355(define (fxlen x) (##core#inline "C_i_fixnum_length" x))
1356(define (fx/ x y) (##core#inline "C_fixnum_divide" x y) )
1357(define (fxgcd x y) (##core#inline "C_i_fixnum_gcd" x y))
1358(define (fxmod x y) (##core#inline "C_fixnum_modulo" x y) )
1359(define (fxrem x y) (##core#inline "C_i_fixnum_remainder_checked" x y) )
1360
1361;; Overflow-detecting versions of some of the above
1362(define (fx+? x y) (##core#inline "C_i_o_fixnum_plus" x y) )
1363(define (fx-? x y) (##core#inline "C_i_o_fixnum_difference" x y) )
1364(define (fx*? x y) (##core#inline "C_i_o_fixnum_times" x y) )
1365(define (fx/? x y) (##core#inline "C_i_o_fixnum_quotient" x y))
1366
1367) ; chicken.fixnum
1368
1369(import chicken.fixnum)
1370
1371
1372;;; System routines:
1373
1374(define (##sys#debug-mode?) (##core#inline "C_i_debug_modep"))
1375
1376(define ##sys#warnings-enabled #t)
1377(define ##sys#notices-enabled (##sys#debug-mode?))
1378
1379(set! chicken.base#warning
1380  (lambda (msg . args)
1381    (when ##sys#warnings-enabled
1382      (apply ##sys#signal-hook #:warning msg args))))
1383
1384(set! chicken.base#notice
1385  (lambda (msg . args)
1386    (when (and ##sys#notices-enabled
1387	       ##sys#warnings-enabled)
1388      (apply ##sys#signal-hook #:notice msg args))))
1389
1390(set! chicken.base#enable-warnings
1391  (lambda bool
1392    (if (pair? bool)
1393	(set! ##sys#warnings-enabled (car bool))
1394	##sys#warnings-enabled)))
1395
1396(define ##sys#error error)
1397(define ##sys#warn warning)
1398(define ##sys#notice notice)
1399
1400(define (##sys#error/errno err . args)
1401  (if (pair? args)
1402      (apply ##sys#signal-hook/errno #:error err #f args)
1403      (##sys#signal-hook/errno #:error err #f)))
1404
1405(define-foreign-variable strerror c-string "strerror(errno)")
1406
1407(define ##sys#gc (##core#primitive "C_gc"))
1408(define (##sys#setslot x i y) (##core#inline "C_i_setslot" x i y))
1409(define (##sys#setislot x i y) (##core#inline "C_i_set_i_slot" x i y))
1410(define ##sys#allocate-vector (##core#primitive "C_allocate_vector"))
1411(define ##sys#allocate-bytevector (##core#primitive "C_allocate_bytevector"))
1412(define ##sys#make-structure (##core#primitive "C_make_structure"))
1413(define ##sys#ensure-heap-reserve (##core#primitive "C_ensure_heap_reserve"))
1414(define ##sys#symbol-table-info (##core#primitive "C_get_symbol_table_info"))
1415(define ##sys#memory-info (##core#primitive "C_get_memory_info"))
1416
1417(define (##sys#start-timer)
1418  (##sys#gc #t)
1419  (##core#inline "C_start_timer"))
1420
1421(define (##sys#stop-timer)
1422  (let ((info ((##core#primitive "C_stop_timer"))))
1423    ;; Run a major GC one more time to get memory usage information in
1424    ;; case there was no major GC while the timer was running
1425    (##sys#gc #t)
1426    (##sys#setslot info 6 (##sys#slot ((##core#primitive "C_stop_timer")) 6))
1427    info))
1428
1429(define (##sys#immediate? x) (not (##core#inline "C_blockp" x)))
1430(define (##sys#message str) (##core#inline "C_message" str))
1431(define (##sys#byte x i) (##core#inline "C_subbyte" x i))
1432(define ##sys#void void)
1433(define ##sys#undefined-value (##core#undefined))
1434(define (##sys#halt msg) (##core#inline "C_halt" msg))
1435(define ##sys#become! (##core#primitive "C_become"))
1436(define (##sys#block-ref x i) (##core#inline "C_i_block_ref" x i))
1437(define ##sys#apply-values (##core#primitive "C_apply_values"))
1438(define ##sys#copy-closure (##core#primitive "C_copy_closure"))
1439
1440(define (##sys#block-set! x i y)
1441  (when (or (not (##core#inline "C_blockp" x))
1442	    (and (##core#inline "C_specialp" x) (fx= i 0))
1443	    (##core#inline "C_byteblockp" x) )
1444    (##sys#signal-hook '#:type-error '##sys#block-set! "slot not accessible" x) )
1445  (##sys#check-range i 0 (##sys#size x) '##sys#block-set!)
1446  (##sys#setslot x i y) )
1447
1448(module chicken.time
1449    ;; NOTE: We don't emit the import lib.  Due to syntax exports, it has
1450    ;; to be a hardcoded primitive module.
1451    ;;
1452    ;; [syntax] time
1453    (cpu-time
1454     current-process-milliseconds current-seconds)
1455
1456(import scheme)
1457(import (only chicken.module reexport))
1458
1459(define (current-process-milliseconds)
1460  (##core#inline_allocate ("C_a_i_current_process_milliseconds" 7) #f))
1461
1462(define (current-seconds)
1463  (##core#inline_allocate ("C_a_get_current_seconds" 7) #f))
1464
1465(define cpu-time
1466  (let () ;; ((buf (vector #f #f))) Disabled for now: vector is defined below!
1467    (lambda ()
1468      (let ((buf (vector #f #f)))
1469	;; should be thread-safe as no context-switch will occur after
1470	;; function entry and `buf' contents will have been extracted
1471	;; before `values' gets called.
1472	(##core#inline_allocate ("C_a_i_cpu_time" 8) buf)
1473	(values (##sys#slot buf 0) (##sys#slot buf 1)) )) ))
1474
1475) ; chicken.time
1476
1477(define (##sys#check-structure x y . loc)
1478  (if (pair? loc)
1479      (##core#inline "C_i_check_structure_2" x y (car loc))
1480      (##core#inline "C_i_check_structure" x y) ) )
1481
1482;; DEPRECATED
1483(define (##sys#check-blob x . loc)
1484  (if (pair? loc)
1485      (##core#inline "C_i_check_bytevector_2" x (car loc))
1486      (##core#inline "C_i_check_bytevector" x) ) )
1487
1488(define ##sys#check-bytevector ##sys#check-blob)
1489
1490(define (##sys#check-pair x . loc)
1491  (if (pair? loc)
1492      (##core#inline "C_i_check_pair_2" x (car loc))
1493      (##core#inline "C_i_check_pair" x) ) )
1494
1495(define (##sys#check-list x . loc)
1496  (if (pair? loc)
1497      (##core#inline "C_i_check_list_2" x (car loc))
1498      (##core#inline "C_i_check_list" x) ) )
1499
1500(define (##sys#check-string x . loc)
1501  (if (pair? loc)
1502      (##core#inline "C_i_check_string_2" x (car loc))
1503      (##core#inline "C_i_check_string" x) ) )
1504
1505(define (##sys#check-number x . loc)
1506  (if (pair? loc)
1507      (##core#inline "C_i_check_number_2" x (car loc))
1508      (##core#inline "C_i_check_number" x) ) )
1509
1510(define (##sys#check-fixnum x . loc)
1511  (if (pair? loc)
1512      (##core#inline "C_i_check_fixnum_2" x (car loc))
1513      (##core#inline "C_i_check_fixnum" x) ) )
1514
1515(define (##sys#check-bytevector x . loc)
1516  (if (pair? loc)
1517      (##core#inline "C_i_check_bytevector_2" x (car loc))
1518      (##core#inline "C_i_check_bytevector" x) ) )
1519
1520(define (##sys#check-exact x . loc) ;; DEPRECATED
1521  (if (pair? loc)
1522      (##core#inline "C_i_check_exact_2" x (car loc))
1523      (##core#inline "C_i_check_exact" x) ) )
1524
1525(define (##sys#check-inexact x . loc)
1526  (if (pair? loc)
1527      (##core#inline "C_i_check_inexact_2" x (car loc))
1528      (##core#inline "C_i_check_inexact" x) ) )
1529
1530(define (##sys#check-symbol x . loc)
1531  (if (pair? loc)
1532      (##core#inline "C_i_check_symbol_2" x (car loc))
1533      (##core#inline "C_i_check_symbol" x) ) )
1534
1535(define (##sys#check-keyword x . loc)
1536  (if (pair? loc)
1537      (##core#inline "C_i_check_keyword_2" x (car loc))
1538      (##core#inline "C_i_check_keyword" x) ) )
1539
1540(define (##sys#check-vector x . loc)
1541  (if (pair? loc)
1542      (##core#inline "C_i_check_vector_2" x (car loc))
1543      (##core#inline "C_i_check_vector" x) ) )
1544
1545(define (##sys#check-char x . loc)
1546  (if (pair? loc)
1547      (##core#inline "C_i_check_char_2" x (car loc))
1548      (##core#inline "C_i_check_char" x) ) )
1549
1550(define (##sys#check-boolean x . loc)
1551  (if (pair? loc)
1552      (##core#inline "C_i_check_boolean_2" x (car loc))
1553      (##core#inline "C_i_check_boolean" x) ) )
1554
1555(define (##sys#check-locative x . loc)
1556  (if (pair? loc)
1557      (##core#inline "C_i_check_locative_2" x (car loc))
1558      (##core#inline "C_i_check_locative" x) ) )
1559
1560(define (##sys#check-integer x . loc)
1561  (unless (##core#inline "C_i_integerp" x)
1562    (##sys#error-bad-integer x (and (pair? loc) (car loc))) ) )
1563
1564(define (##sys#check-exact-integer x . loc)
1565  (unless (##core#inline "C_i_exact_integerp" x)
1566    (##sys#error-bad-exact-integer x (and (pair? loc) (car loc))) ) )
1567
1568(define (##sys#check-exact-uinteger x . loc)
1569  (when (or (not (##core#inline "C_i_exact_integerp" x))
1570	    (##core#inline "C_i_integer_negativep" x))
1571    (##sys#error-bad-exact-uinteger x (and (pair? loc) (car loc))) ) )
1572
1573(define (##sys#check-real x . loc)
1574  (unless (##core#inline "C_i_realp" x)
1575    (##sys#error-bad-real x (and (pair? loc) (car loc))) ) )
1576
1577(define (##sys#check-range i from to . loc)
1578  (if (pair? loc)
1579      (##core#inline "C_i_check_range_2" i from to (car loc))
1580      (##core#inline "C_i_check_range" i from to) ) )
1581
1582(define (##sys#check-range/including i from to . loc)
1583  (if (pair? loc)
1584      (##core#inline "C_i_check_range_including_2" i from to (car loc))
1585      (##core#inline "C_i_check_range_including" i from to) ) )
1586
1587(define (##sys#check-special ptr . loc)
1588  (unless (and (##core#inline "C_blockp" ptr) (##core#inline "C_specialp" ptr))
1589    (##sys#signal-hook #:type-error (and (pair? loc) (car loc)) "bad argument type - not a pointer-like object" ptr) ) )
1590
1591(define (##sys#check-closure x . loc)
1592  (if (pair? loc)
1593      (##core#inline "C_i_check_closure_2" x (car loc))
1594      (##core#inline "C_i_check_closure" x) ) )
1595
1596(set! scheme#force
1597  (lambda (obj)
1598    (if (##sys#structure? obj 'promise)
1599	(let lp ((promise obj)
1600		 (forward #f))
1601	  (let ((val (##sys#slot promise 1)))
1602	    (cond ((null? val) (##sys#values))
1603		  ((pair? val) (apply ##sys#values val))
1604		  ((procedure? val)
1605		   (when forward (##sys#setslot forward 1 promise))
1606		   (let ((results (##sys#call-with-values val ##sys#list)))
1607		     (cond ((not (procedure? (##sys#slot promise 1)))
1608			    (lp promise forward)) ; in case of reentrance
1609			   ((and (not (null? results)) (null? (cdr results))
1610				 (##sys#structure? (##sys#slot results 0) 'promise))
1611			    (let ((result0 (##sys#slot results 0)))
1612			      (##sys#setslot promise 1 (##sys#slot result0 1))
1613			      (lp promise result0)))
1614			   (else
1615			    (##sys#setslot promise 1 results)
1616			    (apply ##sys#values results)))))
1617		  ((##sys#structure? val 'promise)
1618		   (lp val forward)))))
1619	obj)))
1620
1621
1622;;; Dynamic Load
1623
1624(define ##sys#dload (##core#primitive "C_dload"))
1625(define ##sys#set-dlopen-flags! (##core#primitive "C_set_dlopen_flags"))
1626
1627(define (##sys#error-not-a-proper-list arg #!optional loc)
1628  (##sys#error-hook
1629   (foreign-value "C_NOT_A_PROPER_LIST_ERROR" int) loc arg))
1630
1631(define (##sys#error-bad-number arg #!optional loc)
1632  (##sys#error-hook
1633   (foreign-value "C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR" int) loc arg))
1634
1635(define (##sys#error-bad-integer arg #!optional loc)
1636  (##sys#error-hook
1637   (foreign-value "C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR" int) loc arg))
1638
1639(define (##sys#error-bad-exact-integer arg #!optional loc)
1640  (##sys#error-hook
1641   (foreign-value "C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR" int) loc arg))
1642
1643(define (##sys#error-bad-exact-uinteger arg #!optional loc)
1644  (##sys#error-hook
1645   (foreign-value "C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR" int) loc arg))
1646
1647(define (##sys#error-bad-inexact arg #!optional loc)
1648  (##sys#error-hook
1649   (foreign-value "C_CANT_REPRESENT_INEXACT_ERROR" int) loc arg))
1650
1651(define (##sys#error-bad-real arg #!optional loc)
1652  (##sys#error-hook
1653   (foreign-value "C_BAD_ARGUMENT_TYPE_NO_REAL_ERROR" int) loc arg))
1654
1655(define (##sys#error-bad-base arg #!optional loc)
1656  (##sys#error-hook
1657   (foreign-value "C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR" int) loc arg))
1658
1659(set! scheme#append
1660  (lambda lsts
1661    (if (eq? lsts '())
1662	lsts
1663	(let loop ((lsts lsts))
1664	  (if (eq? (##sys#slot lsts 1) '())
1665	      (##sys#slot lsts 0)
1666	      (let copy ((node (##sys#slot lsts 0)))
1667		(cond ((eq? node '()) (loop (##sys#slot lsts 1)))
1668		      ((pair? node)
1669		       (cons (##sys#slot node 0) (copy (##sys#slot node 1))) )
1670		      (else
1671		       (##sys#error-not-a-proper-list
1672			(##sys#slot lsts 0) 'append)) ) )))) ) )
1673
1674(define (##sys#fast-reverse lst0)
1675  (let loop ((lst lst0) (rest '()))
1676    (if (pair? lst)
1677	(loop (##sys#slot lst 1) (cons (##sys#slot lst 0) rest))
1678	rest)))
1679
1680
1681;;; Strings:
1682
1683(define (##sys#make-bytevector size #!optional (fill 0))
1684  (##sys#allocate-bytevector size fill))
1685
1686(define (##sys#make-string size #!optional (fill #\space))
1687  (let* ((count (##core#inline "C_utf_bytes" fill))
1688         (n (fx* count size))
1689         (bv (##sys#allocate-bytevector (fx+ n 1) 0)))
1690    (##core#inline "C_utf_fill" bv fill)
1691    (##core#inline_allocate ("C_a_ustring" 5) bv size)))
1692
1693(define (##sys#buffer->string! buf len)
1694  (##core#inline "C_utf_set_bv_size" buf len)
1695  (##core#inline_allocate ("C_a_ustring" 5) buf
1696                          (##core#inline "C_utf_range_length" buf 0 len)))
1697
1698(define (##sys#buffer->string buf start len)
1699  (let ((bv (##sys#make-bytevector (fx+ len 1))))
1700    (##core#inline "C_copy_memory_with_offset" bv buf 0 start len)
1701    (##core#inline_allocate ("C_a_ustring" 5) bv
1702                            (##core#inline "C_utf_range_length" bv 0 len))))
1703
1704(define (##sys#utf-decoder buf start len k)
1705  (k buf start len))
1706
1707(define (##sys#utf-encoder buf start len k)
1708  (k buf start len))
1709
1710(define (##sys#utf-scanner state byte)
1711  (if state
1712      (if (fx> state 1)
1713          (fx- state 1)
1714          #f)
1715      (let ((n (##core#inline "C_utf_bytes_needed" byte)))
1716        (if (eq? n 1)
1717            #f
1718            (fx- n 1)))))
1719
1720(define (##sys#latin-decoder bv start len k)
1721  (let* ((buf (##sys#make-bytevector (fx* len 2)))
1722         (n (##core#inline "C_latin_to_utf" bv buf start len)))
1723    (k buf 0 n)))
1724
1725(define (##sys#latin-encoder bv start len k)
1726  (let* ((buf (##sys#make-bytevector (fx+ len 1)))
1727         (n (##core#inline "C_utf_to_latin" bv buf start len)))
1728    (k buf 0 n)))
1729
1730(define (##sys#latin-scanner state byte) #f)
1731
1732(define (##sys#binary-decoder bv start len k)
1733  (k bv start len) )
1734
1735(define (##sys#binary-encoder bv start len k)
1736  (k bv start len) )
1737
1738(define (##sys#binary-scanner state byte) #f)
1739
1740;; invokes k with encoding and decoding procedures
1741(define (##sys#encoding-hook enc k)
1742  (case enc
1743    ((binary) (k ##sys#binary-decoder ##sys#binary-encoder ##sys#binary-scanner))
1744    ((utf-8) (k ##sys#utf-decoder ##sys#utf-encoder ##sys#utf-scanner))
1745    ((latin-1) (k ##sys#latin-decoder ##sys#latin-encoder ##sys#latin-scanner))
1746    (else (##sys#signal-hook #:type-error #f "invalid file port encoding" enc))))
1747
1748(define (##sys#register-encoding names dec enc scan)
1749  (let ((old ##sys#encoding-hook))
1750    (set! ##sys#encoding-hook
1751      (lambda (enc k)
1752        (if (or (eq? enc names)
1753                (and (pair? names) (memq enc names)))
1754            (k dec enc scan)
1755            (old enc k))))))
1756
1757;; decode buffer and create string
1758(define (##sys#buffer->string/encoding buf start len enc)
1759  (##sys#encoding-hook
1760    enc
1761    (lambda (decoder _ _) (decoder buf start len ##sys#buffer->string))))
1762
1763;; encode buffer into bytevector
1764(define (##sys#encode-buffer bv start len enc k)
1765  (##sys#encoding-hook
1766    enc
1767    (lambda (_ encoder _) (encoder bv start len k))))
1768
1769;; decode buffer into bytevector
1770(define (##sys#decode-buffer bv start len enc k)
1771  (##sys#encoding-hook
1772    enc
1773    (lambda (decoder _ _) (decoder bv start len k))))
1774
1775;; encode a single character into bytevector, return number of bytes
1776(define (##sys#encode-char c bv enc)
1777  (##sys#encoding-hook
1778    enc
1779    (lambda (_ encoder _)
1780      (let* ((bv1 (##sys#make-bytevector 4))
1781             (n (##core#inline "C_utf_insert" bv1 0 c)))
1782        (encoder bv1 0 n
1783                 (lambda (buf start len)
1784                   (##core#inline "C_copy_memory_with_offset" bv buf 0 start len)
1785                   len))))))
1786
1787(define (##sys#decode-char bv enc start)
1788  (##sys#decode-buffer
1789    bv start (##sys#size bv) enc
1790    (lambda (buf start _)
1791      (##core#inline "C_utf_decode" buf start))))
1792
1793;; read char from port with encoding, scanning minimal number of bytes ahead
1794(define (##sys#read-char/encoding p enc k)
1795  (##sys#encoding-hook
1796    enc
1797    (lambda (dec _ scan)
1798      (let ((buf (##sys#make-bytevector 5))
1799            (rbv! (##sys#slot (##sys#slot p 2) 7))) ; read-bytevector!
1800        (let loop ((state #f) (i 0))
1801          (let ((rn (rbv! p 1 buf i)))
1802            (if (eq? 0 rn)
1803                (if (eq? i 0)
1804                    #!eof
1805                    (##sys#signal-hook #:file-error 'read-char "incomplete character sequence while decoding" buf i))
1806                (let ((s2 (scan state (##core#inline "C_subbyte" buf i))))
1807                  (if s2
1808                      (loop s2 (fx+ i 1))
1809                      (k buf 0 (fx+ i 1) dec))))))))))
1810
1811(set! scheme#make-string
1812  (lambda (size . fill)
1813    (##sys#check-fixnum size 'make-string)
1814    (when (fx< size 0)
1815      (##sys#signal-hook #:bounds-error 'make-string "size is negative" size))
1816    (##sys#make-string
1817     size
1818     (if (null? fill)
1819	 #\space
1820	 (let ((c (car fill)))
1821	   (##sys#check-char c 'make-string)
1822	   c ) ) ) ) )
1823
1824(set! scheme#string->list
1825  (lambda (s #!optional start end)
1826    (##sys#check-string s 'string->list)
1827    (let ((len (##sys#slot s 1)))
1828      (if start
1829          (##sys#check-range/including start 0 len 'string->list)
1830          (set! start 0))
1831      (if end
1832          (##sys#check-range/including end 0 len 'string->list)
1833          (set! end len))
1834      (let loop ((i (fx- end 1)) (ls '()))
1835	(if (fx< i start)
1836	    ls
1837	    (loop (fx- i 1)
1838		  (cons (string-ref s i) ls)) ) ) )))
1839
1840(define ##sys#string->list string->list)
1841
1842(set! scheme#list->string
1843  (lambda (lst0)
1844    (if (not (list? lst0))
1845	(##sys#error-not-a-proper-list lst0 'list->string)
1846	(let* ((len (##core#inline "C_utf_list_size" lst0))
1847	       (bv (##sys#make-bytevector (fx+ 1 len))))
1848	  (let loop ((i 0)
1849                     (p 0)
1850                     (lst lst0))
1851            (if (not (pair? lst))
1852                (##core#inline_allocate ("C_a_ustring" 5) bv i)
1853                (let ((c (##sys#slot lst 0)))
1854                  (##sys#check-char c 'list->string)
1855                  (##core#inline "C_utf_insert" bv p c)
1856                  (loop (fx+ i 1)
1857                        (fx+ p (##core#inline "C_utf_bytes" c))
1858                        (##sys#slot lst 1)))))))))
1859
1860(define ##sys#list->string list->string)
1861
1862(define (##sys#reverse-list->string l)
1863  (let* ((sz (##core#inline "C_utf_list_size" l))
1864         (bv (##sys#make-bytevector (fx+ sz 1))))
1865    (let loop ((p sz) (l l) (n 0))
1866      (cond ((null? l)
1867             (##core#inline_allocate ("C_a_ustring" 5) bv n))
1868            ((pair? l)
1869             (let ((c (##sys#slot l 0)))
1870               (##sys#check-char c 'reverse-list->string)
1871               (let* ((bs (##core#inline "C_utf_bytes" c))
1872                      (p2 (fx- p bs)))
1873                 (##core#inline "C_utf_insert" bv p2 c)
1874                 (loop p2 (##sys#slot l 1) (fx+ n 1)))))
1875            (else (##sys#error-not-a-proper-list l 'reverse-list->string) ) ))))
1876
1877(set! scheme#string-fill!
1878  (lambda (s c #!optional start end)
1879    (##sys#check-string s 'string-fill!)
1880    (##sys#check-char c 'string-fill!)
1881    (let ((len (string-length s)))
1882      (cond (start (##sys#check-range start 0 len 'string-fill!)
1883                   (if end
1884                       (##sys#check-range end 0 len 'string-fill!)
1885                       (set! end len)))
1886            (else
1887              (set! start 0)
1888              (set! end len))))
1889    (let* ((bv (##sys#slot s 0))
1890           (bvlen (##sys#size bv))
1891           (count (fxmax 0 (fx- end start)))
1892           (code (char->integer c)))
1893      (if (and (eq? (fx- bvlen 1) (##sys#slot s 1))
1894               (fx< code 128))
1895          (##core#inline "C_fill_bytevector" bv code start count)
1896          (do ((i start (fx+ i 1)))
1897              ((fx>= i end))
1898              (string-set! s i c))))))
1899
1900(set! scheme#string-copy
1901  (lambda (s #!optional start end)
1902    (##sys#check-string s 'string-copy)
1903    (let ((len (string-length s))
1904          (start1 0))
1905      (when start
1906        (##sys#check-range/including start 0 len 'string-copy)
1907        (set! start1 start))
1908      (if end
1909          (##sys#check-range/including end 0 len 'string-copy)
1910          (set! end len))
1911      (let* ((bv (##sys#slot (if start (##sys#substring s start1 end) s) 0))
1912             (len (##sys#size bv))
1913             (n (fx- end start1))
1914             (bv2 (##sys#make-bytevector len)) )
1915        (##core#inline "C_copy_memory" bv2 bv len)
1916        (##core#inline_allocate ("C_a_ustring" 5) bv2 n)))))
1917
1918(set! scheme#string-copy!
1919  (lambda (to at from #!optional start end)
1920    (##sys#check-string to 'string-copy!)
1921    (##sys#check-string from 'string-copy!)
1922    (let ((tlen (string-length to))
1923          (flen (string-length from))
1924          (d (fx- end start)))
1925      (##sys#check-range at 0 tlen 'string-copy!)
1926      (if start
1927          (begin
1928            (##sys#check-range/including start 0 flen 'string-copy!)
1929            (if end
1930                (##sys#check-range/including end 0 flen 'string-copy!)
1931                (set! end flen)))
1932          (set! start 0))
1933      (if (and (eq? to from) (fx< start at))
1934          (do ((at (fx- (fx+ at d) 1) (fx- at 1))
1935               (i (fx- end 1) (fx- i 1)))
1936              ((fx< i start))
1937              (string-set! to at (string-ref from i)))
1938          (do ((at at (fx+ at 1))
1939               (i start (fx+ i 1)))
1940              ((fx>= i end))
1941              (string-set! to at (string-ref from i)))))))
1942
1943(define (##sys#substring s start end)
1944  (let* ((n (##core#inline "C_utf_range" s start end))
1945         (bv (##sys#make-bytevector (fx+ n 1)))
1946         (str (##core#inline_allocate ("C_a_ustring" 5) bv (fx- end start))))
1947    (##core#inline "C_utf_copy" s str start end 0)
1948    str ) )
1949
1950(set! scheme#substring
1951  (lambda (s start . end)
1952    (##sys#check-string s 'substring)
1953    (##sys#check-fixnum start 'substring)
1954    (let ((end (if (pair? end)
1955                   (let ((end (car end)))
1956                     (##sys#check-fixnum end 'substring)
1957                     end)
1958                   (string-length s) ) ) )
1959      (let ((len (string-length s)))
1960        (if (and (fx<= start end)
1961                 (fx>= start 0)
1962                 (fx<= end len) )
1963            (##sys#substring s start end)
1964            (##sys#error-hook
1965             (foreign-value "C_OUT_OF_BOUNDS_ERROR" int)
1966             'substring s start) ) ) )))
1967
1968(let ((compare
1969        (lambda (s1 s2 more loc cmp)
1970          (##sys#check-string s1 loc)
1971          (##sys#check-string s2 loc)
1972          (let* ((len1 (string-length s1))
1973                 (len2 (string-length s2))
1974                 (c (##core#inline "C_utf_compare"
1975                     s1 s2 0 0
1976                     (if (fx< len1 len2) len1 len2))))
1977            (let loop ((s s2) 
1978                       (len len2) 
1979                       (ss more)
1980                       (f (cmp c len1 len2)))
1981              (and f 
1982                   (or (null? ss)
1983                       (let* ((s2 (##sys#slot ss 0))
1984                              (len2 (string-length s2))
1985                              (c (##core#inline "C_utf_compare"
1986                                  s s2 0 0
1987                                  (if (fx< len len2) len len2))))
1988                         (loop s2 len2 (##sys#slot ss 1)
1989                               (cmp c len len2))))))))))
1990  (set! scheme#string<? (lambda (s1 s2 . more)
1991                          (compare
1992                            s1 s2 more 'string<?
1993                            (lambda (cmp len1 len2)
1994                              (or (fx< cmp 0)
1995                                  (and (fx< len1 len2)
1996                                       (eq? cmp 0) ) ) ) ) ) )
1997  (set! scheme#string>? (lambda (s1 s2 . more)
1998                          (compare
1999                            s1 s2 more 'string>?
2000                            (lambda (cmp len1 len2)
2001                              (or (fx> cmp 0)
2002                                  (and (fx> len1 len2)
2003                                       (eq? cmp 0) ) ) ) ) ) )
2004  (set! scheme#string<=? (lambda (s1 s2 . more)
2005                           (compare
2006                             s1 s2 more 'string<=?
2007                             (lambda (cmp len1 len2)
2008                               (if (eq? cmp 0)
2009                                   (fx<= len1 len2)
2010                                   (fx< cmp 0) ) ) ) ) )
2011  (set! scheme#string>=? (lambda (s1 s2 . more)
2012                           (compare
2013                             s1 s2 more 'string>=?
2014                             (lambda (cmp len1 len2)
2015                               (if (eq? cmp 0)
2016                                   (fx>= len1 len2)
2017                                   (fx> cmp 0) ) ) ) ) ) )
2018
2019(let ((compare
2020        (lambda (s1 s2 more loc cmp)
2021          (##sys#check-string s1 loc)
2022          (##sys#check-string s2 loc)
2023          (let* ((len1 (string-length s1))
2024                 (len2 (string-length s2))
2025                 (c (##core#inline "C_utf_compare_ci"
2026                     s1 s2 0 0
2027                     (if (fx< len1 len2) len1 len2))))
2028            (let loop ((s s2)
2029                       (len len2)
2030                       (ss more)
2031                       (f (cmp c len1 len2)))
2032              (and f
2033                   (or (null? ss)
2034                       (let* ((s2 (##sys#slot ss 0))
2035                              (len2 (string-length s2))
2036                              (c (##core#inline "C_utf_compare_ci"
2037                                  s s2 0 0
2038                                  (if (fx< len len2) len len2))))
2039                         (loop s2 len2 (##sys#slot ss 1)
2040                               (cmp c len len2))))))))))
2041  (set! scheme#string-ci<? (lambda (s1 s2 . more)
2042                             (compare
2043                               s1 s2 more 'string-ci<?
2044                               (lambda (cmp len1 len2)
2045                                 (or (fx< cmp 0)
2046                                     (and (fx< len1 len2)
2047                                          (eq? cmp 0) ) )))))
2048  (set! scheme#string-ci>? (lambda (s1 s2 . more)
2049                             (compare
2050                               s1 s2 more 'string-ci>?
2051                               (lambda (cmp len1 len2)
2052                                 (or (fx> cmp 0)
2053                                     (and (fx> len1 len2)
2054                                          (eq? cmp 0) ) ) ) ) ) )
2055  (set! scheme#string-ci<=? (lambda (s1 s2 . more)
2056                              (compare
2057                                s1 s2 more 'string-ci<=?
2058                                (lambda (cmp len1 len2)
2059                                  (if (eq? cmp 0)
2060                                      (fx<= len1 len2)
2061                                      (fx< cmp 0) ) ) ) ) )
2062  (set! scheme#string-ci>=? (lambda (s1 s2 . more)
2063                              (compare
2064                                s1 s2 more 'string-ci>=?
2065                                (lambda (cmp len1 len2)
2066                                  (if (eq? cmp 0)
2067                                      (fx>= len1 len2)
2068                                      (fx> cmp 0) ) ) ) ) ) )
2069
2070(define (##sys#string-append x y)
2071  (let* ((bv1 (##sys#slot x 0))
2072         (bv2 (##sys#slot y 0))
2073         (s1 (fx- (##sys#size bv1) 1))
2074	 (s2 (fx- (##sys#size bv2) 1))
2075	 (z (##sys#make-bytevector (fx+ s1 (fx+ s2 1)) 0)))
2076    (##core#inline "C_copy_memory_with_offset" z bv1 0 0 s1)
2077    (##core#inline "C_copy_memory_with_offset" z bv2 s1 0 s2)
2078    (##core#inline_allocate ("C_a_ustring" 5) z
2079                            (fx+ (##sys#slot x 1) (##sys#slot y 1)))))
2080
2081(set! scheme#string-append
2082  (lambda all
2083    (let ((snew #f)
2084          (slen 0))
2085      (let loop ((strs all) (n 0) (ul 0))
2086	(cond ((eq? strs '())
2087                (set! snew (##sys#make-bytevector (fx+ n 1) 0))
2088                (set! slen ul))
2089              (else
2090                (let ((s (##sys#slot strs 0)))
2091                  (##sys#check-string s 'string-append)
2092                  (let* ((bv (##sys#slot s 0))
2093                         (len (fx- (##sys#size bv) 1))
2094                         (ulen (##sys#slot s 1)))
2095                    (loop (##sys#slot strs 1) (fx+ n len) (fx+ ul ulen))
2096                    (##core#inline "C_copy_memory_with_offset" snew bv n 0 len) ) ) ) ) )
2097      (##core#inline_allocate ("C_a_ustring" 5) snew slen))))
2098
2099(set! scheme#string
2100  (let ([list->string list->string])
2101    (lambda chars (list->string chars)) ) )
2102
2103;; legacy procedure, used in some eggs, should be removed one day...
2104(define (##sys#char->utf8-string c)
2105  (scheme#string c))
2106
2107(set! chicken.base#chop
2108  (lambda (lst n)
2109    (##sys#check-fixnum n 'chop)
2110    (when (fx<= n 0) (##sys#error 'chop "invalid numeric argument" n))
2111    (let ((len (length lst)))
2112      (let loop ((lst lst) (i len))
2113	(cond ((null? lst) '())
2114	      ((fx< i n) (list lst))
2115	      (else
2116	       (do ((hd '() (cons (##sys#slot tl 0) hd))
2117		    (tl lst (##sys#slot tl 1))
2118		    (c n (fx- c 1)) )
2119		   ((fx= c 0)
2120		    (cons (reverse hd) (loop tl (fx- i n))) ) ) ) ) ) ) ) )
2121
2122;;; Numeric routines:
2123;; Abbreviations of paper and book titles used in comments are:
2124;; [Knuth] Donald E. Knuth, "The Art of Computer Programming", Volume 2
2125;; [MpNT]  Tiplea at al., "MpNT: A Multi-Precision Number Theory Package"
2126;; [MCA]   Richard P. Brent & Paul Zimmermann, "Modern Computer Arithmetic"
2127
2128(module chicken.flonum *
2129(import scheme)
2130(import chicken.foreign)
2131(import (only chicken.base flonum?))
2132(import chicken.internal.syntax)
2133
2134(define maximum-flonum (foreign-value "DBL_MAX" double))
2135(define minimum-flonum (foreign-value "DBL_MIN" double))
2136(define flonum-radix (foreign-value "FLT_RADIX" int))
2137(define flonum-epsilon (foreign-value "DBL_EPSILON" double))
2138(define flonum-precision (foreign-value "DBL_MANT_DIG" int))
2139(define flonum-decimal-precision (foreign-value "DBL_DIG" int))
2140(define flonum-maximum-exponent (foreign-value "DBL_MAX_EXP" int))
2141(define flonum-minimum-exponent (foreign-value "DBL_MIN_EXP" int))
2142(define flonum-maximum-decimal-exponent (foreign-value "DBL_MAX_10_EXP" int))
2143(define flonum-minimum-decimal-exponent (foreign-value "DBL_MIN_10_EXP" int))
2144
2145(define-inline (fp-check-flonum x loc)
2146  (unless (flonum? x)
2147    (##sys#error-hook (foreign-value "C_BAD_ARGUMENT_TYPE_NO_FLONUM_ERROR" int) loc x) ) )
2148
2149(define-inline (fp-check-flonums x y loc)
2150  (unless (and (flonum? x) (flonum? y))
2151    (##sys#error-hook (foreign-value "C_BAD_ARGUMENT_TYPE_NO_FLONUM_ERROR" int) loc x y) ) )
2152
2153(define (fp+ x y)
2154  (fp-check-flonums x y 'fp+)
2155  (##core#inline_allocate ("C_a_i_flonum_plus" 4) x y) )
2156
2157(define (fp- x y)
2158  (fp-check-flonums x y 'fp-)
2159  (##core#inline_allocate ("C_a_i_flonum_difference" 4) x y) )
2160
2161(define (fp* x y)
2162  (fp-check-flonums x y 'fp*)
2163  (##core#inline_allocate ("C_a_i_flonum_times" 4) x y) )
2164
2165(define (fp/ x y)
2166  (fp-check-flonums x y 'fp/)
2167  (##core#inline_allocate ("C_a_i_flonum_quotient" 4) x y) )
2168
2169(define (fp*+ x y z)
2170  (unless (and (flonum? x) (flonum? y) (flonum? z))
2171    (##sys#error-hook (foreign-value "C_BAD_ARGUMENT_TYPE_NO_FLONUM_ERROR" int)
2172      'fp*+ x y z) )
2173  (##core#inline_allocate ("C_a_i_flonum_multiply_add" 4) x y z) )
2174
2175(define (fpgcd x y)
2176  (fp-check-flonums x y 'fpgcd)
2177  (##core#inline_allocate ("C_a_i_flonum_gcd" 4) x y))
2178
2179(define (fp/? x y)			; undocumented
2180  (fp-check-flonums x y 'fp/?)
2181  (##core#inline_allocate ("C_a_i_flonum_quotient_checked" 4) x y) )
2182
2183(define (fp= x y)
2184  (fp-check-flonums x y 'fp=)
2185  (##core#inline "C_flonum_equalp" x y) )
2186
2187(define (fp> x y)
2188  (fp-check-flonums x y 'fp>)
2189  (##core#inline "C_flonum_greaterp" x y) )
2190
2191(define (fp< x y)
2192  (fp-check-flonums x y 'fp<)
2193  (##core#inline "C_flonum_lessp" x y) )
2194
2195(define (fp>= x y)
2196  (fp-check-flonums x y 'fp>=)
2197  (##core#inline "C_flonum_greater_or_equal_p" x y) )
2198
2199(define (fp<= x y)
2200  (fp-check-flonums x y 'fp<=)
2201  (##core#inline "C_flonum_less_or_equal_p" x y) )
2202
2203(define (fpneg x)
2204  (fp-check-flonum x 'fpneg)
2205  (##core#inline_allocate ("C_a_i_flonum_negate" 4) x) )
2206
2207(define (fpmax x y)
2208  (fp-check-flonums x y 'fpmax)
2209  (##core#inline "C_i_flonum_max" x y) )
2210
2211(define (fpmin x y)
2212  (fp-check-flonums x y 'fpmin)
2213  (##core#inline "C_i_flonum_min" x y) )
2214
2215(define (fpfloor x)
2216  (fp-check-flonum x 'fpfloor)
2217  (##core#inline_allocate ("C_a_i_flonum_floor" 4) x))
2218
2219(define (fptruncate x)
2220  (fp-check-flonum x 'fptruncate)
2221  (##core#inline_allocate ("C_a_i_flonum_truncate" 4) x))
2222
2223(define (fpround x)
2224  (fp-check-flonum x 'fpround)
2225  (##core#inline_allocate ("C_a_i_flonum_round" 4) x))
2226
2227(define (fpceiling x)
2228  (fp-check-flonum x 'fpceiling)
2229  (##core#inline_allocate ("C_a_i_flonum_ceiling" 4) x))
2230
2231(define (fpsin x)
2232  (fp-check-flonum x 'fpsin)
2233  (##core#inline_allocate ("C_a_i_flonum_sin" 4) x))
2234
2235(define (fpcos x)
2236  (fp-check-flonum x 'fpcos)
2237  (##core#inline_allocate ("C_a_i_flonum_cos" 4) x))
2238
2239(define (fptan x)
2240  (fp-check-flonum x 'fptan)
2241  (##core#inline_allocate ("C_a_i_flonum_tan" 4) x))
2242
2243(define (fpasin x)
2244  (fp-check-flonum x 'fpasin)
2245  (##core#inline_allocate ("C_a_i_flonum_asin" 4) x))
2246
2247(define (fpacos x)
2248  (fp-check-flonum x 'fpacos)
2249  (##core#inline_allocate ("C_a_i_flonum_acos" 4) x))
2250
2251(define (fpatan x)
2252  (fp-check-flonum x 'fpatan)
2253  (##core#inline_allocate ("C_a_i_flonum_atan" 4) x))
2254
2255(define (fpatan2 x y)
2256  (fp-check-flonums x y 'fpatan2)
2257  (##core#inline_allocate ("C_a_i_flonum_atan2" 4) x y))
2258
2259(define (fpsinh x)
2260  (fp-check-flonum x 'fpsinh)
2261  (##core#inline_allocate ("C_a_i_flonum_sinh" 4) x))
2262
2263(define (fpcosh x)
2264  (fp-check-flonum x 'fpcosh)
2265  (##core#inline_allocate ("C_a_i_flonum_cosh" 4) x))
2266
2267(define (fptanh x)
2268  (fp-check-flonum x 'fptanh)
2269  (##core#inline_allocate ("C_a_i_flonum_tanh" 4) x))
2270
2271(define (fpasinh x)
2272  (fp-check-flonum x 'fpasinh)
2273  (##core#inline_allocate ("C_a_i_flonum_asinh" 4) x))
2274
2275(define (fpacosh x)
2276  (fp-check-flonum x 'fpacosh)
2277  (##core#inline_allocate ("C_a_i_flonum_acosh" 4) x))
2278
2279(define (fpatanh x)
2280  (fp-check-flonum x 'fpatanh)
2281  (##core#inline_allocate ("C_a_i_flonum_atanh" 4) x))
2282
2283(define (fpexp x)
2284  (fp-check-flonum x 'fpexp)
2285  (##core#inline_allocate ("C_a_i_flonum_exp" 4) x))
2286
2287(define (fpexpt x y)
2288  (fp-check-flonums x y 'fpexpt)
2289  (##core#inline_allocate ("C_a_i_flonum_expt" 4) x y))
2290
2291(define (fplog x)
2292  (fp-check-flonum x 'fplog)
2293  (##core#inline_allocate ("C_a_i_flonum_log" 4) x))
2294
2295(define (fpsqrt x)
2296  (fp-check-flonum x 'fpsqrt)
2297  (##core#inline_allocate ("C_a_i_flonum_sqrt" 4) x))
2298
2299(define (fpabs x)
2300  (fp-check-flonum x 'fpabs)
2301  (##core#inline_allocate ("C_a_i_flonum_abs" 4) x))
2302
2303(define (fpinteger? x)
2304  (fp-check-flonum x 'fpinteger?)
2305  (##core#inline "C_u_i_fpintegerp" x))
2306
2307(define (flonum-print-precision #!optional prec)
2308  (let ((prev (##core#inline "C_get_print_precision")))
2309    (when prec
2310      (##sys#check-fixnum prec 'flonum-print-precision)
2311      (##core#inline "C_set_print_precision" prec))
2312    prev)))
2313
2314(import chicken.flonum)
2315
2316(define-inline (integer-negate x)
2317  (##core#inline_allocate ("C_s_a_u_i_integer_negate" 5) x))
2318
2319;;; Complex numbers
2320
2321(define-inline (%cplxnum-real c) (##core#inline "C_u_i_cplxnum_real" c))
2322(define-inline (%cplxnum-imag c) (##core#inline "C_u_i_cplxnum_imag" c))
2323
2324(define (make-complex r i)
2325  (if (eq? i 0)
2326      r
2327      (##core#inline_allocate ("C_a_i_cplxnum" 3)
2328			      (if (inexact? i) (exact->inexact r) r)
2329			      (if (inexact? r) (exact->inexact i) i)) ) )
2330
2331(set! scheme#make-rectangular
2332  (lambda (r i)
2333    (##sys#check-real r 'make-rectangular)
2334    (##sys#check-real i 'make-rectangular)
2335    (make-complex r i) ))
2336
2337(set! scheme#make-polar
2338  (lambda (r phi)
2339    (##sys#check-real r 'make-polar)
2340    (##sys#check-real phi 'make-polar)
2341    (let ((fphi (exact->inexact phi)))
2342      (make-complex
2343       (* r (##core#inline_allocate ("C_a_i_cos" 4) fphi))
2344       (* r (##core#inline_allocate ("C_a_i_sin" 4) fphi))) ) ))
2345
2346(set! scheme#real-part
2347  (lambda (x)
2348    (cond ((cplxnum? x) (%cplxnum-real x))
2349	  ((number? x) x)
2350	  (else (##sys#error-bad-number x 'real-part)) )))
2351
2352(set! scheme#imag-part
2353  (lambda (x)
2354    (cond ((cplxnum? x) (%cplxnum-imag x))
2355	  ((##core#inline "C_i_flonump" x) 0.0)
2356	  ((number? x) 0)
2357	  (else (##sys#error-bad-number x 'imag-part)) )))
2358
2359(set! scheme#angle
2360  (lambda (n)
2361    (##sys#check-number n 'angle)
2362    (##core#inline_allocate ("C_a_i_atan2" 4)
2363			    (exact->inexact (imag-part n))
2364			    (exact->inexact (real-part n))) ))
2365
2366(set! scheme#magnitude
2367  (lambda (x)
2368    (cond ((cplxnum? x)
2369	   (let ((r (%cplxnum-real x))
2370		 (i (%cplxnum-imag x)) )
2371	     (sqrt (+ (* r r) (* i i))) ))
2372	  ((number? x) (abs x))
2373	  (else (##sys#error-bad-number x 'magnitude))) ))
2374
2375;;; Rational numbers
2376
2377(define-inline (%ratnum-numerator r) (##core#inline "C_u_i_ratnum_num" r))
2378(define-inline (%ratnum-denominator r) (##core#inline "C_u_i_ratnum_denom" r))
2379(define-inline (%make-ratnum n d) (##core#inline_allocate ("C_a_i_ratnum" 3) n d))
2380
2381(define (ratnum m n)
2382  (cond
2383   ((eq? n 1) m)
2384   ((eq? n -1) (integer-negate m))
2385   ((negative? n)
2386    (%make-ratnum (integer-negate m) (integer-negate n)))
2387   (else (%make-ratnum m n))))
2388
2389(set! scheme#numerator
2390  (lambda (n)
2391    (cond ((##core#inline "C_i_exact_integerp" n) n)
2392          ((##core#inline "C_i_flonump" n)
2393           (cond ((not (finite? n)) (##sys#error-bad-inexact n 'numerator))
2394                 ((##core#inline "C_u_i_fpintegerp" n) n)
2395                 (else (exact->inexact (numerator (inexact->exact n))))))
2396          ((ratnum? n) (%ratnum-numerator n))
2397          (else (##sys#signal-hook
2398                 #:type-error 'numerator
2399                 "bad argument type - not a rational number" n) ) )))
2400
2401
2402(set! scheme#denominator
2403  (lambda (n)
2404    (cond ((##core#inline "C_i_exact_integerp" n) 1)
2405          ((##core#inline "C_i_flonump" n)
2406           (cond ((not (finite? n)) (##sys#error-bad-inexact n 'denominator))
2407                 ((##core#inline "C_u_i_fpintegerp" n) 1.0)
2408                 (else (exact->inexact (denominator (inexact->exact n))))))
2409          ((ratnum? n) (%ratnum-denominator n))
2410          (else (##sys#signal-hook
2411                 #:type-error 'numerator
2412                 "bad argument type - not a rational number" n) ) )))
2413
2414
2415(define (##sys#extended-signum x)
2416  (cond
2417   ((ratnum? x) (##core#inline "C_u_i_integer_signum" (%ratnum-numerator x)))
2418   ((cplxnum? x) (make-polar 1 (angle x)))
2419   (else (##sys#error-bad-number x 'signum))))
2420
2421(define-inline (%flo->int x)
2422  (##core#inline_allocate ("C_s_a_u_i_flo_to_int" 5) x))
2423
2424(define (flonum->ratnum x)
2425  ;; Try to multiply by two until we reach an integer
2426  (define (float-fraction-length x)
2427    (do ((x x (fp* x 2.0))
2428         (i 0 (fx+ i 1)))
2429        ((##core#inline "C_u_i_fpintegerp" x) i)))
2430
2431  (define (deliver y d)
2432    (let* ((q (##sys#integer-power 2 (float-fraction-length y)))
2433           (scaled-y (* y (exact->inexact q))))
2434      (if (finite? scaled-y)          ; Shouldn't this always be true?
2435          (##sys#/-2 (##sys#/-2 (%flo->int scaled-y) q) d)
2436          (##sys#error-bad-inexact x 'inexact->exact))))
2437
2438  (if (and (fp< x 1.0)         ; Watch out for denormalized numbers
2439           (fp> x -1.0))       ; XXX: Needs a test, it seems pointless
2440      (deliver (* x (expt 2.0 flonum-precision))
2441               ;; Can be bignum (is on 32-bit), so must wait until after init.
2442               ;; We shouldn't need to calculate this every single time, tho..
2443               (##sys#integer-power 2 flonum-precision))
2444      (deliver x 1)))
2445
2446(set! scheme#inexact->exact
2447  (lambda (x)
2448    (cond ((exact? x) x)
2449	  ((##core#inline "C_i_flonump" x)
2450	   (cond ((##core#inline "C_u_i_fpintegerp" x) (%flo->int x))
2451		 ((##core#inline "C_u_i_flonum_finitep" x) (flonum->ratnum x))
2452		 (else (##sys#error-bad-inexact x 'inexact->exact))))
2453	  ((cplxnum? x)
2454	   (make-complex (inexact->exact (%cplxnum-real x))
2455			 (inexact->exact (%cplxnum-imag x))))
2456	  (else (##sys#error-bad-number x 'inexact->exact)) )))
2457
2458
2459;;; Bitwise operations:
2460
2461;; From SRFI-33
2462
2463(module chicken.bitwise *
2464(import scheme)
2465(define bitwise-and (##core#primitive "C_bitwise_and"))
2466(define bitwise-ior (##core#primitive "C_bitwise_ior"))
2467(define bitwise-xor (##core#primitive "C_bitwise_xor"))
2468(define (bitwise-not n) (##core#inline_allocate ("C_s_a_i_bitwise_not" 5) n))
2469(define (bit->boolean n i) (##core#inline "C_i_bit_to_bool" n i)) ; DEPRECATED
2470;; XXX NOT YET! Reintroduce at a later time.  See #1385:
2471;; (define (bit-set? i n) (##core#inline "C_i_bit_setp" i n))
2472(define (integer-length x) (##core#inline "C_i_integer_length" x))
2473(define (arithmetic-shift n m)
2474  (##core#inline_allocate ("C_s_a_i_arithmetic_shift" 5) n m))
2475
2476) ; chicken.bitwise
2477
2478(import chicken.bitwise)
2479
2480;;; Basic arithmetic:
2481
2482(define-inline (%integer-gcd a b)
2483  (##core#inline_allocate ("C_s_a_u_i_integer_gcd" 5) a b))
2484
2485(set! scheme#/
2486  (lambda (arg1 . args)
2487    (if (null? args)
2488	(##sys#/-2 1 arg1)
2489	(let loop ((args (##sys#slot args 1))
2490		   (x (##sys#/-2 arg1 (##sys#slot args 0))))
2491	  (if (null? args)
2492	      x
2493	      (loop (##sys#slot args 1)
2494		    (##sys#/-2 x (##sys#slot args 0))) ) ) ) ))
2495
2496(define-inline (%integer-quotient a b)
2497  (##core#inline_allocate ("C_s_a_u_i_integer_quotient" 5) a b))
2498
2499(define (##sys#/-2 x y)
2500  (when (eq? y 0)
2501    (##sys#error-hook (foreign-value "C_DIVISION_BY_ZERO_ERROR" int) '/ x y))
2502  (cond ((and (##core#inline "C_i_exact_integerp" x)
2503              (##core#inline "C_i_exact_integerp" y))
2504         (let ((g (%integer-gcd x y)))
2505           (ratnum (%integer-quotient x g) (%integer-quotient y g))))
2506        ;; Compnum *must* be checked first
2507        ((or (cplxnum? x) (cplxnum? y))
2508         (let* ((a (real-part x)) (b (imag-part x))
2509                (c (real-part y)) (d (imag-part y))
2510                (r (+ (* c c) (* d d)))
2511                (x (##sys#/-2 (+ (* a c) (* b d)) r))
2512                (y (##sys#/-2 (- (* b c) (* a d)) r)) )
2513           (make-complex x y) ))
2514        ((or (##core#inline "C_i_flonump" x) (##core#inline "C_i_flonump" y))
2515         ;; This may be incorrect when one is a ratnum consisting of bignums
2516         (fp/ (exact->inexact x) (exact->inexact y)))
2517        ((ratnum? x)
2518         (if (ratnum? y)
2519             ;; a/b / c/d = a*d / b*c  [generic]
2520             ;;   = ((a / g1) * (d / g2) * sign(a)) / abs((b / g2) * (c / g1))
2521             ;; With   g1 = gcd(a, c)   and    g2 = gcd(b, d) [Knuth, 4.5.1 ex. 4]
2522             (let* ((a (%ratnum-numerator x)) (b (%ratnum-denominator x))
2523                    (c (%ratnum-numerator y)) (d (%ratnum-denominator y))
2524                    (g1 (%integer-gcd a c))
2525                    (g2 (%integer-gcd b d)))
2526               (ratnum (* (quotient a g1) (quotient d g2))
2527                       (* (quotient b g2) (quotient c g1))))
2528             ;; a/b / c/d = a*d / b*c  [with d = 1]
2529             ;;   = ((a / g) * sign(a)) / abs(b * (c / g))
2530             ;; With   g = gcd(a, c)   and  c = y  [Knuth, 4.5.1 ex. 4]
2531             (let* ((a (%ratnum-numerator x))
2532                    (g (##sys#internal-gcd '/ a y))
2533                    (num (quotient a g))
2534                    (denom (* (%ratnum-denominator x) (quotient y g))))
2535               (if (##core#inline "C_i_flonump" denom)
2536                   (##sys#/-2 num denom)
2537                   (ratnum num denom)))))
2538        ((ratnum? y)
2539         ;; a/b / c/d = a*d / b*c  [with b = 1]
2540         ;;   = ((a / g1) * d * sign(a)) / abs(c / g1)
2541         ;; With   g1 = gcd(a, c)   and   a = x  [Knuth, 4.5.1 ex. 4]
2542         (let* ((c (%ratnum-numerator y))
2543                (g (##sys#internal-gcd '/ x c))
2544                (num (* (quotient x g) (%ratnum-denominator y)))
2545                (denom (quotient c g)))
2546           (if (##core#inline "C_i_flonump" denom)
2547               (##sys#/-2 num denom)
2548               (ratnum num denom))))
2549        ((not (number? x)) (##sys#error-bad-number x '/))
2550        (else (##sys#error-bad-number y '/))) )
2551
2552(set! scheme#floor
2553  (lambda (x)
2554    (cond ((##core#inline "C_i_exact_integerp" x) x)
2555          ((##core#inline "C_i_flonump" x) (fpfloor x))
2556          ;; (floor x) = greatest integer <= x
2557          ((ratnum? x) (let* ((n (%ratnum-numerator x))
2558                              (q (quotient n (%ratnum-denominator x))))
2559                         (if (>= n 0) q (- q 1))))
2560          (else (##sys#error-bad-real x 'floor)) )))
2561
2562(set! scheme#ceiling
2563  (lambda (x)
2564    (cond ((##core#inline "C_i_exact_integerp" x) x)
2565          ((##core#inline "C_i_flonump" x) (fpceiling x))
2566          ;; (ceiling x) = smallest integer >= x
2567          ((ratnum? x) (let* ((n (%ratnum-numerator x))
2568                              (q (quotient n (%ratnum-denominator x))))
2569                         (if (>= n 0) (+ q 1) q)))
2570          (else (##sys#error-bad-real x 'ceiling)) )))
2571
2572(set! scheme#truncate
2573  (lambda (x)
2574    (cond ((##core#inline "C_i_exact_integerp" x) x)
2575          ((##core#inline "C_i_flonump" x) (fptruncate x))
2576          ;; (rational-truncate x) = integer of largest magnitude <= (abs x)
2577          ((ratnum? x) (quotient (%ratnum-numerator x)
2578                                 (%ratnum-denominator x)))
2579          (else (##sys#error-bad-real x 'truncate)) )))
2580
2581(set! scheme#round
2582  (lambda (x)
2583    (cond ((##core#inline "C_i_exact_integerp" x) x)
2584          ((##core#inline "C_i_flonump" x)
2585           (##core#inline_allocate ("C_a_i_flonum_round_proper" 4) x))
2586          ((ratnum? x)
2587           (let* ((x+1/2 (+ x (%make-ratnum 1 2)))
2588                  (r (floor x+1/2)))
2589             (if (and (= r x+1/2) (odd? r)) (- r 1) r)))
2590          (else (##sys#error-bad-real x 'round)) )))
2591
2592(define (find-ratio-between x y)
2593  (define (sr x y)
2594    (let ((fx (inexact->exact (floor x)))
2595	  (fy (inexact->exact (floor y))))
2596      (cond ((not (< fx x)) (list fx 1))
2597	    ((= fx fy)
2598	     (let ((rat (sr (##sys#/-2 1 (- y fy))
2599			    (##sys#/-2 1 (- x fx)))))
2600	       (list (+ (cadr rat) (* fx (car rat)))
2601		     (car rat))))
2602	    (else (list (+ 1 fx) 1)))))
2603  (cond ((< y x) (find-ratio-between y x))
2604	((not (< x y)) (list x 1))
2605	((positive? x) (sr x y))
2606	((negative? y) (let ((rat (sr (- y) (- x))))
2607                         (list (- (car rat)) (cadr rat))))
2608	(else '(0 1))))
2609
2610(define (find-ratio x e) (find-ratio-between (- x e) (+ x e)))
2611
2612(set! scheme#rationalize
2613  (lambda (x e)
2614    (let ((result (apply ##sys#/-2 (find-ratio x e))))
2615      (if (or (inexact? x) (inexact? e))
2616	  (exact->inexact result)
2617	  result)) ))
2618
2619(set! scheme#max
2620  (lambda (x1 . xs)
2621    (let loop ((i (##core#inline "C_i_flonump" x1)) (m x1) (xs xs))
2622      (##sys#check-number m 'max)
2623      (if (null? xs)
2624	  (if i (exact->inexact m) m)
2625	  (let ((h (##sys#slot xs 0)))
2626	    (loop (or i (##core#inline "C_i_flonump" h))
2627		  (if (> h m) h m)
2628		  (##sys#slot xs 1)) ) ) ) ))
2629
2630(set! scheme#min
2631  (lambda (x1 . xs)
2632    (let loop ((i (##core#inline "C_i_flonump" x1)) (m x1) (xs xs))
2633      (##sys#check-number m 'min)
2634      (if (null? xs)
2635	  (if i (exact->inexact m) m)
2636	  (let ((h (##sys#slot xs 0)))
2637	    (loop (or i (##core#inline "C_i_flonump" h))
2638		  (if (< h m) h m)
2639		  (##sys#slot xs 1)) ) ) ) ))
2640
2641(set! scheme#exp
2642  (lambda (n)
2643    (##sys#check-number n 'exp)
2644    (if (cplxnum? n)
2645	(* (##core#inline_allocate ("C_a_i_exp" 4)
2646				   (exact->inexact (%cplxnum-real n)))
2647	   (let ((p (%cplxnum-imag n)))
2648	     (make-complex
2649	      (##core#inline_allocate ("C_a_i_cos" 4) (exact->inexact p))
2650	      (##core#inline_allocate ("C_a_i_sin" 4) (exact->inexact p)) ) ) )
2651	(##core#inline_allocate ("C_a_i_flonum_exp" 4) (exact->inexact n)) ) ))
2652
2653(define (##sys#log-1 x)		       ; log_e(x)
2654  (cond
2655   ((eq? x 0)			       ; Exact zero?  That's undefined
2656    (##sys#signal-hook #:arithmetic-error 'log "log of exact 0 is undefined" x))
2657   ;; avoid calling inexact->exact on X here (to avoid overflow?)
2658   ((or (cplxnum? x) (negative? x)) ; General case
2659    (+ (##sys#log-1 (magnitude x))
2660       (* (make-complex 0 1) (angle x))))
2661   (else ; Real number case (< already ensured the argument type is a number)
2662    (##core#inline_allocate ("C_a_i_log" 4) (exact->inexact x)))))
2663
2664(set! scheme#log
2665  (lambda (a #!optional b)
2666    (if b (##sys#/-2 (##sys#log-1 a) (##sys#log-1 b)) (##sys#log-1 a))))
2667
2668(set! scheme#sin
2669  (lambda (n)
2670    (##sys#check-number n 'sin)
2671    (if (cplxnum? n)
2672	(let ((in (* +i n)))
2673	  (##sys#/-2 (- (exp in) (exp (- in))) +2i))
2674	(##core#inline_allocate ("C_a_i_sin" 4) (exact->inexact n)) ) ))
2675
2676(set! scheme#cos
2677  (lambda (n)
2678    (##sys#check-number n 'cos)
2679    (if (cplxnum? n)
2680	(let ((in (* +i n)))
2681	  (##sys#/-2 (+ (exp in) (exp (- in))) 2) )
2682	(##core#inline_allocate ("C_a_i_cos" 4) (exact->inexact n)) ) ))
2683
2684(set! scheme#tan
2685  (lambda (n)
2686    (##sys#check-number n 'tan)
2687    (if (cplxnum? n)
2688	(##sys#/-2 (sin n) (cos n))
2689	(##core#inline_allocate ("C_a_i_tan" 4) (exact->inexact n)) ) ))
2690
2691;; General case: sin^{-1}(z) = -i\ln(iz + \sqrt{1-z^2})
2692(set! scheme#asin
2693  (lambda (n)
2694    (##sys#check-number n 'asin)
2695    (cond ((and (##core#inline "C_i_flonump" n) (fp>= n -1.0) (fp<= n 1.0))
2696	   (##core#inline_allocate ("C_a_i_asin" 4) n))
2697	  ((and (##core#inline "C_fixnump" n) (fx>= n -1) (fx<= n 1))
2698	   (##core#inline_allocate ("C_a_i_asin" 4)
2699				   (##core#inline_allocate
2700				    ("C_a_i_fix_to_flo" 4) n)))
2701	  ;; General definition can return compnums
2702	  (else (* -i (##sys#log-1
2703		       (+ (* +i n)
2704			  (##sys#sqrt/loc 'asin (- 1 (* n n))))) )) ) ))
2705
2706;; General case:
2707;; cos^{-1}(z) = 1/2\pi + i\ln(iz + \sqrt{1-z^2}) = 1/2\pi - sin^{-1}(z) = sin(1) - sin(z)
2708(set! scheme#acos
2709  (let ((asin1 (##core#inline_allocate ("C_a_i_asin" 4) 1)))
2710    (lambda (n)
2711      (##sys#check-number n 'acos)
2712      (cond ((and (##core#inline "C_i_flonump" n) (fp>= n -1.0) (fp<= n 1.0))
2713             (##core#inline_allocate ("C_a_i_acos" 4) n))
2714            ((and (##core#inline "C_fixnump" n) (fx>= n -1) (fx<= n 1))
2715             (##core#inline_allocate ("C_a_i_acos" 4)
2716                                     (##core#inline_allocate
2717                                      ("C_a_i_fix_to_flo" 4) n)))
2718            ;; General definition can return compnums
2719            (else (- asin1 (asin n)))))))
2720
2721(set! scheme#atan
2722  (lambda (n #!optional b)
2723    (##sys#check-number n 'atan)
2724    (cond ((cplxnum? n)
2725	   (if b
2726	       (##sys#error-bad-real n 'atan)
2727	       (let ((in (* +i n)))
2728		 (##sys#/-2 (- (##sys#log-1 (+ 1 in))
2729			       (##sys#log-1 (- 1 in))) +2i))))
2730	  (b
2731	   (##core#inline_allocate
2732	    ("C_a_i_atan2" 4) (exact->inexact n) (exact->inexact b)))
2733	  (else
2734	   (##core#inline_allocate
2735	    ("C_a_i_atan" 4) (exact->inexact n))) ) ))
2736
2737;; This is "Karatsuba Square Root" as described by Paul Zimmermann,
2738;; which is 3/2K(n) + O(n log n) for an input of 2n words, where K(n)
2739;; is the number of operations performed by Karatsuba multiplication.
2740(define (##sys#exact-integer-sqrt a)
2741  ;; Because we assume a3b+a2 >= b^2/4, we must check a few edge cases:
2742  (if (and (fixnum? a) (fx<= a 4))
2743      (case a
2744        ((0 1) (values a 0))
2745        ((2)   (values 1 1))
2746        ((3)   (values 1 2))
2747        ((4)   (values 2 0))
2748        (else  (error "this should never happen")))
2749      (let*-values
2750          (((len/4) (fxshr (fx+ (integer-length a) 1) 2))
2751           ((len/2) (fxshl len/4 1))
2752           ((s^ r^) (##sys#exact-integer-sqrt
2753		     (arithmetic-shift a (fxneg len/2))))
2754           ((mask)  (- (arithmetic-shift 1 len/4) 1))
2755           ((a0)    (bitwise-and a mask))
2756           ((a1)    (bitwise-and (arithmetic-shift a (fxneg len/4)) mask))
2757           ((q u)   ((##core#primitive "C_u_integer_quotient_and_remainder")
2758		     (+ (arithmetic-shift r^ len/4) a1)
2759		     (arithmetic-shift s^ 1)))
2760           ((s)     (+ (arithmetic-shift s^ len/4) q))
2761           ((r)     (+ (arithmetic-shift u len/4) (- a0 (* q q)))))
2762        (if (negative? r)
2763            (values (- s 1)
2764		    (- (+ r (arithmetic-shift s 1)) 1))
2765            (values s r)))))
2766
2767(set! scheme#exact-integer-sqrt
2768  (lambda (x)
2769    (##sys#check-exact-uinteger x 'exact-integer-sqrt)
2770    (##sys#exact-integer-sqrt x)))
2771
2772;; This procedure is so large because it tries very hard to compute
2773;; exact results if at all possible.
2774(define (##sys#sqrt/loc loc n)
2775  (cond ((cplxnum? n)     ; Must be checked before we call "negative?"
2776         (let ((p (##sys#/-2 (angle n) 2))
2777               (m (##core#inline_allocate ("C_a_i_sqrt" 4) (magnitude n))) )
2778           (make-complex (* m (cos p)) (* m (sin p)) ) ))
2779        ((negative? n)
2780         (make-complex .0 (##core#inline_allocate
2781			   ("C_a_i_sqrt" 4) (exact->inexact (- n)))))
2782        ((##core#inline "C_i_exact_integerp" n)
2783         (receive (s^2 r) (##sys#exact-integer-sqrt n)
2784           (if (eq? 0 r)
2785               s^2
2786               (##core#inline_allocate ("C_a_i_sqrt" 4) (exact->inexact n)))))
2787        ((ratnum? n) ; Try to compute exact sqrt (we already know n is positive)
2788         (receive (ns^2 nr) (##sys#exact-integer-sqrt (%ratnum-numerator n))
2789           (if (eq? nr 0)
2790               (receive (ds^2 dr)
2791		   (##sys#exact-integer-sqrt (%ratnum-denominator n))
2792                 (if (eq? dr 0)
2793                     (##sys#/-2 ns^2 ds^2)
2794                     (##sys#sqrt/loc loc (exact->inexact n))))
2795               (##sys#sqrt/loc loc (exact->inexact n)))))
2796        (else (##core#inline_allocate ("C_a_i_sqrt" 4) (exact->inexact n)))))
2797
2798(set! scheme#sqrt (lambda (x) (##sys#sqrt/loc 'sqrt x)))
2799
2800;; XXX These are bad bad bad definitions; very inefficient.
2801;; But to improve it we would need to provide another implementation
2802;; of the quotient procedure which floors instead of truncates.
2803(define scheme#truncate/ quotient&remainder)
2804
2805(define (scheme#floor/ x y)
2806  (receive (div rem) (quotient&remainder x y)
2807    (if (positive? y)
2808        (if (negative? rem)
2809            (values (- div 1) (+ rem y))
2810            (values div rem))
2811        (if (positive? rem)
2812            (values (- div 1) (+ rem y))
2813            (values div rem)))))
2814
2815(define (scheme#floor-remainder x y)
2816  (receive (div rem) (scheme#floor/ x y) rem))
2817
2818(define (scheme#floor-quotient x y)
2819  (receive (div rem) (scheme#floor/ x y) div))
2820
2821(define (scheme#square n) (* n n))
2822
2823(set! chicken.base#exact-integer-nth-root
2824  (lambda (k n)
2825    (##sys#check-exact-uinteger k 'exact-integer-nth-root)
2826    (##sys#check-exact-uinteger n 'exact-integer-nth-root)
2827    (##sys#exact-integer-nth-root/loc 'exact-integer-nth-root k n)))
2828
2829;; Generalized Newton's algorithm for positive integers, with a little help
2830;; from Wikipedia ;)  https://en.wikipedia.org/wiki/Nth_root_algorithm
2831(define (##sys#exact-integer-nth-root/loc loc k n)
2832  (if (or (eq? 0 k) (eq? 1 k) (eq? 1 n)) ; Maybe call exact-integer-sqrt on n=2?
2833      (values k 0)
2834      (let ((len (integer-length k)))
2835	(if (< len n)	  ; Idea from Gambit: 2^{len-1} <= k < 2^{len}
2836	    (values 1 (- k 1)) ; Since x >= 2, we know x^{n} can't exist
2837	    ;; Set initial guess to (at least) 2^ceil(ceil(log2(k))/n)
2838	    (let* ((shift-amount (inexact->exact (ceiling (/ (fx+ len 1) n))))
2839		   (g0 (arithmetic-shift 1 shift-amount))
2840		   (n-1 (- n 1)))
2841	      (let lp ((g0 g0)
2842		       (g1 (quotient
2843			    (+ (* n-1 g0)
2844			       (quotient k (##sys#integer-power g0 n-1)))
2845			    n)))
2846		(if (< g1 g0)
2847		    (lp g1 (quotient
2848			    (+ (* n-1 g1)
2849			       (quotient k (##sys#integer-power g1 n-1)))
2850			    n))
2851		    (values g0 (- k (##sys#integer-power g0 n))))))))))
2852
2853(define (##sys#integer-power base e)
2854  (define (square x) (* x x))
2855  (if (negative? e)
2856      (##sys#/-2 1 (##sys#integer-power base (integer-negate e)))
2857      (let lp ((res 1) (e2 e))
2858        (cond
2859         ((eq? e2 0) res)
2860         ((even? e2)	     ; recursion is faster than iteration here
2861          (* res (square (lp 1 (arithmetic-shift e2 -1)))))
2862         (else
2863          (lp (* res base) (- e2 1)))))))
2864
2865(set! scheme#expt
2866  (lambda (a b)
2867    (define (log-expt a b)
2868      (exp (* b (##sys#log-1 a))))
2869    (define (slow-expt a b)
2870      (if (eq? 0 a)
2871	  (##sys#signal-hook
2872	   #:arithmetic-error 'expt
2873	   "exponent of exact 0 with complex argument is undefined" a b)
2874	  (exp (* b (##sys#log-1 a)))))
2875    (cond ((not (number? a)) (##sys#error-bad-number a 'expt))
2876	  ((not (number? b)) (##sys#error-bad-number b 'expt))
2877	  ((and (ratnum? a) (not (inexact? b)))
2878	   ;; (n*d)^b = n^b * d^b = n^b * x^{-b}  | x = 1/b
2879	   ;; Hopefully faster than integer-power
2880	   (* (expt (%ratnum-numerator a) b)
2881	      (expt (%ratnum-denominator a) (- b))))
2882	  ((ratnum? b)
2883	   ;; x^{a/b} = (x^{1/b})^a
2884	   (cond
2885	    ((##core#inline "C_i_exact_integerp" a)
2886	     (if (negative? a)
2887		 (log-expt (exact->inexact a) (exact->inexact b))
2888		 (receive (ds^n r)
2889		     (##sys#exact-integer-nth-root/loc
2890		      'expt a (%ratnum-denominator b))
2891		   (if (eq? r 0)
2892		       (##sys#integer-power ds^n (%ratnum-numerator b))
2893		       (##core#inline_allocate ("C_a_i_flonum_expt" 4)
2894					       (exact->inexact a)
2895					       (exact->inexact b))))))
2896	    ((##core#inline "C_i_flonump" a)
2897	     (log-expt a (exact->inexact b)))
2898	    (else (slow-expt a b))))
2899	  ((or (cplxnum? b) (and (cplxnum? a) (not (integer? b))))
2900	   (slow-expt a b))
2901	  ((and (##core#inline "C_i_flonump" b)
2902		(not (##core#inline "C_u_i_fpintegerp" b)))
2903	   (if (negative? a)
2904	       (log-expt (exact->inexact a) (exact->inexact b))
2905	       (##core#inline_allocate
2906		("C_a_i_flonum_expt" 4) (exact->inexact a) b)))
2907	  ((##core#inline "C_i_flonump" a)
2908	   (##core#inline_allocate ("C_a_i_flonum_expt" 4) a (exact->inexact b)))
2909	  ;; this doesn't work that well, yet...
2910	  ;; (XXX: What does this mean? why not? I do know this is ugly... :P)
2911	  (else (if (or (inexact? a) (inexact? b))
2912		    (exact->inexact (##sys#integer-power a (inexact->exact b)))
2913		    (##sys#integer-power a b)))) ))
2914
2915;; Useful for sane error messages
2916(define (##sys#internal-gcd loc a b)
2917  (cond ((##core#inline "C_i_exact_integerp" a)
2918         (cond ((##core#inline "C_i_exact_integerp" b)
2919                (%integer-gcd a b))
2920               ((and (##core#inline "C_i_flonump" b)
2921                     (##core#inline "C_u_i_fpintegerp" b))
2922                (exact->inexact (%integer-gcd a (inexact->exact b))))
2923               (else (##sys#error-bad-integer b loc))))
2924        ((and (##core#inline "C_i_flonump" a)
2925              (##core#inline "C_u_i_fpintegerp" a))
2926         (cond ((##core#inline "C_i_flonump" b)
2927                (##core#inline_allocate ("C_a_i_flonum_gcd" 4) a b))
2928               ((##core#inline "C_i_exact_integerp" b)
2929                (exact->inexact (%integer-gcd (inexact->exact a) b)))
2930               (else (##sys#error-bad-integer b loc))))
2931        (else (##sys#error-bad-integer a loc))))
2932;; For compat reasons, we define this
2933(define (##sys#gcd a b) (##sys#internal-gcd 'gcd a b))
2934
2935(set! scheme#gcd
2936  (lambda ns
2937    (if (eq? ns '())
2938	0
2939	(let loop ((head (##sys#slot ns 0))
2940		   (next (##sys#slot ns 1)))
2941	  (if (null? next)
2942	      (if (integer? head) (abs head) (##sys#error-bad-integer head 'gcd))
2943	      (let ((n2 (##sys#slot next 0)))
2944		(loop (##sys#internal-gcd 'gcd head n2)
2945		      (##sys#slot next 1)) ) ) ) ) ))
2946
2947(define (##sys#lcm x y)
2948  (let ((gcd (##sys#internal-gcd 'lcm x y))) ; Ensure better error message
2949    (abs (quotient (* x y) gcd) ) ) )
2950
2951(set! scheme#lcm
2952  (lambda ns
2953    (if (null? ns)
2954	1
2955	(let loop ((head (##sys#slot ns 0))
2956		   (next (##sys#slot ns 1)))
2957	  (if (null? next)
2958	      (if (integer? head) (abs head) (##sys#error-bad-integer head 'lcm))
2959	      (let* ((n2 (##sys#slot next 0))
2960		     (gcd (##sys#internal-gcd 'lcm head n2)))
2961		(loop (quotient (* head n2) gcd)
2962		      (##sys#slot next 1)) ) ) ) ) ))
2963
2964;; This simple enough idea is from
2965;; http://www.numberworld.org/y-cruncher/internals/radix-conversion.html
2966(define (##sys#integer->string/recursive n base expected-string-size)
2967  (let*-values (((halfsize) (fxshr (fx+ expected-string-size 1) 1))
2968                ((b^M/2) (##sys#integer-power base halfsize))
2969                ((hi lo) ((##core#primitive "C_u_integer_quotient_and_remainder")
2970			  n b^M/2))
2971                ((strhi) (number->string hi base))
2972                ((strlo) (number->string (abs lo) base)))
2973    (string-append strhi
2974                   ;; Fix up any leading zeroes that were stripped from strlo
2975                   (make-string (fx- halfsize (string-length strlo)) #\0)
2976                   strlo)))
2977
2978(define ##sys#extended-number->string
2979  (let ((string-append string-append))
2980    (lambda (n base)
2981      (cond
2982       ((ratnum? n)
2983	(string-append (number->string (%ratnum-numerator n) base)
2984		       "/"
2985		       (number->string (%ratnum-denominator n) base)))
2986       ((cplxnum? n) (let ((r (%cplxnum-real n))
2987                           (i (%cplxnum-imag n)) )
2988                       (string-append
2989                        (number->string r base)
2990                        ;; The infinities and NaN always print their sign
2991                        (if (and (finite? i) (>= i 0) (not (eqv? i -0.0))) "+" "")
2992                        (number->string i base) "i") ))
2993       (else (##sys#error-bad-number n 'number->string)))  ) ) )
2994
2995(define ##sys#number->string number->string) ; for printer
2996
2997;; We try to prevent memory exhaustion attacks by limiting the
2998;; maximum exponent value.  Perhaps this should be a parameter?
2999(define-constant +maximum-allowed-exponent+ 10000)
3000
3001;; From "Easy Accurate Reading and Writing of Floating-Point Numbers"
3002;; by Aubrey Jaffer.
3003(define (mantexp->dbl mant point)
3004  (if (not (negative? point))
3005      (exact->inexact (* mant (##sys#integer-power 10 point)))
3006      (let* ((scl (##sys#integer-power 10 (abs point)))
3007	     (bex (fx- (fx- (integer-length mant)
3008			    (integer-length scl))
3009                       flonum-precision)))
3010        (if (fx< bex 0)
3011            (let* ((num (arithmetic-shift mant (fxneg bex)))
3012                   (quo (round-quotient num scl)))
3013              (cond ((> (integer-length quo) flonum-precision)
3014                     ;; Too many bits of quotient; readjust
3015                     (set! bex (fx+ 1 bex))
3016                     (set! quo (round-quotient num (* scl 2)))))
3017              (ldexp (exact->inexact quo) bex))
3018            ;; Fall back to exact calculation in extreme cases
3019            (* mant (##sys#integer-power 10 point))))))
3020
3021(define ldexp (foreign-lambda double "ldexp" double int))
3022
3023;; Should we export this?
3024(define (round-quotient n d)
3025  (let ((q (%integer-quotient n d)))
3026    (if ((if (even? q) > >=) (* (abs (remainder n d)) 2) (abs d))
3027        (+ q (if (eqv? (negative? n) (negative? d)) 1 -1))
3028        q)))
3029
3030(define (##sys#string->compnum radix str offset exactness)
3031  ;; Flipped when a sign is encountered (for inexact numbers only)
3032  (define negative #f)
3033  ;; Go inexact unless exact was requested (with #e prefix)
3034  (define (go-inexact! neg?)
3035    (unless (eq? exactness 'e)
3036      (set! exactness 'i)
3037      (set! negative (or negative neg?))))
3038  (define (safe-exponent value e)
3039    (and e (cond
3040            ((not value) 0)
3041            ((> e +maximum-allowed-exponent+)
3042             (and (eq? exactness 'i)
3043                  (cond ((zero? value) 0.0)
3044                        ((> value 0.0) +inf.0)
3045                        (else -inf.0))))
3046            ((< e (fxneg +maximum-allowed-exponent+))
3047             (and (eq? exactness 'i) +0.0))
3048            ((eq? exactness 'i) (mantexp->dbl value e))
3049            (else (* value (##sys#integer-power 10 e))))))
3050  (define (make-nan)
3051    ;; Return fresh NaNs, so eqv? returns #f on two read NaNs.  This
3052    ;; is not mandated by the standard, but compatible with earlier
3053    ;; CHICKENs and it just makes more sense.
3054    (##core#inline_allocate ("C_a_i_flonum_quotient" 4) 0.0 0.0))
3055  (let* ((len (string-length str))
3056         (0..r (fast-i->c (fx+ (char->integer #\0) (fx- radix 1))))
3057         (a..r (fast-i->c (fx+ (char->integer #\a) (fx- radix 11))))
3058         (A..r (fast-i->c (fx+ (char->integer #\A) (fx- radix 11))))
3059         ;; Ugly flag which we need (note that "exactness" is mutated too!)
3060         ;; Since there is (almost) no backtracking we can do this.
3061         (seen-hashes? #f)
3062         ;; All these procedures return #f or an object consed onto an end
3063         ;; position.  If the cdr is false, that's the end of the string.
3064         ;; If just #f is returned, the string contains invalid number syntax.
3065         (scan-digits
3066          (lambda (start cplx?)
3067            (let lp ((i start)
3068                     ;; Drop is true when the last read character is
3069                     ;; an "i" while reading the second part of a
3070                     ;; rectangular complex number literal *and* the
3071                     ;; radix is 19 or above.  In that case, we back
3072                     ;; up one character to ensure we don't consume
3073                     ;; the trailing "i", which we otherwise would.
3074                     (drop? #f))
3075              (if (fx= i len)
3076                  (and (fx> i start)
3077                       (if drop?
3078                           (cons (sub1 i) (sub1 i))
3079                           (cons i #f)))
3080                  (let ((c (string-ref str i)))
3081                    (if (fx<= radix 10)
3082                        (if (and (char>=? c #\0) (char<=? c 0..r))
3083                            (lp (fx+ i 1) #f)
3084                            (and (fx> i start) (cons i i)))
3085                        (if (or (and (char>=? c #\0) (char<=? c #\9))
3086                                (and (char>=? c #\a) (char<=? c a..r))
3087                                (and (char>=? c #\A) (char<=? c A..r)))
3088                            (lp (fx+ i 1)
3089                                (and cplx? (fx>= radix 19)
3090                                     (or (char=? c #\i)
3091                                         (char=? c #\I))))
3092                            (and (fx> i start)
3093                                 (if (and drop? (not (char=? c #\/))) ;; Fractional numbers are an exception - the i may only come after the slash
3094                                     (cons (sub1 i) (sub1 i))
3095                                     (cons i i))))))))))
3096         (scan-hashes
3097          (lambda (start)
3098            (let lp ((i start))
3099              (if (fx= i len)
3100                  (and (fx> i start) (cons i #f))
3101                  (let ((c (string-ref str i)))
3102                    (if (eq? c #\#)
3103                        (lp (fx+ i 1))
3104                        (and (fx> i start) (cons i i))))))))
3105         (scan-digits+hashes
3106          (lambda (start neg? cplx? all-hashes-ok?)
3107            (let* ((digits (and (not seen-hashes?) (scan-digits start cplx?)))
3108                   (hashes (if digits
3109                               (and (cdr digits) (scan-hashes (cdr digits)))
3110                               (and all-hashes-ok? (scan-hashes start))))
3111                   (end (or hashes digits)))
3112              (and-let* ((end)
3113                         (num (##core#inline_allocate
3114			       ("C_s_a_i_digits_to_integer" 6)
3115			       str start (car end) radix neg?)))
3116                (when hashes            ; Eeewww. Feeling dirty yet?
3117                  (set! seen-hashes? #t)
3118                  (go-inexact! neg?))
3119                (cons num (cdr end))))))
3120         (scan-exponent
3121          (lambda (start)
3122            (and (fx< start len)
3123                 (let ((sign (case (string-ref str start)
3124                               ((#\+) 'pos) ((#\-) 'neg) (else #f))))
3125                   (and-let* ((start (if sign (fx+ start 1) start))
3126                              (end (scan-digits start #f)))
3127                     (cons (##core#inline_allocate
3128			    ("C_s_a_i_digits_to_integer" 6)
3129			    str start (car end) radix (eq? sign 'neg))
3130                           (cdr end)))))))
3131         (scan-decimal-tail             ; The part after the decimal dot
3132          (lambda (start neg? decimal-head)
3133            (and (fx< start len)
3134                 (let* ((tail (scan-digits+hashes start neg? #f decimal-head))
3135                        (next (if tail (cdr tail) start)))
3136                   (and (or decimal-head (not next)
3137                            (fx> next start)) ; Don't allow empty "."
3138                        (case (and next (string-ref str next))
3139                          ((#\e #\s #\f #\d #\l
3140                            #\E #\S #\F #\D #\L)
3141                           (and-let* (((fx> len next))
3142                                      (ee (scan-exponent (fx+ next 1)))
3143                                      (e (car ee))
3144                                      (h (safe-exponent decimal-head e)))
3145                             (let* ((te (and tail (fx- e (fx- (cdr tail) start))))
3146                                    (num (and tail (car tail)))
3147                                    (t (safe-exponent num te)))
3148                               (cons (if t (+ h t) h) (cdr ee)))))
3149                          (else (let* ((last (or next len))
3150                                       (te (and tail (fx- start last)))
3151                                       (num (and tail (car tail)))
3152                                       (t (safe-exponent num te))
3153                                       (h (or decimal-head 0)))
3154                                  (cons (if t (+ h t) h) next)))))))))
3155         (scan-ureal
3156          (lambda (start neg? cplx?)
3157            (if (and (fx> len (fx+ start 1)) (eq? radix 10)
3158                     (eq? (string-ref str start) #\.))
3159                (begin
3160                  (go-inexact! neg?)
3161                  (scan-decimal-tail (fx+ start 1) neg? #f))
3162                (and-let* ((end (scan-digits+hashes start neg? cplx? #f)))
3163                  (case (and (cdr end) (string-ref str (cdr end)))
3164                    ((#\.)
3165                     (go-inexact! neg?)
3166                     (and (eq? radix 10)
3167                          (if (fx> len (fx+ (cdr end) 1))
3168                              (scan-decimal-tail (fx+ (cdr end) 1) neg? (car end))
3169                              (cons (car end) #f))))
3170                    ((#\e #\s #\f #\d #\l
3171                      #\E #\S #\F #\D #\L)
3172                     (go-inexact! neg?)
3173                     (and-let* (((eq? radix 10))
3174                                ((fx> len (cdr end)))
3175                                (ee (scan-exponent (fx+ (cdr end) 1)))
3176                                (num (car end))
3177                                (val (safe-exponent num (car ee))))
3178                       (cons val (cdr ee))))
3179                    ((#\/)
3180                     (set! seen-hashes? #f) ; Reset flag for denominator
3181                     (and-let* (((fx> len (cdr end)))
3182                                (d (scan-digits+hashes (fx+ (cdr end) 1) #f cplx? #f))
3183                                (num (car end))
3184                                (denom (car d)))
3185                       (if (not (eq? denom 0))
3186                           (cons (##sys#/-2 num denom) (cdr d))
3187                           ;; Hacky: keep around an inexact until we decide we
3188                           ;; *really* need exact values, then fail at the end.
3189                           (and (not (eq? exactness 'e))
3190                                (case (signum num)
3191                                  ((-1) (cons -inf.0 (cdr d)))
3192                                  ((0)  (cons (make-nan) (cdr d)))
3193                                  ((+1) (cons +inf.0 (cdr d))))))))
3194                    (else end))))))
3195         (scan-real
3196          (lambda (start cplx?)
3197            (and (fx< start len)
3198                 (let* ((sign (case (string-ref str start)
3199                                ((#\+) 'pos) ((#\-) 'neg) (else #f)))
3200                        (next (if sign (fx+ start 1) start)))
3201                   (and (fx< next len)
3202                        (case (string-ref str next)
3203                          ((#\i #\I)
3204                           (or (and sign
3205                                    (cond
3206                                     ((and (fx= (fx+ next 1) len)  ; [+-]i
3207                                           ;; Reject bare "+i" in higher radixes where this would be ambiguous
3208                                           (or cplx?
3209                                               (fx< radix 19)))
3210                                      (cons (if (eq? sign 'neg) -1 1) next))
3211                                     ((and (fx<= (fx+ next 5) len)
3212                                           (string-ci=? (substring str next (fx+ next 5)) "inf.0"))
3213                                      (go-inexact! (eq? sign 'neg))
3214                                      (cons (if (eq? sign 'neg) -inf.0 +inf.0)
3215                                            (and (fx< (fx+ next 5) len)
3216                                                 (fx+ next 5))))
3217                                     (else #f)))
3218                               (scan-ureal next (eq? sign 'neg) cplx?)))
3219                          ((#\n #\N)
3220                           (or (and sign
3221                                    (fx<= (fx+ next 5) len)
3222                                    (string-ci=? (substring str next (fx+ next 5)) "nan.0")
3223                                    (begin (go-inexact! (eq? sign 'neg))
3224                                           (cons (make-nan)
3225                                                 (and (fx< (fx+ next 5) len)
3226                                                      (fx+ next 5)))))
3227                               (scan-ureal next (eq? sign 'neg) cplx?)))
3228                          (else (scan-ureal next (eq? sign 'neg) cplx?))))))))
3229         (number (and-let* ((r1 (scan-real offset #f)))
3230                   (let ((nf (and r1 (zero? (car r1)) negative)))
3231                     (case (and (cdr r1) (string-ref str (cdr r1)))
3232                       ((#f) (car r1))
3233                       ((#\i #\I) (and (fx= len (fx+ (cdr r1) 1))
3234                                     (or (eq? (string-ref str offset) #\+) ; ugh
3235                                         (eq? (string-ref str offset) #\-))
3236                                     (make-rectangular 0 (if nf (- (car r1)) (car r1)))))
3237                       ((#\+ #\-)
3238                        (set! seen-hashes? #f) ; Reset flag for imaginary part
3239                        (set! negative #f)
3240                        (and-let* ((r2 (scan-real (cdr r1) #t))
3241                                   ((cdr r2))
3242                                   ((fx= len (fx+ (cdr r2) 1)))
3243                                   ((or (eq? (string-ref str (cdr r2)) #\i)
3244                                        (eq? (string-ref str (cdr r2)) #\I))))
3245                          (make-rectangular 
3246                            (car r1) 
3247                            (let ((n2 (if (and (exact? (car r2)) (eq? exactness 'i))
3248                                          (exact->inexact (car r2))
3249                                          (car r2))))
3250                              (if (and negative (>= n2 0) (not (eqv? n2 -0.0)))
3251                                  (- n2)
3252                                  n2)))))
3253                       ((#\@)
3254                        (set! seen-hashes? #f) ; Reset flag for angle
3255                        (and-let* ((r2 (scan-real (fx+ (cdr r1) 1) #f))
3256                                   ((not (cdr r2))))
3257                          (make-polar (car r1) (car r2))))
3258                       (else #f))))))
3259    (and number (if (eq? exactness 'i)
3260                    (let ((r (exact->inexact number)))
3261                      ;; Stupid hack because flonums can represent negative zero,
3262                      ;; but we're coming from an exact which has no such thing.
3263                      (if (and negative (zero? r)) (fpneg r) r))
3264                    ;; Ensure we didn't encounter +inf.0 or +nan.0 with #e
3265                    (and (finite? number) number)))))
3266
3267(set! scheme#string->number
3268  (lambda (str #!optional (base 10))
3269    (##sys#check-string str 'string->number)
3270    (unless (and (##core#inline "C_fixnump" base)
3271		 (fx< 1 base) (fx< base 37)) ; We only have 0-9 and the alphabet!
3272      (##sys#error-bad-base base 'string->number))
3273    (let scan-prefix ((i 0)
3274		      (exness #f)
3275		      (radix #f)
3276		      (len (string-length str)))
3277      (if (and (fx< (fx+ i 2) len) (eq? (string-ref str i) #\#))
3278	  (case (string-ref str (fx+ i 1))
3279	    ((#\i #\I) (and (not exness) (scan-prefix (fx+ i 2) 'i radix len)))
3280	    ((#\e #\E) (and (not exness) (scan-prefix (fx+ i 2) 'e radix len)))
3281	    ((#\b #\B) (and (not radix) (scan-prefix (fx+ i 2) exness 2 len)))
3282	    ((#\o #\O) (and (not radix) (scan-prefix (fx+ i 2) exness 8 len)))
3283	    ((#\d #\D) (and (not radix) (scan-prefix (fx+ i 2) exness 10 len)))
3284	    ((#\x #\X) (and (not radix) (scan-prefix (fx+ i 2) exness 16 len)))
3285	    (else #f))
3286	  (##sys#string->compnum (or radix base) str i exness)))))
3287
3288(define (##sys#string->number str #!optional (radix 10) exactness)
3289  (##sys#string->compnum radix str 0 exactness))
3290
3291(define ##sys#fixnum->string (##core#primitive "C_fixnum_to_string"))
3292(define ##sys#flonum->string (##core#primitive "C_flonum_to_string"))
3293(define ##sys#integer->string (##core#primitive "C_integer_to_string"))
3294(define ##sys#number->string number->string)
3295
3296(set! chicken.base#equal=?
3297  (lambda (x y)
3298    (define (compare-slots x y start)
3299      (let ((l1 (##sys#size x))
3300	    (l2 (##sys#size y)))
3301	(and (eq? l1 l2)
3302	     (or (fx<= l1 start)
3303		 (let ((l1n (fx- l1 1)))
3304		   (let loop ((i start))
3305		     (if (fx= i l1n)
3306			 (walk (##sys#slot x i) (##sys#slot y i)) ; tailcall
3307			 (and (walk (##sys#slot x i) (##sys#slot y i))
3308			      (loop (fx+ i 1))))))))))
3309    (define (walk x y)
3310      (cond ((eq? x y))
3311	    ((number? x)
3312	     (if (number? y)
3313		 (= x y)
3314		 (eq? x y)))
3315	    ((not (##core#inline "C_blockp" x)) #f)
3316	    ((not (##core#inline "C_blockp" y)) #f)
3317	    ((not (##core#inline "C_sametypep" x y)) #f)
3318	    ((##core#inline "C_specialp" x)
3319	     (and (##core#inline "C_specialp" y)
3320		  (if (##core#inline "C_closurep" x)
3321		      (##core#inline "shallow_equal" x y)
3322		      (compare-slots x y 1))))
3323            ((##core#inline "C_stringp" x)
3324             (walk (##sys#slot x 0) (##sys#slot y 0)))
3325	    ((##core#inline "C_byteblockp" x)
3326	     (and (##core#inline "C_byteblockp" y)
3327		  (let ((s1 (##sys#size x)))
3328		    (and (eq? s1 (##sys#size y))
3329			 (##core#inline "C_bv_compare" x y s1)))))
3330	    (else
3331	     (let ((s1 (##sys#size x)))
3332	       (and (eq? s1 (##sys#size y))
3333		    (compare-slots x y 0))))))
3334    (walk x y) ))
3335
3336
3337;;; Symbols:
3338
3339(define ##sys#snafu '##sys#fnord)
3340(define ##sys#intern-symbol (##core#primitive "C_string_to_symbol"))
3341(define ##sys#intern-keyword (##core#primitive "C_string_to_keyword"))
3342(define ##sys#make-symbol (##core#primitive "C_make_symbol"))
3343(define (##sys#interned-symbol? x) (##core#inline "C_lookup_symbol" x))
3344
3345(define (##sys#string->symbol-name s)
3346  (let* ((bv (##sys#slot s 0))
3347         (len (##sys#size bv))
3348         (s2 (##sys#make-bytevector len)))
3349    (##core#inline "C_copy_bytevector" bv s2 len)))
3350
3351(define (##sys#symbol->string/shared s)
3352  (let* ((bv (##sys#slot s 1))
3353         (count (##core#inline "C_utf_length" bv)))
3354    (##core#inline_allocate ("C_a_ustring" 5)
3355                            bv
3356                            count)))
3357
3358(define (##sys#symbol->string s)
3359  (let* ((bv (##sys#slot s 1))
3360         (len (##sys#size bv))
3361         (s2 (##sys#make-bytevector len))
3362         (count (##core#inline "C_utf_length" bv)))
3363    (##core#inline_allocate ("C_a_ustring" 5)
3364                            (##core#inline "C_copy_bytevector" bv s2 len)
3365                            count)))
3366
3367(define (##sys#string->symbol str)
3368  (##sys#intern-symbol (##sys#string->symbol-name str) ))
3369
3370(set! scheme#symbol->string
3371  (lambda (s)
3372    (##sys#check-symbol s 'symbol->string)
3373    (##sys#symbol->string s) ) )
3374
3375(set! scheme#string->symbol
3376  (lambda (str)
3377    (##sys#check-string str 'string->symbol)
3378    (##sys#string->symbol str)))
3379
3380(set! chicken.base#string->uninterned-symbol
3381  (lambda (str)
3382    (##sys#check-string str 'string->uninterned-symbol)
3383    (##sys#make-symbol (##sys#string->symbol-name str))))
3384
3385(set! chicken.base#gensym
3386  (let ((counter -1))
3387    (lambda str-or-sym
3388      (let ((err (lambda (prefix) (##sys#signal-hook #:type-error 'gensym "argument is not a string or symbol" prefix))))
3389	(set! counter (fx+ counter 1))
3390	(##sys#make-symbol
3391         (##sys#string->symbol-name
3392	 (##sys#string-append
3393	  (if (eq? str-or-sym '())
3394	      "g"
3395	      (let ((prefix (car str-or-sym)))
3396		(or (and (##core#inline "C_blockp" prefix)
3397			 (cond ((##core#inline "C_stringp" prefix) prefix)
3398			       ((##core#inline "C_symbolp" prefix) (##sys#symbol->string/shared prefix))
3399			       (else (err prefix))))
3400		    (err prefix) ) ) )
3401	  (##sys#number->string counter) ) ) ) ) ) ) )
3402
3403(set! chicken.base#symbol-append
3404  (let ((string-append string-append))
3405    (lambda ss
3406      (##sys#string->symbol
3407       (apply
3408	string-append
3409	(map (lambda (s)
3410	       (##sys#check-symbol s 'symbol-append)
3411	       (##sys#symbol->string/shared s))
3412	     ss))))))
3413
3414;;; Keywords:
3415
3416(module chicken.keyword
3417  (keyword? get-keyword keyword->string string->keyword)
3418
3419(import scheme)
3420(import chicken.fixnum)
3421
3422(define (keyword? x) (##core#inline "C_i_keywordp" x) )
3423
3424(define string->keyword
3425  (let ([string string] )
3426    (lambda (s)
3427      (##sys#check-string s 'string->keyword)
3428      (##sys#intern-keyword (##sys#string->symbol-name s) ) ) ))
3429
3430(define keyword->string
3431  (let ([keyword? keyword?])
3432    (lambda (kw)
3433      (if (keyword? kw)
3434	  (##sys#symbol->string kw)
3435	  (##sys#signal-hook #:type-error 'keyword->string "bad argument type - not a keyword" kw) ) ) ) )
3436
3437(define get-keyword
3438  (let ((tag (list 'tag)))
3439    (lambda (key args #!optional thunk)
3440      (##sys#check-keyword key 'get-keyword)
3441      (##sys#check-list args 'get-keyword)
3442      (let ((r (##core#inline "C_i_get_keyword" key args tag)))
3443	(if (eq? r tag)			; not found
3444	    (and thunk (thunk))
3445	    r)))))
3446
3447(define ##sys#get-keyword get-keyword))
3448
3449(import chicken.keyword)
3450
3451
3452;;; bytevectors:
3453
3454(define (##sys#bytevector->list v)
3455  (let ((n (##sys#size v)))
3456    (let loop ((i (fx- n 1)) (lst '()))
3457      (if (fx< i 0)
3458          lst
3459          (loop (fx- i 1)
3460                (cons (##core#inline "C_subbyte" v i) lst))))))
3461
3462(define (##sys#list->bytevector lst0)
3463  (let* ((n (length lst0))
3464         (bv (##sys#make-bytevector n)))
3465    (let loop ((lst lst0) (i 0))
3466      (if (null? lst)
3467          bv
3468          (let ((b (car lst)))
3469            (if (##core#inline "C_fixnump" b)
3470                (##core#inline "C_setsubbyte" bv i b)
3471                (##sys#signal-hook #:type-error "can not convert list to bytevector" lst0))
3472            (loop (cdr lst) (fx+ i 1)))))))
3473
3474(module chicken.bytevector
3475  (bytevector? bytevector=? bytevector-length
3476               make-bytevector bytevector bytevector-u8-ref
3477               bytevector-u8-set! bytevector-copy bytevector-copy!
3478               bytevector-append utf8->string string->utf8
3479               latin1->string string->latin1 bytes->string)
3480
3481(import scheme (chicken foreign))
3482
3483(define (make-bytevector size #!optional fill)
3484  (##sys#check-fixnum size 'make-bytevector)
3485  (if fill (##sys#check-fixnum fill 'make-bytevector))
3486  (##sys#make-bytevector size fill) )
3487
3488(define (bytevector? x)
3489  (and (##core#inline "C_blockp" x)
3490       (##core#inline "C_bytevectorp" x) ) )
3491
3492(define (bytevector-length bv)
3493  (##sys#check-bytevector bv 'bytevector-size)
3494  (##sys#size bv) )
3495
3496(define (bytevector-u8-ref bv i)
3497  (##core#inline "C_i_bytevector_ref" bv i))
3498
3499(define (bytevector-u8-set! bv i b)
3500  (##core#inline "C_i_bytevector_set" bv i b))
3501
3502(define (string->utf8 s)
3503  (##sys#check-string s 'string->utf8)
3504  (let* ((sbv (##sys#slot s 0))
3505         (n (##core#inline "C_fixnum_difference" (##sys#size sbv) 1))
3506	 (bv (##sys#make-bytevector n)) )
3507    (##core#inline "C_copy_memory" bv sbv n)
3508    bv) )
3509
3510(define (utf8->string bv #!optional (start 0) end)
3511  (##sys#check-bytevector bv 'utf8->string)
3512  (let* ((n (##sys#size bv))
3513         (to (or end n)))
3514    (if end
3515        (##sys#check-range/including end 0 n 'utf8->string))
3516    (if (not (##core#inline "C_utf_validate" bv n start to))
3517        (##sys#error-hook (foreign-value "C_DECODING_ERROR" int)
3518         'utf8->string bv))
3519    (##sys#buffer->string bv start (##core#inline "C_fixnum_difference" to start))))
3520
3521(define (bytes->string bv #!optional (start 0) end)
3522  (##sys#check-bytevector bv 'bytes->string)
3523  (let* ((n (##sys#size bv))
3524         (to (or end n)))
3525    (if end
3526        (##sys#check-range/including end 0 n 'bytes->string))
3527    (##sys#buffer->string bv start (##core#inline "C_fixnum_difference" end start))))
3528
3529(define (string->latin1 s)
3530  (##sys#check-string s 'string->latin1)
3531  (let* ((sbv (##sys#slot s 0))
3532         (len (##sys#slot s 1))
3533         (blen (##core#inline "C_fixnum_difference" (##sys#size sbv) 1))
3534	 (bv (##sys#make-bytevector len)) )
3535    (##core#inline "C_utf_to_latin" sbv bv 0 blen)
3536    bv))
3537
3538(define (latin1->string bv)
3539  (##sys#check-bytevector bv 'latin1->string)
3540  (let* ((len (##sys#size bv))
3541         (buf (##sys#make-bytevector (##core#inline "C_fixnum_times" len 2)))
3542         (n (##core#inline "C_latin_to_utf" bv buf 0 len)))
3543    (##sys#buffer->string! buf n)))
3544
3545(define (bytevector=? b1 b2)
3546  (##sys#check-bytevector b1 'bytevector=?)
3547  (##sys#check-bytevector b2 'bytevector=?)
3548  (let ((n (##sys#size b1)))
3549    (and (eq? (##sys#size b2) n)
3550	 (##core#inline "C_bv_compare" b1 b2 n))))
3551
3552(define (bytevector . args)
3553  (let* ((n (length args))
3554         (bv (##sys#make-bytevector n)))
3555    (let loop ((args args) (i 0))
3556      (cond ((null? args) bv)
3557            (else
3558              (let ((b (car args)))
3559                (##sys#check-fixnum b 'bytevector)
3560                (##core#inline "C_setsubbyte" bv i b)
3561                (loop (cdr args) (##core#inline "C_fixnum_plus" i 1))))))))
3562
3563(define (bytevector-copy bv #!optional (start 0) end)
3564  (##sys#check-bytevector bv 'bytevector-copy)
3565  (let* ((n (##sys#size bv))
3566         (to (or end n)))
3567    (if end
3568      (##sys#check-range/including end 0 n 'bytevector->copy))
3569    (cond ((and (eq? n 0) (eq? start 0) (eq? 0 to))
3570           (##sys#make-bytevector 0))
3571          (else
3572            (##sys#check-range/including start 0 n 'bytevector->copy)
3573            (let* ((n2 (##core#inline "C_fixnum_difference" to start))
3574                   (v2 (##sys#make-bytevector n2)))
3575              (##core#inline "C_copy_memory_with_offset" v2 bv 0 start n2)
3576              v2)))))
3577
3578(define (bytevector-copy! bv1 at bv2 #!optional (start 0) end)
3579  (##sys#check-bytevector bv1 'bytevector-copy!)
3580  (##sys#check-bytevector bv2 'bytevector-copy!)
3581  (let* ((n1 (##sys#size bv1))
3582         (n2 (##sys#size bv2))
3583         (to (or end n2))
3584         (nc (##core#inline "C_fixnum_difference" to start)))
3585    (cond ((and (eq? n2 0) (eq? nc 0) (eq? start 0)) (##core#undefined))
3586          (else
3587            (##sys#check-range/including start 0 n2 'bytevector->copy!)
3588            (##sys#check-range/including at 0 n1 'bytevector->copy!)
3589            (##sys#check-range/including (##core#inline "C_fixnum_plus" at nc)
3590                               0 n1 'bytevector->copy!)
3591            (##core#inline "C_copy_memory_with_offset" bv1 bv2 at start nc)))))
3592
3593(define (bytevector-append . bvs)
3594  (let loop ((lst bvs) (len 0))
3595    (if (null? lst)
3596        (let ((bv (##sys#make-bytevector len)))
3597          (let loop ((lst bvs) (i 0))
3598            (if (null? lst)
3599                bv
3600                (let* ((bv1 (car lst))
3601                       (n (##sys#size bv1)))
3602                  (##core#inline "C_copy_memory_with_offset" bv bv1 i 0 n)
3603                  (loop (cdr lst) (##core#inline "C_fixnum_plus" i n))))))
3604        (let ((bv (car lst)))
3605          (##sys#check-bytevector bv 'bytevector-append)
3606          (loop (cdr lst) (##core#inline "C_fixnum_plus" len (##sys#size bv)))))))
3607
3608) ; chicken.bytevector
3609
3610
3611;;; Vectors:
3612(set! scheme#make-vector
3613  (lambda (size . fill)
3614    (##sys#check-fixnum size 'make-vector)
3615    (when (fx< size 0) (##sys#error 'make-vector "size is negative" size))
3616    (##sys#allocate-vector
3617     size
3618     (if (null? fill)
3619	 (##core#undefined)
3620	 (car fill) ))))
3621
3622(define ##sys#make-vector make-vector)
3623
3624(set! scheme#list->vector
3625  (lambda (lst0)
3626    (if (not (list? lst0))
3627	(##sys#error-not-a-proper-list lst0 'list->vector)
3628	(let* ([len (length lst0)]
3629	       [v (##sys#make-vector len)] )
3630	  (let loop ([lst lst0]
3631		     [i 0])
3632	    (if (null? lst)
3633		v
3634		(begin
3635		  (##sys#setslot v i (##sys#slot lst 0))
3636		  (loop (##sys#slot lst 1) (fx+ i 1)) ) ) ) ) )))
3637
3638(set! scheme#vector->list
3639  (lambda (v #!optional start end)
3640    (##sys#check-vector v 'vector->list)
3641    (let ((len (##sys#size v)))
3642      (if start
3643          (##sys#check-range/including start 0 len 'vector->list)
3644          (set! start 0))
3645      (if end
3646          (##sys#check-range/including end 0 len 'vector->list)
3647          (set! end len))
3648      (let loop ((i start))
3649	(if (fx>= i end)
3650	    '()
3651	    (cons (##sys#slot v i)
3652		  (loop (fx+ i 1)) ) ) ) ) ))
3653
3654(set! scheme#vector (lambda xs (list->vector xs) ))
3655
3656(set! scheme#vector-fill!
3657  (lambda (v x #!optional start end)
3658    (##sys#check-vector v 'vector-fill!)
3659    (let ((len (##sys#size v)))
3660      (if start
3661          (##sys#check-range/including start 0 len 'vector-fill!)
3662          (set! start 0))
3663      (if end
3664          (##sys#check-range/including end 0 len 'vector-fill!)
3665          (set! end len))
3666      (do ((i start (fx+ i 1)))
3667	  ((fx>= i end))
3668	(##sys#setslot v i x) ) ) ))
3669
3670(define (scheme#vector-copy v #!optional start end)
3671  (##sys#check-vector v 'vector-copy)
3672  (let ((copy (lambda (v start end)
3673                (let* ((len (##sys#size v)))
3674                  (##sys#check-range/including start 0 end 'vector-copy)
3675                  (##sys#check-range/including end start len 'vector-copy)
3676                  (let ((vec (##sys#make-vector (fx- end start))))
3677                    (do ((ti 0 (fx+ ti 1))
3678                         (fi start (fx+ fi 1)))
3679                        ((fx>= fi end) vec)
3680                      (##sys#setslot vec ti (##sys#slot v fi))))))))
3681    (if end
3682        (copy v start end)
3683        (copy v (or start 0) (##sys#size v)))))
3684
3685(define (scheme#vector-copy! to at from #!optional start end)
3686  (##sys#check-vector to 'vector-copy!)
3687  (##sys#check-vector from 'vector-copy!)
3688  (let ((copy! (lambda (to at from start end)
3689                 (let* ((tlen (##sys#size to))
3690                        (flen (##sys#size from))
3691                        (d (fx- end start)))
3692                   (##sys#check-range/including at 0 tlen 'vector-copy!)
3693                   (##sys#check-range/including start 0 end 'vector-copy!)
3694                   (##sys#check-range/including end start flen 'vector-copy!)
3695                   (##sys#check-range/including d 0 (fx- tlen at) 'vector-copy!)
3696                   (if (and (eq? to from) (fx< start at))
3697                       (do ((fi (fx- end 1) (fx- fi 1))
3698                            (ti (fx- (fx+ at d) 1) (fx- ti 1)))
3699                           ((fx< fi start))
3700                           (##sys#setslot to ti (##sys#slot from fi)))
3701                       (do ((fi start (fx+ fi 1))
3702                            (ti at (fx+ ti 1)))
3703                           ((fx= fi end))
3704                           (##sys#setslot to ti (##sys#slot from fi))))))))
3705    (if end
3706        (copy! to at from start end)
3707        (copy! to at from (or start 0) (##sys#size from)))))
3708
3709(define (scheme#vector-append . vs)
3710  (##sys#for-each (cut ##sys#check-vector <> 'vector-append) vs)
3711  (let* ((lens (map ##sys#size vs))
3712         (vec  (##sys#make-vector (foldl fx+ 0 lens))))
3713    (do ((vs vs (cdr vs))
3714         (lens lens (cdr lens))
3715         (i 0 (fx+ i (car lens))))
3716        ((null? vs) vec)
3717      (scheme#vector-copy! vec i (car vs) 0 (car lens)))))
3718
3719(set! chicken.base#subvector
3720  (lambda (v i #!optional j)
3721    (##sys#check-vector v 'subvector)
3722    (let* ((len (##sys#size v))
3723	   (j (or j len))
3724	   (len2 (fx- j i)))
3725      (##sys#check-range/including i 0 len 'subvector)
3726      (##sys#check-range/including j 0 len 'subvector)
3727      (let ((v2 (make-vector len2)))
3728	(do ((k 0 (fx+ k 1)))
3729	    ((fx>= k len2) v2)
3730	  (##sys#setslot v2 k (##sys#slot v (fx+ k i))))))))
3731
3732(set! chicken.base#vector-resize
3733  (lambda (v n #!optional init)
3734    (##sys#check-vector v 'vector-resize)
3735    (##sys#check-fixnum n 'vector-resize)
3736    (##sys#vector-resize v n init)))
3737
3738(define (##sys#vector-resize v n init)
3739  (let ((v2 (##sys#make-vector n init))
3740	(len (min (##sys#size v) n)) )
3741    (do ((i 0 (fx+ i 1)))
3742	((fx>= i len) v2)
3743      (##sys#setslot v2 i (##sys#slot v i)) ) ) )
3744
3745;;; Characters:
3746
3747(set! scheme#char-ci=?
3748  (lambda (x y . more)
3749    (##sys#check-char x 'char-ci=?)
3750    (##sys#check-char y 'char-ci=?)
3751    (let ((c2 (##core#inline "C_utf_char_foldcase" y)))
3752      (let loop ((c c2) (cs more)
3753                 (f (eq? (##core#inline "C_utf_char_foldcase" x) c2)))
3754        (if (null? cs)
3755            f
3756            (let ((c2 (##sys#slot cs 0)))
3757              (##sys#check-char c2 'char-ci=?)
3758              (let ((c2 ((##core#inline "C_utf_char_foldcase" c2))))
3759                (loop c2 (##sys#slot cs 1)
3760                      (and f (eq? c c2))))))))))
3761
3762(set! scheme#char-ci>?
3763  (lambda (x y . more)
3764    (##sys#check-char x 'char-ci>?)
3765    (##sys#check-char y 'char-ci>?)
3766    (let ((c2 (##core#inline "C_utf_char_foldcase" y)))
3767      (let loop ((c c2) (cs more)
3768                 (f (##core#inline "C_u_i_char_greaterp"
3769                                   (##core#inline "C_utf_char_foldcase" x)
3770                                   c2)))
3771        (if (null? cs)
3772            f
3773            (let ((c2 (##sys#slot cs 0)))
3774              (##sys#check-char c2 'char-ci>?)
3775              (let ((c2 ((##core#inline "C_utf_char_foldcase" c2))))
3776                (loop c2 (##sys#slot cs 1)
3777                      (and f (##core#inline "C_u_i_char_greaterp" c c2))))))))))
3778
3779(set! scheme#char-ci<?
3780  (lambda (x y . more)
3781    (##sys#check-char x 'char-ci<?)
3782    (##sys#check-char y 'char-ci<?)
3783    (let ((c2 (##core#inline "C_utf_char_foldcase" y)))
3784      (let loop ((c c2) (cs more)
3785                 (f (##core#inline "C_u_i_char_lessp"
3786                                   (##core#inline "C_utf_char_foldcase" x)
3787                                   c2)))
3788        (if (null? cs)
3789            f
3790            (let ((c2 (##sys#slot cs 0)))
3791              (##sys#check-char c2 'char-ci<?)
3792              (let ((c2 ((##core#inline "C_utf_char_foldcase" c2))))
3793                (loop c2 (##sys#slot cs 1)
3794                      (and f (##core#inline "C_u_i_char_lessp" c c2))))))))))
3795
3796(set! scheme#char-ci>=?
3797  (lambda (x y . more)
3798    (##sys#check-char x 'char-ci>=?)
3799    (##sys#check-char y 'char-ci>=?)
3800    (let ((c2 (##core#inline "C_utf_char_foldcase" y)))
3801      (let loop ((c c2) (cs more)
3802                 (f (##core#inline "C_u_i_char_greater_or_equal_p"
3803                                   (##core#inline "C_utf_char_foldcase" x)
3804                                   c2)))
3805        (if (null? cs)
3806            f
3807            (let ((c2 (##sys#slot cs 0)))
3808              (##sys#check-char c2 'char-ci>=?)
3809              (let ((c2 ((##core#inline "C_utf_char_foldcase" c2))))
3810                (loop c2 (##sys#slot cs 1)
3811                      (and f (##core#inline "C_u_i_char_greater_or_equal_p" c c2))))))))))
3812
3813(set! scheme#char-ci<=?
3814  (lambda (x y . more)
3815    (##sys#check-char x 'char-ci<=?)
3816    (##sys#check-char y 'char-ci<=?)
3817    (let ((c2 (##core#inline "C_utf_char_foldcase" y)))
3818      (let loop ((c c2) (cs more)
3819                 (f (##core#inline "C_u_i_char_less_or_equal_p"
3820                                   (##core#inline "C_utf_char_foldcase" x)
3821                                   c2)))
3822        (if (null? cs)
3823            f
3824            (let ((c2 (##sys#slot cs 0)))
3825              (##sys#check-char c2 'char-ci<=?)
3826              (let ((c2 ((##core#inline "C_utf_char_foldcase" c2))))
3827                (loop c2 (##sys#slot cs 1)
3828                      (and f (##core#inline "C_u_i_char_less_or_equal_p" c c2))))))))))
3829
3830(set! chicken.base#char-name
3831  (let ((chars-to-names (make-vector char-name-table-size '()))
3832        (names-to-chars '()))
3833    (define (lookup-char c)
3834      (let* ((code (char->integer c))
3835             (key (##core#inline "C_fixnum_modulo" code char-name-table-size)) )
3836        (let loop ((b (##sys#slot chars-to-names key)))
3837          (and (pair? b)
3838               (let ((a (##sys#slot b 0)))
3839                 (if (eq? (##sys#slot a 0) c)
3840                     a
3841                     (loop (##sys#slot b 1)) ) ) ) ) ) )
3842    (lambda (x #!optional (chr #:none))
3843      (cond ((char? x)
3844             (and-let* ((a (lookup-char x)))
3845               (case chr
3846                 ((#:none)
3847                  (##sys#slot a 1) )
3848                 ((#f)
3849                  (##sys#setslot a 0 #f)
3850                  (##sys#setslot (assq (##sys#slot a 1) names-to-chars) 0 #f)
3851                  (##core#undefined))
3852                 (else
3853                   (##sys#signal-hook #:type-error 'char-name 
3854                    "expected second boolean argument" chr) ))))
3855            ((symbol? x)
3856             (let ((a (assq x names-to-chars)))
3857               (case chr
3858                 ((#:none) (and a (##sys#slot a 1)))
3859                 ((#f) 
3860                  (when a 
3861                    (##sys#setslot a 0 #f)
3862                    (##sys#setslot (lookup-char (##sys#slot a 1)) 0 #f))
3863                  (##core#undefined))
3864                 (else
3865                   (##sys#check-char chr 'char-name)
3866                   (when (fx< (##sys#size (##sys#slot x 1)) 2)
3867                     (##sys#signal-hook #:type-error 'char-name "invalid character name" x) )
3868                   (let ((a (lookup-char chr)))
3869                     (if a
3870                         (let ((b (assq x names-to-chars)))
3871                           (##sys#setslot a 1 x)
3872                           (if b
3873                               (##sys#setislot b 1 chr)
3874                               (set! names-to-chars (cons (cons x chr) names-to-chars)) ) )
3875                         (let ((key (##core#inline "C_fixnum_modulo" (char->integer chr) 
3876                                     char-name-table-size)))
3877                           (set! names-to-chars (cons (cons x chr) names-to-chars))
3878                           (##sys#setslot
3879                            chars-to-names key
3880                            (cons (cons chr x) (##sys#slot chars-to-names key))) ) ) ) ))))
3881            (else (##sys#signal-hook #:type-error 'char-name "invalid argument type" x))))))
3882
3883;; TODO: Use the character names here in the next release?  Or just
3884;; use the numbers everywhere, for clarity?
3885(char-name 'space #\space)
3886(char-name 'tab #\tab)
3887(char-name 'linefeed #\linefeed)
3888(char-name 'newline #\newline)
3889(char-name 'vtab (integer->char 11))
3890(char-name 'delete (integer->char 127))
3891(char-name 'esc (integer->char 27))
3892(char-name 'escape (integer->char 27))
3893(char-name 'alarm (integer->char 7))
3894(char-name 'nul (integer->char 0))
3895(char-name 'null (integer->char 0))
3896(char-name 'return #\return)
3897(char-name 'page (integer->char 12))
3898(char-name 'backspace (integer->char 8))
3899
3900
3901;;; Procedures:
3902
3903(define ##sys#call-with-current-continuation (##core#primitive "C_call_cc"))
3904(define ##sys#call-with-cthulhu (##core#primitive "C_call_with_cthulhu"))
3905(define ##sys#call-with-values call-with-values)
3906
3907(define (##sys#for-each p lst0)
3908  (let loop ((lst lst0))
3909    (cond ((eq? lst '()) (##core#undefined))
3910	  ((pair? lst)
3911	   (p (##sys#slot lst 0))
3912	   (loop (##sys#slot lst 1)) )
3913	  (else (##sys#error-not-a-proper-list lst0 'for-each)) ) ))
3914
3915(define (##sys#map p lst0)
3916  (let loop ((lst lst0))
3917    (cond ((eq? lst '()) lst)
3918	  ((pair? lst)
3919	   (cons (p (##sys#slot lst 0)) (loop (##sys#slot lst 1))) )
3920	  (else (##sys#error-not-a-proper-list lst0 'map)) ) ))
3921
3922(letrec ((mapsafe
3923	  (lambda (p lsts loc)
3924	    (call-with-current-continuation
3925	     (lambda (empty)
3926	       (let lp ((lsts lsts))
3927		 (if (eq? lsts '())
3928		     lsts
3929		     (let ((item (##sys#slot lsts 0)))
3930		       (cond ((eq? item '()) (empty '()))
3931			     ((pair? item)
3932			      (cons (p item) (lp (##sys#slot lsts 1))))
3933			     (else (##sys#error-not-a-proper-list item loc)))))))))))
3934
3935  (set! scheme#for-each
3936    (lambda (fn lst1 . lsts)
3937      (if (null? lsts)
3938	  (##sys#for-each fn lst1)
3939	  (let loop ((all (cons lst1 lsts)))
3940	    (let* ((first (##sys#slot all 0))
3941		   (safe-args (mapsafe (lambda (x) (car x)) all 'for-each))) ; ensure inlining
3942	      (when (pair? safe-args)
3943		(apply fn safe-args)
3944		(loop (mapsafe (lambda (x) (cdr x)) all 'for-each))))))))
3945
3946  (set! scheme#map
3947    (lambda (fn lst1 . lsts)
3948      (if (null? lsts)
3949	  (##sys#map fn lst1)
3950	  (let loop ((all (cons lst1 lsts)))
3951	    (let* ((first (##sys#slot all 0))
3952		   (safe-args (mapsafe (lambda (x) (car x)) all 'map)))
3953	      (if (pair? safe-args)
3954		  (cons (apply fn safe-args)
3955			(loop (mapsafe (lambda (x) (cdr x)) all 'map)))
3956		  '())))))))
3957
3958
3959;;; dynamic-wind:
3960;
3961; (taken more or less directly from SLIB)
3962;
3963; This implementation is relatively costly: we have to shadow call/cc
3964; with a new version that unwinds suspended thunks, but for this to
3965; happen the return-values of the escaping procedure have to be saved
3966; temporarily in a list. Since call/cc is very efficient under this
3967; implementation, and because allocation of memory that is to be
3968; garbage soon has also quite low overhead, the performance-penalty
3969; might be acceptable (ctak needs about 4 times longer).
3970
3971(define ##sys#dynamic-winds '())
3972
3973(set! scheme#dynamic-wind
3974  (lambda (before thunk after)
3975    (before)
3976    (set! ##sys#dynamic-winds (cons (cons before after) ##sys#dynamic-winds))
3977    (##sys#call-with-values
3978     thunk
3979     (lambda results
3980       (set! ##sys#dynamic-winds (##sys#slot ##sys#dynamic-winds 1))
3981       (after)
3982       (apply ##sys#values results) ) ) ))
3983
3984(define ##sys#dynamic-wind dynamic-wind)
3985
3986(set! scheme#call-with-current-continuation
3987  (lambda (proc)
3988    (let ((winds ##sys#dynamic-winds))
3989      (##sys#call-with-current-continuation
3990       (lambda (cont)
3991	 (define (continuation . results)
3992	   (unless (eq? ##sys#dynamic-winds winds)
3993	     (##sys#dynamic-unwind winds (fx- (length ##sys#dynamic-winds) (length winds))) )
3994	   (apply cont results) )
3995	 (proc continuation) ))) ))
3996
3997(set! scheme#call/cc call-with-current-continuation)
3998
3999(define (##sys#dynamic-unwind winds n)
4000  (cond [(eq? ##sys#dynamic-winds winds)]
4001	[(fx< n 0)
4002	 (##sys#dynamic-unwind (##sys#slot winds 1) (fx+ n 1))
4003	 ((##sys#slot (##sys#slot winds 0) 0))
4004	 (set! ##sys#dynamic-winds winds) ]
4005	[else
4006	 (let ([after (##sys#slot (##sys#slot ##sys#dynamic-winds 0) 1)])
4007	   (set! ##sys#dynamic-winds (##sys#slot ##sys#dynamic-winds 1))
4008	   (after)
4009	   (##sys#dynamic-unwind winds (fx- n 1)) ) ] ) )
4010
4011
4012;;; Ports:
4013
4014(set! chicken.base#port-closed?
4015  (lambda (p)
4016    (##sys#check-port p 'port-closed?)
4017    (eq? (##sys#slot p 8) 0)))
4018
4019;;; Custom ports:
4020
4021;;; Port layout:
4022;
4023; 0:  file ptr (special)
4024; 1:  direction (fixnum, 1 = input)
4025; 2:  class (vector of procedures)
4026; 3:  name (string)
4027; 4:  row (fixnum)
4028; 5:  col (fixnum)
4029; 6:  EOF (bool)
4030; 7:  type ('stream | 'custom | 'string | 'socket)
4031; 8:  closed (fixnum)
4032; 9:  data
4033; 10-12: reserved, port class specific
4034; 13: case sensitive? (boolean)
4035; 14: mode ('textual | 'binary)
4036; 15: reserved (encoding)
4037;
4038; Port-class:
4039;
4040; 0:  (read-char PORT) -> CHAR | EOF
4041; 1:  (peek-char PORT) -> CHAR | EOF
4042; 2:  (write-char PORT CHAR)
4043; 3:  (write-bytevector PORT BYTEVECTOR START END)
4044; 4:  (close PORT DIRECTION)
4045; 5:  (flush-output PORT)
4046; 6:  (char-ready? PORT) -> BOOL
4047; 7:  (read-bytevector! PORT COUNT BYTEVECTOR START) -> COUNT'
4048; 8:  (read-line PORT LIMIT) -> STRING | EOF
4049; 9:  (read-buffered PORT) -> STRING
4050
4051(define (##sys#make-port i/o class name type)
4052  (let ((port (##core#inline_allocate ("C_a_i_port" 17))))
4053    (##sys#setislot port 1 i/o)
4054    (##sys#setslot port 2 class)
4055    (##sys#setslot port 3 name)
4056    (##sys#setislot port 4 1)
4057    (##sys#setislot port 5 0)
4058    (##sys#setislot port 6 #f)
4059    (##sys#setslot port 7 type)
4060    (##sys#setslot port 8 i/o)
4061    (##sys#setislot port 10 #f)
4062    (##sys#setislot port 13 #t)
4063    (##sys#setislot port 14 'textual)  ; default, only used for R7RS port predicates
4064    (##sys#setslot port 15 'utf-8)
4065    port) )
4066
4067;;; Stream ports:
4068; Input port slots:
4069;   10: peek buffer
4070;   12: Static buffer for read-line, allocated on-demand
4071
4072(define ##sys#stream-port-class
4073  (vector (lambda (p)      ; read-char
4074            (let loop ()
4075              (let ((peeked (##sys#slot p 10)))
4076                (cond (peeked
4077                        (##sys#setislot p 10 #f)
4078                        (##sys#decode-char peeked (##sys#slot p 15) 0))
4079                      ((eq? 'utf-8  (##sys#slot p 15)) ; fast path
4080                       (let ((c (##core#inline "C_read_char" p)))
4081                         (if (eq? -1 c)
4082                             (let ((err (##sys#update-errno)))
4083                               (if (eq? err (foreign-value "EINTR" int))
4084                                   (##sys#dispatch-interrupt loop)
4085                                   (##sys#signal-hook/errno
4086                                    #:file-error err 'read-char
4087                                    (##sys#string-append "cannot read from port - " strerror)
4088                                    p)))
4089                             c)))
4090                      (else (##sys#read-char/encoding
4091                             p (##sys#slot p 15)
4092                             (lambda (buf start len dec)
4093                               (dec buf start len
4094                                    (lambda (buf start len)
4095                                      (##core#inline "C_utf_decode" buf start))))))))))
4096          (lambda (p)      ; peek-char
4097            (let ((pb (##sys#slot p 10))
4098                  (enc (##sys#slot p 15)))
4099              (if pb
4100                  (##sys#decode-char pb enc 0)
4101                  (##sys#read-char/encoding
4102                   p enc
4103                   (lambda (buf start len dec)
4104                     (let ((pb (##sys#make-bytevector len 1)))
4105                       (##core#inline "C_copy_memory_with_offset" pb buf 0 start len)
4106                       (##sys#setslot p 10 pb)
4107                       (dec buf start len
4108                            (lambda (buf start _)
4109                              (##core#inline "C_utf_decode" buf start)))))))))
4110          (lambda (p c)                ; write-char
4111            (let ((enc (##sys#slot p 15)))
4112              (if (eq? enc 'utf-8) ;; fast path
4113                  (##core#inline "C_display_char" p c)
4114                  (let* ((bv (##sys#make-bytevector 4))
4115                         (n (##sys#encode-char c bv enc)))
4116                    ((##sys#slot (##sys#slot p 2) 3) p bv 0 n))))) ; write-bytevector
4117          (lambda (p bv from to)                     ; write-bytevector
4118            (##sys#encode-buffer
4119             bv from (fx- to from) (##sys#slot p 15)
4120             (lambda (bv start len)
4121               (##core#inline "C_display_string" p bv start len))))
4122          (lambda (p d)                ; close
4123            (##core#inline "C_close_file" p)
4124            (##sys#update-errno) )
4125          (lambda (p)      ; flush-output
4126            (##core#inline "C_flush_output" p) )
4127          (lambda (p)      ; char-ready?
4128            (##core#inline "C_char_ready_p" p) )
4129          (lambda (p n dest start)           ; read-bytevector!
4130            (let ((pb (##sys#slot p 10))
4131                  (nc 0))
4132              (when pb
4133                (set! nc (##sys#size pb))
4134                (##core#inline "C_copy_memory_with_offset" dest pb start 0 nc)
4135                (set! start (fx+ start nc))
4136                (set! n (fx- n nc))
4137                (##sys#setislot p 10 #f))
4138              ;;XXX "n" below always true?
4139              (let loop ((rem (or n (fx- (##sys#size dest) start)))
4140                         (act nc)
4141                         (start start))
4142                (let ((len (##core#inline "fast_read_string_from_file" dest p rem start)))
4143                  (cond ((eof-object? len) ; EOF returns 0 bytes read
4144                         act)
4145                        ((fx< len 0)
4146                         (let ((err (##sys#update-errno)))
4147                           (if (eq? err (foreign-value "EINTR" int))
4148                               (##sys#dispatch-interrupt
4149                                (lambda () (loop rem act start)))
4150                               (##sys#signal-hook/errno
4151                                #:file-error err 'read-bytevector!
4152                                (##sys#string-append "cannot read from port - " strerror)
4153                                p n dest start))))
4154                        ((fx< len rem)
4155                         (loop (fx- rem len) (fx+ act len) (fx+ start len)))
4156                        (else (fx+ act len) ) ) ))))
4157          (lambda (p rlimit)       ; read-line
4158            (when rlimit (##sys#check-fixnum rlimit 'read-line))
4159            (let ((sblen read-line-buffer-initial-size))
4160              (unless (##sys#slot p 12)
4161                (##sys#setslot p 12 (##sys#make-bytevector sblen)))
4162              (let loop ([len sblen]
4163                         [limit (or rlimit maximal-string-length)]
4164                         [buffer (##sys#slot p 12)]
4165                         [result ""]
4166                         [f #f])
4167                (let* ((nlimit (fxmin limit len))
4168                       (n (##core#inline "fast_read_line_from_file" buffer
4169                          p nlimit)))
4170                  (cond ((eof-object? n) (if f result #!eof))
4171                        ((not n)
4172                         (let ((prev (##sys#buffer->string/encoding buffer 0 nlimit
4173                                      (##sys#slot p 15))))
4174                           (if (fx< limit len)
4175                               (##sys#string-append result prev)
4176                               (loop (fx* len 2)
4177                                     (fx- limit len)
4178                                     (##sys#make-bytevector (fx* len 2))
4179                                     (##sys#string-append result prev)
4180                                     #t)) ) )
4181                        ((fx< n 0)
4182                         (let ((err (##sys#update-errno)))
4183                           (if (eq? err (foreign-value "EINTR" int))
4184                                (let ((n (fx- (fxneg n) 1)))
4185                                  (##sys#dispatch-interrupt
4186                                   (lambda ()
4187                                     (loop len limit buffer
4188                                           (##sys#string-append
4189                                            result
4190                                            (##sys#buffer->string/encoding buffer 0 n (##sys#slot p 15)))
4191                                           #t))))
4192                               (##sys#signal-hook/errno
4193                                #:file-error err 'read-line
4194                                (##sys#string-append "cannot read from port - " strerror)
4195                                p rlimit))))
4196                        (f (##sys#setislot p 4 (fx+ (##sys#slot p 4) 1))
4197                           (##sys#string-append result
4198                            (##sys#buffer->string/encoding buffer 0 n (##sys#slot p 15))))
4199                        (else
4200                          (##sys#setislot p 4 (fx+ (##sys#slot p 4) 1))
4201                          (##sys#buffer->string/encoding buffer 0 n (##sys#slot p 15))))))))
4202          #f  ; read-buffered
4203          ) )
4204
4205(define ##sys#open-file-port (##core#primitive "C_open_file_port"))
4206
4207(define ##sys#standard-input (##sys#make-port 1 ##sys#stream-port-class "(stdin)" 'stream))
4208(define ##sys#standard-output (##sys#make-port 2 ##sys#stream-port-class "(stdout)" 'stream))
4209(define ##sys#standard-error (##sys#make-port 2 ##sys#stream-port-class "(stderr)" 'stream))
4210
4211(##sys#open-file-port ##sys#standard-input 0 #f)
4212(##sys#open-file-port ##sys#standard-output 1 #f)
4213(##sys#open-file-port ##sys#standard-error 2 #f)
4214
4215(define (##sys#check-input-port x open . loc)
4216  (if (pair? loc)
4217      (##core#inline "C_i_check_port_2" x 1 open (car loc))
4218      (##core#inline "C_i_check_port" x 1 open)))
4219
4220(define (##sys#check-output-port x open . loc)
4221  (if (pair? loc)
4222      (##core#inline "C_i_check_port_2" x 2 open (car loc))
4223      (##core#inline "C_i_check_port" x 2 open)))
4224
4225(define (##sys#check-port x . loc)
4226  (if (pair? loc)
4227      (##core#inline "C_i_check_port_2" x 0 #f (car loc))
4228      (##core#inline "C_i_check_port" x 0 #f) ) )
4229
4230(define (##sys#check-open-port x . loc)
4231  (if (pair? loc)
4232      (##core#inline "C_i_check_port_2" x 0 #t (car loc))
4233      (##core#inline "C_i_check_port" x 0 #t) ) )
4234
4235(set! scheme#current-input-port
4236  (lambda args
4237    (if (null? args)
4238	##sys#standard-input
4239	(let ((p (car args)))
4240	  (##sys#check-port p 'current-input-port)
4241	  (let-optionals (cdr args) ((convert? #t) (set? #t))
4242	    (when set? (set! ##sys#standard-input p)))
4243	  p) ) ))
4244
4245(set! scheme#current-output-port
4246  (lambda args
4247    (if (null? args)
4248	##sys#standard-output
4249	(let ((p (car args)))
4250	  (##sys#check-port p 'current-output-port)
4251	  (let-optionals (cdr args) ((convert? #t) (set? #t))
4252	    (when set? (set! ##sys#standard-output p)))
4253	  p) ) ))
4254
4255(set! chicken.base#current-error-port
4256  (lambda args
4257    (if (null? args)
4258	##sys#standard-error
4259	(let ((p (car args)))
4260	  (##sys#check-port p 'current-error-port)
4261	  (let-optionals (cdr args) ((convert? #t) (set? #t))
4262	    (when set? (set! ##sys#standard-error p)))
4263	  p))))
4264
4265(define (##sys#tty-port? port)
4266  (and (not (zero? (##sys#peek-unsigned-integer port 0)))
4267       (##core#inline "C_tty_portp" port) ) )
4268
4269(define (##sys#port-data port) (##sys#slot port 9))
4270(define (##sys#set-port-data! port data) (##sys#setslot port 9 data))
4271
4272(define ##sys#default-file-encoding)
4273
4274(let ()
4275  (define (open name inp modes loc)
4276    (##sys#check-string name loc)
4277    (let ((fmode (if inp "r" "w"))
4278          (bmode "")
4279          (enc (##sys#default-file-encoding)))
4280      (do ((modes modes (##sys#slot modes 1)))
4281        ((null? modes))
4282        (let ((o (##sys#slot modes 0)))
4283          (case o
4284            ((#:binary binary)
4285             (set! bmode "b")
4286             (set! enc 'binary))
4287            ((#:text text) (set! bmode ""))
4288            ((#:utf-8 utf-8)
4289             (set! enc 'utf-8))
4290            ((#:latin-1 latin-1 #:iso-8859-1 iso-8859-1)
4291             (set! enc 'latin-1))
4292            ((#:unix #:nl unix nl)
4293             (set! bmode "b"))
4294            ((#:crnl crnl)
4295             (set! bmode ""))
4296            ((#:append append)
4297             (if inp
4298               (##sys#error loc "cannot use append mode with input file")
4299               (set! fmode "a") ) )
4300            (else (##sys#error loc "invalid file option" o)) ) ) )
4301      (let ((port (##sys#make-port (if inp 1 2) ##sys#stream-port-class name 'stream)))
4302        (##sys#setslot port 15 enc)
4303        (unless (##sys#open-file-port port name (##sys#string-append fmode bmode))
4304          (##sys#signal-hook/errno #:file-error (##sys#update-errno) loc
4305                                   (##sys#string-append "cannot open file - " strerror)
4306                                   name))
4307        port) ) )
4308
4309  (define (close port inp loc)
4310    (##sys#check-port port loc)
4311    ; repeated closing is ignored
4312    (let ((direction (if inp 1 2)))
4313      (when (##core#inline "C_port_openp" port direction)
4314	(##sys#setislot port 8 (fxand (##sys#slot port 8) (fxnot direction)))
4315	((##sys#slot (##sys#slot port 2) 4) port direction))))
4316
4317  (set! scheme#open-input-file (lambda (name . mode) (open name #t mode 'open-input-file)))
4318  (set! scheme#open-output-file (lambda (name . mode) (open name #f mode 'open-output-file)))
4319  (set! scheme#close-input-port (lambda (port) (close port #t 'close-input-port)))
4320  (set! scheme#close-output-port (lambda (port) (close port #f 'close-output-port))))
4321
4322(set! scheme#call-with-input-file
4323  (let ((open-input-file open-input-file)
4324	(close-input-port close-input-port) )
4325    (lambda (name p . mode)
4326      (let ((f (apply open-input-file name mode)))
4327	(##sys#call-with-values
4328	 (lambda () (p f))
4329	 (lambda results
4330	   (close-input-port f)
4331	   (apply ##sys#values results) ) ) ) ) ) )
4332
4333(set! scheme#call-with-output-file
4334  (let ((open-output-file open-output-file)
4335	(close-output-port close-output-port) )
4336    (lambda (name p . mode)
4337      (let ((f (apply open-output-file name mode)))
4338	(##sys#call-with-values
4339	 (lambda () (p f))
4340	 (lambda results
4341	   (close-output-port f)
4342	   (apply ##sys#values results) ) ) ) ) ) )
4343
4344(set! scheme#with-input-from-file
4345  (let ((open-input-file open-input-file)
4346	(close-input-port close-input-port) )
4347    (lambda (str thunk . mode)
4348      (let ((file (apply open-input-file str mode)))
4349	(fluid-let ((##sys#standard-input file))
4350	  (##sys#call-with-values thunk
4351	    (lambda results
4352	      (close-input-port file)
4353	      (apply ##sys#values results) ) ) ) ) ) ) )
4354
4355(set! scheme#with-output-to-file
4356  (let ((open-output-file open-output-file)
4357	(close-output-port close-output-port) )
4358    (lambda (str thunk . mode)
4359      (let ((file (apply open-output-file str mode)))
4360	(fluid-let ((##sys#standard-output file))
4361	  (##sys#call-with-values thunk
4362	    (lambda results
4363	      (close-output-port file)
4364	      (apply ##sys#values results) ) ) ) ) ) ) )
4365
4366(define (##sys#file-exists? name file? dir? loc)
4367  (case (##core#inline "C_i_file_exists_p" (##sys#make-c-string name loc) file? dir?)
4368    ((#f) #f)
4369    ((#t) #t)
4370    (else
4371     (##sys#signal-hook
4372      #:file-error loc "system error while trying to access file"
4373      name))))
4374
4375(define (##sys#flush-output port)
4376  ((##sys#slot (##sys#slot port 2) 5) port) ; flush-output
4377  (##core#undefined) )
4378
4379(set! chicken.base#flush-output
4380  (lambda (#!optional (port ##sys#standard-output))
4381    (##sys#check-output-port port #t 'flush-output)
4382    (##sys#flush-output port)))
4383
4384(define (##sys#port-line port)
4385  (and (##core#inline "C_input_portp" port)
4386       (##sys#slot port 4) ) )
4387
4388;;; Decorate procedure with arbitrary data
4389;
4390; warning: may modify proc, if it already has a suitable decoration!
4391
4392(define (##sys#decorate-lambda proc pred decorator)
4393  (let ((len (##sys#size proc)))
4394    (let loop ((i (fx- len 1)))
4395      (cond ((zero? i)
4396	     (let ((p2 (make-vector (fx+ len 1))))
4397	       (do ((i 1 (fx+ i 1)))
4398		   ((fx>= i len)
4399		    (##core#inline "C_vector_to_closure" p2)
4400		    (##core#inline "C_copy_pointer" proc p2)
4401		    (decorator p2 i) )
4402		 (##sys#setslot p2 i (##sys#slot proc i)) ) ) )
4403	    (else
4404	     (let ((x (##sys#slot proc i)))
4405	       (if (pred x)
4406		   (decorator proc i)
4407		   (loop (fx- i 1)) ) ) ) ) ) ) )
4408
4409(define (##sys#lambda-decoration proc pred)
4410  (let loop ((i (fx- (##sys#size proc) 1)))
4411    (and (fx> i 0)
4412	 (let ((x (##sys#slot proc i)))
4413	   (if (pred x)
4414	       x
4415	       (loop (fx- i 1)) ) ) ) ) )
4416
4417
4418;;; Create lambda-info object
4419
4420(define (##sys#make-lambda-info str)
4421  (let* ((bv (##sys#slot str 0))
4422         (sz (fx- (##sys#size bv) 1))
4423	 (info (##sys#make-bytevector sz)))
4424    (##core#inline "C_copy_memory" info bv sz)
4425    (##core#inline "C_bytevector_to_lambdainfo" info)
4426    info) )
4427
4428
4429;;; Function debug info:
4430
4431(define (##sys#lambda-info? x)
4432  (and (not (##sys#immediate? x)) (##core#inline "C_lambdainfop" x)))
4433
4434(define (##sys#lambda-info proc)
4435  (##sys#lambda-decoration proc ##sys#lambda-info?))
4436
4437(define (##sys#lambda-info->string info)
4438  (let* ((sz (##sys#size info))
4439	 (bv (##sys#make-bytevector (fx+ sz 1))) )
4440    (##core#inline "C_copy_memory" bv info sz)
4441    (##core#inline_allocate ("C_a_ustring" 5) bv
4442                            (##core#inline "C_utf_length" bv))))
4443
4444(set! chicken.base#procedure-information
4445  (lambda (x)
4446    (##sys#check-closure x 'procedure-information)
4447    (and-let* ((info (##sys#lambda-info x)))
4448      (##sys#read (scheme#open-input-string (##sys#lambda-info->string info)) #f) ) ) )
4449
4450
4451;;; SRFI-17
4452
4453(define setter-tag (vector 'setter))
4454
4455(define-inline (setter? x)
4456  (and (pair? x) (eq? setter-tag (##sys#slot x 0))) )
4457
4458(set! chicken.base#setter
4459  (##sys#decorate-lambda
4460   (lambda (proc)
4461     (or (and-let* (((procedure? proc))
4462		    (d (##sys#lambda-decoration proc setter?)) )
4463	   (##sys#slot d 1) )
4464	 (##sys#error 'setter "no setter defined" proc) ) )
4465   setter?
4466   (lambda (proc i)
4467     (##sys#setslot
4468      proc i
4469      (cons
4470       setter-tag
4471       (lambda (get set)
4472	 (if (procedure? get)
4473	     (let ((get2 (##sys#decorate-lambda
4474			  get
4475			  setter?
4476			  (lambda (proc i) (##sys#setslot proc i (cons setter-tag set)) proc))))
4477	       (if (eq? get get2)
4478		   get
4479		   (##sys#become! (list (cons get get2))) ) )
4480	     (error "can not set setter of non-procedure" get) ) ) ) )
4481     proc) ) )
4482
4483(define ##sys#setter setter)
4484
4485(set! chicken.base#getter-with-setter
4486  (lambda (get set #!optional info)
4487    (##sys#check-closure get 'getter-with-setter)
4488    (##sys#check-closure set 'getter-with-setter)
4489    (let ((getdec (cond (info
4490			 (##sys#check-string info 'getter-with-setter)
4491			 (##sys#make-lambda-info info))
4492			(else (##sys#lambda-info get))))
4493	  (p1 (##sys#decorate-lambda
4494	       (##sys#copy-closure get)
4495	       setter?
4496	       (lambda (proc i)
4497		 (##sys#setslot proc i (cons setter-tag set))
4498		 proc))))
4499      (if getdec
4500	  (##sys#decorate-lambda
4501	   p1
4502	   ##sys#lambda-info?
4503	   (lambda (p i)
4504	     (##sys#setslot p i getdec)
4505	     p))
4506	  p1))))
4507
4508(set! scheme#car (getter-with-setter scheme#car set-car!))
4509(set! scheme#cdr (getter-with-setter scheme#cdr set-cdr!))
4510(set! scheme#caar (getter-with-setter scheme#caar (lambda (x y) (set-car! (car x) y))))
4511(set! scheme#cadr (getter-with-setter scheme#cadr (lambda (x y) (set-car! (cdr x) y))))
4512(set! scheme#cdar (getter-with-setter scheme#cdar (lambda (x y) (set-cdr! (car x) y))))
4513(set! scheme#cddr (getter-with-setter scheme#cddr (lambda (x y) (set-cdr! (cdr x) y))))
4514(set! scheme#caaar (getter-with-setter scheme#caaar (lambda (x y) (set-car! (caar x) y))))
4515(set! scheme#caadr (getter-with-setter scheme#caadr (lambda (x y) (set-car! (cadr x) y))))
4516(set! scheme#cadar (getter-with-setter scheme#cadar (lambda (x y) (set-car! (cdar x) y))))
4517(set! scheme#caddr (getter-with-setter scheme#caddr (lambda (x y) (set-car! (cddr x) y))))
4518(set! scheme#cdaar (getter-with-setter scheme#cdaar (lambda (x y) (set-cdr! (caar x) y))))
4519(set! scheme#cdadr (getter-with-setter scheme#cdadr (lambda (x y) (set-cdr! (cadr x) y))))
4520(set! scheme#cddar (getter-with-setter scheme#cddar (lambda (x y) (set-cdr! (cdar x) y))))
4521(set! scheme#cdddr (getter-with-setter scheme#cdddr (lambda (x y) (set-cdr! (cddr x) y))))
4522(set! scheme#string-ref (getter-with-setter scheme#string-ref string-set!))
4523(set! scheme#vector-ref (getter-with-setter scheme#vector-ref vector-set!))
4524
4525(set! scheme#list-ref
4526  (getter-with-setter
4527   scheme#list-ref
4528   (lambda (x i y) (set-car! (list-tail x i) y))))
4529
4530(set! chicken.bytevector#bytevector-u8-ref
4531  (getter-with-setter chicken.bytevector#bytevector-u8-ref
4532                      chicken.bytevector#bytevector-u8-set!
4533                      "(chicken.bytevector#bytevector-u8-ref v i)"))
4534
4535
4536;;; Parameters:
4537
4538(define ##sys#default-parameter-vector (##sys#make-vector default-parameter-vector-size))
4539(define ##sys#current-parameter-vector '#())
4540
4541(set! scheme#make-parameter
4542  (let ((count 0))
4543    (lambda (init #!optional (guard (lambda (x) x)))
4544      (let* ((val (guard init))
4545	     (i count)
4546	     (assign (lambda (val n convert? set?)
4547		       (when (fx>= i n)
4548			 (set! ##sys#current-parameter-vector
4549			   (##sys#vector-resize
4550			    ##sys#current-parameter-vector
4551			    (fx+ i 1)
4552			    ##sys#snafu) ) )
4553		       (let ((val (if convert? (guard val) val)))
4554			 (when set?
4555			   (##sys#setslot ##sys#current-parameter-vector i val))
4556			 val))))
4557
4558	(set! count (fx+ count 1))
4559	(when (fx>= i (##sys#size ##sys#default-parameter-vector))
4560	  (set! ##sys#default-parameter-vector
4561	    (##sys#vector-resize
4562	     ##sys#default-parameter-vector
4563	     (fx+ i 1)
4564	     (##core#undefined)) ) )
4565	(##sys#setslot ##sys#default-parameter-vector i val)
4566	(getter-with-setter
4567	 (lambda args
4568	   (let ((n (##sys#size ##sys#current-parameter-vector)))
4569	     (cond ((pair? args)
4570		    (let-optionals (cdr args) ((convert? #t)
4571					       (set? #t))
4572		      (assign (car args) n convert? set?)))
4573		   ((fx>= i n)
4574		    (##sys#slot ##sys#default-parameter-vector i) )
4575		   (else
4576		    (let ((val (##sys#slot ##sys#current-parameter-vector i)))
4577		      (if (eq? val ##sys#snafu)
4578			  (##sys#slot ##sys#default-parameter-vector i)
4579			  val) ) ) ) ) )
4580	 (lambda (val)
4581	   (let ((n (##sys#size ##sys#current-parameter-vector)))
4582	     (assign val n #f #t))))))))
4583
4584
4585;;; Input:
4586
4587(set! scheme#char-ready?
4588  (lambda (#!optional (port ##sys#standard-input))
4589    (##sys#check-input-port port #t 'char-ready?)
4590    ((##sys#slot (##sys#slot port 2) 6) port) )) ; char-ready?
4591    
4592(set! scheme#u8-ready? 
4593  (lambda (#!optional (port ##sys#standard-input))
4594    (##sys#check-input-port port #t 'u8-ready?)
4595    ((##sys#slot (##sys#slot port 2) 6) port) )) ; char-ready?
4596
4597(set! scheme#read-char
4598  (lambda (#!optional (port ##sys#standard-input))
4599    (##sys#check-input-port port #t 'read-char)
4600    (##sys#read-char-0 port) ))
4601
4602(define (##sys#read-char-0 p)
4603  (let ([c (if (##sys#slot p 6)
4604	       (begin
4605		 (##sys#setislot p 6 #f)
4606		 #!eof)
4607	       ((##sys#slot (##sys#slot p 2) 0) p) ) ] ) ; read-char
4608    (cond [(eq? c #\newline)
4609	   (##sys#setislot p 4 (fx+ (##sys#slot p 4) 1))
4610	   (##sys#setislot p 5 0) ]
4611	  [(not (##core#inline "C_eofp" c))
4612	   (##sys#setislot p 5 (fx+ (##sys#slot p 5) 1)) ] )
4613    c) )
4614
4615(define (##sys#read-char/port port)
4616  (##sys#check-input-port port #t 'read-char)
4617  (##sys#read-char-0 port) )
4618
4619(define (##sys#peek-char-0 p)
4620  (if (##sys#slot p 6)
4621      #!eof
4622      (let ((c ((##sys#slot (##sys#slot p 2) 1) p))) ; peek-char
4623	(when (##core#inline "C_eofp" c)
4624	  (##sys#setislot p 6 #t) )
4625	c) ) )
4626
4627(set! scheme#peek-char
4628  (lambda (#!optional (port ##sys#standard-input))
4629    (##sys#check-input-port port #t 'peek-char)
4630    (##sys#peek-char-0 port) ))
4631
4632(set! scheme#read
4633  (lambda (#!optional (port ##sys#standard-input))
4634    (##sys#check-input-port port #t 'read)
4635    (##sys#read port ##sys#default-read-info-hook) ))
4636
4637(define ##sys#default-read-info-hook #f)
4638(define ##sys#read-error-with-line-number #f)
4639(define (##sys#read-prompt-hook) #f)	; just here so that srfi-18 works without eval
4640(define (##sys#infix-list-hook lst) lst)
4641
4642(set! ##sys#default-file-encoding (make-parameter 'utf-8))
4643
4644(define (##sys#sharp-number-hook port n)
4645  (##sys#read-error port "invalid `#...' read syntax" n) )
4646
4647(set! chicken.base#case-sensitive (make-parameter #t))
4648(set! chicken.base#parentheses-synonyms (make-parameter #t))
4649(set! chicken.base#symbol-escape (make-parameter #t))
4650
4651(set! chicken.base#keyword-style
4652  (make-parameter #:suffix (lambda (x) (when x (##sys#check-keyword x 'keyword-style)) x)))
4653
4654(define ##sys#current-read-table (make-parameter (##sys#make-structure 'read-table '() '() '())))
4655
4656(define ##sys#read-warning
4657  (let ([string-append string-append])
4658    (lambda (port msg . args)
4659      (apply
4660       ##sys#warn
4661       (let ((ln (##sys#port-line port)))
4662	 (if (and ##sys#read-error-with-line-number ln)
4663	     (string-append "(line " (##sys#number->string ln) ") " msg)
4664	     msg) )
4665       args) ) ) )
4666
4667(define ##sys#read-error
4668  (let ([string-append string-append] )
4669    (lambda (port msg . args)
4670      (apply
4671       ##sys#signal-hook
4672       #:syntax-error
4673       (let ((ln (##sys#port-line port)))
4674	 (if (and ##sys#read-error-with-line-number ln)
4675	     (string-append "(line " (##sys#number->string ln) ") " msg)
4676	     msg) )
4677       args) ) ) )
4678
4679(define ##sys#read
4680  (let ((string-append string-append)
4681	(keyword-style keyword-style)
4682	(parentheses-synonyms parentheses-synonyms)
4683        (case-sensitive case-sensitive)
4684	(symbol-escape symbol-escape)
4685        (integer->char integer->char)
4686	(current-read-table ##sys#current-read-table))
4687    (lambda (port infohandler)
4688      (let ((csp (and (case-sensitive) (##sys#slot port 13)))
4689	    (ksp (keyword-style))
4690	    (psp (parentheses-synonyms))
4691	    (sep (symbol-escape))
4692	    (crt (current-read-table))
4693	    (warn #f)
4694            (shared '())
4695	    ; set below - needs more state to make a decision
4696	    (terminating-characters '(#\, #\; #\( #\) #\' #\" #\[ #\] #\{ #\}))
4697	    (reserved-characters #f) )
4698
4699	(define (container c)
4700	  (##sys#read-error port "unexpected list terminator" c) )
4701
4702	(define (info class data val)
4703	  (if infohandler
4704	      (infohandler class data val)
4705	      data) )
4706
4707	(define (skip-to-eol)
4708	  (let skip ((c (##sys#read-char-0 port)))
4709	    (if (and (not (##core#inline "C_eofp" c)) (not (eq? #\newline c)))
4710		(skip (##sys#read-char-0 port)) ) ) )
4711
4712        (define (reserved-character c)
4713          (##sys#read-char-0 port)
4714          (##sys#read-error port "reserved character" c) )
4715
4716        (define (read-unreserved-char-0 port)
4717          (let ((c (##sys#read-char-0 port)))
4718            (if (memq c reserved-characters)
4719                (reserved-character c)
4720                c) ) )
4721
4722        (define (register-shared! n thunk)
4723          (set! shared (cons (cons n thunk) shared)))
4724
4725        (define (unthunk o fail)
4726          (let ((v (o)))
4727            (cond ((not (procedure? v)) v)
4728                  ((eq? v o)
4729                   (fail "self-referential datum"))
4730                  (else
4731                    (unthunk v fail)))))
4732
4733        ;; Fills holes in `o` destructively.
4734        (define (unthunkify! o fail)
4735          (let loop! ((o o))
4736            (cond ((pair? o)
4737                   (if (not (procedure? (car o)))
4738                       (loop! (car o))
4739                       (set-car! o (unthunk (car o) fail)))
4740                   (if (not (procedure? (cdr o)))
4741                       (loop! (cdr o))
4742                       (set-cdr! o (unthunk (cdr o) fail))))
4743                  ((vector? o)
4744                   (let ((len (##sys#size o)))
4745                     (do ((i 0 (fx+ i 1)))
4746                         ((eq? i len))
4747                         (let ((v (##sys#slot o i)))
4748                           (if (not (procedure? v))
4749                               (loop! v)
4750                               (##sys#setslot o i (unthunk v fail))))))))))
4751
4752	(define (readrec)
4753
4754	  (define (r-spaces)
4755	    (let loop ([c (##sys#peek-char-0 port)])
4756	      (cond ((##core#inline "C_eofp" c))
4757		    ((eq? #\; c)
4758		     (skip-to-eol)
4759		     (loop (##sys#peek-char-0 port)) )
4760		    ((char-whitespace? c)
4761		     (##sys#read-char-0 port)
4762		     (loop (##sys#peek-char-0 port)) ) ) ) )
4763
4764	  (define (r-usequence u n base)
4765	    (let loop ((seq '()) (n n))
4766	      (if (eq? n 0)
4767		  (let* ((str (##sys#reverse-list->string seq))
4768			 (n (string->number str base)))
4769		    (or n
4770			(##sys#read-error
4771			 port
4772			 (string-append
4773			  "invalid escape-sequence '\\" u str "\'")) ) )
4774		  (let ((x (##sys#read-char-0 port)))
4775		    (if (or (eof-object? x) (char=? #\" x))
4776			(##sys#read-error port "unterminated string constant")
4777			(loop (cons x seq) (fx- n 1)) ) ) ) ) )
4778
4779          (define (r-xsequence delim)
4780            (define (parse seq)
4781              (let* ((str (##sys#reverse-list->string seq))
4782                     (n (string->number str 16)))
4783                (or n
4784                    (##sys#read-error port
4785                     (string-append "invalid escape-sequence '\\x"
4786                                    str ";\'")))))
4787            (define (complain)
4788              (set! warn "unterminated hexadecimal escape sequence"))
4789            (define (abort)
4790              (##sys#read-error port "unterminated hexadecimal escape sequence") )
4791            (let loop ((seq '()))
4792              (let ((x (##sys#peek-char-0 port)))
4793                (cond ((eof-object? x) (abort))
4794                      ((eq? delim x)
4795                       (let ((n (parse seq)))
4796                         (if (fx> n #x1ffff)
4797                             (abort)
4798                             (begin (complain) n))))
4799                      ((eq? #\; x)
4800                       (##sys#read-char-0 port)
4801		       (parse seq))
4802                      ((or (and (char>=? x #\0) (char<=? x #\9))
4803                           (and (char>=? x #\a) (char<=? x #\f))
4804                           (and (char>=? x #\A) (char<=? x #\F)))
4805                       (loop (cons (##sys#read-char-0 port) seq)))
4806                      (else
4807                        (let ((n (parse seq)))
4808                          (if (fx> n #x1ffff)
4809                              (abort)
4810                              (begin (complain) n))))))))
4811
4812	  (define (r-string term)
4813	    (let loop ((c (##sys#read-char-0 port)) (lst '()))
4814	      (cond ((##core#inline "C_eofp" c)
4815		     (##sys#read-error port "unterminated string") )
4816		    ((eq? #\\ c)
4817		     (set! c (##sys#read-char-0 port))
4818		     (case c
4819		       ((#\t) (loop (##sys#read-char-0 port) (cons #\tab lst)))
4820		       ((#\r) (loop (##sys#read-char-0 port) (cons #\return lst)))
4821		       ((#\b) (loop (##sys#read-char-0 port) (cons #\backspace lst)))
4822		       ((#\n) (loop (##sys#read-char-0 port) (cons #\newline lst)))
4823		       ((#\a) (loop (##sys#read-char-0 port) (cons (integer->char 7) lst)))
4824		       ((#\v) (loop (##sys#read-char-0 port) (cons (integer->char 11) lst)))
4825		       ((#\f) (loop (##sys#read-char-0 port) (cons (integer->char 12) lst)))
4826		       ((#\x)
4827			(let ((ch (integer->char (r-xsequence term))))
4828			  (loop (##sys#read-char-0 port) (cons ch lst)) ) )
4829		       ((#\u)
4830			(let ((n (r-usequence "u" 4 16)))
4831                           (loop (##sys#read-char-0 port)
4832                                 (cons (integer->char n) lst)) ) )
4833		       ((#\U)
4834			(let ((n (r-usequence "U" 8 16)))
4835                           (loop (##sys#read-char-0 port)
4836                                 (cons (integer->char n) lst)) ))
4837		       ((#\\ #\' #\" #\|)
4838			(loop (##sys#read-char-0 port) (cons c lst)))
4839		       ((#\newline #\return #\space #\tab)
4840			;; Read "escaped" <intraline ws>* <nl> <intraline ws>*
4841			(let eat-ws ((c c) (nl? #f))
4842			  (case c
4843			    ((#\space #\tab)
4844			     (eat-ws (##sys#read-char-0 port) nl?))
4845			    ((#\return)
4846			     (if nl?
4847				 (loop c lst)
4848			         (let ((nc (##sys#read-char-0 port)))
4849			           (if (eq? nc #\newline) ; collapse \r\n
4850				       (eat-ws (##sys#read-char-0 port) #t)
4851				       (eat-ws nc #t)))))
4852			    ((#\newline)
4853			     (if nl?
4854				 (loop c lst)
4855				 (eat-ws (##sys#read-char-0 port) #t)))
4856			    (else
4857                             (unless nl?
4858                               (##sys#read-warning
4859				port
4860				"escaped whitespace, but no newline - collapsing anyway"))
4861                             (loop c lst)))))
4862		       (else
4863			(cond ((##core#inline "C_eofp" c)
4864			       (##sys#read-error port "unterminated string"))
4865			      ((and (char-numeric? c)
4866				    (char>=? c #\0)
4867				    (char<=? c #\7))
4868			       (let ((ch (integer->char
4869					  (fx+ (fx* (fx- (char->integer c) 48) 64)
4870					       (r-usequence "" 2 8)))))
4871				 (loop (##sys#read-char-0 port) (cons ch lst)) ))
4872			      (else
4873			       (##sys#read-warning
4874				port
4875				"undefined escape sequence in string - probably forgot backslash"
4876				c)
4877			       (loop (##sys#read-char-0 port) (cons c lst))) ) )))
4878		    ((eq? term c) (##sys#reverse-list->string lst))
4879		    (else (loop (##sys#read-char-0 port) (cons c lst))) ) ))
4880
4881	  (define (r-list start end)
4882	    (if (eq? (##sys#read-char-0 port) start)
4883		(let ((first #f)
4884		      (ln0 #f)
4885		      (outer-container container) )
4886		  (define (starting-line msg)
4887		    (if (and ln0 ##sys#read-error-with-line-number)
4888			(string-append
4889			 msg ", starting in line "
4890			 (##sys#number->string ln0))
4891			msg))
4892		  (##sys#call-with-current-continuation
4893		   (lambda (return)
4894		     (set! container
4895		       (lambda (c)
4896			 (if (eq? c end)
4897			     (return #f)
4898			     (##sys#read-error
4899			      port
4900			      (starting-line "list-terminator mismatch")
4901			      c end) ) ) )
4902		     (let loop ([last '()])
4903		       (r-spaces)
4904		       (unless first (set! ln0 (##sys#port-line port)))
4905		       (let ([c (##sys#peek-char-0 port)])
4906			 (cond ((##core#inline "C_eofp" c)
4907				(##sys#read-error
4908				 port
4909				 (starting-line "unterminated list") ) )
4910			       ((eq? c end)
4911				(##sys#read-char-0 port) )
4912			       ((eq? c #\.)
4913				(##sys#read-char-0 port)
4914				(let ((c2 (##sys#peek-char-0 port)))
4915				  (cond ((or (char-whitespace? c2)
4916					     (eq? c2 #\()
4917					     (eq? c2 #\))
4918					     (eq? c2 #\")
4919					     (eq? c2 #\;) )
4920					 (unless (pair? last)
4921					   (##sys#read-error port "invalid use of `.'") )
4922					 (r-spaces)
4923					 (##sys#setslot last 1 (readrec))
4924					 (r-spaces)
4925					 (unless (eq? (##sys#read-char-0 port) end)
4926					   (##sys#read-error
4927					    port
4928					    (starting-line "missing list terminator")
4929					    end)))
4930					(else
4931					 (r-xtoken
4932					  (lambda (tok kw)
4933					    (let* ((tok (##sys#string-append "." tok))
4934						   (val
4935						    (cond ((and (string=? tok ".:")
4936								(eq? ksp #:suffix))
4937							   ;; Edge case: r-xtoken sees
4938							   ;; a bare ":" and sets kw to #f
4939							   (build-keyword "."))
4940							  (kw (build-keyword tok))
4941							  ((and (char-numeric? c2)
4942								(##sys#string->number tok)))
4943							  (else (build-symbol tok))))
4944						   (node (cons val '())))
4945					      (if first
4946						  (##sys#setslot last 1 node)
4947						  (set! first node) )
4948					      (loop node))))))))
4949			       (else
4950				(let ([node (cons (readrec) '())])
4951				  (if first
4952				      (##sys#setslot last 1 node)
4953				      (set! first node) )
4954				  (loop node) ) ) ) ) ) ) )
4955		  (set! container outer-container)
4956		  (if first
4957		      (info 'list-info (##sys#infix-list-hook first) ln0)
4958		      '() ) )
4959		(##sys#read-error port "missing token" start) ) )
4960
4961	  (define (r-vector)
4962	    (let ((lst (r-list #\( #\))))
4963	      (if (list? lst)
4964		  (##sys#list->vector lst)
4965		  (##sys#read-error port "invalid vector syntax" lst) ) ) )
4966
4967	  (define (r-number radix exactness)
4968	    (r-xtoken
4969	     (lambda (tok kw)
4970	       (cond (kw
4971		      (let ((s (build-keyword tok)))
4972			(info 'symbol-info s (##sys#port-line port)) ))
4973		     ((string=? tok ".")
4974		      (##sys#read-error port "invalid use of `.'"))
4975		     ((and (fx> (string-length tok) 0) (char=? (string-ref tok 0) #\#))
4976		      (##sys#read-error port "unexpected prefix in number syntax" tok))
4977		     ((##sys#string->number tok (or radix 10) exactness))
4978		     (radix (##sys#read-error port "illegal number syntax" tok))
4979		     (else (build-symbol tok))  ) ) ))
4980
4981	  (define (r-number-with-exactness radix)
4982	    (cond [(eq? #\# (##sys#peek-char-0 port))
4983		   (##sys#read-char-0 port)
4984		   (let ([c2 (##sys#read-char-0 port)])
4985		     (cond [(eof-object? c2)
4986			    (##sys#read-error port "unexpected end of numeric literal")]
4987			   [(char=? c2 #\i) (r-number radix 'i)]
4988			   [(char=? c2 #\e) (r-number radix 'e)]
4989			   [else
4990			    (##sys#read-error
4991			     port
4992			     "illegal number syntax - invalid exactness prefix" c2)] ) ) ]
4993		  [else (r-number radix #f)] ) )
4994
4995	  (define (r-number-with-radix exactness)
4996	    (cond [(eq? #\# (##sys#peek-char-0 port))
4997		   (##sys#read-char-0 port)
4998		   (let ([c2 (##sys#read-char-0 port)])
4999		     (cond [(eof-object? c2) (##sys#read-error port "unexpected end of numeric literal")]
5000			   [(char=? c2 #\x) (r-number 16 exactness)]
5001			   [(char=? c2 #\d) (r-number 10 exactness)]
5002			   [(char=? c2 #\o) (r-number 8 exactness)]
5003			   [(char=? c2 #\b) (r-number 2 exactness)]
5004			   [else (##sys#read-error port "illegal number syntax - invalid radix" c2)] ) ) ]
5005		  [else (r-number 10 exactness)] ) )
5006
5007	  (define (r-token)
5008	    (let loop ((c (##sys#peek-char-0 port)) (lst '()))
5009	      (cond ((or (eof-object? c)
5010			 (char-whitespace? c)
5011			 (memq c terminating-characters) )
5012		     (##sys#reverse-list->string lst) )
5013		    ((char=? c #\x00)
5014		     (##sys#read-error port "attempt to read expression from something that looks like binary data"))
5015		    (else
5016		     (read-unreserved-char-0 port)
5017		     (loop (##sys#peek-char-0 port)
5018		           (cons (if csp 
5019		                     c 
5020		                     (##core#inline "C_utf_char_foldcase" c) )
5021		                 lst) ) ) ) ) )
5022
5023	  (define (r-digits)
5024	    (let loop ((c (##sys#peek-char-0 port)) (lst '()))
5025	      (cond ((or (eof-object? c) (not (char-numeric? c)))
5026		     (##sys#reverse-list->string lst) )
5027		    (else
5028		     (##sys#read-char-0 port)
5029		     (loop (##sys#peek-char-0 port) (cons c lst)) ) ) ) )
5030
5031	  (define (r-symbol)
5032	    (r-xtoken
5033	     (lambda (str kw)
5034	       (let ((s (if kw (build-keyword str) (build-symbol str))))
5035		 (info 'symbol-info s (##sys#port-line port)) ) )))
5036
5037	  (define (r-xtoken k)
5038	    (define pkw ; check for prefix keyword immediately
5039	      (and (eq? ksp #:prefix)
5040		   (eq? #\: (##sys#peek-char-0 port))
5041		   (begin (##sys#read-char-0 port) #t)))
5042	    (let loop ((lst '()) (skw #f) (qtd #f))
5043	      (let ((c (##sys#peek-char-0 port)))
5044		(cond ((or (eof-object? c)
5045			   (char-whitespace? c)
5046			   (memq c terminating-characters))
5047		       ;; The various cases here cover:
5048		       ;; - Nonempty keywords formed with colon in the ksp position
5049		       ;; - Empty keywords formed explicitly with vbar quotes
5050		       ;; - Bare colon, which should always be a symbol
5051		       (cond ((and skw (eq? ksp #:suffix) (or qtd (not (null? (cdr lst)))))
5052			      (k (##sys#reverse-list->string (cdr lst)) #t))
5053			     ((and pkw (or qtd (not (null? lst))))
5054			      (k (##sys#reverse-list->string lst) #t))
5055			     ((and pkw (not qtd) (null? lst))
5056			      (k ":" #f))
5057			     (else
5058			      (k (##sys#reverse-list->string lst) #f))))
5059		      ((memq c reserved-characters)
5060		       (reserved-character c))
5061		      (else
5062		       (let ((c (##sys#read-char-0 port)))
5063			 (case c
5064			   ((#\|)
5065			    (let ((part (r-string #\|)))
5066			      (loop (append (##sys#fast-reverse (##sys#string->list part)) lst)
5067				    #f #t)))
5068			   ((#\newline)
5069			    (##sys#read-warning
5070			     port "escaped symbol syntax spans multiple lines"
5071			     (##sys#reverse-list->string lst))
5072			    (loop (cons #\newline lst) #f qtd))
5073			   ((#\:)
5074			    (loop (cons #\: lst) #t qtd))
5075			   ((#\\)
5076			    (let ((c (##sys#read-char-0 port)))
5077			      (if (eof-object? c)
5078				  (##sys#read-error
5079				   port
5080				   "unexpected end of file while reading escaped character")
5081				  (loop (cons c lst) #f qtd))))
5082			   (else
5083			    (loop
5084			     (cons (if csp 
5085			               c 
5086			               (##core#inline "C_utf_char_foldcase" c))
5087			           lst)
5088			     #f qtd)))))))))
5089
5090	  (define (r-char)
5091	    ;; Code contributed by Alex Shinn
5092	    (let* ([c (##sys#peek-char-0 port)]
5093		   [tk (r-token)]
5094		   [len (string-length tk)])
5095	      (cond [(fx> len 1)
5096		     (cond [(and (or (char=? #\x c) (char=? #\u c) (char=? #\U c))
5097				 (##sys#string->number (##sys#substring tk 1 len) 16) )
5098			    => (lambda (n) (integer->char n)) ]
5099			   [(and-let* ((c0 (char->integer (string-ref tk 0)))
5100				       ((fx<= #xC0 c0)) ((fx<= c0 #xF7))
5101				       (n0 (fxand (fxshr c0 4) 3))
5102				       (n (fx+ 2 (fxand (fxior n0 (fxshr n0 1)) (fx- n0 1))))
5103				       ((fx= len n))
5104				       (res (fx+ (fxshl (fxand c0 (fx- (fxshl 1 (fx- 8 n)) 1))
5105							6)
5106						 (fxand (char->integer
5107							 (string-ref tk 1))
5108							#b111111))))
5109			      (cond ((fx>= n 3)
5110				     (set! res (fx+ (fxshl res 6)
5111						    (fxand
5112						     (char->integer
5113						      (string-ref tk 2))
5114						     #b111111)))
5115				     (if (fx= n 4)
5116					 (set! res (fx+ (fxshl res 6)
5117							(fxand (char->integer
5118								(string-ref tk 3))
5119							       #b111111))))))
5120			      (integer->char res))]
5121			   [(char-name (##sys#string->symbol tk))]
5122			   [else (##sys#read-error port "unknown named character" tk)] ) ]
5123		    [(memq c terminating-characters) (##sys#read-char-0 port)]
5124		    [else c] ) ) )
5125
5126	  (define (r-comment)
5127	    (let loop ((i 0))
5128	      (let ((c (##sys#read-char-0 port)))
5129		(case c
5130		  ((#\|) (if (eq? #\# (##sys#read-char-0 port))
5131			     (if (not (eq? i 0))
5132				 (loop (fx- i 1)) )
5133			     (loop i) ) )
5134		  ((#\#) (loop (if (eq? #\| (##sys#read-char-0 port))
5135				   (fx+ i 1)
5136				   i) ) )
5137		  (else (if (eof-object? c)
5138			    (##sys#read-error port "unterminated block-comment")
5139			    (loop i) ) ) ) ) ) )
5140
5141	  (define (r-ext-symbol)
5142	    (let ((tok (r-token)))
5143	      (build-symbol (string-append "##" tok))))
5144
5145	  (define (r-quote q)
5146	    (let ((ln (##sys#port-line port)))
5147	      (info 'list-info (list q (readrec)) ln)))
5148
5149	  (define (build-symbol tok)
5150	    (##sys#string->symbol tok) )
5151
5152	  (define (build-keyword tok)
5153	    (##sys#intern-keyword (##sys#string->symbol-name tok)))
5154
5155          ;; now have the state to make a decision.
5156          (set! reserved-characters
5157                (append (if (not psp) '(#\[ #\] #\{ #\}) '())
5158                        (if (not sep) '(#\|) '())))
5159	  (r-spaces)
5160	  (let* ((c (##sys#peek-char-0 port))
5161		 (srst (##sys#slot crt 1))
5162		 (h (and (not (eof-object? c))
5163			 (assq c srst))))
5164	    (if (and h (##sys#slot h 1))
5165                ;; then handled by read-table entry
5166		(##sys#call-with-values
5167		 (lambda () ((##sys#slot h 1) c port))
5168		 (lambda xs (if (null? xs) (readrec) (car xs))))
5169		;; otherwise chicken extended r5rs syntax
5170		(case c
5171		  ((#\')
5172		   (##sys#read-char-0 port)
5173		   (r-quote 'quote))
5174		  ((#\`)
5175		   (##sys#read-char-0 port)
5176		   (r-quote 'quasiquote))
5177		  ((#\,)
5178		   (##sys#read-char-0 port)
5179		   (cond ((eq? (##sys#peek-char-0 port) #\@)
5180			  (##sys#read-char-0 port)
5181			  (r-quote 'unquote-splicing))
5182			 (else (r-quote 'unquote))))
5183		  ((#\#)
5184		   (##sys#read-char-0 port)
5185		   (let ((dchar (##sys#peek-char-0 port)))
5186		     (cond
5187		      ((eof-object? dchar)
5188		       (##sys#read-error
5189			port "unexpected end of input after reading #-sign"))
5190		      ((char-numeric? dchar)
5191		       (let* ((n (string->number (r-digits)))
5192			      (dchar2 (##sys#peek-char-0 port))
5193			      (spdrst (##sys#slot crt 3)))
5194			 (cond ((eof-object? dchar2)
5195                                (##sys#read-error
5196                                 port "unexpected end of input after reading"
5197                                 c n))
5198                               ;; #<num>=...
5199                               ((eq? #\= dchar2)
5200                                (##sys#read-char-0 port)
5201                                (letrec ((datum (begin
5202                                                  (register-shared! n (lambda () datum))
5203                                                  (readrec))))
5204                                  datum))
5205                               ;; #<num>#
5206                               ((eq? #\# dchar2)
5207                                (##sys#read-char-0 port)
5208                                (cond ((assq n shared) => cdr)
5209                                      (else (##sys#read-error port "undefined datum" n))))
5210                           			 ;; #<num> handled by parameterized # read-table entry?
5211                               ((and (char? dchar2)
5212                                     (let ((a (assq dchar2 spdrst)))
5213                                       (and a (##sys#slot a 1) a))) =>
5214                                (lambda (h)
5215                                  (##sys#call-with-values
5216                                    (lambda () ((##sys#slot h 1) dchar2 port n))
5217                                    (lambda xs (if (null? xs) (readrec) (car xs))))))
5218                               ;; #<num>
5219			       ((or (eq? dchar2 #\)) (char-whitespace? dchar2))
5220				(##sys#sharp-number-hook port n))
5221			       (else (##sys#read-char-0 port) ; Consume it first
5222				     (##sys#read-error
5223				      port
5224				      "invalid parameterized read syntax"
5225				      c n dchar2) ) ) ))
5226		      (else (let* ((sdrst (##sys#slot crt 2))
5227				   (h (assq dchar sdrst)))
5228			      (if (and h (##sys#slot h 1))
5229                                  ;; then handled by # read-table entry
5230				  (##sys#call-with-values
5231				   (lambda () ((##sys#slot h 1) dchar port))
5232				   (lambda xs (if (null? xs) (readrec) (car xs))))
5233                                  ;; otherwise chicken extended R7RS syntax
5234				  (case (char-downcase dchar)
5235				    ((#\x) (##sys#read-char-0 port) (r-number-with-exactness 16))
5236				    ((#\d) (##sys#read-char-0 port) (r-number-with-exactness 10))
5237				    ((#\o) (##sys#read-char-0 port) (r-number-with-exactness 8))
5238				    ((#\b) (##sys#read-char-0 port) (r-number-with-exactness 2))
5239				    ((#\i) (##sys#read-char-0 port) (r-number-with-radix 'i))
5240				    ((#\e) (##sys#read-char-0 port) (r-number-with-radix 'e))
5241				    ((#\() (r-vector))
5242				    ((#\\) (##sys#read-char-0 port) (r-char))
5243				    ((#\|)
5244				     (##sys#read-char-0 port)
5245				     (r-comment) (readrec) )
5246				    ((#\#)
5247				     (##sys#read-char-0 port)
5248				     (r-ext-symbol) )
5249				    ((#\;)
5250				     (##sys#read-char-0 port)
5251				     (readrec) (readrec) )
5252				    ((#\`)
5253				     (##sys#read-char-0 port)
5254				     (r-quote 'quasisyntax))
5255				    ((#\$)
5256				     (##sys#read-char-0 port)
5257                                     ;; HACK: reuse r-quote to add line number info
5258				     (r-quote 'location))
5259				    ((#\:)
5260				     (##sys#read-char-0 port)
5261				     (let ((c (##sys#peek-char-0 port)))
5262				       (fluid-let ((ksp #f))
5263					 (r-xtoken
5264					  (lambda (str kw)
5265					    (if (and (eq? 0 (string-length str))
5266						     (not (char=? c #\|)))
5267						(##sys#read-error port "empty keyword")
5268						(build-keyword str)))))))
5269				    ((#\+)
5270				     (##sys#read-char-0 port)
5271				     (let* ((ln (##sys#port-line port))
5272					    (tst (readrec)))
5273				       (info 'list-info
5274					     (list 'cond-expand (list tst (readrec)) '(else))
5275					     ln)))
5276				    ((#\!)
5277				     (##sys#read-char-0 port)
5278				     (let ((c (##sys#peek-char-0 port)))
5279				       (cond ((and (char? c)
5280						   (or (char-whitespace? c) (char=? #\/ c)))
5281					      (skip-to-eol)
5282					      (readrec) )
5283					     (else
5284					      (let ([tok (r-token)])
5285						(cond ((string=? "eof" tok) #!eof)
5286						      ((string=? "bwp" tok) #!bwp)
5287                                                      ((string=? "fold-case" tok)
5288                                                       (set! csp #f)
5289                                                       (##sys#setislot port 13 csp)
5290                                                       (readrec))
5291                                                      ((string=? "no-fold-case" tok)
5292                                                       (set! csp #t)
5293                                                       (##sys#setislot port 13 csp)
5294                                                       (readrec))
5295						      ((member tok '("optional" "rest" "key"))
5296						       (build-symbol (##sys#string-append "#!" tok)) )
5297						      (else
5298						       (let ((a (assq (string->symbol tok) ##sys#read-marks)))
5299							 (if a
5300							     ((##sys#slot a 1) port)
5301							     (##sys#read-error
5302							      port
5303							      "invalid `#!' token" tok) ) ) ) ) ) ) ) ) )
5304				    (else
5305				     (##sys#call-with-values (lambda () (##sys#user-read-hook dchar port))
5306							     (lambda xs (if (null? xs) (readrec) (car xs)))) ) ) ) )) ) ) )
5307		  ((#\() (r-list #\( #\)))
5308		  ((#\)) (##sys#read-char-0 port) (container c))
5309		  ((#\") (##sys#read-char-0 port) (r-string #\"))
5310		  ((#\.) (r-number #f #f))
5311		  ((#\- #\+) (r-number #f #f))
5312		  (else
5313		   (cond [(eof-object? c) c]
5314			 [(char-numeric? c) (r-number #f #f)]
5315			 ((memq c reserved-characters)
5316			  (reserved-character c))
5317			 (else
5318			  (case c
5319			    ((#\[) (r-list #\[ #\]))
5320			    ((#\{) (r-list #\{ #\}))
5321			    ((#\] #\}) (##sys#read-char-0 port) (container c))
5322			    (else (r-symbol) ) ) ) ) ) ) ) ) )
5323
5324        (let ((x (readrec)))
5325          (when warn (##sys#read-warning port warn))
5326          (when (pair? shared)
5327            (unthunkify! x (lambda a (apply ##sys#read-error p a))))
5328          x)))))
5329
5330;;; Hooks for user-defined read-syntax:
5331;
5332; - Redefine this to handle new read-syntaxes. If 'char' doesn't match
5333;   your character then call the previous handler.
5334; - Don't forget to read 'char', it's only peeked at this point.
5335
5336(define (##sys#user-read-hook char port)
5337  (define (fail item) (##sys#read-error port "invalid sharp-sign read syntax" item))
5338  (case char
5339    ((#\f #\t #\u)
5340     (let ((sym (##sys#read port ##sys#default-read-info-hook)))
5341       (if (not (symbol? sym))
5342           (fail char)
5343           (case sym
5344             ((t true) #t)
5345             ((f false) #f)
5346             ((u8)
5347              ;; u8vectors, srfi-4 handles this already via read-hook but we reimplement it
5348              ;; here in case srfi-4 is not loaded
5349              (let ((d (##sys#read-numvector-data port)))
5350                (if (or (null? d) (pair? d))
5351                    (##sys#list->bytevector (##sys#canonicalize-number-list! d))
5352                    ;; reuse already created bytevector
5353                    (##core#inline "C_chop_bv" (##sys#slot d 0)))))
5354             (else (fail sym))))))
5355    (else (fail char))))
5356
5357(define (##sys#read-numvector-data port)
5358  (let ((c (##sys#peek-char-0 port)))
5359    (case c
5360      ((#\() (##sys#read port ##sys#default-read-info-hook))
5361      ((#\") (##sys#read port ##sys#default-read-info-hook))
5362      (else (##sys#read-error port "invalid numeric vector syntax" c)))))
5363
5364;; This code is too complicated. We try to avoid mapping over
5365;; a potentially large list and creating lots of garbage in the
5366;; process, therefore the final result list is constructed
5367;; via destructive updates and thus rather inelegant yet avoids
5368;; any re-consing unless elements are non-numeric.
5369(define (##sys#canonicalize-number-list! lst1)
5370  (let loop ((lst lst1) (prev #f))
5371    (if (and (##core#inline "C_blockp" lst)
5372             (##core#inline "C_pairp" lst))
5373        (let retry ((x (##sys#slot lst 0)))
5374          (cond ((char? x) (retry (string x)))
5375                ((string? x)
5376                 (if (zero? (string-length x))
5377                     (loop (##sys#slot lst 1) prev)
5378                     (let loop2 ((ns (string->list x)) (prev prev))
5379                       (let ((n (cons (char->integer (##sys#slot ns 0))
5380                                      (##sys#slot lst 1))))
5381                         (if prev
5382                             (##sys#setslot prev 1 n)
5383                             (set! lst1 n))
5384                         (let ((ns2 (##sys#slot ns 1)))
5385                           (if (null? ns2)
5386                               (loop (##sys#slot lst 1) n)
5387                               (loop2 (##sys#slot ns 1) n)))))))
5388                (else (loop (##sys#slot lst 1) lst))))
5389        (cond (prev (##sys#setslot prev 1 '())
5390                    lst1)
5391              (else '())))))
5392
5393;;; Table for specially-handled read-syntax:
5394;
5395; - entries should be #f or a 256-element vector containing procedures
5396; - each procedure is called with two arguments, a char (peeked) and a
5397;   port, and should return an expression
5398
5399(define ##sys#read-marks '()) ; TODO move to read-syntax module
5400
5401
5402;;; Output:
5403
5404(define (##sys#write-char-0 c p)
5405  ((##sys#slot (##sys#slot p 2) 2) p c)
5406  (##sys#void))
5407
5408(define (##sys#write-char/port c port)
5409  (##sys#check-output-port port #t 'write-char)
5410  (##sys#check-char c 'write-char)
5411  (##sys#write-char-0 c port) )
5412
5413(set! scheme#write-char
5414  (lambda (c #!optional (port ##sys#standard-output))
5415    (##sys#check-char c 'write-char)
5416    (##sys#check-output-port port #t 'write-char)
5417    (##sys#write-char-0 c port) ))
5418
5419(set! scheme#newline
5420  (lambda (#!optional (port ##sys#standard-output))
5421    (##sys#write-char/port #\newline port) ))
5422
5423(set! scheme#write
5424  (lambda (x #!optional (port ##sys#standard-output))
5425    (##sys#check-output-port port #t 'write)
5426    (##sys#print x #t port) ))
5427
5428(set! scheme#display
5429  (lambda (x #!optional (port ##sys#standard-output))
5430    (##sys#check-output-port port #t 'display)
5431    (##sys#print x #f port) ))
5432
5433(define-inline (*print-each lst)
5434  (for-each (cut ##sys#print <> #f ##sys#standard-output) lst) )
5435
5436(set! chicken.base#print
5437  (lambda args
5438    (##sys#check-output-port ##sys#standard-output #t 'print)
5439    (*print-each args)
5440    (##sys#write-char-0 #\newline ##sys#standard-output)
5441    (void)))
5442
5443(set! chicken.base#print*
5444  (lambda args
5445    (##sys#check-output-port ##sys#standard-output #t 'print)
5446    (*print-each args)
5447    (##sys#flush-output ##sys#standard-output)
5448    (void)))
5449
5450(define current-print-length (make-parameter 0))
5451(define ##sys#print-length-limit (make-parameter #f))
5452(define ##sys#print-exit (make-parameter #f))
5453
5454(define ##sys#print
5455  (let ((case-sensitive case-sensitive)
5456        (symbol-escape symbol-escape)
5457	(keyword-style keyword-style))
5458    (lambda (x readable port)
5459      (##sys#check-output-port port #t #f)
5460      (let ((csp (case-sensitive))
5461	    (ksp (keyword-style))
5462            (sep (symbol-escape))
5463	    (length-limit (##sys#print-length-limit))
5464	    (special-characters '(#\( #\) #\, #\[ #\] #\{ #\} #\' #\" #\; #\ #\` #\| #\\)) )
5465
5466	(define (outstr port str)
5467	  (if length-limit
5468	      (let* ((len (string-length str))
5469		     (cpp0 (current-print-length))
5470		     (cpl (fx+ cpp0 len)) )
5471		(if (fx> cpl length-limit)
5472		    (let ((n (fx- length-limit cpp0)))
5473		      (when (fx> n 0) (outstr0 port (##sys#substring str 0 n)))
5474		      (outstr0 port "...")
5475		      ((##sys#print-exit) (##sys#void)))
5476		    (outstr0 port str) )
5477		(current-print-length cpl) )
5478	      (outstr0 port str) ) )
5479
5480	(define (outstr0 port str)
5481          (let ((bv (##sys#slot str 0)))
5482  	    ((##sys#slot (##sys#slot port 2) 3) port bv 0 (fx- (##sys#size bv) 1)))) ; write-bytevector
5483
5484	(define (outchr port chr)
5485	  (when length-limit
5486	    (let ((cpp0 (current-print-length)))
5487	      (current-print-length (fx+ cpp0 1))
5488	      (when (fx>= cpp0 length-limit)
5489		(outstr0 port "...")
5490		((##sys#print-exit) (##sys#void)))))
5491	  ((##sys#slot (##sys#slot port 2) 2) port chr))  ; write-char
5492
5493	(define (specialchar? chr)
5494	  (let ([c (char->integer chr)])
5495	    (or (fx<= c 32)
5496		(memq chr special-characters) ) ) )
5497
5498	(define (outsym port sym)
5499	  (let ((str (##sys#symbol->string/shared sym)))
5500	    (if (or (not sep) (not readable) (sym-is-readable? str))
5501		(outstr port str)
5502		(outreadablesym port str))))
5503
5504	(define (outreadablesym port str)
5505	  (let ((len (string-length str)))
5506	    (outchr port #\|)
5507	    (let loop ((i 0))
5508	      (if (fx>= i len)
5509		  (outchr port #\|)
5510		  (let ((c (string-ref str i)))
5511		    (cond ((or (char<? c #\space) (char>? c #\~))
5512			   (outstr port "\\x")
5513			   (let ((n (char->integer c)))
5514			     (outstr port (##sys#number->string n 16))
5515                             (outchr port #\;)
5516			     (loop (fx+ i 1))))
5517			  (else
5518			   (when (or (eq? c #\|) (eq? c #\\)) (outchr port #\\))
5519			   (outchr port c)
5520			   (loop (fx+ i 1)) ) ) ) ) )))
5521
5522	(define (sym-is-readable? str)
5523	  (let ((len (string-length str)))
5524	    (cond ((eq? len 0) #f)
5525		  ((eq? len 1)
5526		   (let ((c (string-ref str 0)))
5527		     (cond ((or (eq? #\# c) (eq? #\. c)) #f)
5528			   ((specialchar? c) #f)
5529			   ((char-numeric? c) #f)
5530			   (else #t))))
5531		  (else
5532		   (let loop ((i (fx- len 1)))
5533		     (if (eq? i 0)
5534			 (let ((c (string-ref str 0)))
5535			   (cond ((char-numeric? c) #f)
5536                                 ((or (eq? c #\+) (eq? c #\-))
5537				  (or (fx= len 1)
5538                                      (not (char-numeric? (string-ref str 1)))))
5539                                 ((eq? c #\.)
5540				  (and (fx> len 1)
5541                                       (not (char-numeric? (string-ref str 1)))))
5542				 ((eq? c #\:) #f)
5543				 ((and (eq? c #\#)
5544				       ;; Not a qualified symbol?
5545				       (not (and (fx> len 2)
5546						 (eq? (string-ref str 1) #\#)
5547						 (not (eq? (string-ref str 2) #\#)))))
5548				  (member str '("#!rest" "#!key" "#!optional"
5549                                                "#!fold-case" "#!no-fold-case")))
5550				 ((specialchar? c) #f)
5551				 (else #t) ) )
5552			 (let ((c (string-ref str i)))
5553			   (and (or csp (not (char-upper-case? c)))
5554				(not (specialchar? c))
5555				(or (not (eq? c #\:))
5556				    (fx< i (fx- len 1)))
5557				(loop (fx- i 1)) ) ) ) ) ) ) ) )
5558
5559	(let out ([x x])
5560	  (cond ((eq? x '()) (outstr port "()"))
5561		((eq? x #t) (outstr port "#t"))
5562		((eq? x #f) (outstr port "#f"))
5563		((##core#inline "C_eofp" x) (outstr port "#!eof"))
5564		((##core#inline "C_undefinedp" x) (outstr port "#<unspecified>"))
5565		((##core#inline "C_bwpp" x) (outstr port "#!bwp"))
5566		((##core#inline "C_charp" x)
5567		 (cond [readable
5568			(outstr port "#\\")
5569			(let ([code (char->integer x)])
5570			  (cond [(char-name x)
5571				 => (lambda (cn)
5572				      (outstr port (##sys#symbol->string/shared cn)) ) ]
5573				[(or (fx< code 32) (fx> code #x1ffff))
5574				 (outchr port #\x)
5575				 (outstr port (##sys#number->string code 16)) ]
5576				[else (outchr port x)] ) ) ]
5577		       [else (outchr port x)] ) )
5578		((##core#inline "C_fixnump" x) (outstr port (##sys#number->string x)))
5579		((##core#inline "C_unboundvaluep" x) (outstr port "#<unbound value>"))
5580		((not (##core#inline "C_blockp" x)) (outstr port "#<invalid immediate object>"))
5581		((##core#inline "C_forwardedp" x) (outstr port "#<invalid forwarded object>"))
5582		((##core#inline "C_i_keywordp" x)
5583                 ;; Force portable #: style for readable output
5584		 (case (and (not readable) ksp)
5585                   ((#:prefix)
5586                    (outchr port #\:)
5587                    (outsym port x))
5588                   ((#:suffix)
5589                    (outsym port x)
5590                    (outchr port #\:))
5591                   (else
5592                    (outstr port "#:")
5593                    (outsym port x))))
5594		((##core#inline "C_i_symbolp" x) (outsym port x))
5595		((number? x) (outstr port (##sys#number->string x)))
5596		((##core#inline "C_anypointerp" x) (outstr port (##sys#pointer->string x)))
5597		((##core#inline "C_stringp" x)
5598		 (cond (readable
5599			(outchr port #\")
5600			(do ((i 0 (fx+ i 1))
5601			     (c (string-length x) (fx- c 1)) )
5602			    ((eq? c 0)
5603			     (outchr port #\") )
5604			  (let ((chr (char->integer (string-ref x i))))
5605			    (case chr
5606			      ((34) (outstr port "\\\""))
5607			      ((92) (outstr port "\\\\"))
5608			      (else
5609			       (cond ((or (fx< chr 32)
5610					  (fx= chr #x1ffff))
5611				      (outchr port #\\)
5612				      (case chr
5613                                        ((7) (outchr port #\a))
5614					((8) (outchr port #\b))
5615					((9) (outchr port #\t))
5616					((10) (outchr port #\n))
5617					((11) (outchr port #\v))
5618					((12) (outchr port #\f))
5619					((13) (outchr port #\r))
5620					(else
5621					 (outchr port #\x)
5622					 (when (fx< chr 16) (outchr port #\0))
5623					 (outstr port (##sys#number->string chr 16))
5624					 (outchr port #\;) ) ) )
5625				     (else (outchr port (##core#inline "C_fix_to_char" chr)) ) ) ) ) ) ) )
5626		       (else (outstr port x)) ) )
5627		((##core#inline "C_pairp" x)
5628		 (outchr port #\()
5629		 (out (##sys#slot x 0))
5630		 (do ((x (##sys#slot x 1) (##sys#slot x 1)))
5631		     ((or (not (##core#inline "C_blockp" x)) (not (##core#inline "C_pairp" x)))
5632		      (if (not (eq? x '()))
5633			  (begin
5634			    (outstr port " . ")
5635			    (out x) ) )
5636		      (outchr port #\)) )
5637		   (outchr port #\space)
5638		   (out (##sys#slot x 0)) ) )
5639		((##core#inline "C_bytevectorp" x)
5640		 (outstr port "#u8")
5641                 (out (##sys#bytevector->list x)))
5642		((##core#inline "C_structurep" x) (##sys#user-print-hook x readable port))
5643		((##core#inline "C_closurep" x) (outstr port (##sys#procedure->string x)))
5644		((##core#inline "C_locativep" x) (outstr port "#<locative>"))
5645		((##core#inline "C_lambdainfop" x)
5646		 (outstr port "#<lambda info ")
5647		 (outstr port (##sys#lambda-info->string x))
5648		 (outchr port #\>) )
5649		((##core#inline "C_portp" x)
5650		 (case (##sys#slot x 1)
5651		   ((1)  (outstr port "#<input port \""))
5652		   ((2)  (outstr port "#<output port \""))
5653		   (else (outstr port "#<port \"")))
5654		 (outstr port (##sys#slot x 3))
5655		 (outstr port "\">") )
5656		((##core#inline "C_vectorp" x)
5657		 (let ((n (##sys#size x)))
5658		   (cond ((eq? 0 n)
5659			  (outstr port "#()") )
5660			 (else
5661			  (outstr port "#(")
5662			  (out (##sys#slot x 0))
5663			  (do ((i 1 (fx+ i 1))
5664			       (c (fx- n 1) (fx- c 1)) )
5665			      ((eq? c 0)
5666			       (outchr port #\)) )
5667			    (outchr port #\space)
5668			    (out (##sys#slot x i)) ) ) ) ) )
5669		(else (##sys#error "unprintable block object encountered")))))
5670      (##sys#void))))
5671
5672(define ##sys#procedure->string
5673  (let ((string-append string-append))
5674    (lambda (x)
5675      (let ((info (##sys#lambda-info x)))
5676	(if info
5677	    (string-append "#<procedure " (##sys#lambda-info->string info) ">")
5678	    "#<procedure>") ) ) ) )
5679
5680(define ##sys#record-printers '())
5681
5682(set! chicken.base#record-printer
5683  (lambda (type)
5684    (let ((a (assq type ##sys#record-printers)))
5685      (and a (cdr a)))))
5686
5687(set! chicken.base#set-record-printer!
5688  (lambda (type proc)
5689    (##sys#check-closure proc 'set-record-printer!)
5690    (let ((a (assq type ##sys#record-printers)))
5691      (if a
5692	  (##sys#setslot a 1 proc)
5693	  (set! ##sys#record-printers (cons (cons type proc) ##sys#record-printers)))
5694      (##core#undefined))))
5695
5696;; OBSOLETE can be removed after bootstrapping
5697(set! ##sys#register-record-printer chicken.base#set-record-printer!)
5698
5699(set! chicken.base#record-printer
5700  (getter-with-setter record-printer set-record-printer!))
5701
5702(define (##sys#user-print-hook x readable port)
5703  (let* ((type (##sys#slot x 0))
5704	 (a (assq type ##sys#record-printers))
5705         (name (if (vector? type) (##sys#slot type 0) type)))
5706    (cond (a (handle-exceptions ex
5707		(begin
5708		  (##sys#print "#<Error in printer of record type `" #f port)
5709		  (##sys#print name #f port)
5710		  (if (##sys#structure? ex 'condition)
5711		      (and-let* ((a (member '(exn . message) (##sys#slot ex 2))))
5712			(##sys#print "': " #f port)
5713			(##sys#print (cadr a) #f port)
5714			(##sys#write-char-0 #\> port))
5715		      (##sys#print "'>" #f port)))
5716	       ((##sys#slot a 1) x port)))
5717	  (else
5718	   (##sys#print "#<" #f port)
5719	   (##sys#print name #f port)
5720	   (case type
5721	     ((condition)
5722	      (##sys#print ": " #f port)
5723	      (##sys#print (##sys#slot x 1) #f port) )
5724	     ((thread)
5725	      (##sys#print ": " #f port)
5726	      (##sys#print (##sys#slot x 6) #f port) ) )
5727	   (##sys#write-char-0 #\> port) ) ) ) )
5728
5729(define ##sys#with-print-length-limit
5730  (let ([call-with-current-continuation call-with-current-continuation])
5731    (lambda (limit thunk)
5732      (call-with-current-continuation
5733       (lambda (return)
5734	 (parameterize ((##sys#print-length-limit limit)
5735			(##sys#print-exit return)
5736			(current-print-length 0))
5737	   (thunk)))))))
5738
5739
5740;;; String ports:
5741;
5742; - Port-slots:
5743;
5744;   Input:
5745;
5746;   10: position (in bytes)
5747;   11: len
5748;   12: input bytevector
5749;
5750;   Output:
5751;
5752;   10: position (in bytes)
5753;   11: limit
5754;   12: output bytevector
5755
5756(define ##sys#string-port-class
5757  (letrec ((check
5758	    (lambda (p n)
5759	      (let* ((position (##sys#slot p 10))
5760		     (limit (##sys#slot p 11))
5761		     (output (##sys#slot p 12))
5762		     (limit2 (fx+ position n)))
5763		(when (fx>= limit2 limit)
5764		  (when (fx>= limit2 maximal-string-length)
5765		    (##sys#error "string buffer full" p) )
5766		  (let* ([limit3 (fxmin maximal-string-length (fx+ limit limit))]
5767			 [buf (##sys#make-bytevector limit3)] )
5768		    (##core#inline "C_copy_memory_with_offset" buf output 0 0 position)
5769		    (##sys#setslot p 12 buf)
5770		    (##sys#setislot p 11 limit3)
5771		    (check p n) ) ) ) ) ) )
5772    (vector
5773     (lambda (p)			; read-char
5774       (let ((position (##sys#slot p 10))
5775             (input (##sys#slot p 12))
5776             (len (##sys#slot p 11)))
5777         (if (fx>= position len)
5778             #!eof
5779             (let ((c (##core#inline "C_utf_decode" input position)))
5780               (##sys#setislot p 10
5781                               (##core#inline "C_utf_advance" input position))
5782               c))))
5783     (lambda (p)			; peek-char
5784       (let ((position (##sys#slot p 10))
5785             (input (##sys#slot p 12))
5786             (len (##sys#slot p 11)))
5787         (if (fx>= position len)
5788             #!eof
5789             (##core#inline "C_utf_decode" input position))))
5790     (lambda (p c)			; write-char
5791       (check p 1)
5792       (let ([position (##sys#slot p 10)]
5793	     [output (##sys#slot p 12)] )
5794         (##sys#setislot p 10 (##core#inline "C_utf_insert" output position c))))
5795     (lambda (p bv from to)			; write-bytevector
5796       (let ((len (fx- to from)))
5797	 (check p len)
5798	 (let* ((position (##sys#slot p 10))
5799	        (output (##sys#slot p 12)))
5800	   (##core#inline "C_copy_memory_with_offset" output bv position from len)
5801	   (##sys#setislot p 10 (fx+ position len)) ) ) )
5802     void ; close
5803     (lambda (p) #f)			; flush-output
5804     (lambda (p) #t)			; char-ready?
5805     (lambda (p n dest start)		; read-bytevector!
5806       (let* ((pos (##sys#slot p 10))
5807              (input (##sys#slot p 12))
5808	      (n2 (fx- (##sys#slot p 11) pos)))
5809	 (when (or (not n) (fx> n n2)) (set! n n2))
5810	 (##core#inline "C_copy_memory_with_offset" dest input start pos n)
5811	 (##sys#setislot p 10 (fx+ pos n))
5812	 n))
5813     (lambda (p limit)			; read-line
5814       (let* ((pos (##sys#slot p 10))
5815	      (size (##sys#slot p 11))
5816	      (buf (##sys#slot p 12))
5817	      (end (if limit (fx+ pos limit) size)))
5818	 (if (fx>= pos size)
5819	     #!eof
5820	     (receive (next line full-line?)
5821		 (##sys#scan-buffer-line
5822		  buf (if (fx> end size) size end) pos
5823		  (lambda (pos) (values #f pos #f) ) )
5824	       ;; Update row & column position
5825	       (if full-line?
5826		   (begin
5827		     (##sys#setislot p 4 (fx+ (##sys#slot p 4) 1))
5828		     (##sys#setislot p 5 0))
5829		   (##sys#setislot p 5 (fx+ (##sys#slot p 5) (string-length line))))
5830	       (##sys#setislot p 10 next)
5831	       line) ) ) )
5832     (lambda (p)			; read-buffered
5833       (let ((pos (##sys#slot p 10))
5834	     (buf (##sys#slot p 12))
5835	     (len (##sys#slot p 11)) )
5836	 (if (fx>= pos len)
5837	     ""
5838	     (let* ((rest (fx- len pos))
5839                    (buffered (##sys#buffer->string buffered pos rest)))
5840	       (##sys#setislot p 10 len)
5841	       buffered))))
5842     )))
5843
5844;; Invokes the eos handler when EOS is reached to get more data.
5845;; The eos-handler is responsible for stopping, either when EOF is hit or
5846;; a user-supplied limit is reached (ie, it's indistinguishable from EOF)
5847(define (##sys#scan-buffer-line buf limit start-pos eos-handler #!optional enc)
5848  (let* ((hold 1024)
5849         (dpos 0)
5850         (line (##sys#make-bytevector hold)))
5851    (define (grow)
5852      (let* ((h2 (fx* hold 2))
5853             (l2 (##sys#make-bytevector h2)))
5854        (##core#inline "C_copy_memory" l2 line dpos)
5855        (set! line l2)
5856        (set! hold h2)))
5857    (define (conc buf from to)
5858      (let ((len (fx- to from)))
5859        (when (fx>= (fx+ dpos len) hold) (grow))
5860        (##core#inline "C_copy_memory_with_offset" line buf dpos from len)
5861        (set! dpos (fx+ dpos len))))
5862    (define (conc1 b)
5863      (when (fx>= (fx+ dpos 1) hold) (grow))
5864      (##core#inline "C_setsubbyte" line dpos b)
5865      (set! dpos (fx+ dpos 1)))
5866    (define (getline)
5867      (if enc
5868          (##sys#buffer->string/encoding line 0 dpos enc)
5869          (##sys#buffer->string line 0 dpos)))
5870    (let loop ((buf buf)
5871               (offset start-pos)
5872               (pos start-pos)
5873               (limit limit))
5874      (cond ((fx= pos limit)
5875             (conc buf offset pos)
5876             (receive (buf offset limit) (eos-handler pos)
5877               (if buf
5878                   (loop buf offset offset limit)
5879                   (values offset (getline) #f))))
5880            (else
5881              (let ((c (##core#inline "C_subbyte" buf pos)))
5882                (cond ((eq? c 10)
5883                       (conc buf offset pos)
5884                       (values (fx+ pos 1) (getline) #t))
5885                      ((and (eq? c 13)	; \r\n -> drop \r from string
5886                            (fx> limit (fx+ pos 1))
5887                            (eq? (##core#inline "C_subbyte" buf (fx+ pos 1)) 10))
5888                       (conc buf offset pos)
5889                       (values (fx+ pos 2) (getline) #t))
5890                      ((and (eq? c 13)	; Edge case (#568): \r{read}[\n|xyz]
5891                            (fx= limit (fx+ pos 1)))
5892                       (conc buf offset pos)
5893                       (receive (buf offset limit) (eos-handler pos)
5894                         (if buf
5895                             (if (eq? (##core#inline "C_subbyte" buf offset) 10)
5896                                 (values (fx+ offset 1) (getline) #t)
5897                                 ;; "Restore" \r we didn't copy, loop w/ new string
5898                                 (begin
5899                                   (conc1 13)
5900                                   (loop buf offset offset limit)))
5901                             ;; Restore \r here, too (when we reached EOF)
5902                             (begin
5903                               (conc1 13)
5904                               (values offset (getline) #t)))))
5905                      ((eq? c 13)
5906                       (conc buf offset pos)
5907                       (values (fx+ pos 1) (getline) #t))
5908                      (else (loop buf offset (fx+ pos 1) limit)) ) ) ) ) )))
5909
5910(define ##sys#print-to-string
5911  (let ([get-output-string get-output-string]
5912	[open-output-string open-output-string] )
5913    (lambda (xs)
5914      (let ([out (open-output-string)])
5915	(for-each (lambda (x) (##sys#print x #f out)) xs)
5916	(get-output-string out) ) ) ) )
5917
5918(define ##sys#pointer->string
5919  (let ((string-append string-append))
5920    (lambda (x)
5921      (if (##core#inline "C_taggedpointerp" x)
5922	  (string-append
5923	   "#<tagged pointer "
5924	   (##sys#print-to-string
5925	    (let ((tag (##sys#slot x 1)))
5926	      (list (if (pair? tag) (car tag) tag) ) ) )
5927	   " "
5928	   (##sys#number->string (##sys#pointer->address x) 16)
5929	   ">")
5930	  (string-append "#<pointer 0x" (##sys#number->string (##sys#pointer->address x) 16) ">") ) ) ) )
5931
5932
5933;;; Access backtrace:
5934
5935(define-constant +trace-buffer-entry-slot-count+ 5)
5936
5937(set! chicken.base#get-call-chain
5938  (let ((extract
5939	 (foreign-lambda* nonnull-c-string ((scheme-object x)) "C_return((C_char *)x);")))
5940    (lambda (#!optional (start 0) (thread ##sys#current-thread))
5941      (let* ((tbl (foreign-value "C_trace_buffer_size" int))
5942	     ;; 5 slots: "raw" location (for compiled code), "cooked" location (for interpreted code), cooked1, cooked2, thread
5943	     (c +trace-buffer-entry-slot-count+)
5944	     (vec (##sys#make-vector (fx* c tbl) #f))
5945	     (r (##core#inline "C_fetch_trace" start vec))
5946	     (n (if (fixnum? r) r (fx* c tbl)))
5947             (t-id (and thread (##sys#slot thread 14))))
5948	(let loop ((i 0))
5949	  (if (fx>= i n)
5950	      '()
5951	      (let ((t (##sys#slot vec (fx+ i 4)))) ; thread id
5952		(if (or (not t) (not thread) (eq? t-id t))
5953		    (cons (vector
5954			   (or (##sys#slot vec (fx+ i 1)) ; cooked_location
5955			       (extract (##sys#slot vec i))) ; raw_location
5956			   (##sys#slot vec (fx+ i 2))   ; cooked1
5957			   (##sys#slot vec (fx+ i 3)))  ; cooked2
5958			  (loop (fx+ i c)))
5959		    (loop (fx+ i c))))))))))
5960
5961(define (##sys#really-print-call-chain port chain header)
5962  (when (pair? chain)
5963    (##sys#print header #f port)
5964    (for-each
5965     (lambda (info)
5966       (let* ((more1 (##sys#slot info 1)) ; cooked1 (expr/form)
5967	      (more2 (##sys#slot info 2)) ; cooked2 (cntr/frameinfo)
5968	      (fi (##sys#structure? more2 'frameinfo)))
5969	 (##sys#print "\n\t" #f port)
5970	 (##sys#print (##sys#slot info 0) #f port) ; raw (mode)
5971	 (##sys#print "\t  " #f port)
5972	 (when (and more2 (if fi (##sys#slot more2 1)))
5973	   (##sys#write-char-0 #\[ port)
5974	   (##sys#print
5975	    (if fi
5976		(##sys#slot more2 1)	; cntr
5977		more2)
5978	    #f port)
5979	   (##sys#print "] " #f port))
5980	 (when more1
5981	   (##sys#with-print-length-limit
5982	    100
5983	    (lambda ()
5984	      (##sys#print more1 #t port))))))
5985     chain)
5986    (##sys#print "\t<--\n" #f port)))
5987
5988(set! chicken.base#print-call-chain
5989  (lambda (#!optional (port ##sys#standard-output) (start 0)
5990		      (thread ##sys#current-thread)
5991		      (header "\n\tCall history:\n"))
5992    (##sys#check-output-port port #t 'print-call-chain)
5993    (##sys#check-fixnum start 'print-call-chain)
5994    (##sys#check-string header 'print-call-chain)
5995    (##sys#really-print-call-chain port (get-call-chain start thread) header)))
5996
5997
5998;;; Interrupt handling:
5999
6000(define (##sys#user-interrupt-hook)
6001  (define (break) (##sys#signal-hook #:user-interrupt #f))
6002  (if (eq? ##sys#current-thread ##sys#primordial-thread)
6003      (break)
6004      (##sys#setslot ##sys#primordial-thread 1 break) ) )
6005
6006
6007;;; Default handlers
6008
6009(define-foreign-variable _ex_software int "EX_SOFTWARE")
6010
6011(define exit-in-progress #f)
6012
6013(define (cleanup-before-exit)
6014  (set! exit-in-progress #t)
6015  (##core#inline "C_flush_all_files" #f)
6016  (when (##core#inline "C_i_dump_heap_on_exitp")
6017    (##sys#print "\n" #f ##sys#standard-error)
6018    (##sys#dump-heap-state))
6019  (when (##core#inline "C_i_profilingp")
6020    (##core#inline "C_i_dump_statistical_profile"))
6021  (let loop ()
6022    (let ((tasks chicken.base#cleanup-tasks))
6023      (set! chicken.base#cleanup-tasks '())
6024      (unless (null? tasks)
6025	(for-each (lambda (t) (t)) tasks)
6026	(loop))))
6027  (when (fx> (##sys#slot ##sys#pending-finalizers 0) 0)
6028    (##sys#run-pending-finalizers #f))
6029  (when (fx> (##core#inline "C_i_live_finalizer_count") 0)
6030    (when (##sys#debug-mode?)
6031      (##sys#print "[debug] forcing finalizers...\n" #f ##sys#standard-error))
6032    (when (chicken.gc#force-finalizers)
6033      (##sys#force-finalizers))))
6034
6035(set! chicken.base#exit-handler
6036  (make-parameter
6037   (lambda (#!optional (code 0))
6038     (##sys#check-fixnum code)
6039     (cond (exit-in-progress
6040	    (##sys#warn "\"exit\" called while processing on-exit tasks"))
6041	   (else
6042	    (cleanup-before-exit)
6043	    (##core#inline "C_exit_runtime" code))))))
6044
6045(set! chicken.base#implicit-exit-handler
6046  (make-parameter
6047   (lambda ()
6048     (cleanup-before-exit))))
6049
6050(define ##sys#reset-handler ; Exposed by chicken.repl
6051  (make-parameter
6052   (lambda ()
6053     ((exit-handler) _ex_software))))
6054
6055(define (##sys#dbg-hook . args)
6056  (##core#inline "C_dbg_hook" #f)
6057  (##core#undefined))
6058
6059
6060;;; Condition handling:
6061
6062(module chicken.condition
6063    ;; NOTE: We don't emit the import lib.  Due to syntax exports, it
6064    ;; has to be a hardcoded primitive module.
6065    (abort signal current-exception-handler
6066     print-error-message with-exception-handler
6067
6068     ;; [syntax] condition-case handle-exceptions
6069
6070     ;; Condition object manipulation
6071     make-property-condition make-composite-condition
6072     condition condition? condition->list condition-predicate
6073     condition-property-accessor get-condition-property)
6074
6075(import scheme chicken.base chicken.fixnum chicken.foreign)
6076(import chicken.internal.syntax)
6077(import (only (scheme base) make-parameter open-output-string get-output-string))
6078
6079(define (##sys#signal-hook/errno mode errno msg . args)
6080  (##core#inline "C_dbg_hook" #f)
6081  (##core#inline "signal_debug_event" mode msg args)
6082  (case mode
6083    [(#:user-interrupt)
6084     (abort
6085      (##sys#make-structure
6086       'condition
6087       '(user-interrupt)
6088       '() ) ) ]
6089    [(#:warning #:notice)
6090     (##sys#print
6091      (if (eq? mode #:warning) "\nWarning: " "\nNote: ")
6092      #f ##sys#standard-error)
6093     (##sys#print msg #f ##sys#standard-error)
6094     (if (or (null? args) (fx> (length args) 1))
6095	 (##sys#write-char-0 #\newline ##sys#standard-error)
6096	 (##sys#print ": " #f ##sys#standard-error))
6097     (for-each
6098      (lambda (x)
6099	(##sys#with-print-length-limit
6100	 400
6101	 (lambda ()
6102	   (##sys#print x #t ##sys#standard-error)
6103	   (##sys#write-char-0 #\newline ##sys#standard-error))))
6104      args)
6105     (##sys#flush-output ##sys#standard-error)]
6106    (else
6107     (when (and (symbol? msg) (null? args))
6108       (set! msg (symbol->string msg)))
6109     (let* ([hasloc (and (or (not msg) (symbol? msg)) (pair? args))]
6110	    [loc (and hasloc msg)]
6111	    [msg (if hasloc (##sys#slot args 0) msg)]
6112	    [args (if hasloc (##sys#slot args 1) args)] )
6113       (abort
6114	(##sys#make-structure
6115	 'condition
6116	 (case mode
6117	   [(#:type-error)		'(exn type)]
6118	   [(#:syntax-error)		'(exn syntax)]
6119	   [(#:bounds-error)		'(exn bounds)]
6120	   [(#:arithmetic-error)	'(exn arithmetic)]
6121	   [(#:file-error)		'(exn i/o file)]
6122	   [(#:runtime-error)		'(exn runtime)]
6123	   [(#:process-error)		'(exn process)]
6124	   [(#:network-error)		'(exn i/o net)]
6125	   [(#:network-timeout-error)   '(exn i/o net timeout)]
6126	   [(#:limit-error)		'(exn runtime limit)]
6127	   [(#:arity-error)		'(exn arity)]
6128	   [(#:access-error)		'(exn access)]
6129	   [(#:domain-error)		'(exn domain)]
6130	   ((#:memory-error)            '(exn memory))
6131	   [else			'(exn)] )
6132         (let ((props
6133                (list '(exn . message) msg
6134                      '(exn . arguments) args
6135                      '(exn . call-chain) (get-call-chain)
6136                      '(exn . location) loc)))
6137           (if errno
6138               (cons '(exn . errno) (cons errno props))
6139               props))))))))
6140
6141(define (##sys#signal-hook mode msg . args)
6142  (if (pair? args)
6143      (apply ##sys#signal-hook/errno mode #f msg args)
6144      (##sys#signal-hook/errno mode #f msg)))
6145
6146(define (abort x)
6147  (##sys#current-exception-handler x)
6148  (abort
6149   (##sys#make-structure
6150    'condition
6151    '(exn)
6152    (list '(exn . message) "exception handler returned"
6153	  '(exn . arguments) '()
6154	  '(exn . location) #f) ) ) )
6155
6156(define (signal x)
6157  (##sys#current-exception-handler x) )
6158
6159(define ##sys#error-handler
6160  (make-parameter
6161   (let ([string-append string-append])
6162     (lambda (msg . args)
6163       (##sys#error-handler (lambda args (##core#inline "C_halt" "error in error")))
6164       (cond ((not (foreign-value "C_gui_mode" bool))
6165	      (##sys#print "\nError" #f ##sys#standard-error)
6166	      (when msg
6167		(##sys#print ": " #f ##sys#standard-error)
6168		(##sys#print msg #f ##sys#standard-error))
6169	      (##sys#with-print-length-limit
6170	       400
6171	       (lambda ()
6172		 (cond [(fx= 1 (length args))
6173			(##sys#print ": " #f ##sys#standard-error)
6174			(##sys#print (##sys#slot args 0) #t ##sys#standard-error)]
6175		       [else
6176			(##sys#for-each
6177			 (lambda (x)
6178			   (##sys#print #\newline #f ##sys#standard-error)
6179			   (##sys#print x #t ##sys#standard-error))
6180			 args)])))
6181	      (##sys#print #\newline #f ##sys#standard-error)
6182	      (print-call-chain ##sys#standard-error)
6183	      (##core#inline "C_halt" #f))
6184	     (else
6185	      (let ((out (open-output-string)))
6186		(when msg (##sys#print msg #f out))
6187		(##sys#print #\newline #f out)
6188		(##sys#for-each (lambda (x) (##sys#print x #t out) (##sys#print #\newline #f out)) args)
6189		(##core#inline "C_halt" (get-output-string out)))))))))
6190
6191
6192(define ##sys#last-exception #f)	; used in csi for ,exn command
6193
6194(define ##sys#current-exception-handler
6195  ;; Exception-handler for the primordial thread:
6196  (let ((string-append string-append))
6197    (lambda (c)
6198      (when (##sys#structure? c 'condition)
6199	(set! ##sys#last-exception c)
6200	(let ((kinds (##sys#slot c 1)))
6201	  (cond ((memq 'exn kinds)
6202		 (let* ((props (##sys#slot c 2))
6203			(msga (member '(exn . message) props))
6204			(argsa (member '(exn . arguments) props))
6205			(loca (member '(exn . location) props)) )
6206		   (apply
6207		    (##sys#error-handler)
6208		    (if msga
6209			(let ((msg (cadr msga))
6210			      (loc (and loca (cadr loca))) )
6211			  (if (and loc (symbol? loc))
6212			      (string-append
6213			       "(" (##sys#symbol->string/shared loc) ") "
6214			       (cond ((symbol? msg) (##sys#slot msg 1))
6215				     ((string? msg) msg)
6216				     (else "") ) ) ; Hm...
6217			      msg) )
6218			"<exn: has no `message' property>")
6219		    (if argsa
6220			(cadr argsa)
6221			'() ) )
6222		   ;; in case error-handler returns, which shouldn't happen:
6223		   ((##sys#reset-handler)) ) )
6224		((eq? 'user-interrupt (##sys#slot kinds 0))
6225		 (##sys#print "\n*** user interrupt ***\n" #f ##sys#standard-error)
6226		 ((##sys#reset-handler)) )
6227		((eq? 'uncaught-exception (##sys#slot kinds 0))
6228		 ((##sys#error-handler)
6229		  "uncaught exception"
6230		  (cadr (member '(uncaught-exception . reason) (##sys#slot c 2))) )
6231		 ((##sys#reset-handler)) ) ) ) )
6232      (abort
6233       (##sys#make-structure
6234	'condition
6235	'(uncaught-exception)
6236	(list '(uncaught-exception . reason) c)) ) ) ) )
6237
6238(define (with-exception-handler handler thunk)
6239  (let ([oldh ##sys#current-exception-handler])
6240    (##sys#dynamic-wind
6241      (lambda () (set! ##sys#current-exception-handler handler))
6242      thunk
6243      (lambda () (set! ##sys#current-exception-handler oldh)) ) ) )
6244
6245;; TODO: Make this a proper parameter
6246(define (current-exception-handler . args)
6247  (if (null? args)
6248      ##sys#current-exception-handler
6249      (let ((proc (car args)))
6250	(##sys#check-closure proc 'current-exception-handler)
6251	(let-optionals (cdr args) ((convert? #t) (set? #t))
6252	  (when set? (set! ##sys#current-exception-handler proc)))
6253	proc)))
6254
6255;;; Condition object manipulation
6256
6257(define (prop-list->kind-prefixed-prop-list loc kind plist)
6258  (let loop ((props plist))
6259    (cond ((null? props) '())
6260	  ((or (not (pair? props)) (not (pair? (cdr props))))
6261	   (##sys#signal-hook
6262	    #:type-error loc "argument is not an even property list" plist))
6263	  (else (cons (cons kind (car props))
6264		      (cons (cadr props)
6265			    (loop (cddr props))))))))
6266
6267(define (make-property-condition kind . props)
6268  (##sys#make-structure
6269   'condition (list kind)
6270   (prop-list->kind-prefixed-prop-list
6271    'make-property-condition kind props)))
6272
6273(define (make-composite-condition c1 . conds)
6274  (let ([conds (cons c1 conds)])
6275    (for-each (lambda (c) (##sys#check-structure c 'condition 'make-composite-condition)) conds)
6276    (##sys#make-structure
6277     'condition
6278     (apply ##sys#append (map (lambda (c) (##sys#slot c 1)) conds))
6279     (apply ##sys#append (map (lambda (c) (##sys#slot c 2)) conds)) ) ) )
6280
6281(define (condition arg1 . args)
6282  (let* ((args (cons arg1 args))
6283	 (keys (apply ##sys#append
6284		      (map (lambda (c)
6285			     (prop-list->kind-prefixed-prop-list
6286			      'condition (car c) (cdr c)))
6287			     args))))
6288    (##sys#make-structure 'condition (map car args) keys)))
6289
6290(define (condition? x) (##sys#structure? x 'condition))
6291
6292(define (condition->list x)
6293  (unless (condition? x)
6294    (##sys#signal-hook
6295     #:type-error 'condition->list
6296     "argument is not a condition object" x))
6297  (map (lambda (k)
6298	 (cons k (let loop ((props (##sys#slot x 2)))
6299		   (cond ((null? props) '())
6300			 ((eq? (caar props) k)
6301			  (cons (cdar props)
6302				(cons (cadr props)
6303				      (loop (cddr props)))))
6304			 (else
6305			  (loop (cddr props)))))))
6306       (##sys#slot x 1)))
6307
6308(define (condition-predicate kind)
6309  (lambda (c)
6310    (and (condition? c)
6311         (if (memv kind (##sys#slot c 1)) #t #f)) ) )
6312
6313(define (condition-property-accessor kind prop . err-def)
6314  (let ((err? (null? err-def))
6315	(k+p (cons kind prop)) )
6316    (lambda (c)
6317      (##sys#check-structure c 'condition)
6318      (and (memv kind (##sys#slot c 1))
6319	   (let ([a (member k+p (##sys#slot c 2))])
6320	     (cond [a (cadr a)]
6321		   [err? (##sys#signal-hook
6322			  #:type-error 'condition-property-accessor
6323			  "condition has no such property" prop) ]
6324		   [else (car err-def)] ) ) ) ) ) )
6325
6326(define get-condition-property
6327  (lambda (c kind prop . err-def)
6328    ((apply condition-property-accessor kind prop err-def) c)))
6329
6330
6331;;; Convenient error printing:
6332
6333(define print-error-message
6334  (let* ((display display)
6335	 (newline newline)
6336	 (write write)
6337	 (string-append string-append)
6338	 (errmsg (condition-property-accessor 'exn 'message #f))
6339	 (errloc (condition-property-accessor 'exn 'location #f))
6340	 (errargs (condition-property-accessor 'exn 'arguments #f))
6341	 (writeargs
6342	  (lambda (args port)
6343	    (##sys#for-each
6344	     (lambda (x)
6345	       (##sys#with-print-length-limit 80 (lambda () (write x port)))
6346	       (newline port) )
6347	     args) ) ) )
6348    (lambda (ex . args)
6349      (let-optionals args ((port ##sys#standard-output)
6350			   (header "Error"))
6351	(##sys#check-output-port port #t 'print-error-message)
6352	(newline port)
6353	(display header port)
6354	(cond ((and (not (##sys#immediate? ex)) (eq? 'condition (##sys#slot ex 0)))
6355	       (cond ((errmsg ex) =>
6356		      (lambda (msg)
6357			(display ": " port)
6358			(let ((loc (errloc ex)))
6359			  (when (and loc (symbol? loc))
6360			    (display (string-append "(" (##sys#symbol->string/shared loc) ") ") port) ) )
6361			(display msg port) ) )
6362		     (else
6363		      (let ((kinds (##sys#slot ex 1)))
6364			(if (equal? '(user-interrupt) kinds)
6365			    (display ": *** user interrupt ***" port)
6366			    (begin
6367			      (display ": <condition> " port)
6368			      (display (##sys#slot ex 1) port) ) ) ) ) )
6369	       (let ((args (errargs ex)))
6370		 (cond
6371		   ((not args))
6372		   ((fx= 1 (length args))
6373		    (display ": " port)
6374		    (writeargs args port))
6375		   (else
6376		    (newline port)
6377		    (writeargs args port)))))
6378	      ((string? ex)
6379	       (display ": " port)
6380	       (display ex port)
6381	       (newline port))
6382	      (else
6383	       (display ": uncaught exception: " port)
6384	       (writeargs (list ex) port) ) ) ) ) ) )
6385
6386
6387;;; Show exception message and backtrace as warning
6388;;; (used for threads and finalizers)
6389
6390(define ##sys#show-exception-warning
6391  (let ((print-error-message print-error-message)
6392	(display display)
6393	(write-char write-char)
6394	(print-call-chain print-call-chain)
6395	(open-output-string open-output-string)
6396	(get-output-string get-output-string) )
6397    (lambda (exn cause #!optional (thread ##sys#current-thread))
6398      (when ##sys#warnings-enabled
6399	(let ((o (open-output-string)))
6400	  (display "Warning" o)
6401	  (when thread
6402	    (display " (" o)
6403	    (display thread o)
6404	    (write-char #\) o))
6405	  (display ": " o)
6406	  (display cause o)
6407	  (print-error-message exn ##sys#standard-error (get-output-string o))
6408	  (print-call-chain ##sys#standard-error 0 thread) ) ))))
6409
6410
6411;;; Error hook (called by runtime-system):
6412
6413(define ##sys#error-hook
6414  (let ([string-append string-append])
6415    (lambda (code loc . args)
6416      (case code
6417	((1) (let ([c (car args)]
6418		   [n (cadr args)]
6419		   [fn (caddr args)] )
6420	       (apply
6421		##sys#signal-hook
6422		#:arity-error loc
6423		(string-append "bad argument count - received " (##sys#number->string n) " but expected "
6424			       (##sys#number->string c) )
6425		(if fn (list fn) '())) ) )
6426	((2) (let ([c (car args)]
6427		   [n (cadr args)]
6428		   [fn (caddr args)] )
6429	       (apply
6430		##sys#signal-hook
6431		#:arity-error loc
6432		(string-append "too few arguments - received " (##sys#number->string n) " but expected "
6433			       (##sys#number->string c) )
6434		(if fn (list fn) '()))))
6435	((3) (apply ##sys#signal-hook #:type-error loc "bad argument type" args))
6436	((4) (apply ##sys#signal-hook #:runtime-error loc "unbound variable" args))
6437	((5) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a keyword" args))
6438	((6) (apply ##sys#signal-hook #:limit-error loc "out of memory" args))
6439	((7) (apply ##sys#signal-hook #:arithmetic-error loc "division by zero" args))
6440	((8) (apply ##sys#signal-hook #:bounds-error loc "out of range" args))
6441	((9) (apply ##sys#signal-hook #:type-error loc "call of non-procedure" args))
6442	((10) (apply ##sys#signal-hook #:arity-error loc "continuation cannot receive multiple values" args))
6443	((11) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a non-cyclic list" args))
6444	((12) (apply ##sys#signal-hook #:limit-error loc "recursion too deep" args))
6445	((13) (apply ##sys#signal-hook #:type-error loc "inexact number cannot be represented as an exact number" args))
6446	((14) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a proper list" args))
6447	((15) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a fixnum" args))
6448	((16) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a number" args))
6449	((17) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a string" args))
6450	((18) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a pair" args))
6451	((19) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a list" args))
6452	((20) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a character" args))
6453	((21) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a vector" args))
6454	((22) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a symbol" args))
6455	((23) (apply ##sys#signal-hook #:limit-error loc "stack overflow" args))
6456	((24) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a structure of the required type" args))
6457	((25) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a bytevector" args))
6458	((26) (apply ##sys#signal-hook #:type-error loc "locative refers to reclaimed object" args))
6459	((27) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a block object" args))
6460	((28) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a number vector" args))
6461	((29) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an integer" args))
6462	((30) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an unsigned integer" args))
6463	((31) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a pointer" args))
6464	((32) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a tagged pointer" args))
6465	((33) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a flonum" args))
6466	((34) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a procedure" args))
6467	((35) (apply ##sys#signal-hook #:type-error loc "bad argument type - invalid base" args))
6468	((36) (apply ##sys#signal-hook #:limit-error loc "recursion too deep or circular data encountered" args))
6469	((37) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a boolean" args))
6470	((38) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a locative" args))
6471	((39) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a port" args))
6472	((40) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a port of the correct type" args))
6473	((41) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an input-port" args))
6474	((42) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an output-port" args))
6475	((43) (apply ##sys#signal-hook #:file-error loc "port already closed" args))
6476	((44) (apply ##sys#signal-hook #:type-error loc "cannot represent string with NUL bytes as C string" args))
6477	((45) (apply ##sys#signal-hook #:memory-error loc "segmentation violation" args))
6478	((46) (apply ##sys#signal-hook #:arithmetic-error loc "floating-point exception" args))
6479	((47) (apply ##sys#signal-hook #:runtime-error loc "illegal instruction" args))
6480	((48) (apply ##sys#signal-hook #:memory-error loc "bus error" args))
6481	((49) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an exact number" args))
6482	((50) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an inexact number" args))
6483	((51) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a real" args))
6484	((52) (apply ##sys#signal-hook #:type-error loc "bad argument type - complex number has no ordering" args))
6485	((53) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an exact integer" args))
6486	((54) (apply ##sys#signal-hook #:type-error loc "number does not fit in foreign type" args))
6487	((55) (apply ##sys#signal-hook #:type-error loc "cannot compute absolute value of complex number" args))
6488	((56) (let ((c (car args))
6489		    (n (cadr args))
6490		    (fn (caddr args)))
6491	        (apply
6492		 ##sys#signal-hook
6493		 #:bounds-error loc
6494		 (string-append "attempted rest argument access at index " (##sys#number->string n)
6495                                " but rest list length is " (##sys#number->string c) )
6496		 (if fn (list fn) '()))))
6497        ((57) (apply ##sys#signal-hook #:type-error loc "string contains invalid UTF-8 sequence" args))
6498        ((58) (apply ##sys#signal-hook #:type-error loc "bad argument type - numeric value exceeds range" args))
6499	(else (apply ##sys#signal-hook #:runtime-error loc "unknown internal error" args)) ) ) ) )
6500
6501) ; chicken.condition
6502
6503(import chicken.condition)
6504
6505;;; R7RS exceptions
6506
6507(define ##sys#r7rs-exn-handlers
6508  (make-parameter
6509    (let ((lst (list ##sys#current-exception-handler)))
6510      (set-cdr! lst lst)
6511      lst)))
6512
6513(define scheme#with-exception-handler
6514  (let ((eh ##sys#r7rs-exn-handlers))
6515    (lambda (handler thunk)
6516      (dynamic-wind
6517       (lambda ()
6518         ;; We might be interoperating with srfi-12 handlers set by intermediate
6519         ;; non-R7RS code, so check if a new handler was set in the meanwhile.
6520         (unless (eq? (car (eh)) ##sys#current-exception-handler)
6521           (eh (cons ##sys#current-exception-handler (eh))))
6522         (eh (cons handler (eh)))
6523         (set! ##sys#current-exception-handler handler))
6524       thunk
6525       (lambda ()
6526         (eh (cdr (eh)))
6527         (set! ##sys#current-exception-handler (car (eh))))))))
6528
6529(define scheme#raise
6530  (let ((eh ##sys#r7rs-exn-handlers))
6531    (lambda (obj)
6532      (scheme#with-exception-handler
6533        (cadr (eh))
6534        (lambda ()
6535          ((cadr (eh)) obj)
6536          ((car (eh))
6537           (make-property-condition
6538            'exn
6539            'message "exception handler returned"
6540            'arguments '()
6541            'location #f)))))))
6542
6543(define scheme#raise-continuable
6544  (let ((eh ##sys#r7rs-exn-handlers))
6545     (lambda (obj)
6546       (scheme#with-exception-handler
6547        (cadr (eh))
6548        (lambda ()
6549          ((cadr (eh)) obj))))))
6550
6551(define scheme#error-object? condition?)
6552(define scheme#error-object-message (condition-property-accessor 'exn 'message))
6553(define scheme#error-object-irritants (condition-property-accessor 'exn 'arguments))
6554
6555(define scheme#read-error?)
6556(define scheme#file-error?)
6557
6558(let ((exn?    (condition-predicate 'exn))
6559      (i/o?    (condition-predicate 'i/o))
6560      (file?   (condition-predicate 'file))
6561      (syntax? (condition-predicate 'syntax)))
6562  (set! scheme#read-error?
6563    (lambda (obj)
6564      (and (exn? obj)
6565           (or (i/o? obj) ; XXX Not fine-grained enough.
6566               (syntax? obj)))))
6567  (set! scheme#file-error?
6568    (lambda (obj)
6569      (and (exn? obj)
6570           (file? obj)))))
6571
6572
6573;;; Miscellaneous low-level routines:
6574
6575(define (##sys#structure? x s) (##core#inline "C_i_structurep" x s))
6576(define (##sys#generic-structure? x) (##core#inline "C_structurep" x))
6577(define (##sys#slot x i) (##core#inline "C_slot" x i))
6578(define (##sys#size x) (##core#inline "C_block_size" x))
6579(define ##sys#make-pointer (##core#primitive "C_make_pointer"))
6580(define ##sys#make-tagged-pointer (##core#primitive "C_make_tagged_pointer"))
6581(define (##sys#pointer? x) (##core#inline "C_anypointerp" x))
6582(define (##sys#set-pointer-address! ptr addr) (##core#inline "C_update_pointer" addr ptr))
6583(define (##sys#bytevector? x) (##core#inline "C_bytevectorp" x))
6584(define (##sys#string->pbytevector s) (##core#inline "C_string_to_pbytevector" s))
6585(define (##sys#permanent? x) (##core#inline "C_permanentp" x))
6586(define (##sys#block-address x) (##core#inline_allocate ("C_block_address" 6) x))
6587(define (##sys#locative? x) (##core#inline "C_locativep" x))
6588
6589(define (##sys#srfi-4-vector? x)
6590  (or (##core#inline "C_i_srfi_4_vectorp" x)
6591      (and (##core#inline "C_blockp" x)
6592           (##core#inline "C_structurep" x)
6593           (let ((t (##sys#slot x 0)))
6594             (or (eq? t 'c64vector) (eq? t 'c128vector))))))
6595
6596(define (##sys#null-pointer)
6597  (let ([ptr (##sys#make-pointer)])
6598    (##core#inline "C_update_pointer" 0 ptr)
6599    ptr) )
6600
6601(define (##sys#null-pointer? x)
6602  (eq? 0 (##sys#pointer->address x)) )
6603
6604(define (##sys#address->pointer addr)
6605  (let ([ptr (##sys#make-pointer)])
6606    (##core#inline "C_update_pointer" addr ptr)
6607    ptr) )
6608
6609(define (##sys#pointer->address ptr)
6610  ;;XXX '6' is platform dependent!
6611  (##core#inline_allocate ("C_a_unsigned_int_to_num" 6) (##sys#slot ptr 0)) )
6612
6613(define (##sys#make-c-string str #!optional loc)
6614  (let ((bv (##sys#slot str 0)))
6615    (if (fx= (##core#inline "C_asciiz_strlen" bv) (fx- (##sys#size bv) 1))
6616        bv
6617        (##sys#error-hook (foreign-value "C_ASCIIZ_REPRESENTATION_ERROR" int)
6618                          loc str))) )
6619
6620(define ##sys#peek-signed-integer (##core#primitive "C_peek_signed_integer"))
6621(define ##sys#peek-unsigned-integer (##core#primitive "C_peek_unsigned_integer"))
6622(define (##sys#peek-fixnum b i) (##core#inline "C_peek_fixnum" b i))
6623(define (##sys#peek-byte ptr i) (##core#inline "C_peek_byte" ptr i))
6624
6625(define (##sys#vector->structure! vec) (##core#inline "C_vector_to_structure" vec))
6626
6627(define (##sys#peek-double b i)
6628  (##core#inline_allocate ("C_a_f64peek" 4) b i))
6629
6630(define (##sys#peek-c-string b i)
6631  (and (not (##sys#null-pointer? b))
6632       (##sys#peek-nonnull-c-string b i)))
6633
6634(define (##sys#peek-nonnull-c-string b i)
6635  (let* ([len (##core#inline "C_fetch_c_strlen" b i)]
6636	 [bv (##sys#make-bytevector (fx+ len 1) 0)] )
6637    (##core#inline "C_peek_c_string" b i bv len)
6638    (##sys#buffer->string! bv len)))
6639
6640(define (##sys#peek-and-free-c-string b i)
6641  (let ((str (##sys#peek-c-string b i)))
6642    (##core#inline "C_free_mptr" b i)
6643    str))
6644
6645(define (##sys#peek-and-free-nonnull-c-string b i)
6646  (let ((str (##sys#peek-nonnull-c-string b i)))
6647    (##core#inline "C_free_mptr" b i)
6648    str))
6649
6650(define (##sys#poke-c-string b i s)
6651  (##core#inline "C_poke_c_string" b i (##sys#make-c-string s) s) )
6652
6653(define (##sys#poke-integer b i n) (##core#inline "C_poke_integer" b i n))
6654(define (##sys#poke-double b i n) (##core#inline "C_poke_double" b i n))
6655
6656(define ##sys#peek-c-string-list
6657  (let ((fetch (foreign-lambda c-string "C_peek_c_string_at" c-pointer int)))
6658    (lambda (ptr n)
6659      (let loop ((i 0))
6660	(if (and n (fx>= i n))
6661	    '()
6662	    (let ((s (fetch ptr i)))
6663	      (if s
6664		  (cons s (loop (fx+ i 1)))
6665		  '() ) ) ) ) ) ) )
6666
6667(define ##sys#peek-and-free-c-string-list
6668  (let ((fetch (foreign-lambda c-string "C_peek_c_string_at" c-pointer int))
6669	(free (foreign-lambda void "C_free" c-pointer)))
6670    (lambda (ptr n)
6671      (let ((lst (let loop ((i 0))
6672		   (if (and n (fx>= i n))
6673		       '()
6674		       (let ((s (fetch ptr i)))
6675			 (cond (s
6676				(##core#inline "C_free_sptr" ptr i)
6677				(cons s (loop (fx+ i 1))) )
6678			       (else '() ) ) ) ) ) ) )
6679	(free ptr)
6680	lst) ) ) )
6681
6682(define (##sys#vector->closure! vec addr)
6683  (##core#inline "C_vector_to_closure" vec)
6684  (##core#inline "C_update_pointer" addr vec) )
6685
6686(define (##sys#symbol-has-toplevel-binding? s)
6687  (##core#inline "C_boundp" s))
6688
6689(define (##sys#block-pointer x)
6690  (let ([ptr (##sys#make-pointer)])
6691    (##core#inline "C_pointer_to_block" ptr x)
6692    ptr) )
6693
6694
6695;;; Support routines for foreign-function calling:
6696
6697(define (##sys#foreign-char-argument x) (##core#inline "C_i_foreign_char_argumentp" x))
6698(define (##sys#foreign-fixnum-argument x) (##core#inline "C_i_foreign_fixnum_argumentp" x))
6699(define (##sys#foreign-flonum-argument x) (##core#inline "C_i_foreign_flonum_argumentp" x))
6700(define (##sys#foreign-block-argument x) (##core#inline "C_i_foreign_block_argumentp" x))
6701
6702(define (##sys#foreign-cplxnum-argument x)
6703  (if (##core#inline "C_i_numberp" x)
6704	  (##core#inline_allocate ("C_a_i_exact_to_inexact" 12) x)
6705   	  (##sys#signal-hook
6706    	#:type-error #f "bad argument type - not a complex number"
6707	    x)))
6708
6709(define (##sys#foreign-struct-wrapper-argument t x)
6710  (##core#inline "C_i_foreign_struct_wrapper_argumentp" t x))
6711
6712(define (##sys#foreign-string-argument x) (##core#inline "C_i_foreign_string_argumentp" x))
6713(define (##sys#foreign-symbol-argument x) (##core#inline "C_i_foreign_symbol_argumentp" x))
6714(define (##sys#foreign-pointer-argument x) (##core#inline "C_i_foreign_pointer_argumentp" x))
6715(define (##sys#foreign-tagged-pointer-argument x tx) (##core#inline "C_i_foreign_tagged_pointer_argumentp" x tx))
6716
6717(define (##sys#foreign-ranged-integer-argument obj size)
6718  (##core#inline "C_i_foreign_ranged_integer_argumentp" obj size))
6719(define (##sys#foreign-unsigned-ranged-integer-argument obj size)
6720  (##core#inline "C_i_foreign_unsigned_ranged_integer_argumentp" obj size))
6721
6722(define (##sys#wrap-struct type rec)
6723  (##sys#setslot rec 0 type)
6724  rec)
6725
6726;;; Low-level threading interface:
6727
6728(define ##sys#default-thread-quantum 10000)
6729
6730(define (##sys#default-exception-handler arg)
6731  (##core#inline "C_halt" "internal error: default exception handler shouldn't be called!") )
6732
6733(define (##sys#make-thread thunk state name q)
6734  (##sys#make-structure
6735   'thread
6736   thunk				; #1 thunk
6737   #f					; #2 result list
6738   state				; #3 state
6739   #f					; #4 block-timeout
6740   (vector				; #5 state buffer
6741    ##sys#dynamic-winds
6742    ##sys#standard-input
6743    ##sys#standard-output
6744    ##sys#standard-error
6745    ##sys#default-exception-handler
6746    (##sys#vector-resize ##sys#current-parameter-vector
6747			 (##sys#size ##sys#current-parameter-vector) #f) )
6748   name					; #6 name
6749   (##core#undefined)			; #7 end-exception
6750   '()					; #8 owned mutexes
6751   q					; #9 quantum
6752   (##core#undefined)			; #10 specific
6753   #f					; #11 block object (type depends on blocking type)
6754   '()					; #12 recipients
6755   #f					; #13 unblocked by timeout?
6756   (cons #f #f)))            		; #14 ID (just needs to be unique)
6757
6758(define ##sys#primordial-thread
6759  (##sys#make-thread #f 'running 'primordial ##sys#default-thread-quantum))
6760
6761(define ##sys#current-thread ##sys#primordial-thread)
6762
6763(define (##sys#make-mutex id owner)
6764  (##sys#make-structure
6765   'mutex
6766   id					; #1 name
6767   owner				; #2 thread or #f
6768   '()					; #3 list of waiting threads
6769   #f					; #4 abandoned
6770   #f					; #5 locked
6771   (##core#undefined) ) )		; #6 specific
6772
6773(define (##sys#schedule) ((##sys#slot ##sys#current-thread 1)))
6774
6775(define (##sys#thread-yield!)
6776  (##sys#call-with-current-continuation
6777   (lambda (return)
6778     (let ((ct ##sys#current-thread))
6779       (##sys#setslot ct 1 (lambda () (return (##core#undefined))))
6780       (##sys#schedule) ) ) ) )
6781
6782(define (##sys#kill-other-threads thunk)
6783  (thunk))	     ; does nothing, will be modified by scheduler.scm
6784
6785;; these two procedures should redefined in thread APIs (e.g. srfi-18):
6786(define (##sys#resume-thread-on-event t) #f)
6787
6788(define (##sys#suspend-thread-on-event t)
6789  ;; wait until signal handler fires. If we are only waiting for a finalizer,
6790  ;; then this will wait forever:
6791  (##sys#sleep-until-interrupt))
6792
6793(define (##sys#sleep-until-interrupt)
6794  (##core#inline "C_i_sleep_until_interrupt" 100)
6795  (##sys#dispatch-interrupt (lambda _ #f)))
6796
6797
6798;;; event queues (for signals and finalizers)
6799
6800(define (##sys#make-event-queue)
6801  (##sys#make-structure 'event-queue
6802                        '() ; head
6803                        '() ; tail
6804                        #f)) ; suspended thread
6805
6806(define (##sys#add-event-to-queue! q e)
6807  (let ((h (##sys#slot q 1))
6808        (t (##sys#slot q 2))
6809        (item (cons e '())))
6810    (if (null? h)
6811        (##sys#setslot q 1 item)
6812        (##sys#setslot t 1 item))
6813    (##sys#setslot q 2 item)
6814    (let ((st (##sys#slot q 3))) ; thread suspended?
6815      (when st
6816        (##sys#setslot q 3 #f)
6817        (##sys#resume-thread-on-event st)))))
6818
6819(define (##sys#get-next-event q)
6820  (let ((st (##sys#slot q 3)))
6821    (and (not st)
6822         (let ((h (##sys#slot q 1)))
6823           (and (not (null? h))
6824                (let ((x (##sys#slot h 0))
6825                      (n (##sys#slot h 1)))
6826                  (##sys#setslot q 1 n)
6827                  (when (null? n) (##sys#setslot q 2 '()))
6828                  x))))))
6829
6830(define (##sys#wait-for-next-event q)
6831  (let ((st (##sys#slot q 3)))
6832    (when st
6833      (##sys#signal-hook #:runtime-error #f "event queue blocked" q))
6834    (let again ()
6835      (let ((h (##sys#slot q 1)))
6836        (cond ((null? h)
6837               (##sys#setslot q 3 ##sys#current-thread)
6838               (##sys#suspend-thread-on-event ##sys#current-thread)
6839               (again))
6840              (else
6841                (let ((x (##sys#slot h 0))
6842                      (n (##sys#slot h 1)))
6843                  (##sys#setslot q 1 n)
6844                  (when (null? n) (##sys#setslot q 2 '()))
6845                  x)))))))
6846
6847
6848;;; Sleeping:
6849
6850(define (chicken.base#sleep-hook n) ; modified by scheduler.scm
6851  (##core#inline "C_i_process_sleep" n))
6852
6853(set! chicken.base#sleep
6854  (lambda (n)
6855    (##sys#check-fixnum n 'sleep)
6856    (chicken.base#sleep-hook n)
6857    (##core#undefined)))
6858
6859
6860;;; Interrupt-handling:
6861
6862(define ##sys#context-switch (##core#primitive "C_context_switch"))
6863
6864(define ##sys#signal-vector (make-vector 256 #f))
6865
6866(define (##sys#interrupt-hook reason state)
6867  (let loop ((reason reason))
6868    (when reason
6869      (let ((handler (##sys#slot ##sys#signal-vector reason)))
6870	(when handler
6871	  (handler reason))
6872	(loop (##core#inline "C_i_pending_interrupt" #f)))))
6873    (cond ((fx> (##sys#slot ##sys#pending-finalizers 0) 0)
6874	   (##sys#run-pending-finalizers state) )
6875	  ((procedure? state) (state))
6876	  (else (##sys#context-switch state) ) ) )
6877
6878(define (##sys#dispatch-interrupt k)
6879  (##sys#interrupt-hook
6880   (##core#inline "C_i_pending_interrupt" #f)
6881   k))
6882
6883
6884;;; Accessing "errno":
6885
6886(define-foreign-variable _errno int "errno")
6887
6888(define ##sys#update-errno)
6889(define ##sys#errno)
6890
6891(let ((n 0))
6892  (set! ##sys#update-errno (lambda () (set! n _errno) n))
6893  (set! ##sys#errno (lambda () n)))
6894
6895
6896;;; Format error string for unterminated here-docs:
6897
6898(define (##sys#format-here-doc-warning end)
6899  (##sys#print-to-string `("unterminated here-doc string literal `" ,end "'")))
6900
6901;;; Special string quoting syntax:
6902
6903(set! ##sys#user-read-hook
6904  (let ([old ##sys#user-read-hook]
6905	[read read]
6906	[display display] )
6907    (define (readln port)
6908      (let ([ln (open-output-string)])
6909	(do ([c (##sys#read-char-0 port) (##sys#read-char-0 port)])
6910	    ((or (eof-object? c) (char=? #\newline c))
6911	     (if (eof-object? c) c (get-output-string ln)))
6912	  (##sys#write-char-0 c ln) ) ) )
6913    (define (read-escaped-sexp port skip-brace?)
6914      (when skip-brace? (##sys#read-char-0 port))
6915      (let* ((form (read port)))
6916	(when skip-brace?
6917	      (let loop ()
6918		;; Skips all characters until #\}
6919		(let ([c (##sys#read-char-0 port)])
6920		  (cond [(eof-object? c)
6921			 (##sys#read-error port "unexpected end of file - unterminated `#{...}' item in `here' string literal") ]
6922			[(not (char=? #\} c)) (loop)] ) ) ) )
6923	form))
6924    (lambda (char port)
6925      (cond [(not (char=? #\< char)) (old char port)]
6926	    [else
6927	     (read-char port)
6928	     (case (##sys#peek-char-0 port)
6929	       [(#\<)
6930		(##sys#read-char-0 port)
6931		(let ([str (open-output-string)]
6932		      [end (readln port)]
6933		      [f #f] )
6934		  (let ((endlen (if (eof-object? end) 0 (string-length end))))
6935		    (cond
6936		     ((fx= endlen 0)
6937		      (##sys#read-warning
6938		       port "Missing tag after #<< here-doc token"))
6939		     ((or (char=? (string-ref end (fx- endlen 1)) #\space)
6940			  (char=? (string-ref end (fx- endlen 1)) #\tab))
6941		      (##sys#read-warning
6942		       port "Whitespace after #<< here-doc tag"))
6943		     ))
6944		  (do ([ln (readln port) (readln port)])
6945		      ((or (eof-object? ln) (string=? end ln))
6946		       (when (eof-object? ln)
6947			 (##sys#read-warning port
6948			  (##sys#format-here-doc-warning end)))
6949		       (get-output-string str) )
6950		    (if f
6951			(##sys#write-char-0 #\newline str)
6952			(set! f #t) )
6953		    (display ln str) ) ) ]
6954	       [(#\#)
6955		(##sys#read-char-0 port)
6956		(let ([end (readln port)]
6957		      [str (open-output-string)] )
6958		  (define (get/clear-str)
6959		    (let ((s (get-output-string str)))
6960		      (set! str (open-output-string))
6961		      s))
6962
6963		  (let ((endlen (if (eof-object? end) 0 (string-length end))))
6964		    (cond
6965		     ((fx= endlen 0)
6966		      (##sys#read-warning
6967		       port "Missing tag after #<# here-doc token"))
6968		     ((or (char=? (string-ref end (fx- endlen 1)) #\space)
6969			  (char=? (string-ref end (fx- endlen 1)) #\tab))
6970		      (##sys#read-warning
6971		       port "Whitespace after #<# here-doc tag"))
6972		     ))
6973
6974		  (let loop [(lst '())]
6975		    (let ([c (##sys#read-char-0 port)])
6976		      (case c
6977			[(#\newline #!eof)
6978			 (let ([s (get/clear-str)])
6979			   (cond [(or (eof-object? c) (string=? end s))
6980				  (when (eof-object? c)
6981				    (##sys#read-warning
6982				     port (##sys#format-here-doc-warning end)))
6983				  `(##sys#print-to-string
6984				    ;;Can't just use `(list ,@lst) because of 126 argument apply limit
6985				    ,(let loop2 ((lst (cdr lst)) (next-string '()) (acc ''())) ; drop last newline
6986				       (cond ((null? lst)
6987					      `(cons ,(##sys#print-to-string next-string) ,acc))
6988					     ((or (string? (car lst)) (char? (car lst)))
6989					      (loop2 (cdr lst) (cons (car lst) next-string) acc))
6990					     (else
6991					      (loop2 (cdr lst)
6992						     '()
6993						     `(cons ,(car lst)
6994							    (cons ,(##sys#print-to-string next-string) ,acc))))))) ]
6995				 [else (loop (cons #\newline (cons s lst)))] ) ) ]
6996			[(#\#)
6997			 (let ([c (##sys#peek-char-0 port)])
6998			   (case c
6999			     [(#\#)
7000			      (##sys#write-char-0 (##sys#read-char-0 port) str)
7001			      (loop lst) ]
7002			     [(#\{) (loop (cons (read-escaped-sexp port #t)
7003						(cons (get/clear-str) lst) ) ) ]
7004			     [else  (loop (cons (read-escaped-sexp port #f)
7005						(cons (get/clear-str) lst) ) ) ] ) ) ]
7006			[else
7007			 (##sys#write-char-0 c str)
7008			 (loop lst) ] ) ) ) ) ]
7009	       [else (##sys#read-error port "unreadable object")] ) ] ) ) ) )
7010
7011
7012;;; Accessing process information (cwd, environ, etc.)
7013
7014#>
7015#if defined(_WIN32) && !defined(__CYGWIN__)
7016#include <direct.h>
7017
7018static C_word C_chdir(C_word str) {
7019	return C_fix(_wchdir(C_utf16(str, 0)));
7020}
7021
7022static C_word C_curdir(C_word buf, C_word size) {
7023	C_WCHAR *cwd = _wgetcwd((C_WCHAR *)C_c_string(buf), C_unfix(size));
7024        if(cwd == NULL) return C_SCHEME_FALSE;
7025	C_char *up = C_utf8(cwd);
7026	C_char *p = up;
7027	while(*p) {
7028		*p = *p == '\\' ? '/' : *p;
7029		++p;
7030	}
7031	int len = C_strlen(up);
7032	C_memcpy(cwd, up, len + 1);
7033        return C_fix(len);
7034}
7035#else
7036# define C_chdir(str) C_fix(chdir(C_c_string(str)))
7037# define C_curdir(buf, size) (getcwd(C_c_string(buf), size) ? C_fix(strlen(C_c_string(buf))) : C_SCHEME_FALSE)
7038#endif
7039
7040<#
7041
7042(module chicken.process-context
7043  (argv argc+argv command-line-arguments
7044   program-name executable-pathname
7045   change-directory current-directory
7046   get-environment-variable get-environment-variables
7047   set-environment-variable! unset-environment-variable!)
7048
7049(import scheme)
7050(import chicken.base chicken.fixnum chicken.foreign)
7051(import chicken.internal.syntax)
7052(import (only (scheme base) make-parameter))
7053
7054;;; Current directory access:
7055
7056(define (change-directory name)
7057  (##sys#check-string name 'change-directory)
7058  (let ((sname (##sys#make-c-string name 'change-directory)))
7059    (unless (fx= (##core#inline "C_chdir" sname) 0)
7060      (##sys#signal-hook/errno #:file-error (##sys#update-errno) 'change-directory
7061       (string-append "cannot change current directory - " strerror) name))
7062    name))
7063
7064(define (##sys#change-directory-hook dir) ; set! by posix for fd support
7065  (change-directory dir))
7066
7067(define current-directory
7068  (getter-with-setter
7069    (lambda ()
7070      (let* ((buffer-size (foreign-value "C_MAX_PATH" size_t))
7071             (buffer (##sys#make-bytevector buffer-size))
7072             (len (##core#inline "C_curdir" buffer buffer-size)))
7073        (unless ##sys#windows-platform ; FIXME need `cond-expand' here
7074          (##sys#update-errno))
7075        (if len
7076            (##sys#buffer->string buffer 0 len)
7077            (##sys#signal-hook/errno
7078             #:file-error
7079             (##sys#errno)
7080             'current-directory "cannot retrieve current directory"))))
7081    (lambda (dir)
7082      (##sys#change-directory-hook dir))
7083    "(chicken.process-context#current-directory)"))
7084
7085
7086;;; Environment access:
7087
7088(define _getenv
7089  (foreign-lambda c-string "C_getenv" scheme-object))
7090
7091(define (get-environment-variable var)
7092  (_getenv (##sys#make-c-string var 'get-environment-variable)))
7093
7094(define get-environment-entry
7095  (foreign-lambda c-string* "C_getenventry" int))
7096
7097(define (set-environment-variable! var val)
7098  (##sys#check-string var 'set-environment-variable!)
7099  (##core#inline "C_i_setenv"
7100   (##sys#make-c-string var 'set-environment-variable!)
7101   (and val
7102        (begin
7103          (##sys#check-string val 'set-environment-variable!)
7104          (##sys#make-c-string val 'set-environment-variable!))))
7105  (##core#undefined))
7106
7107(define (unset-environment-variable! var)
7108  (##sys#check-string var 'unset-environment-variable!)
7109  (##core#inline "C_i_setenv"
7110   (##sys#make-c-string var 'unset-environment-variable!)
7111   #f)
7112  (##core#undefined))
7113
7114(define get-environment-variables
7115   (lambda ()
7116      (let loop ((i 0))
7117        (let ((entry (get-environment-entry i)))
7118          (if entry
7119              (let scan ((j 0))
7120                (if (char=? #\= (string-ref entry j))
7121                    (cons (cons (##sys#substring entry 0 j)
7122                                (##sys#substring entry (fx+ j 1) (string-length entry)))
7123                          (loop (fx+ i 1)))
7124                    (scan (fx+ j 1))))
7125              '())))))
7126
7127
7128;;; Command line handling
7129
7130(define-foreign-variable main_argc int "C_main_argc")
7131(define-foreign-variable main_argv c-pointer "C_main_argv")
7132
7133(define executable-pathname
7134  (foreign-lambda c-string* "C_executable_pathname"))
7135
7136(define (argc+argv)
7137  (##sys#values main_argc main_argv))
7138
7139(define argv				; includes program name
7140  (let ((cache #f)
7141        (fetch-arg (foreign-lambda* c-string ((scheme-object i))
7142                     "C_return(C_main_argv[C_unfix(i)]);")))
7143    (lambda ()
7144      (unless cache
7145        (set! cache (do ((i (fx- main_argc 1) (fx- i 1))
7146                         (v '() (cons (fetch-arg i) v)))
7147                        ((fx< i 0) v))))
7148      cache)))
7149
7150(define program-name
7151  (make-parameter
7152   (if (null? (argv))
7153       "<unknown>" ; may happen if embedded in C application
7154       (car (argv)))
7155   (lambda (x)
7156     (##sys#check-string x 'program-name)
7157     x) ) )
7158
7159(define command-line-arguments
7160  (make-parameter
7161   (let ((args (argv)))
7162     (if (pair? args)
7163	 (let loop ((args (##sys#slot args 1)))	; Skip over program name (argv[0])
7164	   (if (null? args)
7165	       '()
7166	       (let ((arg (##sys#slot args 0))
7167		     (rest (##sys#slot args 1)) )
7168		 (cond
7169		  ((string=? "-:" arg)	; Consume first "empty" runtime options list, return rest
7170		   rest)
7171
7172		  ((and (fx>= (string-length arg) 3)
7173			(string=? "-:" (##sys#substring arg 0 2)))
7174		   (loop rest))
7175
7176		  ;; First non-runtime option and everything following it is returned as-is
7177		  (else args) ) ) ) )
7178	 args) )
7179   (lambda (x)
7180     (##sys#check-list x 'command-line-arguments)
7181     x) ) )
7182
7183) ; chicken.process-context
7184
7185
7186(module chicken.gc
7187    (current-gc-milliseconds gc memory-statistics
7188     set-finalizer! make-finalizer add-to-finalizer
7189     set-gc-report! force-finalizers)
7190
7191(import scheme)
7192(import chicken.base chicken.fixnum chicken.foreign)
7193(import chicken.internal.syntax)
7194(import (only (scheme base) make-parameter))
7195
7196;;; GC info:
7197
7198(define (current-gc-milliseconds)
7199  (##core#inline "C_i_accumulated_gc_time"))
7200
7201(define (set-gc-report! flag)
7202  (##core#inline "C_set_gc_report" flag))
7203
7204;;; Memory info:
7205
7206(define (memory-statistics)
7207  (let* ((free (##sys#gc #t))
7208	 (info (##sys#memory-info))
7209	 (half-size (fx/ (##sys#slot info 0) 2)))
7210    (vector half-size (fx- half-size free) (##sys#slot info 1))))
7211
7212;;; Finalization:
7213
7214(define-foreign-variable _max_pending_finalizers int "C_max_pending_finalizers")
7215
7216(define ##sys#pending-finalizers
7217  (##sys#make-vector (fx+ (fx* 2 _max_pending_finalizers) 1) (##core#undefined)) )
7218
7219(##sys#setislot ##sys#pending-finalizers 0 0)
7220
7221(define ##sys#set-finalizer! (##core#primitive "C_register_finalizer"))
7222
7223(define ##sys#init-finalizer
7224  (let ((string-append string-append))
7225    (lambda (x y)
7226      (when (fx>= (##core#inline "C_i_live_finalizer_count") _max_pending_finalizers)
7227	(cond ((##core#inline "C_resize_pending_finalizers" (fx* 2 _max_pending_finalizers))
7228	       (set! ##sys#pending-finalizers
7229		 (##sys#vector-resize ##sys#pending-finalizers
7230				      (fx+ (fx* 2 _max_pending_finalizers) 1)
7231				      (##core#undefined)))
7232	       (when (##sys#debug-mode?)
7233		 (##sys#print
7234		  (string-append
7235		   "[debug] too many finalizers ("
7236		   (##sys#number->string
7237		    (##core#inline "C_i_live_finalizer_count"))
7238		   "), resized max finalizers to "
7239		   (##sys#number->string _max_pending_finalizers)
7240		   "\n")
7241		  #f ##sys#standard-error)))
7242	      (else
7243	       (when (##sys#debug-mode?)
7244		 (##sys#print
7245		  (string-append
7246		   "[debug] too many finalizers ("
7247		   (##core#inline "C_i_live_finalizer_count")
7248		   "), forcing ...\n")
7249		  #f ##sys#standard-error))
7250	       (##sys#force-finalizers) ) ) )
7251      (##sys#set-finalizer! x y) ) ) )
7252
7253(define set-finalizer! ##sys#init-finalizer)
7254
7255(define finalizer-tag (vector 'finalizer))
7256
7257(define (finalizer? x)
7258  (and (pair? x) (eq? finalizer-tag (##sys#slot x 0))) )
7259
7260(define (make-finalizer . objects)
7261  (let ((q (##sys#make-event-queue)))
7262    (define (handler o) (##sys#add-event-to-queue! q o))
7263    (define (handle o) (##sys#init-finalizer o handler))
7264    (for-each handle objects)
7265    (##sys#decorate-lambda
7266       (lambda (#!optional mode)
7267         (if mode
7268             (##sys#wait-for-next-event q)
7269             (##sys#get-next-event q)))
7270       finalizer?
7271       (lambda (proc i)
7272         (##sys#setslot proc i (cons finalizer-tag handle))
7273         proc))))
7274
7275(define (add-to-finalizer f . objects)
7276  (let ((af (and (procedure? f)
7277                 (##sys#lambda-decoration f finalizer?))))
7278    (unless af
7279      (error 'add-to-finalizer "bad argument type - not a finalizer procedure"
7280             f))
7281    (for-each (cdr af) objects)))
7282
7283(define ##sys#run-pending-finalizers
7284  (let ((vector-fill! vector-fill!)
7285	(string-append string-append)
7286	(working-thread #f) )
7287    (lambda (state)
7288      (cond
7289       ((not working-thread)
7290	(set! working-thread ##sys#current-thread)
7291	(let* ((c (##sys#slot ##sys#pending-finalizers 0)) )
7292	  (when (##sys#debug-mode?)
7293	    (##sys#print
7294	     (string-append "[debug] running " (##sys#number->string c)
7295			    " finalizer(s) ("
7296			    (##sys#number->string
7297			     (##core#inline "C_i_live_finalizer_count"))
7298			    " live, "
7299			    (##sys#number->string
7300			     (##core#inline "C_i_allocated_finalizer_count"))
7301			    " allocated) ...\n")
7302	     #f ##sys#standard-error))
7303	  (do ([i 0 (fx+ i 1)])
7304	      ((fx>= i c))
7305	    (let ([i2 (fx+ 1 (fx* i 2))])
7306	      (handle-exceptions ex
7307		  (##sys#show-exception-warning ex "in finalizer" #f)
7308		((##sys#slot ##sys#pending-finalizers (fx+ i2 1))
7309		 (##sys#slot ##sys#pending-finalizers i2)) ) ))
7310	  (vector-fill! ##sys#pending-finalizers (##core#undefined))
7311	  (##sys#setislot ##sys#pending-finalizers 0 0)
7312	  (set! working-thread #f)))
7313       (state)         ; Got here due to interrupt; continue w/o error
7314       ((eq? working-thread ##sys#current-thread)
7315	 (##sys#signal-hook
7316	  #:error '##sys#run-pending-finalizers
7317	  "re-entry from finalizer thread (maybe (gc #t) was called from a finalizer)"))
7318       (else
7319	;; Give finalizer thread a change to run
7320	(##sys#thread-yield!)))
7321      (cond ((not state))
7322	    ((procedure? state) (state))
7323	    (state (##sys#context-switch state) ) ) ) ))
7324
7325(define force-finalizers (make-parameter #t))
7326
7327(define (##sys#force-finalizers)
7328  (let loop ()
7329    (let ([n (##sys#gc)])
7330      (cond ((fx> (##sys#slot ##sys#pending-finalizers 0) 0)
7331	     (##sys#run-pending-finalizers #f)
7332	     (loop) )
7333	    (else n) ) ) ))
7334
7335(define (gc . arg)
7336  (let ((a (and (pair? arg) (car arg))))
7337    (if a
7338	(##sys#force-finalizers)
7339	(##sys#gc a)))))
7340
7341;;; Auxilliary definitions for safe use in quasiquoted forms and evaluated code:
7342
7343(define ##sys#list->vector list->vector)
7344(define ##sys#list list)
7345(define ##sys#length length)
7346(define ##sys#cons cons)
7347(define ##sys#append append)
7348(define ##sys#vector vector)
7349(define ##sys#apply apply)
7350(define ##sys#values values)
7351(define ##sys#equal? equal?)
7352(define ##sys#car car)
7353(define ##sys#cdr cdr)
7354(define ##sys#pair? pair?)
7355(define ##sys#vector? vector?)
7356(define ##sys#vector->list vector->list)
7357(define ##sys#vector-length vector-length)
7358(define ##sys#vector-ref vector-ref)
7359(define ##sys#>= >=)
7360(define ##sys#= =)
7361(define ##sys#+ +)
7362(define ##sys#eq? eq?)
7363(define ##sys#eqv? eqv?)
7364(define ##sys#list? list?)
7365(define ##sys#null? null?)
7366(define ##sys#map-n map)
7367
7368;;; We need this here so `location' works:
7369
7370(define (##sys#make-locative obj index weak? loc)
7371  (cond [(##sys#immediate? obj)
7372	 (##sys#signal-hook #:type-error loc "locative cannot refer to immediate object" obj) ]
7373	[(or (vector? obj) (pair? obj))
7374	 (##sys#check-range index 0 (##sys#size obj) loc)
7375	 (##core#inline_allocate ("C_a_i_make_locative" 5) 0 obj index weak?) ]
7376	[(and (##core#inline "C_blockp" obj)
7377	      (##core#inline "C_bytevectorp" obj) )
7378	 (##sys#check-range index 0 (##sys#size obj) loc)
7379	 (##core#inline_allocate ("C_a_i_make_locative" 5) 2 obj index weak?) ]
7380	[(##sys#generic-structure? obj)
7381	 (case (##sys#slot obj 0)
7382	   ((u8vector)
7383	    (let ([v (##sys#slot obj 1)])
7384	      (##sys#check-range index 0 (##sys#size v) loc)
7385	      (##core#inline_allocate ("C_a_i_make_locative" 5) 2 v index weak?))  )
7386	   ((s8vector)
7387	    (let ([v (##sys#slot obj 1)])
7388	      (##sys#check-range index 0 (##sys#size v) loc)
7389	      (##core#inline_allocate ("C_a_i_make_locative" 5) 3 v index weak?) ) )
7390	   ((u16vector)
7391	    (let ([v (##sys#slot obj 1)])
7392	      (##sys#check-range index 0 (##sys#size v) loc)
7393	      (##core#inline_allocate ("C_a_i_make_locative" 5) 4 v index weak?) ) )
7394	   ((s16vector)
7395	    (let ([v (##sys#slot obj 1)])
7396	      (##sys#check-range index 0 (##sys#size v) loc)
7397	      (##core#inline_allocate ("C_a_i_make_locative" 5) 5 v index weak?) ) )
7398	   ((u32vector)
7399	    (let ([v (##sys#slot obj 1)])
7400	      (##sys#check-range index 0 (##sys#size v) loc)
7401	      (##core#inline_allocate ("C_a_i_make_locative" 5) 6 v index weak?) ) )
7402	   ((s32vector)
7403	    (let ([v (##sys#slot obj 1)])
7404	      (##sys#check-range index 0 (##sys#size v) loc)
7405	      (##core#inline_allocate ("C_a_i_make_locative" 5) 7 v index weak?) ) )
7406	   ((u64vector)
7407	    (let ([v (##sys#slot obj 1)])
7408	      (##sys#check-range index 0 (##sys#size v) loc)
7409	      (##core#inline_allocate ("C_a_i_make_locative" 5) 8 v index weak?) ) )
7410	   ((s64vector)
7411	    (let ([v (##sys#slot obj 1)])
7412	      (##sys#check-range index 0 (##sys#size v) loc)
7413	      (##core#inline_allocate ("C_a_i_make_locative" 5) 9 v index weak?) ) )
7414	   ((f32vector)
7415	    (let ([v (##sys#slot obj 1)])
7416	      (##sys#check-range index 0 (##sys#size v) loc)
7417	      (##core#inline_allocate ("C_a_i_make_locative" 5) 10 v index weak?) ) )
7418	   ((f64vector)
7419	    (let ([v (##sys#slot obj 1)])
7420	      (##sys#check-range index 0 (##sys#size v) loc)
7421	      (##core#inline_allocate ("C_a_i_make_locative" 5) 11 v index weak?) ) )
7422	   ;;XXX pointer-vector currently not supported
7423	   (else
7424	    (##sys#check-range index 0 (fx- (##sys#size obj) 1) loc)
7425	    (##core#inline_allocate ("C_a_i_make_locative" 5) 0 obj (fx+ index 1) weak?) ) ) ]
7426	((string? obj)
7427	 (let ((bv (##sys#slot obj 0))
7428               (p (##core#inline "C_utf_position" obj index)))
7429           (##sys#check-range index 0 (##sys#slot obj 1) loc)
7430  	   (##core#inline_allocate ("C_a_i_make_locative" 5) 1 bv p weak?) ) )
7431	[else
7432	 (##sys#signal-hook
7433	  #:type-error loc
7434	  "bad argument type - locative cannot refer to objects of this type"
7435	  obj) ] ) )
7436
7437
7438;;; Property lists
7439
7440(module chicken.plist
7441  (get get-properties put! remprop! symbol-plist)
7442
7443(import scheme)
7444(import (only chicken.base getter-with-setter))
7445(import chicken.internal.syntax)
7446
7447(define (put! sym prop val)
7448  (##sys#check-symbol sym 'put!)
7449  (##core#inline_allocate ("C_a_i_putprop" 8) sym prop val) )
7450
7451(define (get sym prop #!optional default)
7452  (##sys#check-symbol sym 'get)
7453  (##core#inline "C_i_getprop" sym prop default))
7454
7455(define ##sys#put! put!)
7456(define ##sys#get get)
7457
7458(set! get (getter-with-setter get put!))
7459
7460(define (remprop! sym prop)
7461  (##sys#check-symbol sym 'remprop!)
7462  (let loop ((plist (##sys#slot sym 2)) (ptl #f))
7463    (and (not (null? plist))
7464	 (let* ((tl (##sys#slot plist 1))
7465		(nxt (##sys#slot tl 1)))
7466	   (or (and (eq? (##sys#slot plist 0) prop)
7467		    (begin
7468		      (if ptl
7469			  (##sys#setslot ptl 1 nxt)
7470			  (##sys#setslot sym 2 nxt) )
7471		      #t ) )
7472	       (loop nxt tl) ) ) ) )
7473  (when (null? (##sys#slot sym 2))
7474    ;; This will only unpersist if symbol is also unbound
7475    (##core#inline "C_i_unpersist_symbol" sym) ) )
7476
7477(define symbol-plist
7478  (getter-with-setter
7479   (lambda (sym)
7480     (##sys#check-symbol sym 'symbol-plist)
7481     (##sys#slot sym 2) )
7482   (lambda (sym lst)
7483     (##sys#check-symbol sym 'symbol-plist)
7484     (##sys#check-list lst 'symbol-plist/setter)
7485     (if (##core#inline "C_i_fixnumevenp" (##core#inline "C_i_length" lst))
7486	 (##sys#setslot sym 2 lst)
7487	 (##sys#signal-hook
7488	  #:type-error "property-list must be of even length"
7489	  lst sym))
7490     (if (null? lst)
7491	 (##core#inline "C_i_unpersist_symbol" sym)
7492	 (##core#inline "C_i_persist_symbol" sym)))
7493   "(chicken.plist#symbol-plist sym)"))
7494
7495(define (get-properties sym props)
7496  (##sys#check-symbol sym 'get-properties)
7497  (unless (pair? props)
7498    (set! props (list props)) )
7499  (let loop ((plist (##sys#slot sym 2)))
7500    (if (null? plist)
7501	(values #f #f #f)
7502	(let* ((prop (##sys#slot plist 0))
7503	       (tl (##sys#slot plist 1))
7504	       (nxt (##sys#slot tl 1)))
7505	  (if (memq prop props)
7506	      (values prop (##sys#slot tl 0) nxt)
7507	      (loop nxt) ) ) ) ) )
7508
7509) ; chicken.plist
7510
7511
7512;;; Print timing information (support for "time" macro):
7513
7514(define (##sys#display-times info)
7515  (define (pstr str) (##sys#print str #f ##sys#standard-error))
7516  (define (pchr chr) (##sys#write-char-0 chr ##sys#standard-error))
7517  (define (pnum num)
7518    (##sys#print (if (zero? num) "0" (##sys#number->string num)) #f ##sys#standard-error))
7519  (define (round-to x y) ; Convert to fp with y digits after the point
7520    (/ (round (* x (expt 10 y))) (expt 10.0 y)))
7521  (define (pmem bytes)
7522    (cond ((> bytes (expt 1024 3))
7523	   (pnum (round-to (/ bytes (expt 1024 3)) 2)) (pstr " GiB"))
7524	  ((> bytes (expt 1024 2))
7525	   (pnum (round-to (/ bytes (expt 1024 2)) 2)) (pstr " MiB"))
7526	  ((> bytes 1024)
7527	   (pnum (round-to (/ bytes 1024) 2)) (pstr " KiB"))
7528	  (else (pnum bytes) (pstr " bytes"))))
7529  (##sys#flush-output ##sys#standard-output)
7530  (pnum (##sys#slot info 0))
7531  (pstr "s CPU time")
7532  (let ((gctime (##sys#slot info 1)))
7533    (when (> gctime 0)
7534      (pstr ", ")
7535      (pnum gctime)
7536      (pstr "s GC time (major)")))
7537  (let ((mut (##sys#slot info 2))
7538	(umut (##sys#slot info 3)))
7539    (when (fx> mut 0)
7540      (pstr ", ")
7541      (pnum mut)
7542      (pchr #\/)
7543      (pnum umut)
7544      (pstr " mutations (total/tracked)")))
7545  (let ((minor (##sys#slot info 4))
7546	(major (##sys#slot info 5)))
7547    (when (or (fx> minor 0) (fx> major 0))
7548      (pstr ", ")
7549      (pnum major)
7550      (pchr #\/)
7551      (pnum minor)
7552      (pstr " GCs (major/minor)")))
7553  (let ((maximum-heap-usage (##sys#slot info 6)))
7554    (pstr ", maximum live heap: ")
7555    (pmem maximum-heap-usage))
7556  (##sys#write-char-0 #\newline ##sys#standard-error)
7557  (##sys#flush-output ##sys#standard-error))
7558
7559
7560;;; Dump heap state to stderr:
7561
7562(define ##sys#dump-heap-state (##core#primitive "C_dump_heap_state"))
7563(define ##sys#filter-heap-objects (##core#primitive "C_filter_heap_objects"))
7564
7565
7566;;; Platform configuration inquiry:
7567
7568(module chicken.platform
7569    (build-platform chicken-version chicken-home
7570     feature? machine-byte-order machine-type
7571     repository-path installation-repository
7572     register-feature! unregister-feature! include-path
7573     software-type software-version return-to-host
7574     system-config-directory system-cache-directory
7575     )
7576
7577(import scheme)
7578(import chicken.fixnum chicken.foreign chicken.keyword chicken.process-context)
7579(import chicken.internal.syntax)
7580(import (only (scheme base) make-parameter))
7581
7582(define software-type
7583  (let ((sym (string->symbol ((##core#primitive "C_software_type")))))
7584    (lambda () sym)))
7585
7586(define machine-type
7587  (let ((sym (string->symbol ((##core#primitive "C_machine_type")))))
7588    (lambda () sym)))
7589
7590(define machine-byte-order
7591  (let ((sym (string->symbol ((##core#primitive "C_machine_byte_order")))))
7592    (lambda () sym)))
7593
7594(define software-version
7595  (let ((sym (string->symbol ((##core#primitive "C_software_version")))))
7596    (lambda () sym)))
7597
7598(define build-platform
7599  (let ((sym (string->symbol ((##core#primitive "C_build_platform")))))
7600    (lambda () sym)))
7601
7602(define ##sys#windows-platform
7603  (and (eq? 'windows (software-type))
7604       ;; Still windows even if 'Linux-like'
7605       (not (eq? 'cygwin (software-version)))))
7606
7607(define (chicken-version #!optional full)
7608  (define (get-config)
7609    (let ((bp (build-platform))
7610	  (st (software-type))
7611	  (sv (software-version))
7612	  (mt (machine-type)))
7613      (define (str x)
7614	(if (eq? 'unknown x)
7615	    ""
7616	    (string-append (symbol->string x) "-")))
7617      (string-append (str sv) (str st) (str bp) (##sys#symbol->string/shared mt))))
7618  (if full
7619      (let ((spec (string-append
7620		   " " (number->string (foreign-value "C_WORD_SIZE" int)) "bit"
7621		   (if (feature? #:dload) " dload" "")
7622		   (if (feature? #:ptables) " ptables" "")
7623		   (if (feature? #:gchooks) " gchooks" "")
7624		   (if (feature? #:cross-chicken) " cross" ""))))
7625	(string-append
7626	 "Version " ##sys#build-version
7627	 (if ##sys#build-branch (string-append " (" ##sys#build-branch ")") "")
7628	 (if ##sys#build-id (string-append " (rev " ##sys#build-id ")") "")
7629	 "\n"
7630	 (get-config)
7631	 (if (zero? (string-length spec))
7632	     ""
7633	     (string-append " [" spec " ]"))))
7634      ##sys#build-version))
7635
7636;;; Installation locations
7637
7638(define-foreign-variable binary-version int "C_BINARY_VERSION")
7639(define-foreign-variable installation-home c-string "C_INSTALL_SHARE_HOME")
7640(define-foreign-variable install-egg-home c-string "C_INSTALL_EGG_HOME")
7641
7642;; DEPRECATED
7643(define (chicken-home) installation-home)
7644
7645(define (include-path #!optional new)
7646  (when new
7647    (##sys#check-list new 'include-path)
7648    (set! ##sys#include-pathnames new))
7649  ##include-pathnames)
7650
7651(define path-list-separator
7652  (if ##sys#windows-platform #\; #\:))
7653
7654(define ##sys#split-path
7655  (let ((cache '(#f)))
7656    (lambda (path)
7657      (cond ((not path) '())
7658            ((equal? path (car cache))
7659             (cdr cache))
7660            (else
7661              (let* ((len (string-length path))
7662                     (lst (let loop ((start 0) (pos 0))
7663                            (cond ((fx>= pos len)
7664                                   (if (fx= pos start)
7665                                       '()
7666                                       (list (substring path start pos))))
7667                                  ((char=? (string-ref path pos)
7668                                           path-list-separator)
7669                                   (cons (substring path start pos)
7670                                         (loop (fx+ pos 1)
7671                                               (fx+ pos 1))))
7672                                  (else
7673                                    (loop start (fx+ pos 1)))))))
7674                (set! cache (cons path lst))
7675                lst))))))
7676
7677(define repository-path
7678  (make-parameter
7679   (cond ((foreign-value "C_private_repository_path()" c-string)
7680           => list)
7681         ((get-environment-variable "CHICKEN_REPOSITORY_PATH")
7682           => ##sys#split-path)
7683         (install-egg-home
7684           => list)
7685         (else #f))
7686   (lambda (new)
7687     (and new
7688          (begin
7689            (##sys#check-list new 'repository-path)
7690            (for-each (lambda (p) (##sys#check-string p 'repository-path)) new)
7691            new)))))
7692
7693(define installation-repository
7694  (make-parameter
7695   (or (foreign-value "C_private_repository_path()" c-string)
7696       (get-environment-variable "CHICKEN_INSTALL_REPOSITORY")
7697       install-egg-home)))
7698
7699(define (chop-separator str)
7700  (let ((len (fx- (string-length str) 1)))
7701    (if (and (> len 0)
7702             (memq (string-ref str len) '(#\\ #\/)))
7703        (substring str 0 len)
7704        str) ) )
7705
7706(define ##sys#include-pathnames
7707  (cond ((get-environment-variable "CHICKEN_INCLUDE_PATH")
7708         => (lambda (p)
7709              (map chop-separator (##sys#split-path p))))
7710        (else (list installation-home))))
7711
7712(define (include-path) ##sys#include-pathnames)
7713
7714
7715;;; Feature identifiers:
7716
7717(define ->feature-id ; TODO: export this?  It might be useful..
7718  (let ()
7719    (define (err . args)
7720      (apply ##sys#signal-hook #:type-error "bad argument type - not a valid feature identifer" args))
7721    (define (prefix s)
7722      (if s (##sys#string-append s "-") ""))
7723    (lambda (x)
7724      (cond ((keyword? x) x)
7725	    ((string? x) (string->keyword x))
7726	    ((symbol? x) (string->keyword (##sys#symbol->string/shared x)))
7727	    (else (err x))))))
7728
7729(define ##sys#features
7730  '(#:chicken
7731    #:srfi-6 #:srfi-12 #:srfi-17 #:srfi-23 #:srfi-30
7732    #:exact-complex #:srfi-39 #:srfi-62 #:srfi-88 #:full-numeric-tower #:full-unicode))
7733
7734;; Add system features:
7735
7736;; all platforms we support have this
7737(set! ##sys#features `(#:posix #:r7rs #:ieee-float #:ratios ,@##sys#features))
7738
7739(let ((check (lambda (f)
7740	       (unless (eq? 'unknown f)
7741		 (set! ##sys#features (cons (->feature-id f) ##sys#features))))))
7742  (check (software-type))
7743  (check (software-version))
7744  (check (build-platform))
7745  (check (machine-type))
7746  (check (machine-byte-order)))
7747
7748(when (foreign-value "HAVE_DLOAD" bool)
7749  (set! ##sys#features (cons #:dload ##sys#features)))
7750(when (foreign-value "HAVE_PTABLES" bool)
7751  (set! ##sys#features (cons #:ptables ##sys#features)))
7752(when (foreign-value "HAVE_GCHOOKS" bool)
7753  (set! ##sys#features (cons #:gchooks ##sys#features)))
7754(when (foreign-value "IS_CROSS_CHICKEN" bool)
7755  (set! ##sys#features (cons #:cross-chicken ##sys#features)))
7756
7757;; Register a feature to represent the word size (e.g., 32bit, 64bit)
7758(set! ##sys#features
7759      (cons (string->keyword
7760             (string-append
7761              (number->string (foreign-value "C_WORD_SIZE" int))
7762              "bit"))
7763            ##sys#features))
7764
7765(set! ##sys#features
7766  (let ((major (##sys#number->string (foreign-value "C_MAJOR_VERSION" int)))
7767	(minor (##sys#number->string (foreign-value "C_MINOR_VERSION" int))))
7768    (cons (->feature-id (string-append "chicken-" major))
7769	  (cons (->feature-id (string-append "chicken-" major "." minor))
7770		##sys#features))))
7771
7772(define (register-feature! . fs)
7773  (for-each
7774   (lambda (f)
7775     (let ((id (->feature-id f)))
7776       (unless (memq id ##sys#features) (set! ##sys#features (cons id ##sys#features)))))
7777   fs)
7778  (##core#undefined))
7779
7780(define (unregister-feature! . fs)
7781  (let ((fs (map ->feature-id fs)))
7782    (set! ##sys#features
7783      (let loop ((ffs ##sys#features))
7784	(if (null? ffs)
7785	    '()
7786	    (let ((f (##sys#slot ffs 0))
7787		  (r (##sys#slot ffs 1)))
7788	      (if (memq f fs)
7789		  (loop r)
7790		  (cons f (loop r)))))))
7791    (##core#undefined)))
7792
7793(define (feature? . ids)
7794  (let loop ((ids ids))
7795    (or (null? ids)
7796	(and (memq (->feature-id (##sys#slot ids 0)) ##sys#features)
7797	     (loop (##sys#slot ids 1))))))
7798
7799(define return-to-host
7800  (##core#primitive "C_return_to_host"))
7801
7802(define (system-config-directory)
7803  (or (get-environment-variable "XDG_CONFIG_HOME")
7804      (if ##sys#windows-platform
7805          (get-environment-variable "APPDATA")
7806          (let ((home (get-environment-variable "HOME")))
7807            (and home (string-append home "/.config"))))))
7808
7809(define (system-cache-directory)
7810  (or (get-environment-variable "XDG_CACHE_HOME")
7811      (if ##sys#windows-platform
7812          (or (get-environment-variable "LOCALAPPDATA")
7813              (get-environment-variable "APPDATA"))
7814          (let ((home (get-environment-variable "HOME")))
7815            (and home (string-append home "/.cache"))))))
7816
7817) ; chicken.platform
7818
7819(set! scheme#features
7820  (lambda ()
7821    (map (lambda (s)
7822         (##sys#string->symbol (##sys#symbol->string s)))
7823       ##sys#features)))
7824
7825(set! scheme#make-list
7826 (lambda (n #!optional fill)
7827  (##sys#check-integer n 'make-list)
7828  (unless (fx>= n 0)
7829    (error 'make-list "not a positive integer" n))
7830  (do ((i n (fx- i 1))
7831       (result '() (cons fill result)))
7832      ((eq? i 0) result))))
7833
7834(set! scheme#list-set!
7835 (lambda (l n obj)
7836  (##sys#check-integer n 'list-set!)
7837  (unless (fx>= n 0)
7838    (error 'list-set! "not a positive integer" n))
7839  (do ((i n (fx- i 1))
7840       (l l (cdr l)))
7841      ((fx= i 0) (set-car! l obj))
7842    (when (null? l)
7843      (error 'list-set! "out of range")))))
7844
7845;; TODO: Test if this is the quickest way to do this, or whether we
7846;; should just cons recursively like our SRFI-1 implementation does.
7847(set! scheme#list-copy
7848 (lambda (lst)
7849  (cond ((pair? lst)
7850         (let lp ((res '())
7851                  (lst lst))
7852           (if (pair? lst)
7853               (lp (cons (car lst) res) (cdr lst))
7854               (append (##sys#fast-reverse res) lst))))
7855        (else lst))))
7856
7857(set! scheme#string->vector
7858 (lambda (s #!optional start end)
7859  (##sys#check-string s 'string->vector)
7860  (let ((s->v (lambda (s start end)
7861                (let* ((len (##sys#slot s 1)))
7862                  (##sys#check-range/including start 0 end 'string->vector)
7863                  (##sys#check-range/including end start len 'string->vector)
7864                  (let ((v (##sys#make-vector (fx- end start))))
7865                    (do ((ti 0 (fx+ ti 1))
7866                         (fi start (fx+ fi 1)))
7867                        ((fx= fi end) v)
7868                      (##sys#setslot v ti (##core#inline "C_utf_subchar" s fi))))))))
7869    (if end
7870        (s->v s start end)
7871        (s->v s (or start 0) (string-length s))))))
7872
7873(set! scheme#vector->string
7874  (lambda (v #!optional start end)
7875    (##sys#check-vector v 'vector->string)
7876    (let ((v->s (lambda (v start end)
7877                  (let ((len (##sys#size v)))
7878                    (##sys#check-range/including start 0 end 'vector->string)
7879                    (##sys#check-range/including end start len 'vector->string)
7880                    (let ((bv (##sys#make-bytevector (fx* (fx- end start) 4))))
7881                      (let loop ((i 0)
7882                                 (p start))
7883                        (if (fx= p end)
7884                            (##sys#buffer->string! bv i)
7885                            (let ((c (##sys#slot v p)))
7886                              (##sys#check-char c 'vector->string)
7887                              (loop (##core#inline "C_utf_insert" bv i c)
7888                                    (fx+ p 1))))))))))
7889      (if end
7890          (v->s v start end)
7891          (v->s v (or start 0) (##sys#size v))))))
7892
7893(set! scheme#string-map
7894  (lambda (proc str . more)
7895    (define (%string-map proc s)
7896      (let* ((len (string-length s))
7897             (ans (##sys#make-bytevector (fx* 4 len))))
7898        (let loop ((i 0)
7899                   (j 0))
7900          (if (fx>= j len)
7901              (##sys#buffer->string! ans i)
7902              (let ((r (proc (string-ref s j))))
7903                (##sys#check-char r 'string-map)
7904                (loop (##core#inline "C_utf_insert" ans i r)
7905                      (fx+ j 1)))))))
7906    (if (null? more)
7907        (%string-map proc str)
7908        (let ((strs (cons str more)))
7909          (##sys#check-closure proc 'string-map)
7910          (##sys#for-each (cut ##sys#check-string <> 'string-map) strs)
7911          (let* ((len (foldl fxmin most-positive-fixnum (map string-length strs)))
7912                 (str (##sys#make-string len)))
7913            (do ((i 0 (fx+ i 1)))
7914                ((fx= i len) str)
7915                (string-set! str i (apply proc (map (cut string-ref <> i) strs)))))))))
7916
7917(set! scheme#string-for-each
7918  (lambda (proc str . more)
7919    (define (%string-for-each proc s)
7920      (let ((len (string-length s)))
7921        (let lp ((i 0))
7922          (if (fx< i len)
7923              (begin (proc (string-ref s i))
7924                (lp (fx+ i 1)))))))
7925    (if (null? more)
7926        (%string-for-each proc str)
7927        (let ((strs (cons str more)))
7928          (##sys#check-closure proc 'string-for-each)
7929          (##sys#for-each (cut ##sys#check-string <> 'string-for-each) strs)
7930          (let* ((len (foldl fxmin most-positive-fixnum (map string-length strs)))
7931                 (str (##sys#make-string len)))
7932            (do ((i 0 (fx+ i 1)))
7933                ((fx= i len))
7934                (apply proc (map (cut string-ref <> i) strs))))))))
7935
7936(set! scheme#vector-map
7937 (lambda (proc v . more)
7938  (cond ((null? more)
7939         (##sys#check-closure proc 'vector-map)
7940         (##sys#check-vector v 'vector-map)
7941         (let* ((len (##sys#size v))
7942                (vec (##sys#make-vector len)))
7943           (do ((i 0 (fx+ i 1)))
7944               ((fx= i len) vec)
7945               (##sys#setslot vec i (proc (##sys#slot v i))))))
7946        (else
7947          (let ((vs (cons v more)))
7948            (##sys#check-closure proc 'vector-map)
7949            (##sys#for-each (cut ##sys#check-vector <> 'vector-map) vs)
7950            (let* ((len (foldl fxmin most-positive-fixnum (map ##sys#size vs)))
7951                   (vec (##sys#make-vector len)))
7952              (do ((i 0 (fx+ i 1)))
7953                  ((fx= i len) vec)
7954                  (##sys#setslot vec i (apply proc (map (cut vector-ref <> i) vs))))))))))
7955
7956(set! scheme#vector-for-each
7957 (lambda (proc v . more)
7958  (cond ((null? more)
7959         (##sys#check-closure proc 'vector-for-each)
7960         (##sys#check-vector v 'vector-for-each)
7961         (let ((len (##sys#size v)))
7962           (do ((i 0 (fx+ i 1)))
7963               ((fx= i len))
7964               (proc (##sys#slot v i)))))
7965        (else
7966          (let ((vs (cons v more)))
7967            (##sys#check-closure proc 'vector-for-each)
7968            (##sys#for-each (cut ##sys#check-vector <> 'vector-for-each) vs)
7969            (let* ((len (foldl fxmin most-positive-fixnum (map ##sys#size vs)))
7970                   (vec (##sys#make-vector len)))
7971              (do ((i 0 (fx+ i 1)))
7972                  ((fx= i len) vec)
7973                  (apply proc (map (cut vector-ref <> i) vs)))))))))
7974
7975(set! scheme#close-port
7976 (lambda (port)
7977  (##sys#check-port port 'close-port)
7978  (when (##core#inline "C_port_openp" port 1)
7979    ((##sys#slot (##sys#slot port 2) 4) port 1))
7980  (when (##core#inline "C_port_openp" port 2)
7981    ((##sys#slot (##sys#slot port 2) 4) port 2))
7982  (##sys#setislot port 8 0)))
7983
7984(set! scheme#call-with-port
7985 (lambda (port proc)
7986  (receive ret
7987      (proc port)
7988    (scheme#close-port port)
7989    (apply values ret))))
7990
7991(set! scheme#eof-object (lambda () #!eof))
7992
7993(set! scheme#peek-u8
7994  (case-lambda
7995    (()
7996     (let ((c (peek-char ##sys#standard-input)))
7997       (if (eof-object? c) c
7998           (char->integer c))))
7999    ((port)
8000     (##sys#check-input-port port #t 'peek-u8)
8001     (let ((c (peek-char port)))
8002       (if (eof-object? c) c
8003           (char->integer c))))))
8004
8005(set! scheme#write-string
8006  (lambda (s #!optional (port ##sys#standard-output) start end)
8007    (##sys#check-string s 'write-string)
8008    (##sys#check-output-port port #t 'write-string)
8009    (if start
8010        (##sys#check-fixnum start 'write-string)
8011        (set! start 0))
8012    (if end
8013        (##sys#check-fixnum end 'write-string)
8014        (set! end (string-length s)))
8015    (let* ((part (if start (substring s start end) s))
8016           (bv (##sys#slot part 0))
8017           (len (fx- (##sys#size bv) 1)))
8018      ((##sys#slot (##sys#slot port 2) 3) ; write-bytevector
8019       port bv 0 len))))
8020
8021
8022;; I/O
8023
8024(module chicken.io
8025  (read-list read-buffered read-byte read-line
8026   read-lines read-string read-string! read-token
8027   write-byte write-line write-bytevector read-bytevector
8028   read-bytevector!)
8029
8030(import scheme chicken.base chicken.fixnum)
8031(import chicken.internal.syntax)
8032(import (only (scheme base) open-output-string get-output-string))
8033
8034
8035;;; Read expressions from file:
8036
8037(define read-list
8038  (let ((read read))
8039    (lambda (#!optional (port ##sys#standard-input) (reader read) max)
8040      (##sys#check-input-port port #t 'read-list)
8041      (do ((x (reader port) (reader port))
8042	   (i 0 (fx+ i 1))
8043	   (xs '() (cons x xs)))
8044	  ((or (eof-object? x) (and max (fx>= i max)))
8045	   (##sys#fast-reverse xs))))))
8046
8047
8048;;; Line I/O:
8049
8050(define read-line
8051  (let ()
8052    (lambda args
8053      (let* ([parg (pair? args)]
8054	     [p (if parg (car args) ##sys#standard-input)]
8055	     [limit (and parg (pair? (cdr args)) (cadr args))])
8056	(##sys#check-input-port p #t 'read-line)
8057	(cond ((##sys#slot (##sys#slot p 2) 8) => (lambda (rl) (rl p limit)))
8058	      (else
8059	       (let* ((buffer-len (if limit limit 256))
8060		      (buffer (##sys#make-string buffer-len)))
8061		 (let loop ([i 0])
8062		   (if (and limit (fx>= i limit))
8063		       (##sys#substring buffer 0 i)
8064		       (let ([c (##sys#read-char-0 p)])
8065			 (if (eof-object? c)
8066			     (if (fx= i 0)
8067				 c
8068				 (##sys#substring buffer 0 i) )
8069			     (case c
8070			       [(#\newline) (##sys#substring buffer 0 i)]
8071			       [(#\return)
8072				(let ([c (peek-char p)])
8073				  (if (char=? c #\newline)
8074				      (begin (##sys#read-char-0 p)
8075					     (##sys#substring buffer 0 i))
8076				      (##sys#substring buffer 0 i) ) ) ]
8077			       [else
8078				(when (fx>= i buffer-len)
8079				  (set! buffer
8080				    (##sys#string-append buffer (make-string buffer-len)))
8081				  (set! buffer-len (fx+ buffer-len buffer-len)) )
8082				(string-set! buffer i c)
8083				(loop (fx+ i 1)) ] ) ) ) ) ) ) ) ) ) ) ) )
8084
8085(define read-lines
8086  (lambda (#!optional (port ##sys#standard-input) max)
8087    (##sys#check-input-port port #t 'read-lines)
8088    (when max (##sys#check-fixnum max 'read-lines))
8089    (let loop ((lns '())
8090	       (n (or max most-positive-fixnum)))
8091      (if (eq? n 0)
8092	  (##sys#fast-reverse lns)
8093	  (let ((ln (read-line port)))
8094	    (if (eof-object? ln)
8095		(##sys#fast-reverse lns)
8096		(loop (cons ln lns) (fx- n 1))))))))
8097
8098(define write-line
8099  (lambda (str . port)
8100    (let* ((p (if (##core#inline "C_eqp" port '())
8101                  ##sys#standard-output
8102                  (##sys#slot port 0) ) ))
8103      (##sys#check-output-port p #t 'write-line)
8104      (##sys#check-string str 'write-line)
8105      (let ((bv (##sys#slot str 0)))
8106        ((##sys#slot (##sys#slot p 2) 3)  ; write-bytevector
8107         p
8108         bv
8109         0
8110         (fx- (##sys#size bv) 1)))
8111      (##sys#write-char-0 #\newline p))))
8112
8113
8114;;; Extended I/O
8115
8116(define (read-bytevector!/port n dest port start)
8117  (if (eq? n 0)
8118      0
8119      (let ((rdbvec (##sys#slot (##sys#slot port 2) 7))) ; read-bytevector!
8120        (let loop ((start start) (n n) (m 0))
8121          (let ((n2 (rdbvec port n dest start)))
8122            (##sys#setislot port 5 ; update port-position
8123                            (fx+ (##sys#slot port 5) n2))
8124            (cond ((eq? n2 0) m)
8125                  ((or (not n) (fx< n2 n))
8126                   (loop (fx+ start n2) (and n (fx- n n2)) (fx+ m n2)))
8127                  (else (fx+ n2 m))))))))
8128
8129(define (read-string!/port n dest port start)
8130  (let ((buf (##sys#make-bytevector (fx* n 4)))
8131        (enc (##sys#slot port 15)))
8132    (##sys#encoding-hook
8133     enc
8134     (lambda (decoder _ _)
8135       (define (readb n buf port p)
8136         (let ((bytes (read-bytevector!/port n buf port p)))
8137           (if (eq? enc 'utf-8) ; fast path, avoid copying
8138               bytes
8139               (decoder buf p bytes
8140                        (lambda (dbuf start len)
8141                          (##core#inline "C_copy_memory_with_offset" buf dbuf p start len)
8142                          len)))))
8143       (define (finish un bytes)
8144         (##core#inline "C_utf_overwrite" dest start un buf bytes)
8145         un)
8146       (let loop ((p 0) (n n) (un 0) (bn 0))
8147         (let ((bytes (readb n buf port p)))
8148           (cond ((eq? bytes 0) (finish un bn))
8149                 ((eq? enc 'utf-8)
8150                  ;; read incomplete fragments
8151                  ;; FIXME: hardcoded, should be encoding-specific!
8152                  (let recount ((bytes bytes))
8153                    (let* ((fc (##core#inline "C_utf_fragment_counts" buf p bytes))
8154                           (full (fxshr fc 4))
8155                           (left (fxand fc 15))
8156                           (total (fx+ un full))
8157                           (tbytes (fx+ bn bytes))
8158                           (remain (fx- n full)))
8159                      (cond ((fx> left 0)
8160                             (let ((b2 (readb left buf port (fx+ p bytes))))
8161                               (if (fx< b2 left)
8162                                   (finish total tbytes)
8163                                   (recount (fx+ bytes b2)))))
8164                            ((eq? remain 0) (finish total tbytes))
8165                            (else (loop (fx+ p bytes) remain total
8166                                        tbytes))))))
8167                 ((fx> bytes n)
8168                  (loop (fx+ p bytes) (fx- n bytes)
8169                        (fx+ un bytes) (fx+ bn bytes)))
8170                 (else (finish un bn)))))))))
8171
8172(define (read-string! n dest #!optional (port ##sys#standard-input) (start 0))
8173  (##sys#check-input-port port #t 'read-string!)
8174  (##sys#check-string dest 'read-string!)
8175  (when n (##sys#check-fixnum n 'read-string!))
8176  (let ((dest-size (string-length dest)))
8177    (unless (and n (fx<= (fx+ start n) dest-size))
8178      (set! n (fx- dest-size start))))
8179  (##sys#check-fixnum start 'read-string!)
8180  (read-string!/port n dest port start))
8181
8182(define (read-bytevector! dest #!optional (port ##sys#standard-input) (start 0) end)
8183  (##sys#check-input-port port #t 'read-bytevector!)
8184  (##sys#check-bytevector dest 'read-bytevector!)
8185  (##sys#check-fixnum start 'read-bytevector!)
8186  (when end (##sys#check-fixnum end 'read-bytevector!))
8187  (let* ((size (##sys#size dest))
8188         (n (fx- (or end size) start)))
8189    (read-bytevector!/port n dest port start)))
8190
8191(define read-string/port
8192  (lambda (n p)
8193    (cond ((eq? n 0) "") ; Don't attempt to peek (fd might not be ready)
8194          ((eof-object? (##sys#peek-char-0 p)) #!eof)
8195          (n (let* ((str (##sys#make-string n))
8196                    (n2 (read-string!/port n str p 0)))
8197               (if (eq? n n2)
8198                   str
8199                   (##sys#substring str 0 n2))))
8200          (else
8201            (##sys#read-remaining
8202              p
8203              (lambda (buf len)
8204                (##sys#buffer->string/encoding buf 0 len
8205                                               (##sys#slot p 15))))))))
8206
8207(define (##sys#read-remaining p k)
8208  (let ((len 1024))
8209    (let loop ((buf (##sys#make-bytevector len))
8210               (bsize len)
8211               (pos 0))
8212      (let* ((nr (fx- (##sys#size buf) pos))
8213             (n (read-bytevector!/port nr buf p pos)))
8214        (cond ((eq? n nr)
8215               (let* ((bsize2 (fx* bsize 2))
8216                      (buf2 (##sys#make-bytevector bsize2)))
8217                 (##core#inline "C_copy_memory" buf2 buf bsize)
8218                 (loop buf2 bsize2 (fx+ pos n))))
8219              (else (k buf (fx+ n pos))))))))
8220
8221(define read-bytevector/port
8222  (lambda (n p)
8223    (let* ((bv (##sys#make-bytevector n))
8224           (n2 (read-bytevector!/port n bv p 0)))
8225      (if (eq? n n2)
8226          bv
8227          (let ((bv2 (##sys#make-bytevector n2)))
8228            (##core#inline "C_copy_memory" bv2 bv n2)
8229            bv2)))))
8230
8231(define (read-string #!optional n (port ##sys#standard-input))
8232  (##sys#check-input-port port #t 'read-string)
8233  (when n (##sys#check-fixnum n 'read-string))
8234  (read-string/port n port))
8235
8236(define (read-bytevector #!optional n (port ##sys#standard-input))
8237  (##sys#check-input-port port #t 'read-bytevector)
8238  (cond (n (##sys#check-fixnum n 'read-bytevector)
8239           (let ((r (read-bytevector/port n port)))
8240             (if (eq? (##sys#size r) 0)
8241                 #!eof
8242                 r)))
8243        (else
8244          (##sys#read-remaining
8245            port
8246            (lambda (buf len)
8247              (if (eq? len 0)
8248                  #!eof
8249                  (let ((r (##sys#make-bytevector len)))
8250                    (##core#inline "C_copy_memory" r buf len)
8251                    r)))))))
8252
8253
8254;; Make internal reader procedures available for use in srfi-4.scm:
8255
8256(define chicken.io#read-string/port read-string/port)
8257(define chicken.io#read-string!/port read-string!/port)
8258(define chicken.io#read-bytevector/port read-bytevector/port)
8259(define chicken.io#read-bytevector!/port read-bytevector!/port)
8260
8261(define (read-buffered #!optional (port ##sys#standard-input))
8262  (##sys#check-input-port port #t 'read-buffered)
8263  (let ((rb (##sys#slot (##sys#slot port 2) 9))) ; read-buffered method
8264    (if rb
8265	(rb port)
8266	"")))
8267
8268
8269;;; read token of characters that satisfy a predicate
8270
8271(define read-token
8272  (lambda (pred . port)
8273    (let ([port (optional port ##sys#standard-input)])
8274      (##sys#check-input-port port #t 'read-token)
8275      (let ([out (open-output-string)])
8276	(let loop ()
8277	  (let ([c (##sys#peek-char-0 port)])
8278	    (if (and (not (eof-object? c)) (pred c))
8279		(begin
8280		  (##sys#write-char-0 (##sys#read-char-0 port) out)
8281		  (loop) )
8282		(get-output-string out) ) ) ) ) ) ) )
8283
8284
8285;;; Binary I/O
8286
8287(define (read-byte #!optional (port ##sys#standard-input))
8288  (##sys#check-input-port port #t 'read-byte)
8289  (let* ((bv (##sys#make-bytevector 1))
8290         (n (read-bytevector!/port 1 bv port 0)))
8291    (if (fx< n 1)
8292        #!eof
8293        (##core#inline "C_subbyte" bv 0))))
8294
8295(define (write-byte byte #!optional (port ##sys#standard-output))
8296  (##sys#check-fixnum byte 'write-byte)
8297  (##sys#check-output-port port #t 'write-byte)
8298  (let ((bv (##sys#make-bytevector 1 byte)))
8299    ((##sys#slot (##sys#slot port 2) 3) ; write-bytevector
8300     port bv 0 1)))
8301
8302(define (write-bytevector bv #!optional (port ##sys#standard-output) (start 0)
8303                          end)
8304  (##sys#check-bytevector bv 'write-bytevector)
8305  (##sys#check-output-port port #t 'write-bytevector)
8306  (##sys#check-fixnum start 'write-bytevector)
8307  (let ((len (##sys#size bv)))
8308    (##sys#check-range/including start 0 len 'write-bytevector)
8309    (when end (##sys#check-range/including end 0 len 'write-bytevector))
8310    (let ((end (if end (fxmin end len) len)))
8311      ((##sys#slot (##sys#slot port 2) 3) ; write-bytevector
8312       port bv start end))))
8313
8314) ; module chicken.io
Trap