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