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