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