~ chicken-core (master) /library.scm


   1;;;; library.scm - R5RS/R7RS library for the CHICKEN compiler
   2;
   3; Copyright (c) 2008-2022, The CHICKEN Team
   4; Copyright (c) 2000-2007, Felix L. Winkelmann
   5; All rights reserved.
   6;
   7; Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
   8; conditions are met:
   9;
  10;   Redistributions of source code must retain the above copyright notice, this list of conditions and the following
  11;     disclaimer.
  12;   Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
  13;     disclaimer in the documentation and/or other materials provided with the distribution.
  14;   Neither the name of the author nor the names of its contributors may be used to endorse or promote
  15;     products derived from this software without specific prior written permission.
  16;
  17; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
  18; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  19; AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
  20; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  21; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  22; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  23; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  24; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  25; POSSIBILITY OF SUCH DAMAGE.
  26
  27
  28(declare
  29  (unit library)
  30  (uses build-version)
  31  (disable-interrupts)
  32  (hide ##sys#dynamic-unwind
  33	##sys#vector-resize ##sys#default-parameter-vector
  34	current-print-length setter-tag
  35	##sys#print-exit ##sys#r7rs-exn-handlers
  36	##sys#format-here-doc-warning
  37	exit-in-progress cleanup-before-exit chicken.base#cleanup-tasks
  38        maximal-string-length find-ratio-between find-ratio
  39	make-complex flonum->ratnum ratnum
  40	+maximum-allowed-exponent+ mantexp->dbl ldexp round-quotient
  41	##sys#string->compnum ##sys#internal-gcd)
  42  (not inline chicken.base#sleep-hook ##sys#change-directory-hook
  43       ##sys#user-read-hook ##sys#error-hook ##sys#signal-hook ##sys#signal-hook/errno
  44       ##sys#default-read-info-hook ##sys#infix-list-hook
  45       ##sys#sharp-number-hook ##sys#user-print-hook
  46       ##sys#user-interrupt-hook ##sys#windows-platform
  47       ##sys#resume-thread-on-event ##sys#suspend-thread-on-event
  48       ##sys#schedule ##sys#features)
  49  (foreign-declare #<<EOF
  50#include <errno.h>
  51#include <float.h>
  52
  53#ifdef HAVE_SYSEXITS_H
  54# include <sysexits.h>
  55#endif
  56
  57#ifndef EX_SOFTWARE
  58# define EX_SOFTWARE	70
  59#endif
  60
  61#define C_close_file(p)	      (C_fclose((C_FILEPTR)(C_port_file(p))), C_SCHEME_UNDEFINED)
  62#define C_a_f64peek(ptr, c, b, i)  C_flonum(ptr, ((double *)C_data_pointer(b))[ C_unfix(i) ])
  63#define C_fetch_c_strlen(b, i) C_fix(strlen((C_char *)C_block_item(b, C_unfix(i))))
  64#define C_asciiz_strlen(str) C_fix(strlen(C_c_string(str)))
  65#define C_peek_c_string(b, i, to, len) (C_memcpy(C_data_pointer(to), (C_char *)C_block_item(b, C_unfix(i)), C_unfix(len)), C_SCHEME_UNDEFINED)
  66#define C_free_mptr(p, i)     (C_free((void *)C_block_item(p, C_unfix(i))), C_SCHEME_UNDEFINED)
  67#define C_free_sptr(p, i)     (C_free((void *)(((C_char **)C_block_item(p, 0))[ C_unfix(i) ])), C_SCHEME_UNDEFINED)
  68
  69#define C_a_get_current_seconds(ptr, c, dummy)  C_int64_to_num(ptr, time(NULL))
  70#define C_peek_c_string_at(ptr, i)    ((C_char *)(((C_char **)ptr)[ i ]))
  71
  72#define C_flush_all_files(dummy)    (C_fflush(NULL), C_SCHEME_UNDEFINED)
  73
  74static C_word
  75fast_read_line_from_file(C_word str, C_word start, C_word port, C_word size) {
  76  int n = C_unfix(size);
  77  int i;
  78  int c;
  79  int p = C_unfix(start);
  80  char *buf = C_c_string(str) + p;
  81  C_FILEPTR fp = C_port_file(port);
  82
  83  if ((c = C_getc(fp)) == EOF) {
  84    if (ferror(fp)) {
  85      clearerr(fp);
  86      if(p) return start;
  87      return C_fix(-1);
  88    } else { /* feof (fp) */
  89      if(p) return start;
  90      return C_SCHEME_END_OF_FILE;
  91    }
  92  }
  93
  94  C_ungetc(c, fp);
  95
  96  for (i = 0; i < n; i++) {
  97    c = C_getc(fp);
  98
  99    if(c == EOF && ferror(fp)) {
 100      clearerr(fp);
 101      return C_fix(-(i + 1) + p);
 102    }
 103
 104    switch (c) {
 105    case '\r':	if ((c = C_getc(fp)) != '\n') C_ungetc(c, fp);
 106    case EOF:	clearerr(fp);
 107    case '\n':	return C_fix(i + p);
 108    }
 109    buf[i] = c;
 110  }
 111  if(p) return start;
 112  return C_SCHEME_FALSE;
 113}
 114
 115static C_word
 116fast_read_string_from_file(C_word dest, C_word port, C_word len, C_word pos)
 117{
 118  size_t m;
 119  int n = C_unfix (len);
 120  C_char * buf = C_c_string(dest) + C_unfix(pos);
 121  C_FILEPTR fp = C_port_file (port);
 122
 123  if(feof(fp)) return C_SCHEME_END_OF_FILE;
 124
 125  m = fread (buf, sizeof (char), n, fp);
 126
 127  if (m < n) {
 128    if (ferror(fp)) /* Report to Scheme, which may retry, so clear errors */
 129      clearerr(fp);
 130    else if (feof(fp) && 0 == m) /* eof but m > 0? Return data first, below */
 131      return C_SCHEME_END_OF_FILE; /* Calling again will get us here */
 132  }
 133
 134  return C_fix (m);
 135}
 136
 137static C_word
 138shallow_equal(C_word x, C_word y)
 139{
 140  /* assumes x and y are non-immediate */
 141  int i, len = C_header_size(x);
 142
 143  if(C_header_size(y) != len) return C_SCHEME_FALSE;
 144  else return C_mk_bool(!C_memcmp((void *)x, (void *)y, len * sizeof(C_word)));
 145}
 146
 147static C_word
 148signal_debug_event(C_word mode, C_word msg, C_word args)
 149{
 150  C_DEBUG_INFO cell;
 151  C_word av[ 3 ];
 152  cell.enabled = 1;
 153  cell.event = C_DEBUG_SIGNAL;
 154  cell.loc = "";
 155  cell.val = "";
 156  av[ 0 ] = mode;
 157  av[ 1 ] = msg;
 158  av[ 2 ] = args;
 159  C_debugger(&cell, 3, av);
 160  return C_SCHEME_UNDEFINED;
 161}
 162
 163static C_word C_i_sleep_until_interrupt(C_word secs)
 164{
 165   while(C_i_process_sleep(secs) == C_fix(-1) && errno == EINTR);
 166   return C_SCHEME_UNDEFINED;
 167}
 168
 169#ifdef NO_DLOAD2
 170# define HAVE_DLOAD 0
 171#else
 172# define HAVE_DLOAD 1
 173#endif
 174
 175#ifdef C_ENABLE_PTABLES
 176# define HAVE_PTABLES 1
 177#else
 178# define HAVE_PTABLES 0
 179#endif
 180
 181#ifdef C_GC_HOOKS
 182# define HAVE_GCHOOKS 1
 183#else
 184# define HAVE_GCHOOKS 0
 185#endif
 186
 187#if defined(C_CROSS_CHICKEN) && C_CROSS_CHICKEN
 188# define IS_CROSS_CHICKEN 1
 189#else
 190# define IS_CROSS_CHICKEN 0
 191#endif
 192EOF
 193) )
 194
 195;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 196;; NOTE: Modules defined here will typically exclude syntax
 197;; definitions, those are handled by expand.scm or modules.scm.
 198;; Handwritten import libraries (or a special-case module in
 199;; modules.scm for scheme) contain the value exports merged with
 200;; syntactic exports.  The upshot of this is that any module that
 201;; refers to another module defined *earlier* in this file cannot use
 202;; macros from the earlier module!
 203;;
 204;; We get around this problem by using the "chicken.internal.syntax"
 205;; module, which is baked in and exports *every* available core macro.
 206;; See modules.scm, expand.scm and chicken-syntax.scm for details.
 207;;
 208;; NOTE #2: The module "scheme" is a legacy artifact, with CHICKEN
 209;; 6 "scheme" being just an alias for "scheme.r5rs", and "scheme.base"
 210;; is what used to be the standard Scheme module. We use it only
 211;; to provide a prefix ("scheme#") for the exported toplevel
 212;; identifiers, which now represent what is in the "scheme.base"
 213;; standard module. Yes, this is somewhat confusing, but changing
 214;; all prefixes to use the "proper" name would cause too many
 215;; bootstrapping problems.
 216;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 217
 218;; Pre-declaration of scheme, so it can be used later on.  We only use
 219;; scheme macros and core language forms in here, to avoid a cyclic
 220;; dependency on itself.  All actual definitions are set! below.
 221;; Also, this declaration is incomplete: the module itself is defined
 222;; as a primitive module due to syntax exports, which are missing
 223;; here.  See modules.scm for the full definition.
 224(module scheme
 225    (;; [syntax]
 226     ;; We are reexporting these because otherwise the module here
 227     ;; will be inconsistent with the built-in one, and be void of
 228     ;; syntax definitions, causing problems below.
 229     begin and case cond define define-syntax delay do lambda
 230     if let let* let-syntax letrec letrec-syntax or
 231     quasiquote quote set! syntax-rules
 232
 233     not boolean? eq? eqv? equal? pair? boolean=? symbol=?
 234     cons car cdr caar cadr cdar cddr caaar caadr cadar caddr cdaar
 235     cdadr cddar cdddr caaaar caaadr caadar caaddr cadaar cadadr
 236     caddar cadddr cdaaar cdaadr cdadar cdaddr cddaar cddadr cdddar
 237     cddddr set-car! set-cdr!
 238     null? list? list length list-tail list-ref append reverse memq memv
 239     member assq assv assoc symbol? symbol->string string->symbol number?
 240     integer? exact? real? complex? inexact? rational? zero? odd? even?
 241     positive? negative?  max min + - * / = > < >= <= quotient remainder
 242     exact-integer?
 243     modulo gcd lcm abs floor ceiling truncate round rationalize
 244     exact->inexact inexact->exact exp log expt sqrt
 245     sin cos tan asin acos atan
 246     number->string string->number char? char=? char>? char<? char>=?
 247     char<=? char-ci=? char-ci<? char-ci>?  char-ci>=? char-ci<=?
 248     char-alphabetic? char-whitespace? char-numeric? char-upper-case?
 249     char-lower-case? char-upcase char-downcase
 250     char->integer integer->char
 251     string? string=?  string>? string<? string>=? string<=? string-ci=?
 252     string-ci<? string-ci>? string-ci>=? string-ci<=?  make-string
 253     string-length string-ref string-set! string-append string-copy string-copy!
 254     string->list list->string substring string-fill! vector? make-vector
 255     vector-ref vector-set! string vector vector-length vector->list
 256     list->vector vector-fill! procedure? map for-each apply force
 257     call-with-current-continuation call/cc input-port? output-port?
 258     current-input-port current-output-port call-with-input-file
 259     call-with-output-file open-input-file open-output-file
 260     close-input-port close-output-port
 261     read read-char peek-char write display write-char newline
 262     eof-object? with-input-from-file with-output-to-file
 263     char-ready? imag-part real-part make-rectangular make-polar angle
 264     magnitude numerator denominator values call-with-values dynamic-wind
 265
 266     open-input-string open-output-string open-input-bytevector
 267     open-output-bytevector get-output-string get-output-bytevector
 268     features make-list port? call-with-port peek-u8 make-parameter
 269     string-map vector-map string-for-each vector-for-each u8-ready?
 270     make-list list-set! write-string eof-object list-copy
 271     string->vector vector->string textual-port? binary-port?
 272     input-port-open? output-port-open? floor/ truncate/
 273     exact inexact floor-remainder floor-quotient close-port
 274     
 275     char-foldcase string-foldcase string-upcase string-downcase
 276
 277     ;; The following procedures are overwritten in eval.scm:
 278     eval interaction-environment null-environment
 279     scheme-report-environment load)
 280
 281(import chicken.internal.syntax) ;; See note above
 282
 283;;; Operations on booleans:
 284
 285(define (not x) (##core#inline "C_i_not" x))
 286(define (boolean? x) (##core#inline "C_booleanp" x))
 287
 288
 289;;; Equivalence predicates:
 290
 291(define (eq? x y) (##core#inline "C_eqp" x y))
 292(define (eqv? x y) (##core#inline "C_i_eqvp" x y))
 293(define (equal? x y) (##core#inline "C_i_equalp" x y))
 294
 295(define (boolean=? x y . more)
 296  (##sys#check-boolean x 'boolean=?)
 297  (##sys#check-boolean y 'boolean=?)
 298  (let loop ((bs more) (f (eq? x y)))
 299    (if (null? bs)
 300        f
 301        (let ((b (##sys#slot bs 0)))
 302          (##sys#check-boolean b 'boolean=?)
 303          (loop (##sys#slot bs 1)
 304                (and f (eq? b y)))))))
 305
 306(define (symbol=? x y . more)
 307  (##sys#check-symbol x 'symbol=?)
 308  (##sys#check-symbol y 'symbol=?)
 309  (let loop ((bs more) (f (eq? x y)))
 310    (if (null? bs)
 311        f
 312        (let ((b (##sys#slot bs 0)))
 313          (##sys#check-symbol b 'symbol=?)
 314          (loop (##sys#slot bs 1)
 315                (and f (eq? b y)))))))
 316
 317
 318;;; Pairs and lists:
 319
 320(define (pair? x) (##core#inline "C_i_pairp" x))
 321(define (cons x y) (##core#inline_allocate ("C_a_i_cons" 3) x y))
 322(define (car x) (##core#inline "C_i_car" x))
 323(define (cdr x) (##core#inline "C_i_cdr" x))
 324
 325(define (set-car! x y) (##core#inline "C_i_set_car" x y))
 326(define (set-cdr! x y) (##core#inline "C_i_set_cdr" x y))
 327(define (cadr x) (##core#inline "C_i_cadr" x))
 328(define (caddr x) (##core#inline "C_i_caddr" x))
 329(define (cadddr x) (##core#inline "C_i_cadddr" x))
 330(define (cddddr x) (##core#inline "C_i_cddddr" x))
 331
 332(define (caar x) (##core#inline "C_i_caar" x))
 333(define (cdar x) (##core#inline "C_i_cdar" x))
 334(define (cddr x) (##core#inline "C_i_cddr" x))
 335(define (caaar x) (car (car (car x))))
 336(define (caadr x) (car (##core#inline "C_i_cadr" x)))
 337(define (cadar x) (##core#inline "C_i_cadr" (car x)))
 338(define (cdaar x) (cdr (car (car x))))
 339(define (cdadr x) (cdr (##core#inline "C_i_cadr" x)))
 340(define (cddar x) (cdr (cdr (car x))))
 341(define (cdddr x) (cdr (cdr (cdr x))))
 342(define (caaaar x) (car (car (car (car x)))))
 343(define (caaadr x) (car (car (##core#inline "C_i_cadr" x))))
 344(define (caadar x) (car (##core#inline "C_i_cadr" (car x))))
 345(define (caaddr x) (car (##core#inline "C_i_caddr" x)))
 346(define (cadaar x) (##core#inline "C_i_cadr" (car (car x))))
 347(define (cadadr x) (##core#inline "C_i_cadr" (##core#inline "C_i_cadr" x)))
 348(define (caddar x) (##core#inline "C_i_caddr" (car x)))
 349(define (cdaaar x) (cdr (car (car (car x)))))
 350(define (cdaadr x) (cdr (car (##core#inline "C_i_cadr" x))))
 351(define (cdadar x) (cdr (##core#inline "C_i_cadr" (car x))))
 352(define (cdaddr x) (cdr (##core#inline "C_i_caddr" x)))
 353(define (cddaar x) (cdr (cdr (car (car x)))))
 354(define (cddadr x) (cdr (cdr (##core#inline "C_i_cadr" x))))
 355(define (cdddar x) (cdr (cdr (cdr (car x)))))
 356
 357(define (null? x) (eq? x '()))
 358(define (list . lst) lst)
 359(define (length lst) (##core#inline "C_i_length" lst))
 360(define (list-tail lst i) (##core#inline "C_i_list_tail" lst i))
 361(define (list-ref lst i) (##core#inline "C_i_list_ref" lst i))
 362
 363(define append)
 364
 365(define (reverse lst0)
 366  (let loop ((lst lst0) (rest '()))
 367    (cond ((eq? lst '()) rest)
 368	  ((pair? lst)
 369	   (loop (##sys#slot lst 1) (cons (##sys#slot lst 0) rest)) )
 370	  (else (##sys#error-not-a-proper-list lst0 'reverse)) ) ))
 371
 372(define (memq x lst) (##core#inline "C_i_memq" x lst))
 373(define (memv x lst) (##core#inline "C_i_memv" x lst))
 374
 375(define (member x lst #!optional eq)
 376  (if eq
 377      (let loop ((lst lst))
 378        (and (pair? lst)
 379             (if (eq x (##sys#slot lst 0))
 380                 lst
 381                 (loop (##sys#slot lst 1)))))
 382      (##core#inline "C_i_member" x lst)))
 383
 384(define (assq x lst) (##core#inline "C_i_assq" x lst))
 385(define (assv x lst) (##core#inline "C_i_assv" x lst))
 386
 387(define (assoc x lst #!optional eq)
 388  (if eq
 389      (let loop ((lst lst))
 390        (and (pair? lst)
 391             (if (eq x (car (##sys#slot lst 0)))
 392                 (car lst)
 393                 (loop (##sys#slot lst 1)))))
 394      (##core#inline "C_i_assoc" x lst)))
 395
 396(define (list? x) (##core#inline "C_i_listp" x))
 397
 398;;; Strings:
 399
 400(define make-string)
 401
 402(define (string? x) (##core#inline "C_i_stringp" x))
 403(define (string-length s) (##core#inline "C_i_string_length" s))
 404(define (string-ref s i) (##core#inline "C_i_string_ref" s i))
 405(define (string-set! s i c) (##core#inline "C_i_string_set" s i c))
 406
 407(define (string=? x y . more)
 408  (let loop ((s y) (ss more) (f (##core#inline "C_i_string_equal_p" x y)))
 409    (if (null? ss)
 410        f
 411        (let ((s2 (##sys#slot ss 0)))
 412          (##sys#check-string s2 'string=?)
 413          (loop s2 (##sys#slot ss 1)
 414                (and f (##core#inline "C_i_string_equal_p" s s2)))))))
 415
 416(define (string-ci=? x y . more)
 417  (let loop ((s y) (ss more) (f (##core#inline "C_i_string_ci_equal_p" x y)))
 418    (if (null? ss)
 419        f
 420        (let ((s2 (##sys#slot ss 0)))
 421          (##sys#check-string s2 'string-ci=?)
 422          (loop s2 (##sys#slot ss 1)
 423                (and f (##core#inline "C_i_string_ci_equal_p" s s2)))))))
 424
 425(define string->list)
 426(define list->string)
 427(define string-copy)
 428(define string-copy!)
 429(define substring)
 430(define string-fill!)
 431
 432(define string<?)
 433(define string>?)
 434(define string<=?)
 435(define string>=?)
 436
 437(define string-ci<?)
 438(define string-ci>?)
 439(define string-ci<=?)
 440(define string-ci>=?)
 441
 442(define string)
 443(define string-append)
 444
 445(define open-input-string)
 446(define open-output-string)
 447(define open-input-bytevector)
 448(define open-output-bytevector)
 449(define get-output-string)
 450(define get-output-bytevector)
 451(define features)
 452(define make-list)
 453(define port?)
 454(define call-with-port)
 455(define close-port)
 456(define peek-u8)
 457(define string-map)
 458(define vector-map)
 459(define string-for-each)
 460(define vector-for-each)
 461(define make-list)
 462(define list-set!)
 463(define write-string)
 464(define eof-object)
 465(define list-copy)
 466(define string->vector)
 467(define vector->string)
 468(define input-port-open?)
 469(define output-port-open?)
 470(define floor/)
 471(define truncate/)
 472(define exact)
 473(define inexact)
 474(define floor-remainder)
 475(define floor-quotient)
 476(define make-parameter)
 477
 478;; Complex numbers
 479(define make-rectangular)
 480(define make-polar)
 481(define real-part)
 482(define imag-part)
 483(define angle)
 484(define magnitude)
 485
 486;; Rational numbers
 487(define numerator)
 488(define denominator)
 489(define inexact->exact)
 490(define (exact->inexact x)
 491  (##core#inline_allocate ("C_a_i_exact_to_inexact" 12) x))
 492
 493;; Numerical operations
 494(define (abs x) (##core#inline_allocate ("C_s_a_i_abs" 7) x))
 495(define + (##core#primitive "C_plus"))
 496(define - (##core#primitive "C_minus"))
 497(define * (##core#primitive "C_times"))
 498(define /)
 499(define floor)
 500(define ceiling)
 501(define truncate)
 502(define round)
 503(define rationalize)
 504
 505(define (quotient a b) (##core#inline_allocate ("C_s_a_i_quotient" 5) a b))
 506(define (remainder a b) (##core#inline_allocate ("C_s_a_i_remainder" 5) a b))
 507(define (modulo a b) (##core#inline_allocate ("C_s_a_i_modulo" 5) a b))
 508
 509(define (even? n) (##core#inline "C_i_evenp" n))
 510(define (odd? n) (##core#inline "C_i_oddp" n))
 511
 512(define max)
 513(define min)
 514(define exp)
 515(define log)
 516(define sin)
 517(define cos)
 518(define tan)
 519(define asin)
 520(define acos)
 521(define atan)
 522
 523(define sqrt)
 524(define expt)
 525(define gcd)
 526(define lcm)
 527
 528(define = (##core#primitive "C_nequalp"))
 529(define > (##core#primitive "C_greaterp"))
 530(define < (##core#primitive "C_lessp"))
 531(define >= (##core#primitive "C_greater_or_equal_p"))
 532(define <= (##core#primitive "C_less_or_equal_p"))
 533(define (number? x) (##core#inline "C_i_numberp" x))
 534(define complex? number?)
 535(define (real? x) (##core#inline "C_i_realp" x))
 536(define (rational? n) (##core#inline "C_i_rationalp" n))
 537(define (integer? x) (##core#inline "C_i_integerp" x))
 538(define (exact? x) (##core#inline "C_i_exactp" x))
 539(define (inexact? x) (##core#inline "C_i_inexactp" x))
 540(define (zero? n) (##core#inline "C_i_zerop" n))
 541(define (positive? n) (##core#inline "C_i_positivep" n))
 542(define (negative? n) (##core#inline "C_i_negativep" n))
 543(define (exact-integer? x) (##core#inline "C_i_exact_integerp" x))
 544
 545(define number->string (##core#primitive "C_number_to_string"))
 546(define string->number)
 547
 548
 549;;; Symbols:
 550
 551(define (symbol? x) (##core#inline "C_i_symbolp" x))
 552(define symbol->string)
 553(define string->symbol)
 554
 555;;; Vectors:
 556
 557(define (vector? x) (##core#inline "C_i_vectorp" x))
 558(define (vector-length v) (##core#inline "C_i_vector_length" v))
 559(define (vector-ref v i) (##core#inline "C_i_vector_ref" v i))
 560(define (vector-set! v i x) (##core#inline "C_i_vector_set" v i x))
 561(define make-vector)
 562(define list->vector)
 563(define vector->list)
 564(define vector)
 565(define vector-fill!)
 566
 567;;; Characters:
 568
 569(define (char? x) (##core#inline "C_charp" x))
 570
 571(define (char->integer c)
 572  (##sys#check-char c 'char->integer)
 573  (##core#inline "C_fix" (##core#inline "C_character_code" c)) )
 574
 575(define (##sys#check-char-code n loc)
 576  (if (or (##core#inline "C_fixnum_lessp" n 0)
 577          (##core#inline "C_fixnum_greaterp" n #x10ffff))
 578    (##sys#signal-hook
 579      #:domain-error loc "character code is out of valid range" n)
 580    n))
 581
 582(define-inline (fast-i->c n)
 583  (##core#inline "C_make_character" (##core#inline "C_unfix" n)) )
 584
 585(define (integer->char n)
 586  (##sys#check-fixnum n 'integer->char)
 587  (##sys#check-char-code n 'integer->char)
 588  (fast-i->c n))
 589 
 590(define (char=? c1 c2 . more)
 591  (##sys#check-char c1 'char=?)
 592  (##sys#check-char c2 'char=?)
 593  (let loop ((c c2) (cs more)
 594             (f (##core#inline "C_u_i_char_equalp" c1 c2)))
 595    (if (null? cs)
 596        f
 597        (let ((c2 (##sys#slot cs 0)))
 598          (##sys#check-char c2 'char=?)
 599          (loop c2 (##sys#slot cs 1)
 600                (and f (##core#inline "C_u_i_char_equalp" c c2)))))))
 601
 602(define (char>? c1 c2 . more)
 603  (##sys#check-char c1 'char>?)
 604  (##sys#check-char c2 'char>?)
 605  (let loop ((c c2) (cs more)
 606             (f (##core#inline "C_u_i_char_greaterp" c1 c2)))
 607    (if (null? cs)
 608        f
 609        (let ((c2 (##sys#slot cs 0)))
 610          (##sys#check-char c2 'char>?)
 611          (loop c2 (##sys#slot cs 1)
 612                (and f (##core#inline "C_u_i_char_greaterp" c c2)))))))
 613
 614(define (char<? c1 c2 . more)
 615  (##sys#check-char c1 'char<?)
 616  (##sys#check-char c2 'char<?)
 617  (let loop ((c c2) (cs more)
 618             (f (##core#inline "C_u_i_char_lessp" c1 c2)))
 619    (if (null? cs)
 620        f
 621        (let ((c2 (##sys#slot cs 0)))
 622          (##sys#check-char c2 'char<?)
 623          (loop c2 (##sys#slot cs 1)
 624                (and f (##core#inline "C_u_i_char_lessp" c c2)))))))
 625
 626(define (char>=? c1 c2 . more)
 627  (##sys#check-char c1 'char>=?)
 628  (##sys#check-char c2 'char>=?)
 629  (let loop ((c c2) (cs more)
 630             (f (##core#inline "C_u_i_char_greater_or_equal_p" c1 c2)))
 631    (if (null? cs)
 632        f
 633        (let ((c2 (##sys#slot cs 0)))
 634          (##sys#check-char c2 'char>=?)
 635          (loop c2 (##sys#slot cs 1)
 636                (and f (##core#inline "C_u_i_char_greater_or_equal_p" c c2)))))))
 637
 638(define (char<=? c1 c2 . more)
 639  (##sys#check-char c1 'char<=?)
 640  (##sys#check-char c2 'char<=?)
 641  (let loop ((c c2) (cs more)
 642             (f (##core#inline "C_u_i_char_less_or_equal_p" c1 c2)))
 643    (if (null? cs)
 644        f
 645        (let ((c2 (##sys#slot cs 0)))
 646          (##sys#check-char c2 'char<=?)
 647          (loop c2 (##sys#slot cs 1)
 648                (and f (##core#inline "C_u_i_char_less_or_equal_p" c c2)))))))
 649
 650(define (char-upcase c)
 651  (##sys#check-char c 'char-upcase)
 652  (##core#inline "C_u_i_char_upcase" c))
 653
 654(define (char-downcase c)
 655  (##sys#check-char c 'char-downcase)
 656  (##core#inline "C_u_i_char_downcase" c))
 657
 658(define char-ci=?)
 659(define char-ci>?)
 660(define char-ci<?)
 661(define char-ci>=?)
 662(define char-ci<=?)
 663
 664(define (char-upper-case? c)
 665  (##sys#check-char c 'char-upper-case?)
 666  (##core#inline "C_u_i_char_upper_casep" c) )
 667
 668(define (char-lower-case? c)
 669  (##sys#check-char c 'char-lower-case?)
 670  (##core#inline "C_u_i_char_lower_casep" c) )
 671
 672(define (char-numeric? c)
 673  (##sys#check-char c 'char-numeric?)
 674  (##core#inline "C_u_i_char_numericp" c) )
 675
 676(define (char-whitespace? c)
 677  (##sys#check-char c 'char-whitespace?)
 678  (##core#inline "C_u_i_char_whitespacep" c) )
 679
 680(define (char-alphabetic? c)
 681  (##sys#check-char c 'char-alphabetic?)
 682  (##core#inline "C_u_i_char_alphabeticp" c) )
 683
 684(define (scheme.char#digit-value c)
 685  (##sys#check-char c 'digit-value)
 686  (let ((n (##core#inline "C_u_i_digit_value" c)))
 687    (and (not (eq? n 0))
 688         (##core#inline "C_fixnum_difference" n 1))))
 689
 690;; case folding and conversion
 691
 692(define (char-foldcase c)
 693  (##sys#check-char c 'char-foldcase)
 694  (##core#inline "C_utf_char_foldcase" c))
 695
 696(define (string-foldcase str)
 697  (##sys#check-string str 'string-foldcase)
 698  (let* ((bv (##sys#slot str 0))
 699         (n (##core#inline "C_fixnum_difference" (##sys#size bv) 1))
 700         (buf (##sys#make-bytevector (##core#inline "C_fixnum_times" n 2)))
 701         (len (##core#inline "C_utf_string_foldcase" bv buf n)))
 702    (##sys#buffer->string! buf len)))
 703    
 704(define (string-downcase str)
 705  (##sys#check-string str 'string-downcase)
 706  (let* ((bv (##sys#slot str 0))
 707         (n (##core#inline "C_fixnum_difference" (##sys#size bv) 1))
 708         (buf (##sys#make-bytevector (##core#inline "C_fixnum_times" n 2)))
 709         (len (##core#inline "C_utf_string_downcase" bv buf n)))
 710    (##sys#buffer->string! buf len)))
 711
 712(define (string-upcase str)
 713  (##sys#check-string str 'string-upcase)
 714  (let* ((bv (##sys#slot str 0))
 715         (n (##core#inline "C_fixnum_difference" (##sys#size bv) 1))
 716         (buf (##sys#make-bytevector (##core#inline "C_fixnum_times" n 2)))
 717         (len (##core#inline "C_utf_string_upcase" bv buf n)))
 718    (##sys#buffer->string! buf len)))
 719
 720;;; Procedures:
 721
 722(define (procedure? x) (##core#inline "C_i_closurep" x))
 723(define apply (##core#primitive "C_apply"))
 724(define values (##core#primitive "C_values"))
 725(define call-with-values (##core#primitive "C_call_with_values"))
 726(define call-with-current-continuation)
 727(define call/cc)
 728
 729;;; Ports:
 730
 731(define (input-port? x)
 732  (and (##core#inline "C_blockp" x)
 733       (##core#inline "C_input_portp" x)))
 734
 735(define (output-port? x)
 736  (and (##core#inline "C_blockp" x)
 737       (##core#inline "C_output_portp" x)))
 738
 739(define (binary-port? port)
 740  (and (port? port)
 741       (eq? 'binary (##sys#slot port 14))))
 742
 743(define (textual-port? port)
 744  (and (port? port)
 745       (eq? 'textual (##sys#slot port 14))))
 746
 747(set! scheme#port?
 748  (lambda (x)
 749    (and (##core#inline "C_blockp" x)
 750         (##core#inline "C_portp" x))))
 751
 752(set! scheme#input-port-open?
 753  (lambda (p)
 754    (##sys#check-input-port p 'input-port-open?)
 755    (##core#inline "C_input_port_openp" p)))
 756
 757(set! scheme#output-port-open?
 758  (lambda (p)
 759    (##sys#check-output-port p 'output-port-open?)
 760    (##core#inline "C_output_port_openp" p)))
 761
 762(define current-input-port)
 763(define current-output-port)
 764(define open-input-file)
 765(define open-output-file)
 766(define close-input-port)
 767(define close-output-port)
 768(define call-with-input-file)
 769(define call-with-output-file)
 770(define with-input-from-file)
 771(define with-output-to-file)
 772
 773;;; Input:
 774
 775(define (eof-object? x) (##core#inline "C_eofp" x))
 776(define char-ready?)
 777(define u8-ready?)
 778(define read-char)
 779(define peek-char)
 780(define read)
 781
 782;;; Output:
 783
 784(define write-char)
 785(define newline)
 786(define write)
 787(define display)
 788
 789;;; Evaluation environments:
 790
 791;; All of the stuff below is overwritten with their "real"
 792;; implementations by chicken.eval (see eval.scm)
 793
 794(define (eval x . env)
 795  (##sys#error 'eval "`eval' is not defined - the `eval' unit was probably not linked with this executable"))
 796
 797(define (interaction-environment)
 798  (##sys#error 'interaction-environment "`interaction-environment' is not defined - the `eval' unit was probably not linked with this executable"))
 799
 800(define (scheme-report-environment n)
 801  (##sys#error 'scheme-report-environment "`scheme-report-environment' is not defined - the `eval' unit was probably not linked with this executable"))
 802
 803(define (null-environment)
 804  (##sys#error 'null-environment "`null-environment' is not defined - the `eval' unit was probably not linked with this executable"))
 805
 806(define (load filename . evaluator)
 807  (##sys#error 'load "`load' is not defined - the `eval' unit was probably not linked with this executable"))
 808
 809;; Other stuff:
 810
 811(define force)
 812(define for-each)
 813(define map)
 814(define dynamic-wind)
 815
 816) ; scheme
 817
 818(import scheme)
 819(import (only (scheme base) make-parameter open-output-string get-output-string))
 820
 821;; Pre-declaration of chicken.base, so it can be used later on.  Much
 822;; like the "scheme" module, most declarations will be set! further
 823;; down in this file, mostly to avoid a cyclic dependency on itself.
 824;; The full definition (with macros) is in its own import library.
 825(module chicken.base
 826  (;; [syntax] and-let* case-lambda cut cute declare define-constant
 827   ;; define-inline define-record define-record-type
 828   ;; define-values delay-force fluid-let include
 829   ;; include-relative let-optionals let-values let*-values letrec*
 830   ;; letrec-values nth-value optional parameterize rec receive
 831   ;; require-library require-extension set!-values syntax unless when
 832   bignum? flonum? fixnum? ratnum? cplxnum? finite? infinite? nan?
 833   exact-integer-sqrt exact-integer-nth-root
 834
 835   port-closed? flush-output
 836   get-call-chain print print* add1 sub1 sleep
 837   current-error-port error void gensym print-call-chain
 838   char-name enable-warnings
 839   equal=? finite? foldl foldr getter-with-setter
 840   notice procedure-information setter signum string->uninterned-symbol
 841   subvector symbol-append vector-resize
 842   warning quotient&remainder quotient&modulo
 843   record-printer set-record-printer!
 844   make-promise promise?
 845   alist-ref alist-update alist-update! rassoc atom? butlast chop
 846   compress flatten intersperse join list-of? tail? constantly
 847   complement compose conjoin disjoin each flip identity o
 848
 849   case-sensitive keyword-style parentheses-synonyms symbol-escape
 850
 851   on-exit exit exit-handler implicit-exit-handler emergency-exit
 852   bwp-object? weak-cons weak-pair?)
 853
 854(import scheme chicken.internal.syntax)
 855
 856(define (fixnum? x) (##core#inline "C_fixnump" x))
 857(define (flonum? x) (##core#inline "C_i_flonump" x))
 858(define (bignum? x) (##core#inline "C_i_bignump" x))
 859(define (ratnum? x) (##core#inline "C_i_ratnump" x))
 860(define (cplxnum? x) (##core#inline "C_i_cplxnump" x))
 861(define exact-integer-sqrt)
 862(define exact-integer-nth-root)
 863
 864(define quotient&remainder (##core#primitive "C_quotient_and_remainder"))
 865;; Modulo's sign follows y (whereas remainder's sign follows x)
 866;; Inlining this is not much use: quotient&remainder is primitive
 867(define (quotient&modulo x y)
 868  (call-with-values (lambda () (quotient&remainder x y))
 869    (lambda (div rem)
 870      (if (positive? y)
 871	  (if (negative? rem)
 872	      (values div (+ rem y))
 873	      (values div rem))
 874	  (if (positive? rem)
 875	      (values div (+ rem y))
 876	      (values div rem))))))
 877
 878
 879(define (finite? x) (##core#inline "C_i_finitep" x))
 880(define (infinite? x) (##core#inline "C_i_infinitep" x))
 881(define (nan? x) (##core#inline "C_i_nanp" x))
 882
 883(define signum (##core#primitive "C_signum"))
 884
 885(define equal=?)
 886(define get-call-chain)
 887(define print-call-chain)
 888(define print)
 889(define print*)
 890(define (add1 n) (+ n 1))
 891(define (sub1 n) (- n 1))
 892(define current-error-port)
 893
 894(define (error . args)
 895  (if (pair? args)
 896      (apply ##sys#signal-hook #:error args)
 897      (##sys#signal-hook #:error #f)))
 898
 899(define (void . _) (##core#undefined))
 900
 901(define sleep)
 902
 903(define char-name)
 904(define enable-warnings)
 905; (define enable-notices)???
 906(define getter-with-setter)
 907(define procedure-information)
 908(define setter)
 909(define string->uninterned-symbol)
 910(define record-printer)
 911(define set-record-printer!)
 912
 913(define gensym)
 914
 915(define subvector)
 916(define vector-resize)
 917
 918(define symbol-append)
 919(define warning)
 920(define notice)
 921
 922(define port-closed?)
 923(define flush-output)
 924
 925;;; Promises:
 926
 927(define (promise? x)
 928  (##sys#structure? x 'promise))
 929
 930(define (##sys#make-promise proc)
 931  (##sys#make-structure 'promise proc))
 932
 933(define (make-promise obj)
 934  (if (promise? obj) obj
 935      (##sys#make-promise (lambda () obj))))
 936
 937;;; fast folds with correct argument order
 938
 939(define (foldl f z lst)
 940  (##sys#check-list lst 'foldl)
 941  (let loop ((lst lst) (z z))
 942    (if (not (pair? lst))
 943	z
 944	(loop (##sys#slot lst 1) (f z (##sys#slot lst 0))))))
 945
 946(define (foldr f z lst)
 947  (##sys#check-list lst 'foldr)
 948  (let loop ((lst lst))
 949    (if (not (pair? lst))
 950	z
 951	(f (##sys#slot lst 0) (loop (##sys#slot lst 1))))))
 952
 953;;; Exit:
 954
 955(define implicit-exit-handler)
 956(define exit-handler)
 957
 958(define chicken.base#cleanup-tasks '())
 959
 960(define (on-exit thunk)
 961  (set! cleanup-tasks (cons thunk chicken.base#cleanup-tasks)))
 962
 963(define (exit #!optional (code 0))
 964  ((exit-handler) code))
 965
 966(define (emergency-exit #!optional (code 0))
 967  (##sys#check-fixnum code 'emergency-exit)
 968  (##core#inline "C_exit_runtime" code))
 969
 970;;; Parameters:
 971
 972(define case-sensitive)
 973(define keyword-style)
 974(define parentheses-synonyms)
 975(define symbol-escape)
 976
 977;;; Combinators:
 978
 979(define (identity x) x)
 980
 981(define (conjoin . preds)
 982  (lambda (x)
 983    (let loop ((preds preds))
 984      (or (null? preds)
 985	  (and ((##sys#slot preds 0) x)
 986	       (loop (##sys#slot preds 1)) ) ) ) ) )
 987
 988(define (disjoin . preds)
 989  (lambda (x)
 990    (let loop ((preds preds))
 991      (and (not (null? preds))
 992	   (or ((##sys#slot preds 0) x)
 993	       (loop (##sys#slot preds 1)) ) ) ) ) )
 994
 995(define (constantly . xs)
 996  (if (eq? 1 (length xs))
 997      (let ((x (car xs)))
 998	(lambda _ x) )
 999      (lambda _ (apply values xs)) ) )
 1000
1001(define (flip proc) (lambda (x y) (proc y x)))
1002
1003(define complement
1004  (lambda (p)
1005    (lambda args (not (apply p args))) ) )
1006
1007(define (compose . fns)
1008  (define (rec f0 . fns)
1009    (if (null? fns)
1010	f0
1011	(lambda args
1012	  (call-with-values
1013	      (lambda () (apply (apply rec fns) args))
1014	    f0) ) ) )
1015  (if (null? fns)
1016      values
1017      (apply rec fns) ) )
1018
1019(define (o . fns)
1020  (if (null? fns)
1021      identity
1022      (let loop ((fns fns))
1023	(let ((h (##sys#slot fns 0))
1024	      (t (##sys#slot fns 1)) )
1025	  (if (null? t)
1026	      h
1027	      (lambda (x) (h ((loop t) x))))))))
1028
1029(define (list-of? pred)
1030  (lambda (lst)
1031    (let loop ((lst lst))
1032      (cond ((null? lst) #t)
1033	    ((not (pair? lst)) #f)
1034	    ((pred (##sys#slot lst 0)) (loop (##sys#slot lst 1)))
1035	    (else #f) ) ) ) )
1036
1037(define (each . procs)
1038  (cond ((null? procs) (lambda _ (void)))
1039	((null? (##sys#slot procs 1)) (##sys#slot procs 0))
1040	(else
1041	 (lambda args
1042	   (let loop ((procs procs))
1043	     (let ((h (##sys#slot procs 0))
1044		   (t (##sys#slot procs 1)) )
1045	       (if (null? t)
1046		   (apply h args)
1047		   (begin
1048		     (apply h args)
1049		     (loop t) ) ) ) ) ) ) ) )
1050
1051
1052;;; Weak pairs:
1053(define (bwp-object? x) (##core#inline "C_bwpp" x))
1054(define (weak-cons x y) (##core#inline_allocate ("C_a_i_weak_cons" 3) x y))
1055(define (weak-pair? x) (##core#inline "C_i_weak_pairp" x))
1056
1057;;; List operators:
1058
1059(define (atom? x) (##core#inline "C_i_not_pair_p" x))
1060
1061(define (tail? x y)
1062  (##sys#check-list y 'tail?)
1063  (let loop ((y y))
1064    (cond ((##core#inline "C_eqp" x y) #t)
1065          ((and (##core#inline "C_blockp" y)
1066                (##core#inline "C_pairp" y))
1067           (loop (##sys#slot y 1)))
1068          (else #f))))
1069
1070(define intersperse
1071  (lambda (lst x)
1072    (let loop ((ns lst))
1073      (if (##core#inline "C_eqp" ns '())
1074	  ns
1075	  (let ((tail (cdr ns)))
1076	    (if (##core#inline "C_eqp" tail '())
1077		ns
1078		(cons (##sys#slot ns 0) (cons x (loop tail))) ) ) ) ) ) )
1079
1080(define (butlast lst)
1081  (##sys#check-pair lst 'butlast)
1082  (let loop ((lst lst))
1083    (let ((next (##sys#slot lst 1)))
1084      (if (and (##core#inline "C_blockp" next) (##core#inline "C_pairp" next))
1085	  (cons (##sys#slot lst 0) (loop next))
1086	  '() ) ) ) )
1087
1088(define (flatten . lists0)
1089  (let loop ((lists lists0) (rest '()))
1090    (cond ((null? lists) rest)
1091	  (else
1092	   (let ((head (##sys#slot lists 0))
1093		 (tail (##sys#slot lists 1)) )
1094	     (if (list? head)
1095		 (loop head (loop tail rest))
1096		 (cons head (loop tail rest)) ) ) ) ) ) )
1097
1098(define chop)
1099
1100(define (join lsts . lst)
1101  (let ((lst (if (pair? lst) (car lst) '())))
1102    (##sys#check-list lst 'join)
1103    (let loop ((lsts lsts))
1104      (cond ((null? lsts) '())
1105	    ((not (pair? lsts))
1106	     (##sys#error-not-a-proper-list lsts) )
1107	    (else
1108	     (let ((l (##sys#slot lsts 0))
1109		   (r (##sys#slot lsts 1)) )
1110	       (if (null? r)
1111		   l
1112		   (##sys#append l lst (loop r)) ) ) ) ) ) ) )
1113
1114(define compress
1115  (lambda (blst lst)
1116    (let ((msg "bad argument type - not a proper list"))
1117      (##sys#check-list lst 'compress)
1118      (let loop ((blst blst) (lst lst))
1119	(cond ((null? blst) '())
1120	      ((not (pair? blst))
1121	       (##sys#signal-hook #:type-error 'compress msg blst) )
1122	      ((not (pair? lst))
1123	       (##sys#signal-hook #:type-error 'compress msg lst) )
1124	      ((##sys#slot blst 0)
1125	       (cons (##sys#slot lst 0) (loop (##sys#slot blst 1) (##sys#slot lst 1))))
1126	      (else (loop (##sys#slot blst 1) (##sys#slot lst 1))) ) ) ) ) )
1127
1128
1129;;; Alists:
1130
1131(define (alist-update! x y lst #!optional (cmp eqv?))
1132  (let* ((aq (cond ((eq? eq? cmp) assq)
1133		   ((eq? eqv? cmp) assv)
1134		   ((eq? equal? cmp) assoc)
1135		   (else
1136		    (lambda (x lst)
1137		      (let loop ((lst lst))
1138			(and (pair? lst)
1139			     (let ((a (##sys#slot lst 0)))
1140			       (if (and (pair? a) (cmp x (##sys#slot a 0)))
1141				   a
1142				   (loop (##sys#slot lst 1)) ) ) ) ) ) ) ) )
1143	 (item (aq x lst)) )
1144    (if item
1145	(begin
1146	  (##sys#setslot item 1 y)
1147	  lst)
1148	(cons (cons x y) lst) ) ) )
1149
1150(define (alist-update k v lst #!optional (cmp eqv?))
1151  (let loop ((lst lst))
1152    (cond ((null? lst)
1153           (list (cons k v)))
1154          ((not (pair? lst))
1155           (error 'alist-update "bad argument type" lst))
1156          (else
1157           (let ((a (##sys#slot lst 0)))
1158             (cond ((not (pair? a))
1159                    (error 'alist-update "bad argument type" a))
1160                   ((cmp k (##sys#slot a 0))
1161                    (cons (cons k v) (##sys#slot lst 1)))
1162                   (else
1163                    (cons (cons (##sys#slot a 0) (##sys#slot a 1))
1164                          (loop (##sys#slot lst 1))))))))))
1165
1166(define (alist-ref x lst #!optional (cmp eqv?) (default #f))
1167  (let* ((aq (cond ((eq? eq? cmp) assq)
1168		   ((eq? eqv? cmp) assv)
1169		   ((eq? equal? cmp) assoc)
1170		   (else
1171		    (lambda (x lst)
1172		      (let loop ((lst lst))
1173			(cond
1174			 ((null? lst) #f)
1175			 ((pair? lst)
1176			  (let ((a (##sys#slot lst 0)))
1177			    (##sys#check-pair a 'alist-ref)
1178			    (if (cmp x (##sys#slot a 0))
1179				a
1180				(loop (##sys#slot lst 1)) ) ))
1181			 (else (error 'alist-ref "bad argument type" lst)) )  ) ) ) ) )
1182	 (item (aq x lst)) )
1183    (if item
1184	(##sys#slot item 1)
1185	default) ) )
1186
1187;; TODO: Make inlineable in C without "tst", to be more like assoc?
1188(define (rassoc x lst . tst)
1189  (##sys#check-list lst 'rassoc)
1190  (let ((tst (if (pair? tst) (car tst) eqv?)))
1191    (let loop ((l lst))
1192      (and (pair? l)
1193	   (let ((a (##sys#slot l 0)))
1194	     (##sys#check-pair a 'rassoc)
1195	     (if (tst x (##sys#slot a 1))
1196		 a
1197		 (loop (##sys#slot l 1)) ) ) ) ) ) )
1198
1199) ; chicken.base
1200
1201(import chicken.base)
1202
1203(define-constant output-string-initial-size 256)
1204
1205(set! scheme#open-input-string
1206  (lambda (string)
1207    (##sys#check-string string 'open-input-string)
1208    (let* ((port (##sys#make-port 1 ##sys#string-port-class "(string)" 'string))
1209           (bv (##sys#slot string 0))
1210           (len (##core#inline "C_fixnum_difference" (##sys#size bv) 1))
1211           (bv2 (##sys#make-bytevector len)))
1212      (##core#inline "C_copy_memory" bv2 bv len)
1213      (##sys#setislot port 10 0)
1214      (##sys#setislot port 11 len)
1215      (##sys#setslot port 12 bv2)
1216      port)))
1217
1218(set! scheme#open-output-string
1219  (lambda ()
1220    (let ((port (##sys#make-port 2 ##sys#string-port-class "(string)" 'string)))
1221      (##sys#setislot port 10 0)
1222      (##sys#setislot port 11 output-string-initial-size)
1223      (##sys#setslot port 12 (##sys#make-bytevector output-string-initial-size))
1224      port)))
1225
1226(set! scheme#get-output-string
1227  (lambda (port)
1228    (##sys#check-output-port port #f 'get-output-string)
1229    (if (not (eq? 'string (##sys#slot port 7)))
1230        (##sys#signal-hook
1231         #:type-error 'get-output-string "argument is not a string-output-port" port)
1232        (##sys#buffer->string (##sys#slot port 12) 0 (##sys#slot port 10)))))
1233
1234(set! scheme#open-input-bytevector
1235 (lambda (bv)
1236  (let ((port (##sys#make-port 1 #f "(bytevector)" 'custom)))
1237    (##sys#check-bytevector bv 'open-input-bytevector)
1238    (##sys#setslot port 14 'binary)
1239    (##sys#setslot
1240     port
1241     2
1242     (let ((index 0)
1243           (bv-len (##sys#size bv)))
1244       (vector (lambda (_) ; read-char
1245                 (if (eq? index bv-len)
1246                     #!eof
1247                     (let ((c (##core#inline "C_i_bytevector_ref" bv index)))
1248                       (set! index (##core#inline "C_fixnum_plus" index 1))
1249                       (fast-i->c c))))
1250               (lambda (_) ; peek-char
1251                 (if (eq? index bv-len)
1252                     #!eof
1253                     (##core#inline "C_i_bytevector_ref" bv index)))
1254               #f    ; write-char
1255               #f    ; write-bytevector
1256               (lambda (_ _) ; close
1257                 (##sys#setislot port 8 #t))
1258               #f    ; flush-output
1259               (lambda (_) ; char-ready?
1260                 (not (eq? index bv-len)))
1261               (lambda (p n dest start)    ; read-bytevector!
1262                 (let ((n2 (min n (##core#inline "C_fixnum_difference" bv-len index))))
1263                   (##core#inline "C_copy_memory_with_offset" dest bv start index n2)
1264                   (set! index (##core#inline "C_fixnum_plus" index n2))
1265                   n2))
1266               #f    ; read-line
1267               #f))) ; read-buffered
1268     port)))
1269
1270(set! scheme#open-output-bytevector
1271 (lambda ()
1272  (let ((port (##sys#make-port 2 #f "(bytevector)" 'custom))
1273        (buffer (##sys#make-bytevector 256))
1274        (index 0)
1275        (size 256))
1276    (define (add bv start end)
1277      (let* ((len (##core#inline "C_fixnum_difference" end start))
1278             (i2 (##core#inline "C_fixnum_plus" index len)))
1279        (when (##core#inline "C_fixnum_greaterp" i2 size)
1280          (let* ((sz2 (##core#inline "C_fixnum_plus" size i2))
1281                 (bv2 (##sys#make-bytevector sz2)))
1282            (##core#inline "C_copy_memory_with_offset" bv2 buffer 0 0 index)
1283            (set! size sz2)
1284            (set! buffer bv2)))
1285        (##core#inline "C_copy_memory_with_offset" buffer bv index start len)
1286        (set! index i2)))
1287    (define (getter)
1288      (let ((bv (##sys#make-bytevector index)))
1289        (##core#inline "C_copy_memory_with_offset" bv buffer 0 0 index)
1290        bv))
1291    (##sys#setslot port 9 getter)
1292    (##sys#setslot port 14 'binary)
1293    (##sys#setslot
1294     port
1295     2
1296     (vector #f ; read-char
1297             #f ; peek-char
1298             (lambda (p c)    ; write-char
1299               (let* ((s (string c))
1300                      (bv (##sys#slot s 0)))
1301                 (add bv 0 (##core#inline "C_fixnum_difference" (##sys#size bv) 1))))
1302             (lambda (p bv start end)    ; write-bytevector
1303               (add bv start end))
1304             (lambda (_ _) ; close
1305               (##sys#setislot port 8 #t))
1306             #f    ; flush-output
1307             #f ; char-ready?
1308             #f  ; read-bytevector!
1309             #f    ; read-line
1310             #f)) ; read-buffered
1311     port)))
1312
1313(set! scheme#get-output-bytevector
1314 (lambda (p)
1315  (define (fail) (error 'get-output-bytevector "not an output-bytevector" p))
1316  (##sys#check-port p 'get-output-bytevector)
1317  (if (eq? (##sys#slot p 7) 'custom)
1318      (let ((getter (##sys#slot p 9)))
1319        (if (procedure? getter)
1320            (getter)
1321            (fail)))
1322      (fail))))
1323
1324(define-constant char-name-table-size 37)
1325(define-constant read-line-buffer-initial-size 1024)
1326(define-constant default-parameter-vector-size 16)
1327(define maximal-string-length (- (foreign-value "C_HEADER_SIZE_MASK" unsigned-long) 1))
1328
1329;;; Fixnum arithmetic:
1330
1331(module chicken.fixnum *
1332(import scheme)
1333(import chicken.foreign)
1334
1335(define most-positive-fixnum (foreign-value "C_MOST_POSITIVE_FIXNUM" int))
1336(define most-negative-fixnum (foreign-value "C_MOST_NEGATIVE_FIXNUM" int))
1337(define fixnum-bits (foreign-value "(C_WORD_SIZE - 1)" int))
1338(define fixnum-precision (foreign-value "(C_WORD_SIZE - (1 + 1))" int))
1339
1340(define (fx+ x y) (##core#inline "C_fixnum_plus" x y))
1341(define (fx- x y) (##core#inline "C_fixnum_difference" x y))
1342(define (fx* x y) (##core#inline "C_fixnum_times" x y))
1343(define (fx= x y) (eq? x y))
1344(define (fx> x y) (##core#inline "C_fixnum_greaterp" x y))
1345(define (fx< x y) (##core#inline "C_fixnum_lessp" x y))
1346(define (fx>= x y) (##core#inline "C_fixnum_greater_or_equal_p" x y))
1347(define (fx<= x y) (##core#inline "C_fixnum_less_or_equal_p" x y))
1348(define (fxmin x y) (##core#inline "C_i_fixnum_min" x y))
1349(define (fxmax x y) (##core#inline "C_i_fixnum_max" x y))
1350(define (fxneg x) (##core#inline "C_fixnum_negate" x))
1351(define (fxand x y) (##core#inline "C_fixnum_and" x y))
1352(define (fxior x y) (##core#inline "C_fixnum_or" x y))
1353(define (fxxor x y) (##core#inline "C_fixnum_xor" x y))
1354(define (fxnot x) (##core#inline "C_fixnum_not" x))
1355(define (fxshl x y) (##core#inline "C_fixnum_shift_left" x y))
1356(define (fxshr x y) (##core#inline "C_fixnum_shift_right" x y))
1357(define (fxodd? x) (##core#inline "C_i_fixnumoddp" x))
1358(define (fxeven? x) (##core#inline "C_i_fixnumevenp" x))
1359(define (fxlen x) (##core#inline "C_i_fixnum_length" x))
1360(define (fx/ x y) (##core#inline "C_fixnum_divide" x y) )
1361(define (fxgcd x y) (##core#inline "C_i_fixnum_gcd" x y))
1362(define (fxmod x y) (##core#inline "C_fixnum_modulo" x y) )
1363(define (fxrem x y) (##core#inline "C_i_fixnum_remainder_checked" x y) )
1364
1365;; Overflow-detecting versions of some of the above
1366(define (fx+? x y) (##core#inline "C_i_o_fixnum_plus" x y) )
1367(define (fx-? x y) (##core#inline "C_i_o_fixnum_difference" x y) )
1368(define (fx*? x y) (##core#inline "C_i_o_fixnum_times" x y) )
1369(define (fx/? x y) (##core#inline "C_i_o_fixnum_quotient" x y))
1370
1371) ; chicken.fixnum
1372
1373(import chicken.fixnum)
1374
1375
1376;;; System routines:
1377
1378(define (##sys#debug-mode?) (##core#inline "C_i_debug_modep"))
1379
1380(define ##sys#warnings-enabled #t)
1381(define ##sys#notices-enabled (##sys#debug-mode?))
1382
1383(set! chicken.base#warning
1384  (lambda (msg . args)
1385    (when ##sys#warnings-enabled
1386      (apply ##sys#signal-hook #:warning msg args))))
1387
1388(set! chicken.base#notice
1389  (lambda (msg . args)
1390    (when (and ##sys#notices-enabled
1391	       ##sys#warnings-enabled)
1392      (apply ##sys#signal-hook #:notice msg args))))
1393
1394(set! chicken.base#enable-warnings
1395  (lambda bool
1396    (if (pair? bool)
1397	(set! ##sys#warnings-enabled (car bool))
1398	##sys#warnings-enabled)))
1399
1400(define ##sys#error error)
1401(define ##sys#warn warning)
1402(define ##sys#notice notice)
1403
1404(define (##sys#error/errno err . args)
1405  (if (pair? args)
1406      (apply ##sys#signal-hook/errno #:error err #f args)
1407      (##sys#signal-hook/errno #:error err #f)))
1408
1409(define-foreign-variable strerror c-string "strerror(errno)")
1410
1411(define ##sys#gc (##core#primitive "C_gc"))
1412(define (##sys#setslot x i y) (##core#inline "C_i_setslot" x i y))
1413(define (##sys#setislot x i y) (##core#inline "C_i_set_i_slot" x i y))
1414(define ##sys#allocate-vector (##core#primitive "C_allocate_vector"))
1415(define ##sys#allocate-bytevector (##core#primitive "C_allocate_bytevector"))
1416(define ##sys#make-structure (##core#primitive "C_make_structure"))
1417(define ##sys#ensure-heap-reserve (##core#primitive "C_ensure_heap_reserve"))
1418(define ##sys#symbol-table-info (##core#primitive "C_get_symbol_table_info"))
1419(define ##sys#memory-info (##core#primitive "C_get_memory_info"))
1420
1421(define (##sys#start-timer)
1422  (##sys#gc #t)
1423  (##core#inline "C_start_timer"))
1424
1425(define (##sys#stop-timer)
1426  (let ((info ((##core#primitive "C_stop_timer"))))
1427    ;; Run a major GC one more time to get memory usage information in
1428    ;; case there was no major GC while the timer was running
1429    (##sys#gc #t)
1430    (##sys#setslot info 6 (##sys#slot ((##core#primitive "C_stop_timer")) 6))
1431    info))
1432
1433(define (##sys#immediate? x) (not (##core#inline "C_blockp" x)))
1434(define (##sys#message str) (##core#inline "C_message" str))
1435(define (##sys#byte x i) (##core#inline "C_subbyte" x i))
1436(define ##sys#void void)
1437(define ##sys#undefined-value (##core#undefined))
1438(define (##sys#halt msg) (##core#inline "C_halt" msg))
1439(define ##sys#become! (##core#primitive "C_become"))
1440(define (##sys#block-ref x i) (##core#inline "C_i_block_ref" x i))
1441(define ##sys#apply-values (##core#primitive "C_apply_values"))
1442(define ##sys#copy-closure (##core#primitive "C_copy_closure"))
1443
1444(define (##sys#block-set! x i y)
1445  (when (or (not (##core#inline "C_blockp" x))
1446	    (and (##core#inline "C_specialp" x) (fx= i 0))
1447	    (##core#inline "C_byteblockp" x) )
1448    (##sys#signal-hook '#:type-error '##sys#block-set! "slot not accessible" x) )
1449  (##sys#check-range i 0 (##sys#size x) '##sys#block-set!)
1450  (##sys#setslot x i y) )
1451
1452(module chicken.time
1453    ;; NOTE: We don't emit the import lib.  Due to syntax exports, it has
1454    ;; to be a hardcoded primitive module.
1455    ;;
1456    ;; [syntax] time
1457    (cpu-time
1458     current-process-milliseconds current-seconds)
1459
1460(import scheme)
1461(import (only chicken.module reexport))
1462
1463(define (current-process-milliseconds)
1464  (##core#inline_allocate ("C_a_i_current_process_milliseconds" 7) #f))
1465
1466(define (current-seconds)
1467  (##core#inline_allocate ("C_a_get_current_seconds" 7) #f))
1468
1469(define cpu-time
1470  (let () ;; ((buf (vector #f #f))) Disabled for now: vector is defined below!
1471    (lambda ()
1472      (let ((buf (vector #f #f)))
1473	;; should be thread-safe as no context-switch will occur after
1474	;; function entry and `buf' contents will have been extracted
1475	;; before `values' gets called.
1476	(##core#inline_allocate ("C_a_i_cpu_time" 8) buf)
1477	(values (##sys#slot buf 0) (##sys#slot buf 1)) )) ))
1478
1479) ; chicken.time
1480
1481(define (##sys#check-structure x y . loc)
1482  (if (pair? loc)
1483      (##core#inline "C_i_check_structure_2" x y (car loc))
1484      (##core#inline "C_i_check_structure" x y) ) )
1485
1486;; DEPRECATED
1487(define (##sys#check-blob x . loc)
1488  (if (pair? loc)
1489      (##core#inline "C_i_check_bytevector_2" x (car loc))
1490      (##core#inline "C_i_check_bytevector" x) ) )
1491
1492(define ##sys#check-bytevector ##sys#check-blob)
1493
1494(define (##sys#check-pair x . loc)
1495  (if (pair? loc)
1496      (##core#inline "C_i_check_pair_2" x (car loc))
1497      (##core#inline "C_i_check_pair" x) ) )
1498
1499(define (##sys#check-list x . loc)
1500  (if (pair? loc)
1501      (##core#inline "C_i_check_list_2" x (car loc))
1502      (##core#inline "C_i_check_list" x) ) )
1503
1504(define (##sys#check-string x . loc)
1505  (if (pair? loc)
1506      (##core#inline "C_i_check_string_2" x (car loc))
1507      (##core#inline "C_i_check_string" x) ) )
1508
1509(define (##sys#check-number x . loc)
1510  (if (pair? loc)
1511      (##core#inline "C_i_check_number_2" x (car loc))
1512      (##core#inline "C_i_check_number" x) ) )
1513
1514(define (##sys#check-fixnum x . loc)
1515  (if (pair? loc)
1516      (##core#inline "C_i_check_fixnum_2" x (car loc))
1517      (##core#inline "C_i_check_fixnum" x) ) )
1518
1519(define (##sys#check-bytevector x . loc)
1520  (if (pair? loc)
1521      (##core#inline "C_i_check_bytevector_2" x (car loc))
1522      (##core#inline "C_i_check_bytevector" x) ) )
1523
1524(define (##sys#check-exact x . loc) ;; DEPRECATED
1525  (if (pair? loc)
1526      (##core#inline "C_i_check_exact_2" x (car loc))
1527      (##core#inline "C_i_check_exact" x) ) )
1528
1529(define (##sys#check-inexact x . loc)
1530  (if (pair? loc)
1531      (##core#inline "C_i_check_inexact_2" x (car loc))
1532      (##core#inline "C_i_check_inexact" x) ) )
1533
1534(define (##sys#check-symbol x . loc)
1535  (if (pair? loc)
1536      (##core#inline "C_i_check_symbol_2" x (car loc))
1537      (##core#inline "C_i_check_symbol" x) ) )
1538
1539(define (##sys#check-keyword x . loc)
1540  (if (pair? loc)
1541      (##core#inline "C_i_check_keyword_2" x (car loc))
1542      (##core#inline "C_i_check_keyword" x) ) )
1543
1544(define (##sys#check-vector x . loc)
1545  (if (pair? loc)
1546      (##core#inline "C_i_check_vector_2" x (car loc))
1547      (##core#inline "C_i_check_vector" x) ) )
1548
1549(define (##sys#check-char x . loc)
1550  (if (pair? loc)
1551      (##core#inline "C_i_check_char_2" x (car loc))
1552      (##core#inline "C_i_check_char" x) ) )
1553
1554(define (##sys#check-boolean x . loc)
1555  (if (pair? loc)
1556      (##core#inline "C_i_check_boolean_2" x (car loc))
1557      (##core#inline "C_i_check_boolean" x) ) )
1558
1559(define (##sys#check-locative x . loc)
1560  (if (pair? loc)
1561      (##core#inline "C_i_check_locative_2" x (car loc))
1562      (##core#inline "C_i_check_locative" x) ) )
1563
1564(define (##sys#check-integer x . loc)
1565  (unless (##core#inline "C_i_integerp" x)
1566    (##sys#error-bad-integer x (and (pair? loc) (car loc))) ) )
1567
1568(define (##sys#check-exact-integer x . loc)
1569  (unless (##core#inline "C_i_exact_integerp" x)
1570    (##sys#error-bad-exact-integer x (and (pair? loc) (car loc))) ) )
1571
1572(define (##sys#check-exact-uinteger x . loc)
1573  (when (or (not (##core#inline "C_i_exact_integerp" x))
1574	    (##core#inline "C_i_integer_negativep" x))
1575    (##sys#error-bad-exact-uinteger x (and (pair? loc) (car loc))) ) )
1576
1577(define (##sys#check-real x . loc)
1578  (unless (##core#inline "C_i_realp" x)
1579    (##sys#error-bad-real x (and (pair? loc) (car loc))) ) )
1580
1581(define (##sys#check-range i from to . loc)
1582  (if (pair? loc)
1583      (##core#inline "C_i_check_range_2" i from to (car loc))
1584      (##core#inline "C_i_check_range" i from to) ) )
1585
1586(define (##sys#check-range/including i from to . loc)
1587  (if (pair? loc)
1588      (##core#inline "C_i_check_range_including_2" i from to (car loc))
1589      (##core#inline "C_i_check_range_including" i from to) ) )
1590
1591(define (##sys#check-special ptr . loc)
1592  (unless (and (##core#inline "C_blockp" ptr) (##core#inline "C_specialp" ptr))
1593    (##sys#signal-hook #:type-error (and (pair? loc) (car loc)) "bad argument type - not a pointer-like object" ptr) ) )
1594
1595(define (##sys#check-closure x . loc)
1596  (if (pair? loc)
1597      (##core#inline "C_i_check_closure_2" x (car loc))
1598      (##core#inline "C_i_check_closure" x) ) )
1599
1600(set! scheme#force
1601  (lambda (obj)
1602    (if (##sys#structure? obj 'promise)
1603	(let lp ((promise obj)
1604		 (forward #f))
1605	  (let ((val (##sys#slot promise 1)))
1606	    (cond ((null? val) (##sys#values))
1607		  ((pair? val) (apply ##sys#values val))
1608		  ((procedure? val)
1609		   (when forward (##sys#setslot forward 1 promise))
1610		   (let ((results (##sys#call-with-values val ##sys#list)))
1611		     (cond ((not (procedure? (##sys#slot promise 1)))
1612			    (lp promise forward)) ; in case of reentrance
1613			   ((and (not (null? results)) (null? (cdr results))
1614				 (##sys#structure? (##sys#slot results 0) 'promise))
1615			    (let ((result0 (##sys#slot results 0)))
1616			      (##sys#setslot promise 1 (##sys#slot result0 1))
1617			      (lp promise result0)))
1618			   (else
1619			    (##sys#setslot promise 1 results)
1620			    (apply ##sys#values results)))))
1621		  ((##sys#structure? val 'promise)
1622		   (lp val forward)))))
1623	obj)))
1624
1625
1626;;; Dynamic Load
1627
1628(define ##sys#dload (##core#primitive "C_dload"))
1629(define ##sys#set-dlopen-flags! (##core#primitive "C_set_dlopen_flags"))
1630
1631(define (##sys#error-not-a-proper-list arg #!optional loc)
1632  (##sys#error-hook
1633   (foreign-value "C_NOT_A_PROPER_LIST_ERROR" int) loc arg))
1634
1635(define (##sys#error-bad-number arg #!optional loc)
1636  (##sys#error-hook
1637   (foreign-value "C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR" int) loc arg))
1638
1639(define (##sys#error-bad-integer arg #!optional loc)
1640  (##sys#error-hook
1641   (foreign-value "C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR" int) loc arg))
1642
1643(define (##sys#error-bad-exact-integer arg #!optional loc)
1644  (##sys#error-hook
1645   (foreign-value "C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR" int) loc arg))
1646
1647(define (##sys#error-bad-exact-uinteger arg #!optional loc)
1648  (##sys#error-hook
1649   (foreign-value "C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR" int) loc arg))
1650
1651(define (##sys#error-bad-inexact arg #!optional loc)
1652  (##sys#error-hook
1653   (foreign-value "C_CANT_REPRESENT_INEXACT_ERROR" int) loc arg))
1654
1655(define (##sys#error-bad-real arg #!optional loc)
1656  (##sys#error-hook
1657   (foreign-value "C_BAD_ARGUMENT_TYPE_NO_REAL_ERROR" int) loc arg))
1658
1659(define (##sys#error-bad-base arg #!optional loc)
1660  (##sys#error-hook
1661   (foreign-value "C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR" int) loc arg))
1662
1663(set! scheme#append
1664  (lambda lsts
1665    (if (eq? lsts '())
1666	lsts
1667	(let loop ((lsts lsts))
1668	  (if (eq? (##sys#slot lsts 1) '())
1669	      (##sys#slot lsts 0)
1670	      (let copy ((node (##sys#slot lsts 0)))
1671		(cond ((eq? node '()) (loop (##sys#slot lsts 1)))
1672		      ((pair? node)
1673		       (cons (##sys#slot node 0) (copy (##sys#slot node 1))) )
1674		      (else
1675		       (##sys#error-not-a-proper-list
1676			(##sys#slot lsts 0) 'append)) ) )))) ) )
1677
1678(define (##sys#fast-reverse lst0)
1679  (let loop ((lst lst0) (rest '()))
1680    (if (pair? lst)
1681	(loop (##sys#slot lst 1) (cons (##sys#slot lst 0) rest))
1682	rest)))
1683
1684
1685;;; Strings:
1686
1687(define (##sys#make-bytevector size #!optional (fill 0))
1688  (##sys#allocate-bytevector size fill))
1689
1690(define (##sys#make-string size #!optional (fill #\space))
1691  (let* ((count (##core#inline "C_utf_bytes" fill))
1692         (n (fx* count size))
1693         (bv (##sys#allocate-bytevector (fx+ n 1) 0)))
1694    (##core#inline "C_utf_fill" bv fill)
1695    (##core#inline_allocate ("C_a_ustring" 5) bv size)))
1696
1697(define (##sys#buffer->string! buf len)
1698  (##core#inline "C_utf_set_bv_size" buf len)
1699  (##core#inline_allocate ("C_a_ustring" 5) buf
1700                          (##core#inline "C_utf_range_length" buf 0 len)))
1701
1702(define (##sys#buffer->string buf start len)
1703  (let ((bv (##sys#make-bytevector (fx+ len 1))))
1704    (##core#inline "C_copy_memory_with_offset" bv buf 0 start len)
1705    (##core#inline_allocate ("C_a_ustring" 5) bv
1706                            (##core#inline "C_utf_range_length" bv 0 len))))
1707
1708(define (##sys#utf-decoder buf start len k)
1709  (k buf start len))
1710
1711(define (##sys#utf-encoder buf start len k)
1712  (k buf start len))
1713
1714(define (##sys#utf-scanner state byte)
1715  (if state
1716      (if (fx> state 1)
1717          (fx- state 1)
1718          #f)
1719      (let ((n (##core#inline "C_utf_bytes_needed" byte)))
1720        (if (eq? n 1)
1721            #f
1722            (fx- n 1)))))
1723
1724(define (##sys#latin-decoder bv start len k)
1725  (let* ((buf (##sys#make-bytevector (fx* len 2)))
1726         (n (##core#inline "C_latin_to_utf" bv buf start len)))
1727    (k buf 0 n)))
1728
1729(define (##sys#latin-encoder bv start len k)
1730  (let* ((buf (##sys#make-bytevector (fx+ len 1)))
1731         (n (##core#inline "C_utf_to_latin" bv buf start len)))
1732    (k buf 0 n)))
1733
1734(define (##sys#latin-scanner state byte) #f)
1735
1736(define (##sys#binary-decoder bv start len k)
1737  (k bv start len) )
1738
1739(define (##sys#binary-encoder bv start len k)
1740  (k bv start len) )
1741
1742(define (##sys#binary-scanner state byte) #f)
1743
1744;; invokes k with encoding and decoding procedures
1745(define (##sys#encoding-hook enc k)
1746  (case enc
1747    ((binary) (k ##sys#binary-decoder ##sys#binary-encoder ##sys#binary-scanner))
1748    ((utf-8) (k ##sys#utf-decoder ##sys#utf-encoder ##sys#utf-scanner))
1749    ((latin-1) (k ##sys#latin-decoder ##sys#latin-encoder ##sys#latin-scanner))
1750    (else (##sys#signal-hook #:type-error #f "invalid file port encoding" enc))))
1751
1752(define (##sys#register-encoding names dec enc scan)
1753  (let ((old ##sys#encoding-hook))
1754    (set! ##sys#encoding-hook
1755      (lambda (enc k)
1756        (if (or (eq? enc names)
1757                (and (pair? names) (memq enc names)))
1758            (k dec enc scan)
1759            (old enc k))))))
1760
1761;; decode buffer and create string
1762(define (##sys#buffer->string/encoding buf start len enc)
1763  (##sys#encoding-hook
1764    enc
1765    (lambda (decoder _ _) (decoder buf start len ##sys#buffer->string))))
1766
1767;; encode buffer into bytevector
1768(define (##sys#encode-buffer bv start len enc k)
1769  (##sys#encoding-hook
1770    enc
1771    (lambda (_ encoder _) (encoder bv start len k))))
1772
1773;; decode buffer into bytevector
1774(define (##sys#decode-buffer bv start len enc k)
1775  (##sys#encoding-hook
1776    enc
1777    (lambda (decoder _ _) (decoder bv start len k))))
1778
1779;; encode a single character into bytevector, return number of bytes
1780(define (##sys#encode-char c bv enc)
1781  (##sys#encoding-hook
1782    enc
1783    (lambda (_ encoder _)
1784      (let* ((bv1 (##sys#make-bytevector 4))
1785             (n (##core#inline "C_utf_insert" bv1 0 c)))
1786        (encoder bv1 0 n
1787                 (lambda (buf start len)
1788                   (##core#inline "C_copy_memory_with_offset" bv buf 0 start len)
1789                   len))))))
1790
1791(define (##sys#decode-char bv enc start)
1792  (##sys#decode-buffer
1793    bv start (##sys#size bv) enc
1794    (lambda (buf start _)
1795      (##core#inline "C_utf_decode" buf start))))
1796
1797;; read char from port with encoding, scanning minimal number of bytes ahead
1798(define (##sys#read-char/encoding p enc k)
1799  (##sys#encoding-hook
1800    enc
1801    (lambda (dec _ scan)
1802      (let ((buf (##sys#make-bytevector 5))
1803            (rbv! (##sys#slot (##sys#slot p 2) 7))) ; read-bytevector!
1804        (let loop ((state #f) (i 0))
1805          (let ((rn (rbv! p 1 buf i)))
1806            (if (eq? 0 rn)
1807                (if (eq? i 0)
1808                    #!eof
1809                    (##sys#signal-hook #:file-error 'read-char "incomplete character sequence while decoding" buf i))
1810                (let ((s2 (scan state (##core#inline "C_subbyte" buf i))))
1811                  (if s2
1812                      (loop s2 (fx+ i 1))
1813                      (k buf 0 (fx+ i 1) dec))))))))))
1814
1815(set! scheme#make-string
1816  (lambda (size . fill)
1817    (##sys#check-fixnum size 'make-string)
1818    (when (fx< size 0)
1819      (##sys#signal-hook #:bounds-error 'make-string "size is negative" size))
1820    (##sys#make-string
1821     size
1822     (if (null? fill)
1823	 #\space
1824	 (let ((c (car fill)))
1825	   (##sys#check-char c 'make-string)
1826	   c ) ) ) ) )
1827
1828(set! scheme#string->list
1829  (lambda (s #!optional start end)
1830    (##sys#check-string s 'string->list)
1831    (let ((len (##sys#slot s 1)))
1832      (if start
1833          (##sys#check-range/including start 0 len 'string->list)
1834          (set! start 0))
1835      (if end
1836          (##sys#check-range/including end 0 len 'string->list)
1837          (set! end len))
1838      (let loop ((i (fx- end 1)) (ls '()))
1839	(if (fx< i start)
1840	    ls
1841	    (loop (fx- i 1)
1842		  (cons (string-ref s i) ls)) ) ) )))
1843
1844(define ##sys#string->list string->list)
1845
1846(set! scheme#list->string
1847  (lambda (lst0)
1848    (if (not (list? lst0))
1849	(##sys#error-not-a-proper-list lst0 'list->string)
1850	(let* ((len (##core#inline "C_utf_list_size" lst0))
1851	       (bv (##sys#make-bytevector (fx+ 1 len))))
1852	  (let loop ((i 0)
1853                     (p 0)
1854                     (lst lst0))
1855            (if (not (pair? lst))
1856                (##core#inline_allocate ("C_a_ustring" 5) bv i)
1857                (let ((c (##sys#slot lst 0)))
1858                  (##sys#check-char c 'list->string)
1859                  (##core#inline "C_utf_insert" bv p c)
1860                  (loop (fx+ i 1)
1861                        (fx+ p (##core#inline "C_utf_bytes" c))
1862                        (##sys#slot lst 1)))))))))
1863
1864(define ##sys#list->string list->string)
1865
1866(define (##sys#reverse-list->string l)
1867  (let* ((sz (##core#inline "C_utf_list_size" l))
1868         (bv (##sys#make-bytevector (fx+ sz 1))))
1869    (let loop ((p sz) (l l) (n 0))
1870      (cond ((null? l)
1871             (##core#inline_allocate ("C_a_ustring" 5) bv n))
1872            ((pair? l)
1873             (let ((c (##sys#slot l 0)))
1874               (##sys#check-char c 'reverse-list->string)
1875               (let* ((bs (##core#inline "C_utf_bytes" c))
1876                      (p2 (fx- p bs)))
1877                 (##core#inline "C_utf_insert" bv p2 c)
1878                 (loop p2 (##sys#slot l 1) (fx+ n 1)))))
1879            (else (##sys#error-not-a-proper-list l 'reverse-list->string) ) ))))
1880
1881(set! scheme#string-fill!
1882  (lambda (s c #!optional start end)
1883    (##sys#check-string s 'string-fill!)
1884    (##sys#check-char c 'string-fill!)
1885    (let ((len (string-length s)))
1886      (cond (start (##sys#check-range start 0 len 'string-fill!)
1887                   (if end
1888                       (##sys#check-range end 0 len 'string-fill!)
1889                       (set! end len)))
1890            (else
1891              (set! start 0)
1892              (set! end len))))
1893    (let* ((bv (##sys#slot s 0))
1894           (bvlen (##sys#size bv))
1895           (count (fxmax 0 (fx- end start)))
1896           (code (char->integer c)))
1897      (if (and (eq? (fx- bvlen 1) (##sys#slot s 1))
1898               (fx< code 128))
1899          (##core#inline "C_fill_bytevector" bv code start count)
1900          (do ((i start (fx+ i 1)))
1901              ((fx>= i end))
1902              (string-set! s i c))))))
1903
1904(set! scheme#string-copy
1905  (lambda (s #!optional start end)
1906    (##sys#check-string s 'string-copy)
1907    (let ((len (string-length s))
1908          (start1 0))
1909      (when start
1910        (##sys#check-range/including start 0 len 'string-copy)
1911        (set! start1 start))
1912      (if end
1913          (##sys#check-range/including end 0 len 'string-copy)
1914          (set! end len))
1915      (let* ((bv (##sys#slot (if start (##sys#substring s start1 end) s) 0))
1916             (len (##sys#size bv))
1917             (n (fx- end start1))
1918             (bv2 (##sys#make-bytevector len)) )
1919        (##core#inline "C_copy_memory" bv2 bv len)
1920        (##core#inline_allocate ("C_a_ustring" 5) bv2 n)))))
1921
1922(set! scheme#string-copy!
1923  (lambda (to at from #!optional start end)
1924    (##sys#check-string to 'string-copy!)
1925    (##sys#check-string from 'string-copy!)
1926    (let ((tlen (string-length to))
1927          (flen (string-length from))
1928          (d (fx- end start)))
1929      (##sys#check-range at 0 tlen 'string-copy!)
1930      (if start
1931          (begin
1932            (##sys#check-range/including start 0 flen 'string-copy!)
1933            (if end
1934                (##sys#check-range/including end 0 flen 'string-copy!)
1935                (set! end flen)))
1936          (set! start 0))
1937      (if (and (eq? to from) (fx< start at))
1938          (do ((at (fx- (fx+ at d) 1) (fx- at 1))
1939               (i (fx- end 1) (fx- i 1)))
1940              ((fx< i start))
1941              (string-set! to at (string-ref from i)))
1942          (do ((at at (fx+ at 1))
1943               (i start (fx+ i 1)))
1944              ((fx>= i end))
1945              (string-set! to at (string-ref from i)))))))
1946
1947(define (##sys#substring s start end)
1948  (let* ((n (##core#inline "C_utf_range" s start end))
1949         (bv (##sys#make-bytevector (fx+ n 1)))
1950         (str (##core#inline_allocate ("C_a_ustring" 5) bv (fx- end start))))
1951    (##core#inline "C_utf_copy" s str start end 0)
1952    str ) )
1953
1954(set! scheme#substring
1955  (lambda (s start . end)
1956    (##sys#check-string s 'substring)
1957    (##sys#check-fixnum start 'substring)
1958    (let ((end (if (pair? end)
1959                   (let ((end (car end)))
1960                     (##sys#check-fixnum end 'substring)
1961                     end)
1962                   (string-length s) ) ) )
1963      (let ((len (string-length s)))
1964        (if (and (fx<= start end)
1965                 (fx>= start 0)
1966                 (fx<= end len) )
1967            (##sys#substring s start end)
1968            (##sys#error-hook
1969             (foreign-value "C_OUT_OF_BOUNDS_ERROR" int)
1970             'substring s start) ) ) )))
1971
1972(let ((compare
1973        (lambda (s1 s2 more loc cmp)
1974          (##sys#check-string s1 loc)
1975          (##sys#check-string s2 loc)
1976          (let* ((len1 (string-length s1))
1977                 (len2 (string-length s2))
1978                 (c (##core#inline "C_utf_compare"
1979                     s1 s2 0 0
1980                     (if (fx< len1 len2) len1 len2))))
1981            (let loop ((s s2) 
1982                       (len len2) 
1983                       (ss more)
1984                       (f (cmp c len1 len2)))
1985              (and f 
1986                   (or (null? ss)
1987                       (let* ((s2 (##sys#slot ss 0))
1988                              (len2 (string-length s2))
1989                              (c (##core#inline "C_utf_compare"
1990                                  s s2 0 0
1991                                  (if (fx< len len2) len len2))))
1992                         (loop s2 len2 (##sys#slot ss 1)
1993                               (cmp c len len2))))))))))
1994  (set! scheme#string<? (lambda (s1 s2 . more)
1995                          (compare
1996                            s1 s2 more 'string<?
1997                            (lambda (cmp len1 len2)
1998                              (or (fx< cmp 0)
1999                                  (and (fx< len1 len2)
2000                                       (eq? cmp 0) ) ) ) ) ) )
2001  (set! scheme#string>? (lambda (s1 s2 . more)
2002                          (compare
2003                            s1 s2 more 'string>?
2004                            (lambda (cmp len1 len2)
2005                              (or (fx> cmp 0)
2006                                  (and (fx> len1 len2)
2007                                       (eq? cmp 0) ) ) ) ) ) )
2008  (set! scheme#string<=? (lambda (s1 s2 . more)
2009                           (compare
2010                             s1 s2 more 'string<=?
2011                             (lambda (cmp len1 len2)
2012                               (if (eq? cmp 0)
2013                                   (fx<= len1 len2)
2014                                   (fx< cmp 0) ) ) ) ) )
2015  (set! scheme#string>=? (lambda (s1 s2 . more)
2016                           (compare
2017                             s1 s2 more 'string>=?
2018                             (lambda (cmp len1 len2)
2019                               (if (eq? cmp 0)
2020                                   (fx>= len1 len2)
2021                                   (fx> cmp 0) ) ) ) ) ) )
2022
2023(let ((compare
2024        (lambda (s1 s2 more loc cmp)
2025          (##sys#check-string s1 loc)
2026          (##sys#check-string s2 loc)
2027          (let* ((len1 (string-length s1))
2028                 (len2 (string-length s2))
2029                 (c (##core#inline "C_utf_compare_ci"
2030                     s1 s2 0 0
2031                     (if (fx< len1 len2) len1 len2))))
2032            (let loop ((s s2)
2033                       (len len2)
2034                       (ss more)
2035                       (f (cmp c len1 len2)))
2036              (and f
2037                   (or (null? ss)
2038                       (let* ((s2 (##sys#slot ss 0))
2039                              (len2 (string-length s2))
2040                              (c (##core#inline "C_utf_compare_ci"
2041                                  s s2 0 0
2042                                  (if (fx< len len2) len len2))))
2043                         (loop s2 len2 (##sys#slot ss 1)
2044                               (cmp c len len2))))))))))
2045  (set! scheme#string-ci<? (lambda (s1 s2 . more)
2046                             (compare
2047                               s1 s2 more 'string-ci<?
2048                               (lambda (cmp len1 len2)
2049                                 (or (fx< cmp 0)
2050                                     (and (fx< len1 len2)
2051                                          (eq? cmp 0) ) )))))
2052  (set! scheme#string-ci>? (lambda (s1 s2 . more)
2053                             (compare
2054                               s1 s2 more 'string-ci>?
2055                               (lambda (cmp len1 len2)
2056                                 (or (fx> cmp 0)
2057                                     (and (fx> len1 len2)
2058                                          (eq? cmp 0) ) ) ) ) ) )
2059  (set! scheme#string-ci<=? (lambda (s1 s2 . more)
2060                              (compare
2061                                s1 s2 more 'string-ci<=?
2062                                (lambda (cmp len1 len2)
2063                                  (if (eq? cmp 0)
2064                                      (fx<= len1 len2)
2065                                      (fx< cmp 0) ) ) ) ) )
2066  (set! scheme#string-ci>=? (lambda (s1 s2 . more)
2067                              (compare
2068                                s1 s2 more 'string-ci>=?
2069                                (lambda (cmp len1 len2)
2070                                  (if (eq? cmp 0)
2071                                      (fx>= len1 len2)
2072                                      (fx> cmp 0) ) ) ) ) ) )
2073
2074(define (##sys#string-append x y)
2075  (let* ((bv1 (##sys#slot x 0))
2076         (bv2 (##sys#slot y 0))
2077         (s1 (fx- (##sys#size bv1) 1))
2078	 (s2 (fx- (##sys#size bv2) 1))
2079	 (z (##sys#make-bytevector (fx+ s1 (fx+ s2 1)) 0)))
2080    (##core#inline "C_copy_memory_with_offset" z bv1 0 0 s1)
2081    (##core#inline "C_copy_memory_with_offset" z bv2 s1 0 s2)
2082    (##core#inline_allocate ("C_a_ustring" 5) z
2083                            (fx+ (##sys#slot x 1) (##sys#slot y 1)))))
2084
2085(set! scheme#string-append
2086  (lambda all
2087    (let ((snew #f)
2088          (slen 0))
2089      (let loop ((strs all) (n 0) (ul 0))
2090	(cond ((eq? strs '())
2091                (set! snew (##sys#make-bytevector (fx+ n 1) 0))
2092                (set! slen ul))
2093              (else
2094                (let ((s (##sys#slot strs 0)))
2095                  (##sys#check-string s 'string-append)
2096                  (let* ((bv (##sys#slot s 0))
2097                         (len (fx- (##sys#size bv) 1))
2098                         (ulen (##sys#slot s 1)))
2099                    (loop (##sys#slot strs 1) (fx+ n len) (fx+ ul ulen))
2100                    (##core#inline "C_copy_memory_with_offset" snew bv n 0 len) ) ) ) ) )
2101      (##core#inline_allocate ("C_a_ustring" 5) snew slen))))
2102
2103(set! scheme#string
2104  (let ([list->string list->string])
2105    (lambda chars (list->string chars)) ) )
2106
2107;; legacy procedure, used in some eggs, should be removed one day...
2108(define (##sys#char->utf8-string c)
2109  (scheme#string c))
2110
2111(set! chicken.base#chop
2112  (lambda (lst n)
2113    (##sys#check-fixnum n 'chop)
2114    (when (fx<= n 0) (##sys#error 'chop "invalid numeric argument" n))
2115    (let ((len (length lst)))
2116      (let loop ((lst lst) (i len))
2117	(cond ((null? lst) '())
2118	      ((fx< i n) (list lst))
2119	      (else
2120	       (do ((hd '() (cons (##sys#slot tl 0) hd))
2121		    (tl lst (##sys#slot tl 1))
2122		    (c n (fx- c 1)) )
2123		   ((fx= c 0)
2124		    (cons (reverse hd) (loop tl (fx- i n))) ) ) ) ) ) ) ) )
2125
2126;;; Numeric routines:
2127;; Abbreviations of paper and book titles used in comments are:
2128;; [Knuth] Donald E. Knuth, "The Art of Computer Programming", Volume 2
2129;; [MpNT]  Tiplea at al., "MpNT: A Multi-Precision Number Theory Package"
2130;; [MCA]   Richard P. Brent & Paul Zimmermann, "Modern Computer Arithmetic"
2131
2132(module chicken.flonum *
2133(import scheme)
2134(import chicken.foreign)
2135(import (only chicken.base flonum?))
2136(import chicken.internal.syntax)
2137
2138(define maximum-flonum (foreign-value "DBL_MAX" double))
2139(define minimum-flonum (foreign-value "DBL_MIN" double))
2140(define flonum-radix (foreign-value "FLT_RADIX" int))
2141(define flonum-epsilon (foreign-value "DBL_EPSILON" double))
2142(define flonum-precision (foreign-value "DBL_MANT_DIG" int))
2143(define flonum-decimal-precision (foreign-value "DBL_DIG" int))
2144(define flonum-maximum-exponent (foreign-value "DBL_MAX_EXP" int))
2145(define flonum-minimum-exponent (foreign-value "DBL_MIN_EXP" int))
2146(define flonum-maximum-decimal-exponent (foreign-value "DBL_MAX_10_EXP" int))
2147(define flonum-minimum-decimal-exponent (foreign-value "DBL_MIN_10_EXP" int))
2148
2149(define-inline (fp-check-flonum x loc)
2150  (unless (flonum? x)
2151    (##sys#error-hook (foreign-value "C_BAD_ARGUMENT_TYPE_NO_FLONUM_ERROR" int) loc x) ) )
2152
2153(define-inline (fp-check-flonums x y loc)
2154  (unless (and (flonum? x) (flonum? y))
2155    (##sys#error-hook (foreign-value "C_BAD_ARGUMENT_TYPE_NO_FLONUM_ERROR" int) loc x y) ) )
2156
2157(define (fp+ x y)
2158  (fp-check-flonums x y 'fp+)
2159  (##core#inline_allocate ("C_a_i_flonum_plus" 4) x y) )
2160
2161(define (fp- x y)
2162  (fp-check-flonums x y 'fp-)
2163  (##core#inline_allocate ("C_a_i_flonum_difference" 4) x y) )
2164
2165(define (fp* x y)
2166  (fp-check-flonums x y 'fp*)
2167  (##core#inline_allocate ("C_a_i_flonum_times" 4) x y) )
2168
2169(define (fp/ x y)
2170  (fp-check-flonums x y 'fp/)
2171  (##core#inline_allocate ("C_a_i_flonum_quotient" 4) x y) )
2172
2173(define (fp*+ x y z)
2174  (unless (and (flonum? x) (flonum? y) (flonum? z))
2175    (##sys#error-hook (foreign-value "C_BAD_ARGUMENT_TYPE_NO_FLONUM_ERROR" int)
2176      'fp*+ x y z) )
2177  (##core#inline_allocate ("C_a_i_flonum_multiply_add" 4) x y z) )
2178
2179(define (fpgcd x y)
2180  (fp-check-flonums x y 'fpgcd)
2181  (##core#inline_allocate ("C_a_i_flonum_gcd" 4) x y))
2182
2183(define (fp/? x y)			; undocumented
2184  (fp-check-flonums x y 'fp/?)
2185  (##core#inline_allocate ("C_a_i_flonum_quotient_checked" 4) x y) )
2186
2187(define (fp= x y)
2188  (fp-check-flonums x y 'fp=)
2189  (##core#inline "C_flonum_equalp" x y) )
2190
2191(define (fp> x y)
2192  (fp-check-flonums x y 'fp>)
2193  (##core#inline "C_flonum_greaterp" x y) )
2194
2195(define (fp< x y)
2196  (fp-check-flonums x y 'fp<)
2197  (##core#inline "C_flonum_lessp" x y) )
2198
2199(define (fp>= x y)
2200  (fp-check-flonums x y 'fp>=)
2201  (##core#inline "C_flonum_greater_or_equal_p" x y) )
2202
2203(define (fp<= x y)
2204  (fp-check-flonums x y 'fp<=)
2205  (##core#inline "C_flonum_less_or_equal_p" x y) )
2206
2207(define (fpneg x)
2208  (fp-check-flonum x 'fpneg)
2209  (##core#inline_allocate ("C_a_i_flonum_negate" 4) x) )
2210
2211(define (fpmax x y)
2212  (fp-check-flonums x y 'fpmax)
2213  (##core#inline "C_i_flonum_max" x y) )
2214
2215(define (fpmin x y)
2216  (fp-check-flonums x y 'fpmin)
2217  (##core#inline "C_i_flonum_min" x y) )
2218
2219(define (fpfloor x)
2220  (fp-check-flonum x 'fpfloor)
2221  (##core#inline_allocate ("C_a_i_flonum_floor" 4) x))
2222
2223(define (fptruncate x)
2224  (fp-check-flonum x 'fptruncate)
2225  (##core#inline_allocate ("C_a_i_flonum_truncate" 4) x))
2226
2227(define (fpround x)
2228  (fp-check-flonum x 'fpround)
2229  (##core#inline_allocate ("C_a_i_flonum_round" 4) x))
2230
2231(define (fpceiling x)
2232  (fp-check-flonum x 'fpceiling)
2233  (##core#inline_allocate ("C_a_i_flonum_ceiling" 4) x))
2234
2235(define (fpsin x)
2236  (fp-check-flonum x 'fpsin)
2237  (##core#inline_allocate ("C_a_i_flonum_sin" 4) x))
2238
2239(define (fpcos x)
2240  (fp-check-flonum x 'fpcos)
2241  (##core#inline_allocate ("C_a_i_flonum_cos" 4) x))
2242
2243(define (fptan x)
2244  (fp-check-flonum x 'fptan)
2245  (##core#inline_allocate ("C_a_i_flonum_tan" 4) x))
2246
2247(define (fpasin x)
2248  (fp-check-flonum x 'fpasin)
2249  (##core#inline_allocate ("C_a_i_flonum_asin" 4) x))
2250
2251(define (fpacos x)
2252  (fp-check-flonum x 'fpacos)
2253  (##core#inline_allocate ("C_a_i_flonum_acos" 4) x))
2254
2255(define (fpatan x)
2256  (fp-check-flonum x 'fpatan)
2257  (##core#inline_allocate ("C_a_i_flonum_atan" 4) x))
2258
2259(define (fpatan2 x y)
2260  (fp-check-flonums x y 'fpatan2)
2261  (##core#inline_allocate ("C_a_i_flonum_atan2" 4) x y))
2262
2263(define (fpsinh x)
2264  (fp-check-flonum x 'fpsinh)
2265  (##core#inline_allocate ("C_a_i_flonum_sinh" 4) x))
2266
2267(define (fpcosh x)
2268  (fp-check-flonum x 'fpcosh)
2269  (##core#inline_allocate ("C_a_i_flonum_cosh" 4) x))
2270
2271(define (fptanh x)
2272  (fp-check-flonum x 'fptanh)
2273  (##core#inline_allocate ("C_a_i_flonum_tanh" 4) x))
2274
2275(define (fpasinh x)
2276  (fp-check-flonum x 'fpasinh)
2277  (##core#inline_allocate ("C_a_i_flonum_asinh" 4) x))
2278
2279(define (fpacosh x)
2280  (fp-check-flonum x 'fpacosh)
2281  (##core#inline_allocate ("C_a_i_flonum_acosh" 4) x))
2282
2283(define (fpatanh x)
2284  (fp-check-flonum x 'fpatanh)
2285  (##core#inline_allocate ("C_a_i_flonum_atanh" 4) x))
2286
2287(define (fpexp x)
2288  (fp-check-flonum x 'fpexp)
2289  (##core#inline_allocate ("C_a_i_flonum_exp" 4) x))
2290
2291(define (fpexpt x y)
2292  (fp-check-flonums x y 'fpexpt)
2293  (##core#inline_allocate ("C_a_i_flonum_expt" 4) x y))
2294
2295(define (fplog x)
2296  (fp-check-flonum x 'fplog)
2297  (##core#inline_allocate ("C_a_i_flonum_log" 4) x))
2298
2299(define (fpsqrt x)
2300  (fp-check-flonum x 'fpsqrt)
2301  (##core#inline_allocate ("C_a_i_flonum_sqrt" 4) x))
2302
2303(define (fpabs x)
2304  (fp-check-flonum x 'fpabs)
2305  (##core#inline_allocate ("C_a_i_flonum_abs" 4) x))
2306
2307(define (fpinteger? x)
2308  (fp-check-flonum x 'fpinteger?)
2309  (##core#inline "C_u_i_fpintegerp" x))
2310
2311(define (flonum-print-precision #!optional prec)
2312  (let ((prev (##core#inline "C_get_print_precision")))
2313    (when prec
2314      (##sys#check-fixnum prec 'flonum-print-precision)
2315      (##core#inline "C_set_print_precision" prec))
2316    prev)))
2317
2318(import chicken.flonum)
2319
2320(define-inline (integer-negate x)
2321  (##core#inline_allocate ("C_s_a_u_i_integer_negate" 5) x))
2322
2323;;; Complex numbers
2324
2325(define-inline (%cplxnum-real c) (##core#inline "C_u_i_cplxnum_real" c))
2326(define-inline (%cplxnum-imag c) (##core#inline "C_u_i_cplxnum_imag" c))
2327
2328(define (make-complex r i)
2329  (if (eq? i 0)
2330      r
2331      (##core#inline_allocate ("C_a_i_cplxnum" 3)
2332			      (if (inexact? i) (exact->inexact r) r)
2333			      (if (inexact? r) (exact->inexact i) i)) ) )
2334
2335(set! scheme#make-rectangular
2336  (lambda (r i)
2337    (##sys#check-real r 'make-rectangular)
2338    (##sys#check-real i 'make-rectangular)
2339    (make-complex r i) ))
2340
2341(set! scheme#make-polar
2342  (lambda (r phi)
2343    (##sys#check-real r 'make-polar)
2344    (##sys#check-real phi 'make-polar)
2345    (let ((fphi (exact->inexact phi)))
2346      (make-complex
2347       (* r (##core#inline_allocate ("C_a_i_cos" 4) fphi))
2348       (* r (##core#inline_allocate ("C_a_i_sin" 4) fphi))) ) ))
2349
2350(set! scheme#real-part
2351  (lambda (x)
2352    (cond ((cplxnum? x) (%cplxnum-real x))
2353	  ((number? x) x)
2354	  (else (##sys#error-bad-number x 'real-part)) )))
2355
2356(set! scheme#imag-part
2357  (lambda (x)
2358    (cond ((cplxnum? x) (%cplxnum-imag x))
2359	  ((number? x) 0)
2360	  (else (##sys#error-bad-number x 'imag-part)) )))
2361
2362(set! scheme#angle
2363  (lambda (n)
2364    (##sys#check-number n 'angle)
2365    (##core#inline_allocate ("C_a_i_atan2" 4)
2366			    (exact->inexact (imag-part n))
2367			    (exact->inexact (real-part n))) ))
2368
2369(set! scheme#magnitude
2370  (lambda (x)
2371    (cond ((cplxnum? x)
2372	   (let ((r (%cplxnum-real x))
2373		 (i (%cplxnum-imag x)) )
2374	     (sqrt (+ (* r r) (* i i))) ))
2375	  ((number? x) (abs x))
2376	  (else (##sys#error-bad-number x 'magnitude))) ))
2377
2378;;; Rational numbers
2379
2380(define-inline (%ratnum-numerator r) (##core#inline "C_u_i_ratnum_num" r))
2381(define-inline (%ratnum-denominator r) (##core#inline "C_u_i_ratnum_denom" r))
2382(define-inline (%make-ratnum n d) (##core#inline_allocate ("C_a_i_ratnum" 3) n d))
2383
2384(define (ratnum m n)
2385  (cond
2386   ((eq? n 1) m)
2387   ((eq? n -1) (integer-negate m))
2388   ((negative? n)
2389    (%make-ratnum (integer-negate m) (integer-negate n)))
2390   (else (%make-ratnum m n))))
2391
2392(set! scheme#numerator
2393  (lambda (n)
2394    (cond ((##core#inline "C_i_exact_integerp" n) n)
2395          ((##core#inline "C_i_flonump" n)
2396           (cond ((not (finite? n)) (##sys#error-bad-inexact n 'numerator))
2397                 ((##core#inline "C_u_i_fpintegerp" n) n)
2398                 (else (exact->inexact (numerator (inexact->exact n))))))
2399          ((ratnum? n) (%ratnum-numerator n))
2400          (else (##sys#signal-hook
2401                 #:type-error 'numerator
2402                 "bad argument type - not a rational number" n) ) )))
2403
2404
2405(set! scheme#denominator
2406  (lambda (n)
2407    (cond ((##core#inline "C_i_exact_integerp" n) 1)
2408          ((##core#inline "C_i_flonump" n)
2409           (cond ((not (finite? n)) (##sys#error-bad-inexact n 'denominator))
2410                 ((##core#inline "C_u_i_fpintegerp" n) 1.0)
2411                 (else (exact->inexact (denominator (inexact->exact n))))))
2412          ((ratnum? n) (%ratnum-denominator n))
2413          (else (##sys#signal-hook
2414                 #:type-error 'numerator
2415                 "bad argument type - not a rational number" n) ) )))
2416
2417
2418(define (##sys#extended-signum x)
2419  (cond
2420   ((ratnum? x) (##core#inline "C_u_i_integer_signum" (%ratnum-numerator x)))
2421   ((cplxnum? x) (make-polar 1 (angle x)))
2422   (else (##sys#error-bad-number x 'signum))))
2423
2424(define-inline (%flo->int x)
2425  (##core#inline_allocate ("C_s_a_u_i_flo_to_int" 5) x))
2426
2427(define (flonum->ratnum x)
2428  ;; Try to multiply by two until we reach an integer
2429  (define (float-fraction-length x)
2430    (do ((x x (fp* x 2.0))
2431         (i 0 (fx+ i 1)))
2432        ((##core#inline "C_u_i_fpintegerp" x) i)))
2433
2434  (define (deliver y d)
2435    (let* ((q (##sys#integer-power 2 (float-fraction-length y)))
2436           (scaled-y (* y (exact->inexact q))))
2437      (if (finite? scaled-y)          ; Shouldn't this always be true?
2438          (##sys#/-2 (##sys#/-2 (%flo->int scaled-y) q) d)
2439          (##sys#error-bad-inexact x 'inexact->exact))))
2440
2441  (if (and (fp< x 1.0)         ; Watch out for denormalized numbers
2442           (fp> x -1.0))       ; XXX: Needs a test, it seems pointless
2443      (deliver (* x (expt 2.0 flonum-precision))
2444               ;; Can be bignum (is on 32-bit), so must wait until after init.
2445               ;; We shouldn't need to calculate this every single time, tho..
2446               (##sys#integer-power 2 flonum-precision))
2447      (deliver x 1)))
2448
2449(set! scheme#inexact->exact
2450  (lambda (x)
2451    (cond ((exact? x) x)
2452	  ((##core#inline "C_i_flonump" x)
2453	   (cond ((##core#inline "C_u_i_fpintegerp" x) (%flo->int x))
2454		 ((##core#inline "C_u_i_flonum_finitep" x) (flonum->ratnum x))
2455		 (else (##sys#error-bad-inexact x 'inexact->exact))))
2456	  ((cplxnum? x)
2457	   (make-complex (inexact->exact (%cplxnum-real x))
2458			 (inexact->exact (%cplxnum-imag x))))
2459	  (else (##sys#error-bad-number x 'inexact->exact)) )))
2460
2461
2462;;; Bitwise operations:
2463
2464;; From SRFI-33
2465
2466(module chicken.bitwise *
2467(import scheme)
2468(define bitwise-and (##core#primitive "C_bitwise_and"))
2469(define bitwise-ior (##core#primitive "C_bitwise_ior"))
2470(define bitwise-xor (##core#primitive "C_bitwise_xor"))
2471(define (bitwise-not n) (##core#inline_allocate ("C_s_a_i_bitwise_not" 5) n))
2472(define (bit->boolean n i) (##core#inline "C_i_bit_to_bool" n i)) ; DEPRECATED
2473;; XXX NOT YET! Reintroduce at a later time.  See #1385:
2474;; (define (bit-set? i n) (##core#inline "C_i_bit_setp" i n))
2475(define (integer-length x) (##core#inline "C_i_integer_length" x))
2476(define (arithmetic-shift n m)
2477  (##core#inline_allocate ("C_s_a_i_arithmetic_shift" 5) n m))
2478
2479) ; chicken.bitwise
2480
2481(import chicken.bitwise)
2482
2483;;; Basic arithmetic:
2484
2485(define-inline (%integer-gcd a b)
2486  (##core#inline_allocate ("C_s_a_u_i_integer_gcd" 5) a b))
2487
2488(set! scheme#/
2489  (lambda (arg1 . args)
2490    (if (null? args)
2491	(##sys#/-2 1 arg1)
2492	(let loop ((args (##sys#slot args 1))
2493		   (x (##sys#/-2 arg1 (##sys#slot args 0))))
2494	  (if (null? args)
2495	      x
2496	      (loop (##sys#slot args 1)
2497		    (##sys#/-2 x (##sys#slot args 0))) ) ) ) ))
2498
2499(define-inline (%integer-quotient a b)
2500  (##core#inline_allocate ("C_s_a_u_i_integer_quotient" 5) a b))
2501
2502(define (##sys#/-2 x y)
2503  (when (eq? y 0)
2504    (##sys#error-hook (foreign-value "C_DIVISION_BY_ZERO_ERROR" int) '/ x y))
2505  (cond ((and (##core#inline "C_i_exact_integerp" x)
2506              (##core#inline "C_i_exact_integerp" y))
2507         (let ((g (%integer-gcd x y)))
2508           (ratnum (%integer-quotient x g) (%integer-quotient y g))))
2509        ;; Compnum *must* be checked first
2510        ((or (cplxnum? x) (cplxnum? y))
2511         (let* ((a (real-part x)) (b (imag-part x))
2512                (c (real-part y)) (d (imag-part y))
2513                (r (+ (* c c) (* d d)))
2514                (x (##sys#/-2 (+ (* a c) (* b d)) r))
2515                (y (##sys#/-2 (- (* b c) (* a d)) r)) )
2516           (make-complex x y) ))
2517        ((or (##core#inline "C_i_flonump" x) (##core#inline "C_i_flonump" y))
2518         ;; This may be incorrect when one is a ratnum consisting of bignums
2519         (fp/ (exact->inexact x) (exact->inexact y)))
2520        ((ratnum? x)
2521         (if (ratnum? y)
2522             ;; a/b / c/d = a*d / b*c  [generic]
2523             ;;   = ((a / g1) * (d / g2) * sign(a)) / abs((b / g2) * (c / g1))
2524             ;; With   g1 = gcd(a, c)   and    g2 = gcd(b, d) [Knuth, 4.5.1 ex. 4]
2525             (let* ((a (%ratnum-numerator x)) (b (%ratnum-denominator x))
2526                    (c (%ratnum-numerator y)) (d (%ratnum-denominator y))
2527                    (g1 (%integer-gcd a c))
2528                    (g2 (%integer-gcd b d)))
2529               (ratnum (* (quotient a g1) (quotient d g2))
2530                       (* (quotient b g2) (quotient c g1))))
2531             ;; a/b / c/d = a*d / b*c  [with d = 1]
2532             ;;   = ((a / g) * sign(a)) / abs(b * (c / g))
2533             ;; With   g = gcd(a, c)   and  c = y  [Knuth, 4.5.1 ex. 4]
2534             (let* ((a (%ratnum-numerator x))
2535                    (g (##sys#internal-gcd '/ a y))
2536                    (num (quotient a g))
2537                    (denom (* (%ratnum-denominator x) (quotient y g))))
2538               (if (##core#inline "C_i_flonump" denom)
2539                   (##sys#/-2 num denom)
2540                   (ratnum num denom)))))
2541        ((ratnum? y)
2542         ;; a/b / c/d = a*d / b*c  [with b = 1]
2543         ;;   = ((a / g1) * d * sign(a)) / abs(c / g1)
2544         ;; With   g1 = gcd(a, c)   and   a = x  [Knuth, 4.5.1 ex. 4]
2545         (let* ((c (%ratnum-numerator y))
2546                (g (##sys#internal-gcd '/ x c))
2547                (num (* (quotient x g) (%ratnum-denominator y)))
2548                (denom (quotient c g)))
2549           (if (##core#inline "C_i_flonump" denom)
2550               (##sys#/-2 num denom)
2551               (ratnum num denom))))
2552        ((not (number? x)) (##sys#error-bad-number x '/))
2553        (else (##sys#error-bad-number y '/))) )
2554
2555(set! scheme#floor
2556  (lambda (x)
2557    (cond ((##core#inline "C_i_exact_integerp" x) x)
2558          ((##core#inline "C_i_flonump" x) (fpfloor x))
2559          ;; (floor x) = greatest integer <= x
2560          ((ratnum? x) (let* ((n (%ratnum-numerator x))
2561                              (q (quotient n (%ratnum-denominator x))))
2562                         (if (>= n 0) q (- q 1))))
2563          (else (##sys#error-bad-real x 'floor)) )))
2564
2565(set! scheme#ceiling
2566  (lambda (x)
2567    (cond ((##core#inline "C_i_exact_integerp" x) x)
2568          ((##core#inline "C_i_flonump" x) (fpceiling x))
2569          ;; (ceiling x) = smallest integer >= x
2570          ((ratnum? x) (let* ((n (%ratnum-numerator x))
2571                              (q (quotient n (%ratnum-denominator x))))
2572                         (if (>= n 0) (+ q 1) q)))
2573          (else (##sys#error-bad-real x 'ceiling)) )))
2574
2575(set! scheme#truncate
2576  (lambda (x)
2577    (cond ((##core#inline "C_i_exact_integerp" x) x)
2578          ((##core#inline "C_i_flonump" x) (fptruncate x))
2579          ;; (rational-truncate x) = integer of largest magnitude <= (abs x)
2580          ((ratnum? x) (quotient (%ratnum-numerator x)
2581                                 (%ratnum-denominator x)))
2582          (else (##sys#error-bad-real x 'truncate)) )))
2583
2584(set! scheme#round
2585  (lambda (x)
2586    (cond ((##core#inline "C_i_exact_integerp" x) x)
2587          ((##core#inline "C_i_flonump" x)
2588           (##core#inline_allocate ("C_a_i_flonum_round_proper" 4) x))
2589          ((ratnum? x)
2590           (let* ((x+1/2 (+ x (%make-ratnum 1 2)))
2591                  (r (floor x+1/2)))
2592             (if (and (= r x+1/2) (odd? r)) (- r 1) r)))
2593          (else (##sys#error-bad-real x 'round)) )))
2594
2595(define (find-ratio-between x y)
2596  (define (sr x y)
2597    (let ((fx (inexact->exact (floor x)))
2598	  (fy (inexact->exact (floor y))))
2599      (cond ((not (< fx x)) (list fx 1))
2600	    ((= fx fy)
2601	     (let ((rat (sr (##sys#/-2 1 (- y fy))
2602			    (##sys#/-2 1 (- x fx)))))
2603	       (list (+ (cadr rat) (* fx (car rat)))
2604		     (car rat))))
2605	    (else (list (+ 1 fx) 1)))))
2606  (cond ((< y x) (find-ratio-between y x))
2607	((not (< x y)) (list x 1))
2608	((positive? x) (sr x y))
2609	((negative? y) (let ((rat (sr (- y) (- x))))
2610                         (list (- (car rat)) (cadr rat))))
2611	(else '(0 1))))
2612
2613(define (find-ratio x e) (find-ratio-between (- x e) (+ x e)))
2614
2615(set! scheme#rationalize
2616  (lambda (x e)
2617    (let ((result (apply ##sys#/-2 (find-ratio x e))))
2618      (if (or (inexact? x) (inexact? e))
2619	  (exact->inexact result)
2620	  result)) ))
2621
2622(set! scheme#max
2623  (lambda (x1 . xs)
2624    (##sys#check-number x1 'max)
2625    (let loop ((i (##core#inline "C_i_flonump" x1))
2626               (m x1) 
2627               (xs xs) 
2628               (n (##core#inline "C_i_nanp" x1)))
2629      (if (null? xs)
2630	  (if i (exact->inexact m) m)
2631	  (let* ((h (##sys#slot xs 0))
2632                 (_ (##sys#check-number h 'max))
2633                 (f (##core#inline "C_i_flonump" h))
2634                 (nxt (##sys#slot xs 1)))
2635            (cond ((##core#inline "C_i_nanp" h) (loop i m nxt n))
2636                  (n (loop (or i f) h nxt #f))
2637                  ((> h m) (loop (or i f) h nxt #f))
2638                  (else (loop (or i f) m nxt n))))))))
2639
2640(set! scheme#min
2641  (lambda (x1 . xs)
2642    (##sys#check-number x1 'min)
2643    (let loop ((i (##core#inline "C_i_flonump" x1))
2644               (m x1) 
2645               (xs xs) 
2646               (n (##core#inline "C_i_nanp" x1)))
2647      (if (null? xs)
2648	  (if i (exact->inexact m) m)
2649	  (let* ((h (##sys#slot xs 0))
2650                 (_ (##sys#check-number h 'min))
2651                 (f (##core#inline "C_i_flonump" h))
2652                 (nxt (##sys#slot xs 1)))
2653            (cond ((##core#inline "C_i_nanp" h) (loop i m nxt n))
2654                  (n (loop (or i f) h nxt #f))
2655                  ((< h m) (loop (or i f) h nxt #f))
2656                  (else (loop (or i f) m nxt n))))))))
2657
2658(set! scheme#exp
2659  (lambda (n)
2660    (##sys#check-number n 'exp)
2661    (if (cplxnum? n)
2662	(* (##core#inline_allocate ("C_a_i_exp" 4)
2663				   (exact->inexact (%cplxnum-real n)))
2664	   (let ((p (%cplxnum-imag n)))
2665	     (make-complex
2666	      (##core#inline_allocate ("C_a_i_cos" 4) (exact->inexact p))
2667	      (##core#inline_allocate ("C_a_i_sin" 4) (exact->inexact p)) ) ) )
2668	(##core#inline_allocate ("C_a_i_flonum_exp" 4) (exact->inexact n)) ) ))
2669
2670(define (##sys#log-1 x)		       ; log_e(x)
2671  (cond
2672   ((eq? x 0)			       ; Exact zero?  That's undefined
2673    (##sys#signal-hook #:arithmetic-error 'log "log of exact 0 is undefined" x))
2674   ;; avoid calling inexact->exact on X here (to avoid overflow?)
2675   ((or (cplxnum? x) (negative? x)) ; General case
2676    (+ (##sys#log-1 (magnitude x))
2677       (* (make-complex 0 1) (angle x))))
2678   (else ; Real number case (< already ensured the argument type is a number)
2679    (##core#inline_allocate ("C_a_i_log" 4) (exact->inexact x)))))
2680
2681(set! scheme#log
2682  (lambda (a #!optional b)
2683    (if b (##sys#/-2 (##sys#log-1 a) (##sys#log-1 b)) (##sys#log-1 a))))
2684
2685(set! scheme#sin
2686  (lambda (n)
2687    (##sys#check-number n 'sin)
2688    (if (cplxnum? n)
2689	(let ((in (* +i n)))
2690	  (##sys#/-2 (- (exp in) (exp (- in))) +2i))
2691	(##core#inline_allocate ("C_a_i_sin" 4) (exact->inexact n)) ) ))
2692
2693(set! scheme#cos
2694  (lambda (n)
2695    (##sys#check-number n 'cos)
2696    (if (cplxnum? n)
2697	(let ((in (* +i n)))
2698	  (##sys#/-2 (+ (exp in) (exp (- in))) 2) )
2699	(##core#inline_allocate ("C_a_i_cos" 4) (exact->inexact n)) ) ))
2700
2701(set! scheme#tan
2702  (lambda (n)
2703    (##sys#check-number n 'tan)
2704    (if (cplxnum? n)
2705	(##sys#/-2 (sin n) (cos n))
2706	(##core#inline_allocate ("C_a_i_tan" 4) (exact->inexact n)) ) ))
2707
2708;; General case: sin^{-1}(z) = -i\ln(iz + \sqrt{1-z^2})
2709(set! scheme#asin
2710  (lambda (n)
2711    (##sys#check-number n 'asin)
2712    (cond ((and (##core#inline "C_i_flonump" n) (fp>= n -1.0) (fp<= n 1.0))
2713	   (##core#inline_allocate ("C_a_i_asin" 4) n))
2714	  ((and (##core#inline "C_fixnump" n) (fx>= n -1) (fx<= n 1))
2715	   (##core#inline_allocate ("C_a_i_asin" 4)
2716				   (##core#inline_allocate
2717				    ("C_a_i_fix_to_flo" 4) n)))
2718	  ;; General definition can return compnums
2719	  (else (* -i (##sys#log-1
2720		       (+ (* +i n)
2721			  (##sys#sqrt/loc 'asin (- 1 (* n n))))) )) ) ))
2722
2723;; General case:
2724;; cos^{-1}(z) = 1/2\pi + i\ln(iz + \sqrt{1-z^2}) = 1/2\pi - sin^{-1}(z) = sin(1) - sin(z)
2725(set! scheme#acos
2726  (let ((asin1 (##core#inline_allocate ("C_a_i_asin" 4) 1)))
2727    (lambda (n)
2728      (##sys#check-number n 'acos)
2729      (cond ((and (##core#inline "C_i_flonump" n) (fp>= n -1.0) (fp<= n 1.0))
2730             (##core#inline_allocate ("C_a_i_acos" 4) n))
2731            ((and (##core#inline "C_fixnump" n) (fx>= n -1) (fx<= n 1))
2732             (##core#inline_allocate ("C_a_i_acos" 4)
2733                                     (##core#inline_allocate
2734                                      ("C_a_i_fix_to_flo" 4) n)))
2735            ;; General definition can return compnums
2736            (else (- asin1 (asin n)))))))
2737
2738(set! scheme#atan
2739  (lambda (n #!optional b)
2740    (##sys#check-number n 'atan)
2741    (cond ((cplxnum? n)
2742	   (if b
2743	       (##sys#error-bad-real n 'atan)
2744	       (let ((in (* +i n)))
2745		 (##sys#/-2 (- (##sys#log-1 (+ 1 in))
2746			       (##sys#log-1 (- 1 in))) +2i))))
2747	  (b
2748	   (##core#inline_allocate
2749	    ("C_a_i_atan2" 4) (exact->inexact n) (exact->inexact b)))
2750	  (else
2751	   (##core#inline_allocate
2752	    ("C_a_i_atan" 4) (exact->inexact n))) ) ))
2753
2754;; This is "Karatsuba Square Root" as described by Paul Zimmermann,
2755;; which is 3/2K(n) + O(n log n) for an input of 2n words, where K(n)
2756;; is the number of operations performed by Karatsuba multiplication.
2757(define (##sys#exact-integer-sqrt a)
2758  ;; Because we assume a3b+a2 >= b^2/4, we must check a few edge cases:
2759  (if (and (fixnum? a) (fx<= a 4))
2760      (case a
2761        ((0 1) (values a 0))
2762        ((2)   (values 1 1))
2763        ((3)   (values 1 2))
2764        ((4)   (values 2 0))
2765        (else  (error "this should never happen")))
2766      (let*-values
2767          (((len/4) (fxshr (fx+ (integer-length a) 1) 2))
2768           ((len/2) (fxshl len/4 1))
2769           ((s^ r^) (##sys#exact-integer-sqrt
2770		     (arithmetic-shift a (fxneg len/2))))
2771           ((mask)  (- (arithmetic-shift 1 len/4) 1))
2772           ((a0)    (bitwise-and a mask))
2773           ((a1)    (bitwise-and (arithmetic-shift a (fxneg len/4)) mask))
2774           ((q u)   ((##core#primitive "C_u_integer_quotient_and_remainder")
2775		     (+ (arithmetic-shift r^ len/4) a1)
2776		     (arithmetic-shift s^ 1)))
2777           ((s)     (+ (arithmetic-shift s^ len/4) q))
2778           ((r)     (+ (arithmetic-shift u len/4) (- a0 (* q q)))))
2779        (if (negative? r)
2780            (values (- s 1)
2781		    (- (+ r (arithmetic-shift s 1)) 1))
2782            (values s r)))))
2783
2784(set! scheme#exact-integer-sqrt
2785  (lambda (x)
2786    (##sys#check-exact-uinteger x 'exact-integer-sqrt)
2787    (##sys#exact-integer-sqrt x)))
2788
2789;; This procedure is so large because it tries very hard to compute
2790;; exact results if at all possible.
2791(define (##sys#sqrt/loc loc n)
2792  (cond ((cplxnum? n)     ; Must be checked before we call "negative?"
2793         (let ((p (##sys#/-2 (angle n) 2))
2794               (m (##core#inline_allocate ("C_a_i_sqrt" 4) (magnitude n))) )
2795           (make-complex (* m (cos p)) (* m (sin p)) ) ))
2796        ((negative? n)
2797         (make-complex .0 (##core#inline_allocate
2798			   ("C_a_i_sqrt" 4) (exact->inexact (- n)))))
2799        ((##core#inline "C_i_exact_integerp" n)
2800         (receive (s^2 r) (##sys#exact-integer-sqrt n)
2801           (if (eq? 0 r)
2802               s^2
2803               (##core#inline_allocate ("C_a_i_sqrt" 4) (exact->inexact n)))))
2804        ((ratnum? n) ; Try to compute exact sqrt (we already know n is positive)
2805         (receive (ns^2 nr) (##sys#exact-integer-sqrt (%ratnum-numerator n))
2806           (if (eq? nr 0)
2807               (receive (ds^2 dr)
2808		   (##sys#exact-integer-sqrt (%ratnum-denominator n))
2809                 (if (eq? dr 0)
2810                     (##sys#/-2 ns^2 ds^2)
2811                     (##sys#sqrt/loc loc (exact->inexact n))))
2812               (##sys#sqrt/loc loc (exact->inexact n)))))
2813        (else (##core#inline_allocate ("C_a_i_sqrt" 4) (exact->inexact n)))))
2814
2815(set! scheme#sqrt (lambda (x) (##sys#sqrt/loc 'sqrt x)))
2816
2817;; XXX These are bad bad bad definitions; very inefficient.
2818;; But to improve it we would need to provide another implementation
2819;; of the quotient procedure which floors instead of truncates.
2820(define scheme#truncate/ quotient&remainder)
2821
2822(define (scheme#floor/ x y)
2823  (receive (div rem) (quotient&remainder x y)
2824    (if (positive? y)
2825        (if (negative? rem)
2826            (values (- div 1) (+ rem y))
2827            (values div rem))
2828        (if (positive? rem)
2829            (values (- div 1) (+ rem y))
2830            (values div rem)))))
2831
2832(define (scheme#floor-remainder x y)
2833  (receive (div rem) (scheme#floor/ x y) rem))
2834
2835(define (scheme#floor-quotient x y)
2836  (receive (div rem) (scheme#floor/ x y) div))
2837
2838(define (scheme#square n) (* n n))
2839
2840(set! chicken.base#exact-integer-nth-root
2841  (lambda (k n)
2842    (##sys#check-exact-uinteger k 'exact-integer-nth-root)
2843    (##sys#check-exact-uinteger n 'exact-integer-nth-root)
2844    (##sys#exact-integer-nth-root/loc 'exact-integer-nth-root k n)))
2845
2846;; Generalized Newton's algorithm for positive integers, with a little help
2847;; from Wikipedia ;)  https://en.wikipedia.org/wiki/Nth_root_algorithm
2848(define (##sys#exact-integer-nth-root/loc loc k n)
2849  (if (or (eq? 0 k) (eq? 1 k) (eq? 1 n)) ; Maybe call exact-integer-sqrt on n=2?
2850      (values k 0)
2851      (let ((len (integer-length k)))
2852	(if (< len n)	  ; Idea from Gambit: 2^{len-1} <= k < 2^{len}
2853	    (values 1 (- k 1)) ; Since x >= 2, we know x^{n} can't exist
2854	    ;; Set initial guess to (at least) 2^ceil(ceil(log2(k))/n)
2855	    (let* ((shift-amount (inexact->exact (ceiling (/ (fx+ len 1) n))))
2856		   (g0 (arithmetic-shift 1 shift-amount))
2857		   (n-1 (- n 1)))
2858	      (let lp ((g0 g0)
2859		       (g1 (quotient
2860			    (+ (* n-1 g0)
2861			       (quotient k (##sys#integer-power g0 n-1)))
2862			    n)))
2863		(if (< g1 g0)
2864		    (lp g1 (quotient
2865			    (+ (* n-1 g1)
2866			       (quotient k (##sys#integer-power g1 n-1)))
2867			    n))
2868		    (values g0 (- k (##sys#integer-power g0 n))))))))))
2869
2870(define (##sys#integer-power base e)
2871  (define (square x) (* x x))
2872  (if (negative? e)
2873      (##sys#/-2 1 (##sys#integer-power base (integer-negate e)))
2874      (let lp ((res 1) (e2 e))
2875        (cond
2876         ((eq? e2 0) res)
2877         ((even? e2)	     ; recursion is faster than iteration here
2878          (* res (square (lp 1 (arithmetic-shift e2 -1)))))
2879         (else
2880          (lp (* res base) (- e2 1)))))))
2881
2882(set! scheme#expt
2883  (lambda (a b)
2884    (define (log-expt a b)
2885      (exp (* b (##sys#log-1 a))))
2886    (define (slow-expt a b)
2887      (if (eq? 0 a)
2888	  (##sys#signal-hook
2889	   #:arithmetic-error 'expt
2890	   "exponent of exact 0 with complex argument is undefined" a b)
2891	  (exp (* b (##sys#log-1 a)))))
2892    (cond ((not (number? a)) (##sys#error-bad-number a 'expt))
2893	  ((not (number? b)) (##sys#error-bad-number b 'expt))
2894	  ((and (ratnum? a) (not (inexact? b)))
2895	   ;; (n*d)^b = n^b * d^b = n^b * x^{-b}  | x = 1/b
2896	   ;; Hopefully faster than integer-power
2897	   (* (expt (%ratnum-numerator a) b)
2898	      (expt (%ratnum-denominator a) (- b))))
2899	  ((ratnum? b)
2900	   ;; x^{a/b} = (x^{1/b})^a
2901	   (cond
2902	    ((##core#inline "C_i_exact_integerp" a)
2903	     (if (negative? a)
2904		 (log-expt (exact->inexact a) (exact->inexact b))
2905		 (receive (ds^n r)
2906		     (##sys#exact-integer-nth-root/loc
2907		      'expt a (%ratnum-denominator b))
2908		   (if (eq? r 0)
2909		       (##sys#integer-power ds^n (%ratnum-numerator b))
2910		       (##core#inline_allocate ("C_a_i_flonum_expt" 4)
2911					       (exact->inexact a)
2912					       (exact->inexact b))))))
2913	    ((##core#inline "C_i_flonump" a)
2914	     (log-expt a (exact->inexact b)))
2915	    (else (slow-expt a b))))
2916	  ((or (cplxnum? b) (and (cplxnum? a) (not (integer? b))))
2917	   (slow-expt a b))
2918	  ((and (##core#inline "C_i_flonump" b)
2919		(not (##core#inline "C_u_i_fpintegerp" b)))
2920	   (if (negative? a)
2921	       (log-expt (exact->inexact a) (exact->inexact b))
2922	       (##core#inline_allocate
2923		("C_a_i_flonum_expt" 4) (exact->inexact a) b)))
2924	  ((##core#inline "C_i_flonump" a)
2925	   (##core#inline_allocate ("C_a_i_flonum_expt" 4) a (exact->inexact b)))
2926	  ;; this doesn't work that well, yet...
2927	  ;; (XXX: What does this mean? why not? I do know this is ugly... :P)
2928	  (else (if (or (inexact? a) (inexact? b))
2929		    (exact->inexact (##sys#integer-power a (inexact->exact b)))
2930		    (##sys#integer-power a b)))) ))
2931
2932;; Useful for sane error messages
2933(define (##sys#internal-gcd loc a b)
2934  (cond ((##core#inline "C_i_exact_integerp" a)
2935         (cond ((##core#inline "C_i_exact_integerp" b)
2936                (%integer-gcd a b))
2937               ((and (##core#inline "C_i_flonump" b)
2938                     (##core#inline "C_u_i_fpintegerp" b))
2939                (exact->inexact (%integer-gcd a (inexact->exact b))))
2940               (else (##sys#error-bad-integer b loc))))
2941        ((and (##core#inline "C_i_flonump" a)
2942              (##core#inline "C_u_i_fpintegerp" a))
2943         (cond ((##core#inline "C_i_flonump" b)
2944                (##core#inline_allocate ("C_a_i_flonum_gcd" 4) a b))
2945               ((##core#inline "C_i_exact_integerp" b)
2946                (exact->inexact (%integer-gcd (inexact->exact a) b)))
2947               (else (##sys#error-bad-integer b loc))))
2948        (else (##sys#error-bad-integer a loc))))
2949;; For compat reasons, we define this
2950(define (##sys#gcd a b) (##sys#internal-gcd 'gcd a b))
2951
2952(set! scheme#gcd
2953  (lambda ns
2954    (if (eq? ns '())
2955	0
2956	(let loop ((head (##sys#slot ns 0))
2957		   (next (##sys#slot ns 1)))
2958	  (if (null? next)
2959	      (if (integer? head) (abs head) (##sys#error-bad-integer head 'gcd))
2960	      (let ((n2 (##sys#slot next 0)))
2961		(loop (##sys#internal-gcd 'gcd head n2)
2962		      (##sys#slot next 1)) ) ) ) ) ))
2963
2964(define (##sys#lcm x y)
2965  (let ((gcd (##sys#internal-gcd 'lcm x y))) ; Ensure better error message
2966    (abs (quotient (* x y) gcd) ) ) )
2967
2968(set! scheme#lcm
2969  (lambda ns
2970    (if (null? ns)
2971	1
2972	(let loop ((head (##sys#slot ns 0))
2973		   (next (##sys#slot ns 1)))
2974	  (if (null? next)
2975	      (if (integer? head) (abs head) (##sys#error-bad-integer head 'lcm))
2976	      (let* ((n2 (##sys#slot next 0))
2977		     (gcd (##sys#internal-gcd 'lcm head n2)))
2978		(loop (quotient (* head n2) gcd)
2979		      (##sys#slot next 1)) ) ) ) ) ))
2980
2981;; This simple enough idea is from
2982;; http://www.numberworld.org/y-cruncher/internals/radix-conversion.html
2983(define (##sys#integer->string/recursive n base expected-string-size)
2984  (let*-values (((halfsize) (fxshr (fx+ expected-string-size 1) 1))
2985                ((b^M/2) (##sys#integer-power base halfsize))
2986                ((hi lo) ((##core#primitive "C_u_integer_quotient_and_remainder")
2987			  n b^M/2))
2988                ((strhi) (number->string hi base))
2989                ((strlo) (number->string (abs lo) base)))
2990    (string-append strhi
2991                   ;; Fix up any leading zeroes that were stripped from strlo
2992                   (make-string (fx- halfsize (string-length strlo)) #\0)
2993                   strlo)))
2994
2995(define ##sys#extended-number->string
2996  (let ((string-append string-append))
2997    (lambda (n base)
2998      (cond
2999       ((ratnum? n)
3000	(string-append (number->string (%ratnum-numerator n) base)
3001		       "/"
3002		       (number->string (%ratnum-denominator n) base)))
3003       ((cplxnum? n) (let ((r (%cplxnum-real n))
3004                           (i (%cplxnum-imag n)) )
3005                       (string-append
3006                        (number->string r base)
3007                        ;; The infinities and NaN always print their sign
3008                        (if (and (finite? i) (>= i 0) (not (eqv? i -0.0))) "+" "")
3009                        (number->string i base) "i") ))
3010       (else (##sys#error-bad-number n 'number->string)))  ) ) )
3011
3012(define ##sys#number->string number->string) ; for printer
3013
3014;; We try to prevent memory exhaustion attacks by limiting the
3015;; maximum exponent value.  Perhaps this should be a parameter?
3016(define-constant +maximum-allowed-exponent+ 10000)
3017
3018;; From "Easy Accurate Reading and Writing of Floating-Point Numbers"
3019;; by Aubrey Jaffer.
3020(define (mantexp->dbl mant point)
3021  (if (not (negative? point))
3022      (exact->inexact (* mant (##sys#integer-power 10 point)))
3023      (let* ((scl (##sys#integer-power 10 (abs point)))
3024	     (bex (fx- (fx- (integer-length mant)
3025			    (integer-length scl))
3026                       flonum-precision)))
3027        (if (fx< bex 0)
3028            (let* ((num (arithmetic-shift mant (fxneg bex)))
3029                   (quo (round-quotient num scl)))
3030              (cond ((> (integer-length quo) flonum-precision)
3031                     ;; Too many bits of quotient; readjust
3032                     (set! bex (fx+ 1 bex))
3033                     (set! quo (round-quotient num (* scl 2)))))
3034              (ldexp (exact->inexact quo) bex))
3035            ;; Fall back to exact calculation in extreme cases
3036            (* mant (##sys#integer-power 10 point))))))
3037
3038(define ldexp (foreign-lambda double "ldexp" double int))
3039
3040;; Should we export this?
3041(define (round-quotient n d)
3042  (let ((q (%integer-quotient n d)))
3043    (if ((if (even? q) > >=) (* (abs (remainder n d)) 2) (abs d))
3044        (+ q (if (eqv? (negative? n) (negative? d)) 1 -1))
3045        q)))
3046
3047(define (##sys#string->compnum radix str offset exactness)
3048  ;; Flipped when a sign is encountered (for inexact numbers only)
3049  (define negative #f)
3050  ;; Go inexact unless exact was requested (with #e prefix)
3051  (define (go-inexact! neg?)
3052    (unless (eq? exactness 'e)
3053      (set! exactness 'i)
3054      (set! negative (or negative neg?))))
3055  (define (safe-exponent value e)
3056    (and e (cond
3057            ((not value) 0)
3058            ((> e +maximum-allowed-exponent+)
3059             (and (eq? exactness 'i)
3060                  (cond ((zero? value) 0.0)
3061                        ((> value 0.0) +inf.0)
3062                        (else -inf.0))))
3063            ((< e (fxneg +maximum-allowed-exponent+))
3064             (and (eq? exactness 'i) +0.0))
3065            ((eq? exactness 'i) (mantexp->dbl value e))
3066            (else (* value (##sys#integer-power 10 e))))))
3067  (define (make-nan)
3068    ;; Return fresh NaNs, so eqv? returns #f on two read NaNs.  This
3069    ;; is not mandated by the standard, but compatible with earlier
3070    ;; CHICKENs and it just makes more sense.
3071    (##core#inline_allocate ("C_a_i_flonum_quotient" 4) 0.0 0.0))
3072  (let* ((len (string-length str))
3073         (0..r (fast-i->c (fx+ (char->integer #\0) (fx- radix 1))))
3074         (a..r (fast-i->c (fx+ (char->integer #\a) (fx- radix 11))))
3075         (A..r (fast-i->c (fx+ (char->integer #\A) (fx- radix 11))))
3076         ;; Ugly flag which we need (note that "exactness" is mutated too!)
3077         ;; Since there is (almost) no backtracking we can do this.
3078         (seen-hashes? #f)
3079         ;; All these procedures return #f or an object consed onto an end
3080         ;; position.  If the cdr is false, that's the end of the string.
3081         ;; If just #f is returned, the string contains invalid number syntax.
3082         (scan-digits
3083          (lambda (start cplx?)
3084            (let lp ((i start)
3085                     ;; Drop is true when the last read character is
3086                     ;; an "i" while reading the second part of a
3087                     ;; rectangular complex number literal *and* the
3088                     ;; radix is 19 or above.  In that case, we back
3089                     ;; up one character to ensure we don't consume
3090                     ;; the trailing "i", which we otherwise would.
3091                     (drop? #f))
3092              (if (fx= i len)
3093                  (and (fx> i start)
3094                       (if drop?
3095                           (cons (sub1 i) (sub1 i))
3096                           (cons i #f)))
3097                  (let ((c (string-ref str i)))
3098                    (if (fx<= radix 10)
3099                        (if (and (char>=? c #\0) (char<=? c 0..r))
3100                            (lp (fx+ i 1) #f)
3101                            (and (fx> i start) (cons i i)))
3102                        (if (or (and (char>=? c #\0) (char<=? c #\9))
3103                                (and (char>=? c #\a) (char<=? c a..r))
3104                                (and (char>=? c #\A) (char<=? c A..r)))
3105                            (lp (fx+ i 1)
3106                                (and cplx? (fx>= radix 19)
3107                                     (or (char=? c #\i)
3108                                         (char=? c #\I))))
3109                            (and (fx> i start)
3110                                 (if (and drop? (not (char=? c #\/))) ;; Fractional numbers are an exception - the i may only come after the slash
3111                                     (cons (sub1 i) (sub1 i))
3112                                     (cons i i))))))))))
3113         (scan-hashes
3114          (lambda (start)
3115            (let lp ((i start))
3116              (if (fx= i len)
3117                  (and (fx> i start) (cons i #f))
3118                  (let ((c (string-ref str i)))
3119                    (if (eq? c #\#)
3120                        (lp (fx+ i 1))
3121                        (and (fx> i start) (cons i i))))))))
3122         (scan-digits+hashes
3123          (lambda (start neg? cplx? all-hashes-ok?)
3124            (let* ((digits (and (not seen-hashes?) (scan-digits start cplx?)))
3125                   (hashes (if digits
3126                               (and (cdr digits) (scan-hashes (cdr digits)))
3127                               (and all-hashes-ok? (scan-hashes start))))
3128                   (end (or hashes digits)))
3129              (and-let* ((end)
3130                         (num (##core#inline_allocate
3131			       ("C_s_a_i_digits_to_integer" 6)
3132			       str start (car end) radix neg?)))
3133                (when hashes            ; Eeewww. Feeling dirty yet?
3134                  (set! seen-hashes? #t)
3135                  (go-inexact! neg?))
3136                (cons num (cdr end))))))
3137         (scan-exponent
3138          (lambda (start)
3139            (and (fx< start len)
3140                 (let ((sign (case (string-ref str start)
3141                               ((#\+) 'pos) ((#\-) 'neg) (else #f))))
3142                   (and-let* ((start (if sign (fx+ start 1) start))
3143                              (end (scan-digits start #f)))
3144                     (cons (##core#inline_allocate
3145			    ("C_s_a_i_digits_to_integer" 6)
3146			    str start (car end) radix (eq? sign 'neg))
3147                           (cdr end)))))))
3148         (scan-decimal-tail             ; The part after the decimal dot
3149          (lambda (start neg? decimal-head)
3150            (and (fx< start len)
3151                 (let* ((tail (scan-digits+hashes start neg? #f decimal-head))
3152                        (next (if tail (cdr tail) start)))
3153                   (and (or decimal-head (not next)
3154                            (fx> next start)) ; Don't allow empty "."
3155                        (case (and next (string-ref str next))
3156                          ((#\e #\s #\f #\d #\l
3157                            #\E #\S #\F #\D #\L)
3158                           (and-let* (((fx> len next))
3159                                      (ee (scan-exponent (fx+ next 1)))
3160                                      (e (car ee))
3161                                      (h (safe-exponent decimal-head e)))
3162                             (let* ((te (and tail (fx- e (fx- (cdr tail) start))))
3163                                    (num (and tail (car tail)))
3164                                    (t (safe-exponent num te)))
3165                               (cons (if t (+ h t) h) (cdr ee)))))
3166                          (else (let* ((last (or next len))
3167                                       (te (and tail (fx- start last)))
3168                                       (num (and tail (car tail)))
3169                                       (t (safe-exponent num te))
3170                                       (h (or decimal-head 0)))
3171                                  (cons (if t (+ h t) h) next)))))))))
3172         (scan-ureal
3173          (lambda (start neg? cplx?)
3174            (if (and (fx> len (fx+ start 1)) (eq? radix 10)
3175                     (eq? (string-ref str start) #\.))
3176                (begin
3177                  (go-inexact! neg?)
3178                  (scan-decimal-tail (fx+ start 1) neg? #f))
3179                (and-let* ((end (scan-digits+hashes start neg? cplx? #f)))
3180                  (case (and (cdr end) (string-ref str (cdr end)))
3181                    ((#\.)
3182                     (go-inexact! neg?)
3183                     (and (eq? radix 10)
3184                          (if (fx> len (fx+ (cdr end) 1))
3185                              (scan-decimal-tail (fx+ (cdr end) 1) neg? (car end))
3186                              (cons (car end) #f))))
3187                    ((#\e #\s #\f #\d #\l
3188                      #\E #\S #\F #\D #\L)
3189                     (go-inexact! neg?)
3190                     (and-let* (((eq? radix 10))
3191                                ((fx> len (cdr end)))
3192                                (ee (scan-exponent (fx+ (cdr end) 1)))
3193                                (num (car end))
3194                                (val (safe-exponent num (car ee))))
3195                       (cons val (cdr ee))))
3196                    ((#\/)
3197                     (set! seen-hashes? #f) ; Reset flag for denominator
3198                     (and-let* (((fx> len (cdr end)))
3199                                (d (scan-digits+hashes (fx+ (cdr end) 1) #f cplx? #f))
3200                                (num (car end))
3201                                (denom (car d)))
3202                       (if (not (eq? denom 0))
3203                           (cons (##sys#/-2 num denom) (cdr d))
3204                           ;; Hacky: keep around an inexact until we decide we
3205                           ;; *really* need exact values, then fail at the end.
3206                           (and (not (eq? exactness 'e))
3207                                (case (signum num)
3208                                  ((-1) (cons -inf.0 (cdr d)))
3209                                  ((0)  (cons (make-nan) (cdr d)))
3210                                  ((+1) (cons +inf.0 (cdr d))))))))
3211                    (else end))))))
3212         (scan-real
3213          (lambda (start cplx?)
3214            (and (fx< start len)
3215                 (let* ((sign (case (string-ref str start)
3216                                ((#\+) 'pos) ((#\-) 'neg) (else #f)))
3217                        (next (if sign (fx+ start 1) start)))
3218                   (and (fx< next len)
3219                        (case (string-ref str next)
3220                          ((#\i #\I)
3221                           (or (and sign
3222                                    (cond
3223                                     ((and (fx= (fx+ next 1) len)  ; [+-]i
3224                                           ;; Reject bare "+i" in higher radixes where this would be ambiguous
3225                                           (or cplx?
3226                                               (fx< radix 19)))
3227                                      (cons (if (eq? sign 'neg) -1 1) next))
3228                                     ((and (fx<= (fx+ next 5) len)
3229                                           (string-ci=? (substring str next (fx+ next 5)) "inf.0"))
3230                                      (go-inexact! (eq? sign 'neg))
3231                                      (cons (if (eq? sign 'neg) -inf.0 +inf.0)
3232                                            (and (fx< (fx+ next 5) len)
3233                                                 (fx+ next 5))))
3234                                     (else #f)))
3235                               (scan-ureal next (eq? sign 'neg) cplx?)))
3236                          ((#\n #\N)
3237                           (or (and sign
3238                                    (fx<= (fx+ next 5) len)
3239                                    (string-ci=? (substring str next (fx+ next 5)) "nan.0")
3240                                    (begin (go-inexact! (eq? sign 'neg))
3241                                           (cons (make-nan)
3242                                                 (and (fx< (fx+ next 5) len)
3243                                                      (fx+ next 5)))))
3244                               (scan-ureal next (eq? sign 'neg) cplx?)))
3245                          (else (scan-ureal next (eq? sign 'neg) cplx?))))))))
3246         (number (and-let* ((r1 (scan-real offset #f)))
3247                   (let ((nf (and r1 (zero? (car r1)) negative)))
3248                     (case (and (cdr r1) (string-ref str (cdr r1)))
3249                       ((#f) (car r1))
3250                       ((#\i #\I) (and (fx= len (fx+ (cdr r1) 1))
3251                                     (or (eq? (string-ref str offset) #\+) ; ugh
3252                                         (eq? (string-ref str offset) #\-))
3253                                     (make-rectangular 0 (if nf (- (car r1)) (car r1)))))
3254                       ((#\+ #\-)
3255                        (set! seen-hashes? #f) ; Reset flag for imaginary part
3256                        (set! negative #f)
3257                        (and-let* ((r2 (scan-real (cdr r1) #t))
3258                                   ((cdr r2))
3259                                   ((fx= len (fx+ (cdr r2) 1)))
3260                                   ((or (eq? (string-ref str (cdr r2)) #\i)
3261                                        (eq? (string-ref str (cdr r2)) #\I))))
3262                          (make-rectangular 
3263                            (car r1) 
3264                            (let ((n2 (if (and (exact? (car r2)) (eq? exactness 'i))
3265                                          (exact->inexact (car r2))
3266                                          (car r2))))
3267                              (if (and negative (>= n2 0) (not (eqv? n2 -0.0)))
3268                                  (- n2)
3269                                  n2)))))
3270                       ((#\@)
3271                        (set! seen-hashes? #f) ; Reset flag for angle
3272                        (and-let* ((r2 (scan-real (fx+ (cdr r1) 1) #f))
3273                                   ((not (cdr r2))))
3274                          (make-polar (car r1) (car r2))))
3275                       (else #f))))))
3276    (and number (if (eq? exactness 'i)
3277                    (let ((r (exact->inexact number)))
3278                      ;; Stupid hack because flonums can represent negative zero,
3279                      ;; but we're coming from an exact which has no such thing.
3280                      (if (and negative (zero? r)) (fpneg r) r))
3281                    ;; Ensure we didn't encounter +inf.0 or +nan.0 with #e
3282                    (and (finite? number) number)))))
3283
3284(set! scheme#string->number
3285  (lambda (str #!optional (base 10))
3286    (##sys#check-string str 'string->number)
3287    (unless (and (##core#inline "C_fixnump" base)
3288		 (fx< 1 base) (fx< base 37)) ; We only have 0-9 and the alphabet!
3289      (##sys#error-bad-base base 'string->number))
3290    (let scan-prefix ((i 0)
3291		      (exness #f)
3292		      (radix #f)
3293		      (len (string-length str)))
3294      (if (and (fx< (fx+ i 2) len) (eq? (string-ref str i) #\#))
3295	  (case (string-ref str (fx+ i 1))
3296	    ((#\i #\I) (and (not exness) (scan-prefix (fx+ i 2) 'i radix len)))
3297	    ((#\e #\E) (and (not exness) (scan-prefix (fx+ i 2) 'e radix len)))
3298	    ((#\b #\B) (and (not radix) (scan-prefix (fx+ i 2) exness 2 len)))
3299	    ((#\o #\O) (and (not radix) (scan-prefix (fx+ i 2) exness 8 len)))
3300	    ((#\d #\D) (and (not radix) (scan-prefix (fx+ i 2) exness 10 len)))
3301	    ((#\x #\X) (and (not radix) (scan-prefix (fx+ i 2) exness 16 len)))
3302	    (else #f))
3303	  (##sys#string->compnum (or radix base) str i exness)))))
3304
3305(define (##sys#string->number str #!optional (radix 10) exactness)
3306  (##sys#string->compnum radix str 0 exactness))
3307
3308(define ##sys#fixnum->string (##core#primitive "C_fixnum_to_string"))
3309(define ##sys#flonum->string (##core#primitive "C_flonum_to_string"))
3310(define ##sys#integer->string (##core#primitive "C_integer_to_string"))
3311(define ##sys#number->string number->string)
3312
3313(set! chicken.base#equal=?
3314  (lambda (x y)
3315    (define (compare-slots x y start)
3316      (let ((l1 (##sys#size x))
3317	    (l2 (##sys#size y)))
3318	(and (eq? l1 l2)
3319	     (or (fx<= l1 start)
3320		 (let ((l1n (fx- l1 1)))
3321		   (let loop ((i start))
3322		     (if (fx= i l1n)
3323			 (walk (##sys#slot x i) (##sys#slot y i)) ; tailcall
3324			 (and (walk (##sys#slot x i) (##sys#slot y i))
3325			      (loop (fx+ i 1))))))))))
3326    (define (walk x y)
3327      (cond ((eq? x y))
3328	    ((number? x)
3329	     (if (number? y)
3330		 (= x y)
3331		 (eq? x y)))
3332	    ((not (##core#inline "C_blockp" x)) #f)
3333	    ((not (##core#inline "C_blockp" y)) #f)
3334	    ((not (##core#inline "C_sametypep" x y)) #f)
3335	    ((##core#inline "C_specialp" x)
3336	     (and (##core#inline "C_specialp" y)
3337		  (if (##core#inline "C_closurep" x)
3338		      (##core#inline "shallow_equal" x y)
3339		      (compare-slots x y 1))))
3340            ((##core#inline "C_stringp" x)
3341             (walk (##sys#slot x 0) (##sys#slot y 0)))
3342	    ((##core#inline "C_byteblockp" x)
3343	     (and (##core#inline "C_byteblockp" y)
3344		  (let ((s1 (##sys#size x)))
3345		    (and (eq? s1 (##sys#size y))
3346			 (##core#inline "C_bv_compare" x y s1)))))
3347	    (else
3348	     (let ((s1 (##sys#size x)))
3349	       (and (eq? s1 (##sys#size y))
3350		    (compare-slots x y 0))))))
3351    (walk x y) ))
3352
3353
3354;;; Symbols:
3355
3356(define ##sys#snafu '##sys#fnord)
3357(define ##sys#intern-symbol (##core#primitive "C_string_to_symbol"))
3358(define ##sys#intern-keyword (##core#primitive "C_string_to_keyword"))
3359(define ##sys#make-symbol (##core#primitive "C_make_symbol"))
3360(define (##sys#interned-symbol? x) (##core#inline "C_lookup_symbol" x))
3361
3362(define (##sys#string->symbol-name s)
3363  (let* ((bv (##sys#slot s 0))
3364         (len (##sys#size bv))
3365         (s2 (##sys#make-bytevector len)))
3366    (##core#inline "C_copy_bytevector" bv s2 len)))
3367
3368(define (##sys#symbol->string/shared s)
3369  (let* ((bv (##sys#slot s 1))
3370         (count (##core#inline "C_utf_length" bv)))
3371    (##core#inline_allocate ("C_a_ustring" 5)
3372                            bv
3373                            count)))
3374
3375(define (##sys#symbol->string s)
3376  (let* ((bv (##sys#slot s 1))
3377         (len (##sys#size bv))
3378         (s2 (##sys#make-bytevector len))
3379         (count (##core#inline "C_utf_length" bv)))
3380    (##core#inline_allocate ("C_a_ustring" 5)
3381                            (##core#inline "C_copy_bytevector" bv s2 len)
3382                            count)))
3383
3384(define (##sys#string->symbol str)
3385  (##sys#intern-symbol (##sys#string->symbol-name str) ))
3386
3387(set! scheme#symbol->string
3388  (lambda (s)
3389    (##sys#check-symbol s 'symbol->string)
3390    (##sys#symbol->string s) ) )
3391
3392(set! scheme#string->symbol
3393  (lambda (str)
3394    (##sys#check-string str 'string->symbol)
3395    (##sys#string->symbol str)))
3396
3397(set! chicken.base#string->uninterned-symbol
3398  (lambda (str)
3399    (##sys#check-string str 'string->uninterned-symbol)
3400    (##sys#make-symbol (##sys#string->symbol-name str))))
3401
3402(set! chicken.base#gensym
3403  (let ((counter -1))
3404    (lambda str-or-sym
3405      (let ((err (lambda (prefix) (##sys#signal-hook #:type-error 'gensym "argument is not a string or symbol" prefix))))
3406	(set! counter (fx+ counter 1))
3407	(##sys#make-symbol
3408         (##sys#string->symbol-name
3409	 (##sys#string-append
3410	  (if (eq? str-or-sym '())
3411	      "g"
3412	      (let ((prefix (car str-or-sym)))
3413		(or (and (##core#inline "C_blockp" prefix)
3414			 (cond ((##core#inline "C_stringp" prefix) prefix)
3415			       ((##core#inline "C_symbolp" prefix) (##sys#symbol->string/shared prefix))
3416			       (else (err prefix))))
3417		    (err prefix) ) ) )
3418	  (##sys#number->string counter) ) ) ) ) ) ) )
3419
3420(set! chicken.base#symbol-append
3421  (let ((string-append string-append))
3422    (lambda ss
3423      (##sys#string->symbol
3424       (apply
3425	string-append
3426	(map (lambda (s)
3427	       (##sys#check-symbol s 'symbol-append)
3428	       (##sys#symbol->string/shared s))
3429	     ss))))))
3430
3431;;; Keywords:
3432
3433(module chicken.keyword
3434  (keyword? get-keyword keyword->string string->keyword)
3435
3436(import scheme)
3437(import chicken.fixnum)
3438
3439(define (keyword? x) (##core#inline "C_i_keywordp" x) )
3440
3441(define string->keyword
3442  (let ([string string] )
3443    (lambda (s)
3444      (##sys#check-string s 'string->keyword)
3445      (##sys#intern-keyword (##sys#string->symbol-name s) ) ) ))
3446
3447(define keyword->string
3448  (let ([keyword? keyword?])
3449    (lambda (kw)
3450      (if (keyword? kw)
3451	  (##sys#symbol->string kw)
3452	  (##sys#signal-hook #:type-error 'keyword->string "bad argument type - not a keyword" kw) ) ) ) )
3453
3454(define get-keyword
3455  (let ((tag (list 'tag)))
3456    (lambda (key args #!optional thunk)
3457      (##sys#check-keyword key 'get-keyword)
3458      (##sys#check-list args 'get-keyword)
3459      (let ((r (##core#inline "C_i_get_keyword" key args tag)))
3460	(if (eq? r tag)			; not found
3461	    (and thunk (thunk))
3462	    r)))))
3463
3464(define ##sys#get-keyword get-keyword))
3465
3466(import chicken.keyword)
3467
3468
3469;;; bytevectors:
3470
3471(define (##sys#bytevector->list v)
3472  (let ((n (##sys#size v)))
3473    (let loop ((i (fx- n 1)) (lst '()))
3474      (if (fx< i 0)
3475          lst
3476          (loop (fx- i 1)
3477                (cons (##core#inline "C_subbyte" v i) lst))))))
3478
3479(define (##sys#list->bytevector lst0)
3480  (let* ((n (length lst0))
3481         (bv (##sys#make-bytevector n)))
3482    (let loop ((lst lst0) (i 0))
3483      (if (null? lst)
3484          bv
3485          (let ((b (car lst)))
3486            (if (##core#inline "C_fixnump" b)
3487                (##core#inline "C_setsubbyte" bv i b)
3488                (##sys#signal-hook #:type-error "can not convert list to bytevector" lst0))
3489            (loop (cdr lst) (fx+ i 1)))))))
3490
3491(module chicken.bytevector
3492  (bytevector? bytevector=? bytevector-length
3493               make-bytevector bytevector bytevector-u8-ref
3494               bytevector-u8-set! bytevector-copy bytevector-copy!
3495               bytevector-append utf8->string string->utf8
3496               latin1->string string->latin1 bytes->string)
3497
3498(import scheme (chicken foreign))
3499
3500(define (make-bytevector size #!optional fill)
3501  (##sys#check-fixnum size 'make-bytevector)
3502  (if fill (##sys#check-fixnum fill 'make-bytevector))
3503  (##sys#make-bytevector size fill) )
3504
3505(define (bytevector? x)
3506  (and (##core#inline "C_blockp" x)
3507       (##core#inline "C_bytevectorp" x) ) )
3508
3509(define (bytevector-length bv)
3510  (##sys#check-bytevector bv 'bytevector-size)
3511  (##sys#size bv) )
3512
3513(define (bytevector-u8-ref bv i)
3514  (##core#inline "C_i_bytevector_ref" bv i))
3515
3516(define (bytevector-u8-set! bv i b)
3517  (##core#inline "C_i_bytevector_set" bv i b))
3518
3519(define (string->utf8 s)
3520  (##sys#check-string s 'string->utf8)
3521  (let* ((sbv (##sys#slot s 0))
3522         (n (##core#inline "C_fixnum_difference" (##sys#size sbv) 1))
3523	 (bv (##sys#make-bytevector n)) )
3524    (##core#inline "C_copy_memory" bv sbv n)
3525    bv) )
3526
3527(define (utf8->string bv #!optional (start 0) end)
3528  (##sys#check-bytevector bv 'utf8->string)
3529  (let* ((n (##sys#size bv))
3530         (to (or end n)))
3531    (if end
3532        (##sys#check-range/including end 0 n 'utf8->string))
3533    (if (not (##core#inline "C_utf_validate" bv n start to))
3534        (##sys#error-hook (foreign-value "C_DECODING_ERROR" int) 'utf8->string bv))
3535    (##sys#buffer->string bv start (##core#inline "C_fixnum_difference" to start))))
3536
3537(define (bytes->string bv #!optional (start 0) end)
3538  (##sys#check-bytevector bv 'bytes->string)
3539  (let* ((n (##sys#size bv))
3540         (to (or end n)))
3541    (if end
3542        (##sys#check-range/including end 0 n 'bytes->string))
3543    (##sys#buffer->string bv start (##core#inline "C_fixnum_difference" to start))))
3544
3545(define (string->latin1 s)
3546  (##sys#check-string s 'string->latin1)
3547  (let* ((sbv (##sys#slot s 0))
3548         (len (##sys#slot s 1))
3549         (blen (##core#inline "C_fixnum_difference" (##sys#size sbv) 1))
3550	 (bv (##sys#make-bytevector len)) )
3551    (##core#inline "C_utf_to_latin" sbv bv 0 blen)
3552    bv))
3553
3554(define (latin1->string bv)
3555  (##sys#check-bytevector bv 'latin1->string)
3556  (let* ((len (##sys#size bv))
3557         (buf (##sys#make-bytevector (##core#inline "C_fixnum_times" len 2)))
3558         (n (##core#inline "C_latin_to_utf" bv buf 0 len)))
3559    (##sys#buffer->string! buf n)))
3560
3561(define (bytevector=? b1 b2)
3562  (##sys#check-bytevector b1 'bytevector=?)
3563  (##sys#check-bytevector b2 'bytevector=?)
3564  (let ((n (##sys#size b1)))
3565    (and (eq? (##sys#size b2) n)
3566	 (##core#inline "C_bv_compare" b1 b2 n))))
3567
3568(define (bytevector . args)
3569  (let* ((n (length args))
3570         (bv (##sys#make-bytevector n)))
3571    (let loop ((args args) (i 0))
3572      (cond ((null? args) bv)
3573            (else
3574              (let ((b (car args)))
3575                (##sys#check-fixnum b 'bytevector)
3576                (##core#inline "C_setsubbyte" bv i b)
3577                (loop (cdr args) (##core#inline "C_fixnum_plus" i 1))))))))
3578
3579(define (bytevector-copy bv #!optional (start 0) end)
3580  (##sys#check-bytevector bv 'bytevector-copy)
3581  (let* ((n (##sys#size bv))
3582         (to (or end n)))
3583    (if end
3584      (##sys#check-range/including end 0 n 'bytevector->copy))
3585    (cond ((and (eq? n 0) (eq? start 0) (eq? 0 to))
3586           (##sys#make-bytevector 0))
3587          (else
3588            (##sys#check-range/including start 0 n 'bytevector->copy)
3589            (let* ((n2 (##core#inline "C_fixnum_difference" to start))
3590                   (v2 (##sys#make-bytevector n2)))
3591              (##core#inline "C_copy_memory_with_offset" v2 bv 0 start n2)
3592              v2)))))
3593
3594(define (bytevector-copy! bv1 at bv2 #!optional (start 0) end)
3595  (##sys#check-bytevector bv1 'bytevector-copy!)
3596  (##sys#check-bytevector bv2 'bytevector-copy!)
3597  (let* ((n1 (##sys#size bv1))
3598         (n2 (##sys#size bv2))
3599         (to (or end n2))
3600         (nc (##core#inline "C_fixnum_difference" to start)))
3601    (cond ((and (eq? n2 0) (eq? nc 0) (eq? start 0)) (##core#undefined))
3602          (else
3603            (##sys#check-range/including start 0 n2 'bytevector->copy!)
3604            (##sys#check-range/including at 0 n1 'bytevector->copy!)
3605            (##sys#check-range/including (##core#inline "C_fixnum_plus" at nc)
3606                               0 n1 'bytevector->copy!)
3607            (##core#inline "C_copy_memory_with_offset" bv1 bv2 at start nc)))))
3608
3609(define (bytevector-append . bvs)
3610  (let loop ((lst bvs) (len 0))
3611    (if (null? lst)
3612        (let ((bv (##sys#make-bytevector len)))
3613          (let loop ((lst bvs) (i 0))
3614            (if (null? lst)
3615                bv
3616                (let* ((bv1 (car lst))
3617                       (n (##sys#size bv1)))
3618                  (##core#inline "C_copy_memory_with_offset" bv bv1 i 0 n)
3619                  (loop (cdr lst) (##core#inline "C_fixnum_plus" i n))))))
3620        (let ((bv (car lst)))
3621          (##sys#check-bytevector bv 'bytevector-append)
3622          (loop (cdr lst) (##core#inline "C_fixnum_plus" len (##sys#size bv)))))))
3623
3624) ; chicken.bytevector
3625
3626
3627;;; Vectors:
3628(set! scheme#make-vector
3629  (lambda (size . fill)
3630    (##sys#check-fixnum size 'make-vector)
3631    (when (fx< size 0) (##sys#error 'make-vector "size is negative" size))
3632    (##sys#allocate-vector
3633     size
3634     (if (null? fill)
3635	 (##core#undefined)
3636	 (car fill) ))))
3637
3638(define ##sys#make-vector make-vector)
3639
3640(set! scheme#list->vector
3641  (lambda (lst0)
3642    (if (not (list? lst0))
3643	(##sys#error-not-a-proper-list lst0 'list->vector)
3644	(let* ([len (length lst0)]
3645	       [v (##sys#make-vector len)] )
3646	  (let loop ([lst lst0]
3647		     [i 0])
3648	    (if (null? lst)
3649		v
3650		(begin
3651		  (##sys#setslot v i (##sys#slot lst 0))
3652		  (loop (##sys#slot lst 1) (fx+ i 1)) ) ) ) ) )))
3653
3654(set! scheme#vector->list
3655  (lambda (v #!optional start end)
3656    (##sys#check-vector v 'vector->list)
3657    (let ((len (##sys#size v)))
3658      (if start
3659          (##sys#check-range/including start 0 len 'vector->list)
3660          (set! start 0))
3661      (if end
3662          (##sys#check-range/including end 0 len 'vector->list)
3663          (set! end len))
3664      (let loop ((i start))
3665	(if (fx>= i end)
3666	    '()
3667	    (cons (##sys#slot v i)
3668		  (loop (fx+ i 1)) ) ) ) ) ))
3669
3670(set! scheme#vector (lambda xs (list->vector xs) ))
3671
3672(set! scheme#vector-fill!
3673  (lambda (v x #!optional start end)
3674    (##sys#check-vector v 'vector-fill!)
3675    (let ((len (##sys#size v)))
3676      (if start
3677          (##sys#check-range/including start 0 len 'vector-fill!)
3678          (set! start 0))
3679      (if end
3680          (##sys#check-range/including end 0 len 'vector-fill!)
3681          (set! end len))
3682      (do ((i start (fx+ i 1)))
3683	  ((fx>= i end))
3684	(##sys#setslot v i x) ) ) ))
3685
3686(define (scheme#vector-copy v #!optional start end)
3687  (##sys#check-vector v 'vector-copy)
3688  (let ((copy (lambda (v start end)
3689                (let* ((len (##sys#size v)))
3690                  (##sys#check-range/including start 0 end 'vector-copy)
3691                  (##sys#check-range/including end start len 'vector-copy)
3692                  (let ((vec (##sys#make-vector (fx- end start))))
3693                    (do ((ti 0 (fx+ ti 1))
3694                         (fi start (fx+ fi 1)))
3695                        ((fx>= fi end) vec)
3696                      (##sys#setslot vec ti (##sys#slot v fi))))))))
3697    (if end
3698        (copy v start end)
3699        (copy v (or start 0) (##sys#size v)))))
3700
3701(define (scheme#vector-copy! to at from #!optional start end)
3702  (##sys#check-vector to 'vector-copy!)
3703  (##sys#check-vector from 'vector-copy!)
3704  (let ((copy! (lambda (to at from start end)
3705                 (let* ((tlen (##sys#size to))
3706                        (flen (##sys#size from))
3707                        (d (fx- end start)))
3708                   (##sys#check-range/including at 0 tlen 'vector-copy!)
3709                   (##sys#check-range/including start 0 end 'vector-copy!)
3710                   (##sys#check-range/including end start flen 'vector-copy!)
3711                   (##sys#check-range/including d 0 (fx- tlen at) 'vector-copy!)
3712                   (if (and (eq? to from) (fx< start at))
3713                       (do ((fi (fx- end 1) (fx- fi 1))
3714                            (ti (fx- (fx+ at d) 1) (fx- ti 1)))
3715                           ((fx< fi start))
3716                           (##sys#setslot to ti (##sys#slot from fi)))
3717                       (do ((fi start (fx+ fi 1))
3718                            (ti at (fx+ ti 1)))
3719                           ((fx= fi end))
3720                           (##sys#setslot to ti (##sys#slot from fi))))))))
3721    (if end
3722        (copy! to at from start end)
3723        (copy! to at from (or start 0) (##sys#size from)))))
3724
3725(define (scheme#vector-append . vs)
3726  (##sys#for-each (cut ##sys#check-vector <> 'vector-append) vs)
3727  (let* ((lens (map ##sys#size vs))
3728         (vec  (##sys#make-vector (foldl fx+ 0 lens))))
3729    (do ((vs vs (cdr vs))
3730         (lens lens (cdr lens))
3731         (i 0 (fx+ i (car lens))))
3732        ((null? vs) vec)
3733      (scheme#vector-copy! vec i (car vs) 0 (car lens)))))
3734
3735(set! chicken.base#subvector
3736  (lambda (v i #!optional j)
3737    (##sys#check-vector v 'subvector)
3738    (let* ((len (##sys#size v))
3739	   (j (or j len))
3740	   (len2 (fx- j i)))
3741      (##sys#check-range/including i 0 len 'subvector)
3742      (##sys#check-range/including j 0 len 'subvector)
3743      (let ((v2 (make-vector len2)))
3744	(do ((k 0 (fx+ k 1)))
3745	    ((fx>= k len2) v2)
3746	  (##sys#setslot v2 k (##sys#slot v (fx+ k i))))))))
3747
3748(set! chicken.base#vector-resize
3749  (lambda (v n #!optional init)
3750    (##sys#check-vector v 'vector-resize)
3751    (##sys#check-fixnum n 'vector-resize)
3752    (##sys#vector-resize v n init)))
3753
3754(define (##sys#vector-resize v n init)
3755  (let ((v2 (##sys#make-vector n init))
3756	(len (min (##sys#size v) n)) )
3757    (do ((i 0 (fx+ i 1)))
3758	((fx>= i len) v2)
3759      (##sys#setslot v2 i (##sys#slot v i)) ) ) )
3760
3761;;; Characters:
3762
3763(set! scheme#char-ci=?
3764  (lambda (x y . more)
3765    (##sys#check-char x 'char-ci=?)
3766    (##sys#check-char y 'char-ci=?)
3767    (let ((c2 (##core#inline "C_utf_char_foldcase" y)))
3768      (let loop ((c c2) (cs more)
3769                 (f (eq? (##core#inline "C_utf_char_foldcase" x) c2)))
3770        (if (null? cs)
3771            f
3772            (let ((c2 (##sys#slot cs 0)))
3773              (##sys#check-char c2 'char-ci=?)
3774              (let ((c2 ((##core#inline "C_utf_char_foldcase" c2))))
3775                (loop c2 (##sys#slot cs 1)
3776                      (and f (eq? c c2))))))))))
3777
3778(set! scheme#char-ci>?
3779  (lambda (x y . more)
3780    (##sys#check-char x 'char-ci>?)
3781    (##sys#check-char y 'char-ci>?)
3782    (let ((c2 (##core#inline "C_utf_char_foldcase" y)))
3783      (let loop ((c c2) (cs more)
3784                 (f (##core#inline "C_u_i_char_greaterp"
3785                                   (##core#inline "C_utf_char_foldcase" x)
3786                                   c2)))
3787        (if (null? cs)
3788            f
3789            (let ((c2 (##sys#slot cs 0)))
3790              (##sys#check-char c2 'char-ci>?)
3791              (let ((c2 ((##core#inline "C_utf_char_foldcase" c2))))
3792                (loop c2 (##sys#slot cs 1)
3793                      (and f (##core#inline "C_u_i_char_greaterp" c c2))))))))))
3794
3795(set! scheme#char-ci<?
3796  (lambda (x y . more)
3797    (##sys#check-char x 'char-ci<?)
3798    (##sys#check-char y 'char-ci<?)
3799    (let ((c2 (##core#inline "C_utf_char_foldcase" y)))
3800      (let loop ((c c2) (cs more)
3801                 (f (##core#inline "C_u_i_char_lessp"
3802                                   (##core#inline "C_utf_char_foldcase" x)
3803                                   c2)))
3804        (if (null? cs)
3805            f
3806            (let ((c2 (##sys#slot cs 0)))
3807              (##sys#check-char c2 'char-ci<?)
3808              (let ((c2 ((##core#inline "C_utf_char_foldcase" c2))))
3809                (loop c2 (##sys#slot cs 1)
3810                      (and f (##core#inline "C_u_i_char_lessp" c c2))))))))))
3811
3812(set! scheme#char-ci>=?
3813  (lambda (x y . more)
3814    (##sys#check-char x 'char-ci>=?)
3815    (##sys#check-char y 'char-ci>=?)
3816    (let ((c2 (##core#inline "C_utf_char_foldcase" y)))
3817      (let loop ((c c2) (cs more)
3818                 (f (##core#inline "C_u_i_char_greater_or_equal_p"
3819                                   (##core#inline "C_utf_char_foldcase" x)
3820                                   c2)))
3821        (if (null? cs)
3822            f
3823            (let ((c2 (##sys#slot cs 0)))
3824              (##sys#check-char c2 'char-ci>=?)
3825              (let ((c2 ((##core#inline "C_utf_char_foldcase" c2))))
3826                (loop c2 (##sys#slot cs 1)
3827                      (and f (##core#inline "C_u_i_char_greater_or_equal_p" c c2))))))))))
3828
3829(set! scheme#char-ci<=?
3830  (lambda (x y . more)
3831    (##sys#check-char x 'char-ci<=?)
3832    (##sys#check-char y 'char-ci<=?)
3833    (let ((c2 (##core#inline "C_utf_char_foldcase" y)))
3834      (let loop ((c c2) (cs more)
3835                 (f (##core#inline "C_u_i_char_less_or_equal_p"
3836                                   (##core#inline "C_utf_char_foldcase" x)
3837                                   c2)))
3838        (if (null? cs)
3839            f
3840            (let ((c2 (##sys#slot cs 0)))
3841              (##sys#check-char c2 'char-ci<=?)
3842              (let ((c2 ((##core#inline "C_utf_char_foldcase" c2))))
3843                (loop c2 (##sys#slot cs 1)
3844                      (and f (##core#inline "C_u_i_char_less_or_equal_p" c c2))))))))))
3845
3846(set! chicken.base#char-name
3847  (let ((chars-to-names (make-vector char-name-table-size '()))
3848        (names-to-chars '()))
3849    (define (lookup-char c)
3850      (let* ((code (char->integer c))
3851             (key (##core#inline "C_fixnum_modulo" code char-name-table-size)) )
3852        (let loop ((b (##sys#slot chars-to-names key)))
3853          (and (pair? b)
3854               (let ((a (##sys#slot b 0)))
3855                 (if (eq? (##sys#slot a 0) c)
3856                     a
3857                     (loop (##sys#slot b 1)) ) ) ) ) ) )
3858    (lambda (x #!optional (chr #:none))
3859      (cond ((char? x)
3860             (and-let* ((a (lookup-char x)))
3861               (case chr
3862                 ((#:none)
3863                  (##sys#slot a 1) )
3864                 ((#f)
3865                  (##sys#setslot a 0 #f)
3866                  (##sys#setslot (assq (##sys#slot a 1) names-to-chars) 0 #f)
3867                  (##core#undefined))
3868                 (else
3869                   (##sys#signal-hook #:type-error 'char-name 
3870                    "expected second boolean argument" chr) ))))
3871            ((symbol? x)
3872             (let ((a (assq x names-to-chars)))
3873               (case chr
3874                 ((#:none) (and a (##sys#slot a 1)))
3875                 ((#f) 
3876                  (when a 
3877                    (##sys#setslot a 0 #f)
3878                    (##sys#setslot (lookup-char (##sys#slot a 1)) 0 #f))
3879                  (##core#undefined))
3880                 (else
3881                   (##sys#check-char chr 'char-name)
3882                   (when (fx< (##sys#size (##sys#slot x 1)) 2)
3883                     (##sys#signal-hook #:type-error 'char-name "invalid character name" x) )
3884                   (let ((a (lookup-char chr)))
3885                     (if a
3886                         (let ((b (assq x names-to-chars)))
3887                           (##sys#setslot a 1 x)
3888                           (if b
3889                               (##sys#setislot b 1 chr)
3890                               (set! names-to-chars (cons (cons x chr) names-to-chars)) ) )
3891                         (let ((key (##core#inline "C_fixnum_modulo" (char->integer chr) 
3892                                     char-name-table-size)))
3893                           (set! names-to-chars (cons (cons x chr) names-to-chars))
3894                           (##sys#setslot
3895                            chars-to-names key
3896                            (cons (cons chr x) (##sys#slot chars-to-names key))) ) ) ) ))))
3897            (else (##sys#signal-hook #:type-error 'char-name "invalid argument type" x))))))
3898
3899;; TODO: Use the character names here in the next release?  Or just
3900;; use the numbers everywhere, for clarity?
3901(char-name 'space #\space)
3902(char-name 'tab #\tab)
3903(char-name 'linefeed #\linefeed)
3904(char-name 'newline #\newline)
3905(char-name 'vtab (integer->char 11))
3906(char-name 'delete (integer->char 127))
3907(char-name 'esc (integer->char 27))
3908(char-name 'escape (integer->char 27))
3909(char-name 'alarm (integer->char 7))
3910(char-name 'nul (integer->char 0))
3911(char-name 'null (integer->char 0))
3912(char-name 'return #\return)
3913(char-name 'page (integer->char 12))
3914(char-name 'backspace (integer->char 8))
3915
3916
3917;;; Procedures:
3918
3919(define ##sys#call-with-current-continuation (##core#primitive "C_call_cc"))
3920(define ##sys#call-with-cthulhu (##core#primitive "C_call_with_cthulhu"))
3921(define ##sys#call-with-values call-with-values)
3922
3923(define (##sys#for-each p lst0)
3924  (let loop ((lst lst0))
3925    (cond ((eq? lst '()) (##core#undefined))
3926	  ((pair? lst)
3927	   (p (##sys#slot lst 0))
3928	   (loop (##sys#slot lst 1)) )
3929	  (else (##sys#error-not-a-proper-list lst0 'for-each)) ) ))
3930
3931(define (##sys#map p lst0)
3932  (let loop ((lst lst0))
3933    (cond ((eq? lst '()) lst)
3934	  ((pair? lst)
3935	   (cons (p (##sys#slot lst 0)) (loop (##sys#slot lst 1))) )
3936	  (else (##sys#error-not-a-proper-list lst0 'map)) ) ))
3937
3938(letrec ((mapsafe
3939	  (lambda (p lsts loc)
3940	    (call-with-current-continuation
3941	     (lambda (empty)
3942	       (let lp ((lsts lsts))
3943		 (if (eq? lsts '())
3944		     lsts
3945		     (let ((item (##sys#slot lsts 0)))
3946		       (cond ((eq? item '()) (empty '()))
3947			     ((pair? item)
3948			      (cons (p item) (lp (##sys#slot lsts 1))))
3949			     (else (##sys#error-not-a-proper-list item loc)))))))))))
3950
3951  (set! scheme#for-each
3952    (lambda (fn lst1 . lsts)
3953      (if (null? lsts)
3954	  (##sys#for-each fn lst1)
3955	  (let loop ((all (cons lst1 lsts)))
3956	    (let* ((first (##sys#slot all 0))
3957		   (safe-args (mapsafe (lambda (x) (car x)) all 'for-each))) ; ensure inlining
3958	      (when (pair? safe-args)
3959		(apply fn safe-args)
3960		(loop (mapsafe (lambda (x) (cdr x)) all 'for-each))))))))
3961
3962  (set! scheme#map
3963    (lambda (fn lst1 . lsts)
3964      (if (null? lsts)
3965	  (##sys#map fn lst1)
3966	  (let loop ((all (cons lst1 lsts)))
3967	    (let* ((first (##sys#slot all 0))
3968		   (safe-args (mapsafe (lambda (x) (car x)) all 'map)))
3969	      (if (pair? safe-args)
3970		  (cons (apply fn safe-args)
3971			(loop (mapsafe (lambda (x) (cdr x)) all 'map)))
3972		  '())))))))
3973
3974
3975;;; dynamic-wind:
3976;
3977; (taken more or less directly from SLIB)
3978;
3979; This implementation is relatively costly: we have to shadow call/cc
3980; with a new version that unwinds suspended thunks, but for this to
3981; happen the return-values of the escaping procedure have to be saved
3982; temporarily in a list. Since call/cc is very efficient under this
3983; implementation, and because allocation of memory that is to be
3984; garbage soon has also quite low overhead, the performance-penalty
3985; might be acceptable (ctak needs about 4 times longer).
3986
3987(define ##sys#dynamic-winds '())
3988
3989(set! scheme#dynamic-wind
3990  (lambda (before thunk after)
3991    (before)
3992    (set! ##sys#dynamic-winds (cons (cons before after) ##sys#dynamic-winds))
3993    (##sys#call-with-values
3994     thunk
3995     (lambda results
3996       (set! ##sys#dynamic-winds (##sys#slot ##sys#dynamic-winds 1))
3997       (after)
3998       (apply ##sys#values results) ) ) ))
3999
4000(define ##sys#dynamic-wind dynamic-wind)
4001
4002(set! scheme#call-with-current-continuation
4003  (lambda (proc)
4004    (let ((winds ##sys#dynamic-winds))
4005      (##sys#call-with-current-continuation
4006       (lambda (cont)
4007	 (define (continuation . results)
4008	   (unless (eq? ##sys#dynamic-winds winds)
4009	     (##sys#dynamic-unwind winds (fx- (length ##sys#dynamic-winds) (length winds))) )
4010	   (apply cont results) )
4011	 (proc continuation) ))) ))
4012
4013(set! scheme#call/cc call-with-current-continuation)
4014
4015(define (##sys#dynamic-unwind winds n)
4016  (cond [(eq? ##sys#dynamic-winds winds)]
4017	[(fx< n 0)
4018	 (##sys#dynamic-unwind (##sys#slot winds 1) (fx+ n 1))
4019	 ((##sys#slot (##sys#slot winds 0) 0))
4020	 (set! ##sys#dynamic-winds winds) ]
4021	[else
4022	 (let ([after (##sys#slot (##sys#slot ##sys#dynamic-winds 0) 1)])
4023	   (set! ##sys#dynamic-winds (##sys#slot ##sys#dynamic-winds 1))
4024	   (after)
4025	   (##sys#dynamic-unwind winds (fx- n 1)) ) ] ) )
4026
4027
4028;;; Ports:
4029
4030(set! chicken.base#port-closed?
4031  (lambda (p)
4032    (##sys#check-port p 'port-closed?)
4033    (eq? (##sys#slot p 8) 0)))
4034
4035;;; Custom ports:
4036
4037;;; Port layout:
4038;
4039; 0:  file ptr (special)
4040; 1:  direction (fixnum, 1 = input)
4041; 2:  class (vector of procedures)
4042; 3:  name (string)
4043; 4:  row (fixnum)
4044; 5:  col (fixnum)
4045; 6:  EOF (bool)
4046; 7:  type ('stream | 'custom | 'string | 'socket)
4047; 8:  closed (fixnum)
4048; 9:  data
4049; 10-12: reserved, port class specific
4050; 13: case sensitive? (boolean)
4051; 14: mode ('textual | 'binary)
4052; 15: reserved (encoding)
4053;
4054; Port-class:
4055;
4056; 0:  (read-char PORT) -> CHAR | EOF
4057; 1:  (peek-char PORT) -> CHAR | EOF
4058; 2:  (write-char PORT CHAR)
4059; 3:  (write-bytevector PORT BYTEVECTOR START END)
4060; 4:  (close PORT DIRECTION)
4061; 5:  (flush-output PORT)
4062; 6:  (char-ready? PORT) -> BOOL
4063; 7:  (read-bytevector! PORT COUNT BYTEVECTOR START) -> COUNT'
4064; 8:  (read-line PORT LIMIT) -> STRING | EOF
4065; 9:  (read-buffered PORT) -> STRING
4066
4067(define (##sys#make-port i/o class name type)
4068  (let ((port (##core#inline_allocate ("C_a_i_port" 17))))
4069    (##sys#setislot port 1 i/o)
4070    (##sys#setslot port 2 class)
4071    (##sys#setslot port 3 name)
4072    (##sys#setislot port 4 1)
4073    (##sys#setislot port 5 0)
4074    (##sys#setislot port 6 #f)
4075    (##sys#setslot port 7 type)
4076    (##sys#setslot port 8 i/o)
4077    (##sys#setislot port 10 #f)
4078    (##sys#setislot port 13 #t)
4079    (##sys#setislot port 14 'textual)  ; default, only used for R7RS port predicates
4080    (##sys#setslot port 15 'utf-8)
4081    port) )
4082
4083;;; Stream ports:
4084; Input port slots:
4085;   10: peek buffer
4086;   12: Static buffer for read-line, allocated on-demand
4087
4088(define ##sys#stream-port-class
4089  (vector (lambda (p)      ; read-char
4090            (let loop ()
4091              (let ((peeked (##sys#slot p 10)))
4092                (cond (peeked
4093                        (##sys#setislot p 10 #f)
4094                        (##sys#decode-char peeked (##sys#slot p 15) 0))
4095                      ((eq? 'utf-8  (##sys#slot p 15)) ; fast path
4096                       (let ((c (##core#inline "C_read_char" p)))
4097                         (if (eq? -1 c)
4098                             (let ((err (##sys#update-errno)))
4099                               (if (eq? err (foreign-value "EINTR" int))
4100                                   (##sys#dispatch-interrupt loop)
4101                                   (##sys#signal-hook/errno
4102                                    #:file-error err 'read-char
4103                                    (##sys#string-append "cannot read from port - " strerror)
4104                                    p)))
4105                             c)))
4106                      (else (##sys#read-char/encoding
4107                             p (##sys#slot p 15)
4108                             (lambda (buf start len dec)
4109                               (dec buf start len
4110                                    (lambda (buf start len)
4111                                      (##core#inline "C_utf_decode" buf start))))))))))
4112          (lambda (p)      ; peek-char
4113            (let ((pb (##sys#slot p 10))
4114                  (enc (##sys#slot p 15)))
4115              (if pb
4116                  (##sys#decode-char pb enc 0)
4117                  (##sys#read-char/encoding
4118                   p enc
4119                   (lambda (buf start len dec)
4120                     (let ((pb (##sys#make-bytevector len 1)))
4121                       (##core#inline "C_copy_memory_with_offset" pb buf 0 start len)
4122                       (##sys#setslot p 10 pb)
4123                       (dec buf start len
4124                            (lambda (buf start _)
4125                              (##core#inline "C_utf_decode" buf start)))))))))
4126          (lambda (p c)                ; write-char
4127            (let ((enc (##sys#slot p 15)))
4128              (if (eq? enc 'utf-8) ;; fast path
4129                  (##core#inline "C_display_char" p c)
4130                  (let* ((bv (##sys#make-bytevector 4))
4131                         (n (##sys#encode-char c bv enc)))
4132                    ((##sys#slot (##sys#slot p 2) 3) p bv 0 n))))) ; write-bytevector
4133          (lambda (p bv from to)                     ; write-bytevector
4134            (##sys#encode-buffer
4135             bv from (fx- to from) (##sys#slot p 15)
4136             (lambda (bv start len)
4137               (##core#inline "C_display_string" p bv start len))))
4138          (lambda (p d)                ; close
4139            (##core#inline "C_close_file" p)
4140            (##sys#update-errno) )
4141          (lambda (p)      ; flush-output
4142            (##core#inline "C_flush_output" p) )
4143          (lambda (p)      ; char-ready?
4144            (##core#inline "C_char_ready_p" p) )
4145          (lambda (p n dest start)           ; read-bytevector!
4146            (let ((pb (##sys#slot p 10))
4147                  (nc 0))
4148              (when pb
4149                (set! nc (##sys#size pb))
4150                (##core#inline "C_copy_memory_with_offset" dest pb start 0 nc)
4151                (set! start (fx+ start nc))
4152                (set! n (fx- n nc))
4153                (##sys#setislot p 10 #f))
4154              ;;XXX "n" below always true?
4155              (let loop ((rem (or n (fx- (##sys#size dest) start)))
4156                         (act nc)
4157                         (start start))
4158                (let ((len (##core#inline "fast_read_string_from_file" dest p rem start)))
4159                  (cond ((eof-object? len) ; EOF returns 0 bytes read
4160                         act)
4161                        ((fx< len 0)
4162                         (let ((err (##sys#update-errno)))
4163                           (if (eq? err (foreign-value "EINTR" int))
4164                               (##sys#dispatch-interrupt
4165                                (lambda () (loop rem act start)))
4166                               (##sys#signal-hook/errno
4167                                #:file-error err 'read-bytevector!
4168                                (##sys#string-append "cannot read from port - " strerror)
4169                                p n dest start))))
4170                        ((fx< len rem)
4171                         (loop (fx- rem len) (fx+ act len) (fx+ start len)))
4172                        (else (fx+ act len) ) ) ))))
4173          (lambda (p rlimit)       ; read-line
4174            (when rlimit (##sys#check-fixnum rlimit 'read-line))
4175            (let ((sblen read-line-buffer-initial-size)
4176                  (pb (##sys#slot p 10))
4177                  (buffer (##sys#slot p 12))
4178                  (bpos 0))
4179              (unless buffer
4180                (set! buffer (##sys#make-bytevector sblen))
4181                (##sys#setslot p 12 buffer))
4182              (when pb
4183                (set! bpos (##sys#size pb))
4184                (##core#inline "C_copy_memory_with_offset" buffer pb 0 0 bpos)
4185                (##sys#setislot p 10 #f))
4186              (let loop ([len sblen]
4187                         [limit (or rlimit maximal-string-length)]
4188                         [buffer buffer]
4189                         [result ""]
4190                         [f #f])
4191                (let* ((nlimit (fxmin limit len))
4192                       (n (##core#inline "fast_read_line_from_file" buffer bpos
4193                          p nlimit)))
4194                  (set! bpos 0)
4195                  (cond ((eof-object? n) (if f result #!eof))
4196                        ((not n)
4197                         (let ((prev (##sys#buffer->string/encoding buffer 0 nlimit
4198                                      (##sys#slot p 15))))
4199                           (if (fx< limit len)
4200                               (##sys#string-append result prev)
4201                               (loop (fx* len 2)
4202                                     (fx- limit len)
4203                                     (##sys#make-bytevector (fx* len 2))
4204                                     (##sys#string-append result prev)
4205                                     #t)) ) )
4206                        ((fx< n 0)
4207                         (let ((err (##sys#update-errno)))
4208                           (if (eq? err (foreign-value "EINTR" int))
4209                                (let ((n (fx- (fxneg n) 1)))
4210                                  (##sys#dispatch-interrupt
4211                                   (lambda ()
4212                                     (loop len limit buffer
4213                                           (##sys#string-append
4214                                            result
4215                                            (##sys#buffer->string/encoding buffer 0 n (##sys#slot p 15)))
4216                                           #t))))
4217                               (##sys#signal-hook/errno
4218                                #:file-error err 'read-line
4219                                (##sys#string-append "cannot read from port - " strerror)
4220                                p rlimit))))
4221                        (f (##sys#setislot p 4 (fx+ (##sys#slot p 4) 1))
4222                           (##sys#string-append result
4223                            (##sys#buffer->string/encoding buffer 0 n (##sys#slot p 15))))
4224                        (else
4225                          (##sys#setislot p 4 (fx+ (##sys#slot p 4) 1))
4226                          (##sys#buffer->string/encoding buffer 0 n (##sys#slot p 15))))))))
4227          #f  ; read-buffered
4228          ) )
4229
4230(define ##sys#open-file-port (##core#primitive "C_open_file_port"))
4231
4232(define ##sys#standard-input (##sys#make-port 1 ##sys#stream-port-class "(stdin)" 'stream))
4233(define ##sys#standard-output (##sys#make-port 2 ##sys#stream-port-class "(stdout)" 'stream))
4234(define ##sys#standard-error (##sys#make-port 2 ##sys#stream-port-class "(stderr)" 'stream))
4235
4236(##sys#open-file-port ##sys#standard-input 0 #f)
4237(##sys#open-file-port ##sys#standard-output 1 #f)
4238(##sys#open-file-port ##sys#standard-error 2 #f)
4239
4240(define (##sys#check-input-port x open . loc)
4241  (if (pair? loc)
4242      (##core#inline "C_i_check_port_2" x 1 open (car loc))
4243      (##core#inline "C_i_check_port" x 1 open)))
4244
4245(define (##sys#check-output-port x open . loc)
4246  (if (pair? loc)
4247      (##core#inline "C_i_check_port_2" x 2 open (car loc))
4248      (##core#inline "C_i_check_port" x 2 open)))
4249
4250(define (##sys#check-port x . loc)
4251  (if (pair? loc)
4252      (##core#inline "C_i_check_port_2" x 0 #f (car loc))
4253      (##core#inline "C_i_check_port" x 0 #f) ) )
4254
4255(define (##sys#check-open-port x . loc)
4256  (if (pair? loc)
4257      (##core#inline "C_i_check_port_2" x 0 #t (car loc))
4258      (##core#inline "C_i_check_port" x 0 #t) ) )
4259
4260(set! scheme#current-input-port
4261  (lambda args
4262    (if (null? args)
4263	##sys#standard-input
4264	(let ((p (car args)))
4265	  (##sys#check-port p 'current-input-port)
4266	  (let-optionals (cdr args) ((convert? #t) (set? #t))
4267	    (when set? (set! ##sys#standard-input p)))
4268	  p) ) ))
4269
4270(set! scheme#current-output-port
4271  (lambda args
4272    (if (null? args)
4273	##sys#standard-output
4274	(let ((p (car args)))
4275	  (##sys#check-port p 'current-output-port)
4276	  (let-optionals (cdr args) ((convert? #t) (set? #t))
4277	    (when set? (set! ##sys#standard-output p)))
4278	  p) ) ))
4279
4280(set! chicken.base#current-error-port
4281  (lambda args
4282    (if (null? args)
4283	##sys#standard-error
4284	(let ((p (car args)))
4285	  (##sys#check-port p 'current-error-port)
4286	  (let-optionals (cdr args) ((convert? #t) (set? #t))
4287	    (when set? (set! ##sys#standard-error p)))
4288	  p))))
4289
4290(define (##sys#tty-port? port)
4291  (and (not (zero? (##sys#peek-unsigned-integer port 0)))
4292       (##core#inline "C_tty_portp" port) ) )
4293
4294(define (##sys#port-data port) (##sys#slot port 9))
4295(define (##sys#set-port-data! port data) (##sys#setslot port 9 data))
4296
4297(define ##sys#default-file-encoding)
4298
4299(let ()
4300  (define (open name inp modes loc)
4301    (##sys#check-string name loc)
4302    (let ((fmode (if inp "r" "w"))
4303          (bmode "")
4304          (enc (##sys#default-file-encoding)))
4305      (do ((modes modes (##sys#slot modes 1)))
4306        ((null? modes))
4307        (let ((o (##sys#slot modes 0)))
4308          (case o
4309            ((#:binary binary)
4310             (set! bmode "b")
4311             (set! enc 'binary))
4312            ((#:text text) (set! bmode ""))
4313            ((#:utf-8 utf-8)
4314             (set! enc 'utf-8))
4315            ((#:latin-1 latin-1 #:iso-8859-1 iso-8859-1)
4316             (set! enc 'latin-1))
4317            ((#:unix #:nl unix nl)
4318             (set! bmode "b"))
4319            ((#:crnl crnl)
4320             (set! bmode ""))
4321            ((#:append append)
4322             (if inp
4323               (##sys#error loc "cannot use append mode with input file")
4324               (set! fmode "a") ) )
4325            (else (##sys#error loc "invalid file option" o)) ) ) )
4326      (let ((port (##sys#make-port (if inp 1 2) ##sys#stream-port-class name 'stream)))
4327        (##sys#setslot port 15 enc)
4328        (unless (##sys#open-file-port port name (##sys#string-append fmode bmode))
4329          (##sys#signal-hook/errno #:file-error (##sys#update-errno) loc
4330                                   (##sys#string-append "cannot open file - " strerror)
4331                                   name))
4332        port) ) )
4333
4334  (define (close port inp loc)
4335    (##sys#check-port port loc)
4336    ; repeated closing is ignored
4337    (let ((direction (if inp 1 2)))
4338      (when (##core#inline "C_port_openp" port direction)
4339	(##sys#setislot port 8 (fxand (##sys#slot port 8) (fxnot direction)))
4340	((##sys#slot (##sys#slot port 2) 4) port direction))))
4341
4342  (set! scheme#open-input-file (lambda (name . mode) (open name #t mode 'open-input-file)))
4343  (set! scheme#open-output-file (lambda (name . mode) (open name #f mode 'open-output-file)))
4344  (set! scheme#close-input-port (lambda (port) (close port #t 'close-input-port)))
4345  (set! scheme#close-output-port (lambda (port) (close port #f 'close-output-port))))
4346
4347(set! scheme#call-with-input-file
4348  (let ((open-input-file open-input-file)
4349	(close-input-port close-input-port) )
4350    (lambda (name p . mode)
4351      (let ((f (apply open-input-file name mode)))
4352	(##sys#call-with-values
4353	 (lambda () (p f))
4354	 (lambda results
4355	   (close-input-port f)
4356	   (apply ##sys#values results) ) ) ) ) ) )
4357
4358(set! scheme#call-with-output-file
4359  (let ((open-output-file open-output-file)
4360	(close-output-port close-output-port) )
4361    (lambda (name p . mode)
4362      (let ((f (apply open-output-file name mode)))
4363	(##sys#call-with-values
4364	 (lambda () (p f))
4365	 (lambda results
4366	   (close-output-port f)
4367	   (apply ##sys#values results) ) ) ) ) ) )
4368
4369(set! scheme#with-input-from-file
4370  (let ((open-input-file open-input-file)
4371	(close-input-port close-input-port) )
4372    (lambda (str thunk . mode)
4373      (let ((file (apply open-input-file str mode)))
4374	(fluid-let ((##sys#standard-input file))
4375	  (##sys#call-with-values thunk
4376	    (lambda results
4377	      (close-input-port file)
4378	      (apply ##sys#values results) ) ) ) ) ) ) )
4379
4380(set! scheme#with-output-to-file
4381  (let ((open-output-file open-output-file)
4382	(close-output-port close-output-port) )
4383    (lambda (str thunk . mode)
4384      (let ((file (apply open-output-file str mode)))
4385	(fluid-let ((##sys#standard-output file))
4386	  (##sys#call-with-values thunk
4387	    (lambda results
4388	      (close-output-port file)
4389	      (apply ##sys#values results) ) ) ) ) ) ) )
4390
4391(define (##sys#file-exists? name file? dir? loc)
4392  (case (##core#inline "C_i_file_exists_p" (##sys#make-c-string name loc) file? dir?)
4393    ((#f) #f)
4394    ((#t) #t)
4395    (else
4396     (##sys#signal-hook
4397      #:file-error loc "system error while trying to access file"
4398      name))))
4399
4400(define (##sys#flush-output port)
4401  ((##sys#slot (##sys#slot port 2) 5) port) ; flush-output
4402  (##core#undefined) )
4403
4404(set! chicken.base#flush-output
4405  (lambda (#!optional (port ##sys#standard-output))
4406    (##sys#check-output-port port #t 'flush-output)
4407    (##sys#flush-output port)))
4408
4409(define (##sys#port-line port)
4410  (and (##core#inline "C_input_portp" port)
4411       (##sys#slot port 4) ) )
4412
4413;;; Decorate procedure with arbitrary data
4414;
4415; warning: may modify proc, if it already has a suitable decoration!
4416
4417(define (##sys#decorate-lambda proc pred decorator)
4418  (let ((len (##sys#size proc)))
4419    (let loop ((i (fx- len 1)))
4420      (cond ((zero? i)
4421	     (let ((p2 (make-vector (fx+ len 1))))
4422	       (do ((i 1 (fx+ i 1)))
4423		   ((fx>= i len)
4424		    (##core#inline "C_vector_to_closure" p2)
4425		    (##core#inline "C_copy_pointer" proc p2)
4426		    (decorator p2 i) )
4427		 (##sys#setslot p2 i (##sys#slot proc i)) ) ) )
4428	    (else
4429	     (let ((x (##sys#slot proc i)))
4430	       (if (pred x)
4431		   (decorator proc i)
4432		   (loop (fx- i 1)) ) ) ) ) ) ) )
4433
4434(define (##sys#lambda-decoration proc pred)
4435  (let loop ((i (fx- (##sys#size proc) 1)))
4436    (and (fx> i 0)
4437	 (let ((x (##sys#slot proc i)))
4438	   (if (pred x)
4439	       x
4440	       (loop (fx- i 1)) ) ) ) ) )
4441
4442
4443;;; Create lambda-info object
4444
4445(define (##sys#make-lambda-info str)
4446  (let* ((bv (##sys#slot str 0))
4447         (sz (fx- (##sys#size bv) 1))
4448	 (info (##sys#make-bytevector sz)))
4449    (##core#inline "C_copy_memory" info bv sz)
4450    (##core#inline "C_bytevector_to_lambdainfo" info)
4451    info) )
4452
4453
4454;;; Function debug info:
4455
4456(define (##sys#lambda-info? x)
4457  (and (not (##sys#immediate? x)) (##core#inline "C_lambdainfop" x)))
4458
4459(define (##sys#lambda-info proc)
4460  (##sys#lambda-decoration proc ##sys#lambda-info?))
4461
4462(define (##sys#lambda-info->string info)
4463  (let* ((sz (##sys#size info))
4464	 (bv (##sys#make-bytevector (fx+ sz 1))) )
4465    (##core#inline "C_copy_memory" bv info sz)
4466    (##core#inline_allocate ("C_a_ustring" 5) bv
4467                            (##core#inline "C_utf_length" bv))))
4468
4469(set! chicken.base#procedure-information
4470  (lambda (x)
4471    (##sys#check-closure x 'procedure-information)
4472    (and-let* ((info (##sys#lambda-info x)))
4473      (##sys#read (scheme#open-input-string (##sys#lambda-info->string info)) #f) ) ) )
4474
4475
4476;;; SRFI-17
4477
4478(define setter-tag (vector 'setter))
4479
4480(define-inline (setter? x)
4481  (and (pair? x) (eq? setter-tag (##sys#slot x 0))) )
4482
4483(set! chicken.base#setter
4484  (##sys#decorate-lambda
4485   (lambda (proc)
4486     (or (and-let* (((procedure? proc))
4487		    (d (##sys#lambda-decoration proc setter?)) )
4488	   (##sys#slot d 1) )
4489	 (##sys#error 'setter "no setter defined" proc) ) )
4490   setter?
4491   (lambda (proc i)
4492     (##sys#setslot
4493      proc i
4494      (cons
4495       setter-tag
4496       (lambda (get set)
4497	 (if (procedure? get)
4498	     (let ((get2 (##sys#decorate-lambda
4499			  get
4500			  setter?
4501			  (lambda (proc i) (##sys#setslot proc i (cons setter-tag set)) proc))))
4502	       (if (eq? get get2)
4503		   get
4504		   (##sys#become! (list (cons get get2))) ) )
4505	     (error "can not set setter of non-procedure" get) ) ) ) )
4506     proc) ) )
4507
4508(define ##sys#setter setter)
4509
4510(set! chicken.base#getter-with-setter
4511  (lambda (get set #!optional info)
4512    (##sys#check-closure get 'getter-with-setter)
4513    (##sys#check-closure set 'getter-with-setter)
4514    (let ((getdec (cond (info
4515			 (##sys#check-string info 'getter-with-setter)
4516			 (##sys#make-lambda-info info))
4517			(else (##sys#lambda-info get))))
4518	  (p1 (##sys#decorate-lambda
4519	       (##sys#copy-closure get)
4520	       setter?
4521	       (lambda (proc i)
4522		 (##sys#setslot proc i (cons setter-tag set))
4523		 proc))))
4524      (if getdec
4525	  (##sys#decorate-lambda
4526	   p1
4527	   ##sys#lambda-info?
4528	   (lambda (p i)
4529	     (##sys#setslot p i getdec)
4530	     p))
4531	  p1))))
4532
4533(set! scheme#car (getter-with-setter scheme#car set-car!))
4534(set! scheme#cdr (getter-with-setter scheme#cdr set-cdr!))
4535(set! scheme#caar (getter-with-setter scheme#caar (lambda (x y) (set-car! (car x) y))))
4536(set! scheme#cadr (getter-with-setter scheme#cadr (lambda (x y) (set-car! (cdr x) y))))
4537(set! scheme#cdar (getter-with-setter scheme#cdar (lambda (x y) (set-cdr! (car x) y))))
4538(set! scheme#cddr (getter-with-setter scheme#cddr (lambda (x y) (set-cdr! (cdr x) y))))
4539(set! scheme#caaar (getter-with-setter scheme#caaar (lambda (x y) (set-car! (caar x) y))))
4540(set! scheme#caadr (getter-with-setter scheme#caadr (lambda (x y) (set-car! (cadr x) y))))
4541(set! scheme#cadar (getter-with-setter scheme#cadar (lambda (x y) (set-car! (cdar x) y))))
4542(set! scheme#caddr (getter-with-setter scheme#caddr (lambda (x y) (set-car! (cddr x) y))))
4543(set! scheme#cdaar (getter-with-setter scheme#cdaar (lambda (x y) (set-cdr! (caar x) y))))
4544(set! scheme#cdadr (getter-with-setter scheme#cdadr (lambda (x y) (set-cdr! (cadr x) y))))
4545(set! scheme#cddar (getter-with-setter scheme#cddar (lambda (x y) (set-cdr! (cdar x) y))))
4546(set! scheme#cdddr (getter-with-setter scheme#cdddr (lambda (x y) (set-cdr! (cddr x) y))))
4547(set! scheme#string-ref (getter-with-setter scheme#string-ref string-set!))
4548(set! scheme#vector-ref (getter-with-setter scheme#vector-ref vector-set!))
4549
4550(set! scheme#list-ref
4551  (getter-with-setter
4552   scheme#list-ref
4553   (lambda (x i y) (set-car! (list-tail x i) y))))
4554
4555(set! chicken.bytevector#bytevector-u8-ref
4556  (getter-with-setter chicken.bytevector#bytevector-u8-ref
4557                      chicken.bytevector#bytevector-u8-set!
4558                      "(chicken.bytevector#bytevector-u8-ref v i)"))
4559
4560
4561;;; Parameters:
4562
4563(define ##sys#default-parameter-vector (##sys#make-vector default-parameter-vector-size))
4564(define ##sys#current-parameter-vector '#())
4565
4566(set! scheme#make-parameter
4567  (let ((count 0))
4568    (lambda (init #!optional (guard (lambda (x) x)))
4569      (let* ((val (guard init))
4570	     (i count)
4571	     (assign (lambda (val n convert? set?)
4572		       (when (fx>= i n)
4573			 (set! ##sys#current-parameter-vector
4574			   (##sys#vector-resize
4575			    ##sys#current-parameter-vector
4576			    (fx+ i 1)
4577			    ##sys#snafu) ) )
4578		       (let ((val (if convert? (guard val) val)))
4579			 (when set?
4580			   (##sys#setslot ##sys#current-parameter-vector i val))
4581			 val))))
4582
4583	(set! count (fx+ count 1))
4584	(when (fx>= i (##sys#size ##sys#default-parameter-vector))
4585	  (set! ##sys#default-parameter-vector
4586	    (##sys#vector-resize
4587	     ##sys#default-parameter-vector
4588	     (fx+ i 1)
4589	     (##core#undefined)) ) )
4590	(##sys#setslot ##sys#default-parameter-vector i val)
4591	(getter-with-setter
4592	 (lambda args
4593	   (let ((n (##sys#size ##sys#current-parameter-vector)))
4594	     (cond ((pair? args)
4595		    (let-optionals (cdr args) ((convert? #t)
4596					       (set? #t))
4597		      (assign (car args) n convert? set?)))
4598		   ((fx>= i n)
4599		    (##sys#slot ##sys#default-parameter-vector i) )
4600		   (else
4601		    (let ((val (##sys#slot ##sys#current-parameter-vector i)))
4602		      (if (eq? val ##sys#snafu)
4603			  (##sys#slot ##sys#default-parameter-vector i)
4604			  val) ) ) ) ) )
4605	 (lambda (val)
4606	   (let ((n (##sys#size ##sys#current-parameter-vector)))
4607	     (assign val n #f #t))))))))
4608
4609
4610;;; Input:
4611
4612(set! scheme#char-ready?
4613  (lambda (#!optional (port ##sys#standard-input))
4614    (##sys#check-input-port port #t 'char-ready?)
4615    ((##sys#slot (##sys#slot port 2) 6) port) )) ; char-ready?
4616    
4617(set! scheme#u8-ready? 
4618  (lambda (#!optional (port ##sys#standard-input))
4619    (##sys#check-input-port port #t 'u8-ready?)
4620    ((##sys#slot (##sys#slot port 2) 6) port) )) ; char-ready?
4621
4622(set! scheme#read-char
4623  (lambda (#!optional (port ##sys#standard-input))
4624    (##sys#check-input-port port #t 'read-char)
4625    (##sys#read-char-0 port) ))
4626
4627(define (##sys#read-char-0 p)
4628  (let ([c (if (##sys#slot p 6)
4629	       (begin
4630		 (##sys#setislot p 6 #f)
4631		 #!eof)
4632	       ((##sys#slot (##sys#slot p 2) 0) p) ) ] ) ; read-char
4633    (cond [(eq? c #\newline)
4634	   (##sys#setislot p 4 (fx+ (##sys#slot p 4) 1))
4635	   (##sys#setislot p 5 0) ]
4636	  [(not (##core#inline "C_eofp" c))
4637	   (##sys#setislot p 5 (fx+ (##sys#slot p 5) 1)) ] )
4638    c) )
4639
4640(define (##sys#read-char/port port)
4641  (##sys#check-input-port port #t 'read-char)
4642  (##sys#read-char-0 port) )
4643
4644(define (##sys#peek-char-0 p)
4645  (if (##sys#slot p 6)
4646      #!eof
4647      (let ((c ((##sys#slot (##sys#slot p 2) 1) p))) ; peek-char
4648	(when (##core#inline "C_eofp" c)
4649	  (##sys#setislot p 6 #t) )
4650	c) ) )
4651
4652(set! scheme#peek-char
4653  (lambda (#!optional (port ##sys#standard-input))
4654    (##sys#check-input-port port #t 'peek-char)
4655    (##sys#peek-char-0 port) ))
4656
4657(set! scheme#read
4658  (lambda (#!optional (port ##sys#standard-input))
4659    (##sys#check-input-port port #t 'read)
4660    (##sys#read port ##sys#default-read-info-hook) ))
4661
4662(define ##sys#default-read-info-hook #f)
4663(define ##sys#read-error-with-line-number #f)
4664(define (##sys#read-prompt-hook) #f)	; just here so that srfi-18 works without eval
4665(define (##sys#infix-list-hook lst) lst)
4666
4667(set! ##sys#default-file-encoding (make-parameter 'utf-8))
4668
4669(define (##sys#sharp-number-hook port n)
4670  (##sys#read-error port "invalid `#...' read syntax" n) )
4671
4672(set! chicken.base#case-sensitive (make-parameter #t))
4673(set! chicken.base#parentheses-synonyms (make-parameter #t))
4674(set! chicken.base#symbol-escape (make-parameter #t))
4675
4676(set! chicken.base#keyword-style
4677  (make-parameter #:suffix (lambda (x) (when x (##sys#check-keyword x 'keyword-style)) x)))
4678
4679(define ##sys#current-read-table (make-parameter (##sys#make-structure 'read-table '() '() '())))
4680
4681(define ##sys#read-warning
4682  (let ([string-append string-append])
4683    (lambda (port msg . args)
4684      (apply
4685       ##sys#warn
4686       (let ((ln (##sys#port-line port)))
4687	 (if (and ##sys#read-error-with-line-number ln)
4688	     (string-append "(line " (##sys#number->string ln) ") " msg)
4689	     msg) )
4690       args) ) ) )
4691
4692(define ##sys#read-error
4693  (let ([string-append string-append] )
4694    (lambda (port msg . args)
4695      (apply
4696       ##sys#signal-hook
4697       #:syntax-error
4698       (let ((ln (##sys#port-line port)))
4699	 (if (and ##sys#read-error-with-line-number ln)
4700	     (string-append "(line " (##sys#number->string ln) ") " msg)
4701	     msg) )
4702       args) ) ) )
4703
4704(define ##sys#read
4705  (let ((string-append string-append)
4706	(keyword-style keyword-style)
4707	(parentheses-synonyms parentheses-synonyms)
4708        (case-sensitive case-sensitive)
4709	(symbol-escape symbol-escape)
4710        (integer->char integer->char)
4711	(current-read-table ##sys#current-read-table))
4712    (lambda (port infohandler)
4713      (let ((csp (and (case-sensitive) (##sys#slot port 13)))
4714	    (ksp (keyword-style))
4715	    (psp (parentheses-synonyms))
4716	    (sep (symbol-escape))
4717	    (crt (current-read-table))
4718	    (warn #f)
4719            (shared '())
4720	    ; set below - needs more state to make a decision
4721	    (terminating-characters '(#\, #\; #\( #\) #\' #\" #\[ #\] #\{ #\}))
4722	    (reserved-characters #f) )
4723
4724	(define (container c)
4725	  (##sys#read-error port "unexpected list terminator" c) )
4726
4727	(define (info class data val)
4728	  (if infohandler
4729	      (infohandler class data val)
4730	      data) )
4731
4732	(define (skip-to-eol)
4733	  (let skip ((c (##sys#read-char-0 port)))
4734	    (if (and (not (##core#inline "C_eofp" c)) (not (eq? #\newline c)))
4735		(skip (##sys#read-char-0 port)) ) ) )
4736
4737        (define (reserved-character c)
4738          (##sys#read-char-0 port)
4739          (##sys#read-error port "reserved character" c) )
4740
4741        (define (read-unreserved-char-0 port)
4742          (let ((c (##sys#read-char-0 port)))
4743            (if (memq c reserved-characters)
4744                (reserved-character c)
4745                c) ) )
4746
4747        (define (register-shared! n thunk)
4748          (set! shared (cons (cons n thunk) shared)))
4749
4750        (define (unthunk o fail)
4751          (let ((v (o)))
4752            (cond ((not (procedure? v)) v)
4753                  ((eq? v o)
4754                   (fail "self-referential datum"))
4755                  (else
4756                    (unthunk v fail)))))
4757
4758        ;; Fills holes in `o` destructively.
4759        (define (unthunkify! o fail)
4760          (let loop! ((o o))
4761            (cond ((pair? o)
4762                   (if (not (procedure? (car o)))
4763                       (loop! (car o))
4764                       (set-car! o (unthunk (car o) fail)))
4765                   (if (not (procedure? (cdr o)))
4766                       (loop! (cdr o))
4767                       (set-cdr! o (unthunk (cdr o) fail))))
4768                  ((vector? o)
4769                   (let ((len (##sys#size o)))
4770                     (do ((i 0 (fx+ i 1)))
4771                         ((eq? i len))
4772                         (let ((v (##sys#slot o i)))
4773                           (if (not (procedure? v))
4774                               (loop! v)
4775                               (##sys#setslot o i (unthunk v fail))))))))))
4776
4777	(define (readrec)
4778
4779	  (define (r-spaces)
4780	    (let loop ([c (##sys#peek-char-0 port)])
4781	      (cond ((##core#inline "C_eofp" c))
4782		    ((eq? #\; c)
4783		     (skip-to-eol)
4784		     (loop (##sys#peek-char-0 port)) )
4785		    ((char-whitespace? c)
4786		     (##sys#read-char-0 port)
4787		     (loop (##sys#peek-char-0 port)) ) ) ) )
4788
4789	  (define (r-usequence u n base)
4790	    (let loop ((seq '()) (n n))
4791	      (if (eq? n 0)
4792		  (let* ((str (##sys#reverse-list->string seq))
4793			 (n (string->number str base)))
4794		    (or n
4795			(##sys#read-error
4796			 port
4797			 (string-append
4798			  "invalid escape-sequence '\\" u str "\'")) ) )
4799		  (let ((x (##sys#read-char-0 port)))
4800		    (if (or (eof-object? x) (char=? #\" x))
4801			(##sys#read-error port "unterminated string constant")
4802			(loop (cons x seq) (fx- n 1)) ) ) ) ) )
4803
4804          (define (r-xsequence delim)
4805            (define (parse seq)
4806              (let* ((str (##sys#reverse-list->string seq))
4807                     (n (string->number str 16)))
4808                (or n
4809                    (##sys#read-error port
4810                     (string-append "invalid escape-sequence '\\x"
4811                                    str ";\'")))))
4812            (define (complain)
4813              (set! warn "unterminated hexadecimal escape sequence"))
4814            (define (abort)
4815              (##sys#read-error port "unterminated hexadecimal escape sequence") )
4816            (let loop ((seq '()))
4817              (let ((x (##sys#peek-char-0 port)))
4818                (cond ((eof-object? x) (abort))
4819                      ((eq? delim x)
4820                       (let ((n (parse seq)))
4821                         (if (fx> n #x1ffff)
4822                             (abort)
4823                             (begin (complain) n))))
4824                      ((eq? #\; x)
4825                       (##sys#read-char-0 port)
4826		       (parse seq))
4827                      ((or (and (char>=? x #\0) (char<=? x #\9))
4828                           (and (char>=? x #\a) (char<=? x #\f))
4829                           (and (char>=? x #\A) (char<=? x #\F)))
4830                       (loop (cons (##sys#read-char-0 port) seq)))
4831                      (else
4832                        (let ((n (parse seq)))
4833                          (if (fx> n #x1ffff)
4834                              (abort)
4835                              (begin (complain) n))))))))
4836
4837	  (define (r-string term)
4838	    (let loop ((c (##sys#read-char-0 port)) (lst '()))
4839	      (cond ((##core#inline "C_eofp" c)
4840		     (##sys#read-error port "unterminated string") )
4841		    ((eq? #\\ c)
4842		     (set! c (##sys#read-char-0 port))
4843		     (case c
4844		       ((#\t) (loop (##sys#read-char-0 port) (cons #\tab lst)))
4845		       ((#\r) (loop (##sys#read-char-0 port) (cons #\return lst)))
4846		       ((#\b) (loop (##sys#read-char-0 port) (cons #\backspace lst)))
4847		       ((#\n) (loop (##sys#read-char-0 port) (cons #\newline lst)))
4848		       ((#\a) (loop (##sys#read-char-0 port) (cons (integer->char 7) lst)))
4849		       ((#\v) (loop (##sys#read-char-0 port) (cons (integer->char 11) lst)))
4850		       ((#\f) (loop (##sys#read-char-0 port) (cons (integer->char 12) lst)))
4851		       ((#\x)
4852			(let ((ch (integer->char (r-xsequence term))))
4853			  (loop (##sys#read-char-0 port) (cons ch lst)) ) )
4854		       ((#\u)
4855			(let ((n (r-usequence "u" 4 16)))
4856                           (loop (##sys#read-char-0 port)
4857                                 (cons (integer->char n) lst)) ) )
4858		       ((#\U)
4859			(let ((n (r-usequence "U" 8 16)))
4860                           (loop (##sys#read-char-0 port)
4861                                 (cons (integer->char n) lst)) ))
4862		       ((#\\ #\' #\" #\|)
4863			(loop (##sys#read-char-0 port) (cons c lst)))
4864		       ((#\newline #\return #\space #\tab)
4865			;; Read "escaped" <intraline ws>* <nl> <intraline ws>*
4866			(let eat-ws ((c c) (nl? #f))
4867			  (case c
4868			    ((#\space #\tab)
4869			     (eat-ws (##sys#read-char-0 port) nl?))
4870			    ((#\return)
4871			     (if nl?
4872				 (loop c lst)
4873			         (let ((nc (##sys#read-char-0 port)))
4874			           (if (eq? nc #\newline) ; collapse \r\n
4875				       (eat-ws (##sys#read-char-0 port) #t)
4876				       (eat-ws nc #t)))))
4877			    ((#\newline)
4878			     (if nl?
4879				 (loop c lst)
4880				 (eat-ws (##sys#read-char-0 port) #t)))
4881			    (else
4882                             (unless nl?
4883                               (##sys#read-warning
4884				port
4885				"escaped whitespace, but no newline - collapsing anyway"))
4886                             (loop c lst)))))
4887		       (else
4888			(cond ((##core#inline "C_eofp" c)
4889			       (##sys#read-error port "unterminated string"))
4890			      ((and (char-numeric? c)
4891				    (char>=? c #\0)
4892				    (char<=? c #\7))
4893			       (let ((ch (integer->char
4894					  (fx+ (fx* (fx- (char->integer c) 48) 64)
4895					       (r-usequence "" 2 8)))))
4896				 (loop (##sys#read-char-0 port) (cons ch lst)) ))
4897			      (else
4898			       (##sys#read-warning
4899				port
4900				"undefined escape sequence in string - probably forgot backslash"
4901				c)
4902			       (loop (##sys#read-char-0 port) (cons c lst))) ) )))
4903		    ((eq? term c) (##sys#reverse-list->string lst))
4904		    (else (loop (##sys#read-char-0 port) (cons c lst))) ) ))
4905
4906	  (define (r-list start end)
4907	    (if (eq? (##sys#read-char-0 port) start)
4908		(let ((first #f)
4909		      (ln0 #f)
4910		      (outer-container container) )
4911		  (define (starting-line msg)
4912		    (if (and ln0 ##sys#read-error-with-line-number)
4913			(string-append
4914			 msg ", starting in line "
4915			 (##sys#number->string ln0))
4916			msg))
4917		  (##sys#call-with-current-continuation
4918		   (lambda (return)
4919		     (set! container
4920		       (lambda (c)
4921			 (if (eq? c end)
4922			     (return #f)
4923			     (##sys#read-error
4924			      port
4925			      (starting-line "list-terminator mismatch")
4926			      c end) ) ) )
4927		     (let loop ([last '()])
4928		       (r-spaces)
4929		       (unless first (set! ln0 (##sys#port-line port)))
4930		       (let ([c (##sys#peek-char-0 port)])
4931			 (cond ((##core#inline "C_eofp" c)
4932				(##sys#read-error
4933				 port
4934				 (starting-line "unterminated list") ) )
4935			       ((eq? c end)
4936				(##sys#read-char-0 port) )
4937			       ((eq? c #\.)
4938				(##sys#read-char-0 port)
4939				(let ((c2 (##sys#peek-char-0 port)))
4940				  (cond ((or (char-whitespace? c2)
4941					     (eq? c2 #\()
4942					     (eq? c2 #\))
4943					     (eq? c2 #\")
4944					     (eq? c2 #\;) )
4945					 (unless (pair? last)
4946					   (##sys#read-error port "invalid use of `.'") )
4947					 (r-spaces)
4948					 (##sys#setslot last 1 (readrec))
4949					 (r-spaces)
4950					 (unless (eq? (##sys#read-char-0 port) end)
4951					   (##sys#read-error
4952					    port
4953					    (starting-line "missing list terminator")
4954					    end)))
4955					(else
4956					 (r-xtoken
4957					  (lambda (tok kw)
4958					    (let* ((tok (##sys#string-append "." tok))
4959						   (val
4960						    (cond ((and (string=? tok ".:")
4961								(eq? ksp #:suffix))
4962							   ;; Edge case: r-xtoken sees
4963							   ;; a bare ":" and sets kw to #f
4964							   (build-keyword "."))
4965							  (kw (build-keyword tok))
4966							  ((and (char-numeric? c2)
4967								(##sys#string->number tok)))
4968							  (else (build-symbol tok))))
4969						   (node (cons val '())))
4970					      (if first
4971						  (##sys#setslot last 1 node)
4972						  (set! first node) )
4973					      (loop node))))))))
4974			       (else
4975				(let ([node (cons (readrec) '())])
4976				  (if first
4977				      (##sys#setslot last 1 node)
4978				      (set! first node) )
4979				  (loop node) ) ) ) ) ) ) )
4980		  (set! container outer-container)
4981		  (if first
4982		      (info 'list-info (##sys#infix-list-hook first) ln0)
4983		      '() ) )
4984		(##sys#read-error port "missing token" start) ) )
4985
4986	  (define (r-vector)
4987	    (let ((lst (r-list #\( #\))))
4988	      (if (list? lst)
4989		  (##sys#list->vector lst)
4990		  (##sys#read-error port "invalid vector syntax" lst) ) ) )
4991
4992	  (define (r-number radix exactness)
4993	    (r-xtoken
4994	     (lambda (tok kw)
4995	       (cond (kw
4996		      (let ((s (build-keyword tok)))
4997			(info 'symbol-info s (##sys#port-line port)) ))
4998		     ((string=? tok ".")
4999		      (##sys#read-error port "invalid use of `.'"))
5000		     ((and (fx> (string-length tok) 0) (char=? (string-ref tok 0) #\#))
5001		      (##sys#read-error port "unexpected prefix in number syntax" tok))
5002		     ((##sys#string->number tok (or radix 10) exactness))
5003		     (radix (##sys#read-error port "illegal number syntax" tok))
5004		     (else (build-symbol tok))  ) ) ))
5005
5006	  (define (r-number-with-exactness radix)
5007	    (cond [(eq? #\# (##sys#peek-char-0 port))
5008		   (##sys#read-char-0 port)
5009		   (let ([c2 (##sys#read-char-0 port)])
5010		     (cond [(eof-object? c2)
5011			    (##sys#read-error port "unexpected end of numeric literal")]
5012			   [(char=? c2 #\i) (r-number radix 'i)]
5013			   [(char=? c2 #\e) (r-number radix 'e)]
5014			   [else
5015			    (##sys#read-error
5016			     port
5017			     "illegal number syntax - invalid exactness prefix" c2)] ) ) ]
5018		  [else (r-number radix #f)] ) )
5019
5020	  (define (r-number-with-radix exactness)
5021	    (cond [(eq? #\# (##sys#peek-char-0 port))
5022		   (##sys#read-char-0 port)
5023		   (let ([c2 (##sys#read-char-0 port)])
5024		     (cond [(eof-object? c2) (##sys#read-error port "unexpected end of numeric literal")]
5025			   [(char=? c2 #\x) (r-number 16 exactness)]
5026			   [(char=? c2 #\d) (r-number 10 exactness)]
5027			   [(char=? c2 #\o) (r-number 8 exactness)]
5028			   [(char=? c2 #\b) (r-number 2 exactness)]
5029			   [else (##sys#read-error port "illegal number syntax - invalid radix" c2)] ) ) ]
5030		  [else (r-number 10 exactness)] ) )
5031
5032	  (define (r-token)
5033	    (let loop ((c (##sys#peek-char-0 port)) (lst '()))
5034	      (cond ((or (eof-object? c)
5035			 (char-whitespace? c)
5036			 (memq c terminating-characters) )
5037		     (##sys#reverse-list->string lst) )
5038		    ((char=? c #\x00)
5039		     (##sys#read-error port "attempt to read expression from something that looks like binary data"))
5040		    (else
5041		     (read-unreserved-char-0 port)
5042		     (loop (##sys#peek-char-0 port)
5043		           (cons (if csp 
5044		                     c 
5045		                     (##core#inline "C_utf_char_foldcase" c) )
5046		                 lst) ) ) ) ) )
5047
5048	  (define (r-digits)
5049	    (let loop ((c (##sys#peek-char-0 port)) (lst '()))
5050	      (cond ((or (eof-object? c) (not (char-numeric? c)))
5051		     (##sys#reverse-list->string lst) )
5052		    (else
5053		     (##sys#read-char-0 port)
5054		     (loop (##sys#peek-char-0 port) (cons c lst)) ) ) ) )
5055
5056	  (define (r-symbol)
5057	    (r-xtoken
5058	     (lambda (str kw)
5059	       (let ((s (if kw (build-keyword str) (build-symbol str))))
5060		 (info 'symbol-info s (##sys#port-line port)) ) )))
5061
5062	  (define (r-xtoken k)
5063	    (define pkw ; check for prefix keyword immediately
5064	      (and (eq? ksp #:prefix)
5065		   (eq? #\: (##sys#peek-char-0 port))
5066		   (begin (##sys#read-char-0 port) #t)))
5067	    (let loop ((lst '()) (skw #f) (qtd #f))
5068	      (let ((c (##sys#peek-char-0 port)))
5069		(cond ((or (eof-object? c)
5070			   (char-whitespace? c)
5071			   (memq c terminating-characters))
5072		       ;; The various cases here cover:
5073		       ;; - Nonempty keywords formed with colon in the ksp position
5074		       ;; - Empty keywords formed explicitly with vbar quotes
5075		       ;; - Bare colon, which should always be a symbol
5076		       (cond ((and skw (eq? ksp #:suffix) (or qtd (not (null? (cdr lst)))))
5077			      (k (##sys#reverse-list->string (cdr lst)) #t))
5078			     ((and pkw (or qtd (not (null? lst))))
5079			      (k (##sys#reverse-list->string lst) #t))
5080			     ((and pkw (not qtd) (null? lst))
5081			      (k ":" #f))
5082			     (else
5083			      (k (##sys#reverse-list->string lst) #f))))
5084		      ((memq c reserved-characters)
5085		       (reserved-character c))
5086		      (else
5087		       (let ((c (##sys#read-char-0 port)))
5088			 (case c
5089			   ((#\|)
5090			    (let ((part (r-string #\|)))
5091			      (loop (append (##sys#fast-reverse (##sys#string->list part)) lst)
5092				    #f #t)))
5093			   ((#\newline)
5094			    (##sys#read-warning
5095			     port "escaped symbol syntax spans multiple lines"
5096			     (##sys#reverse-list->string lst))
5097			    (loop (cons #\newline lst) #f qtd))
5098			   ((#\:)
5099			    (loop (cons #\: lst) #t qtd))
5100			   ((#\\)
5101			    (let ((c (##sys#read-char-0 port)))
5102			      (if (eof-object? c)
5103				  (##sys#read-error
5104				   port
5105				   "unexpected end of file while reading escaped character")
5106				  (loop (cons c lst) #f qtd))))
5107			   (else
5108			    (loop
5109			     (cons (if csp 
5110			               c 
5111			               (##core#inline "C_utf_char_foldcase" c))
5112			           lst)
5113			     #f qtd)))))))))
5114
5115	  (define (r-char)
5116	    ;; Code contributed by Alex Shinn
5117	    (let* ([c (##sys#peek-char-0 port)]
5118		   [tk (r-token)]
5119		   [len (string-length tk)])
5120	      (cond [(fx> len 1)
5121		     (cond [(and (or (char=? #\x c) (char=? #\u c) (char=? #\U c))
5122				 (##sys#string->number (##sys#substring tk 1 len) 16) )
5123			    => (lambda (n) (integer->char n)) ]
5124			   [(and-let* ((c0 (char->integer (string-ref tk 0)))
5125				       ((fx<= #xC0 c0)) ((fx<= c0 #xF7))
5126				       (n0 (fxand (fxshr c0 4) 3))
5127				       (n (fx+ 2 (fxand (fxior n0 (fxshr n0 1)) (fx- n0 1))))
5128				       ((fx= len n))
5129				       (res (fx+ (fxshl (fxand c0 (fx- (fxshl 1 (fx- 8 n)) 1))
5130							6)
5131						 (fxand (char->integer
5132							 (string-ref tk 1))
5133							#b111111))))
5134			      (cond ((fx>= n 3)
5135				     (set! res (fx+ (fxshl res 6)
5136						    (fxand
5137						     (char->integer
5138						      (string-ref tk 2))
5139						     #b111111)))
5140				     (if (fx= n 4)
5141					 (set! res (fx+ (fxshl res 6)
5142							(fxand (char->integer
5143								(string-ref tk 3))
5144							       #b111111))))))
5145			      (integer->char res))]
5146			   [(char-name (##sys#string->symbol tk))]
5147			   [else (##sys#read-error port "unknown named character" tk)] ) ]
5148		    [(memq c terminating-characters) (##sys#read-char-0 port)]
5149		    [else c] ) ) )
5150
5151	  (define (r-comment)
5152	    (let loop ((i 0))
5153	      (let ((c (##sys#read-char-0 port)))
5154		(case c
5155		  ((#\|) (if (eq? #\# (##sys#read-char-0 port))
5156			     (if (not (eq? i 0))
5157				 (loop (fx- i 1)) )
5158			     (loop i) ) )
5159		  ((#\#) (loop (if (eq? #\| (##sys#read-char-0 port))
5160				   (fx+ i 1)
5161				   i) ) )
5162		  (else (if (eof-object? c)
5163			    (##sys#read-error port "unterminated block-comment")
5164			    (loop i) ) ) ) ) ) )
5165
5166	  (define (r-ext-symbol)
5167	    (let ((tok (r-token)))
5168	      (build-symbol (string-append "##" tok))))
5169
5170	  (define (r-quote q)
5171	    (let ((ln (##sys#port-line port)))
5172	      (info 'list-info (list q (readrec)) ln)))
5173
5174	  (define (build-symbol tok)
5175	    (##sys#string->symbol tok) )
5176
5177	  (define (build-keyword tok)
5178	    (##sys#intern-keyword (##sys#string->symbol-name tok)))
5179
5180          ;; now have the state to make a decision.
5181          (set! reserved-characters
5182                (append (if (not psp) '(#\[ #\] #\{ #\}) '())
5183                        (if (not sep) '(#\|) '())))
5184	  (r-spaces)
5185	  (let* ((c (##sys#peek-char-0 port))
5186		 (srst (##sys#slot crt 1))
5187		 (h (and (not (eof-object? c))
5188			 (assq c srst))))
5189	    (if (and h (##sys#slot h 1))
5190                ;; then handled by read-table entry
5191		(##sys#call-with-values
5192		 (lambda () ((##sys#slot h 1) c port))
5193		 (lambda xs (if (null? xs) (readrec) (car xs))))
5194		;; otherwise chicken extended r5rs syntax
5195		(case c
5196		  ((#\')
5197		   (##sys#read-char-0 port)
5198		   (r-quote 'quote))
5199		  ((#\`)
5200		   (##sys#read-char-0 port)
5201		   (r-quote 'quasiquote))
5202		  ((#\,)
5203		   (##sys#read-char-0 port)
5204		   (cond ((eq? (##sys#peek-char-0 port) #\@)
5205			  (##sys#read-char-0 port)
5206			  (r-quote 'unquote-splicing))
5207			 (else (r-quote 'unquote))))
5208		  ((#\#)
5209		   (##sys#read-char-0 port)
5210		   (let ((dchar (##sys#peek-char-0 port)))
5211		     (cond
5212		      ((eof-object? dchar)
5213		       (##sys#read-error
5214			port "unexpected end of input after reading #-sign"))
5215		      ((char-numeric? dchar)
5216		       (let* ((n (string->number (r-digits)))
5217			      (dchar2 (##sys#peek-char-0 port))
5218			      (spdrst (##sys#slot crt 3)))
5219			 (cond ((eof-object? dchar2)
5220                                (##sys#read-error
5221                                 port "unexpected end of input after reading"
5222                                 c n))
5223                               ;; #<num>=...
5224                               ((eq? #\= dchar2)
5225                                (##sys#read-char-0 port)
5226                                (letrec ((datum (begin
5227                                                  (register-shared! n (lambda () datum))
5228                                                  (readrec))))
5229                                  datum))
5230                               ;; #<num>#
5231                               ((eq? #\# dchar2)
5232                                (##sys#read-char-0 port)
5233                                (cond ((assq n shared) => cdr)
5234                                      (else (##sys#read-error port "undefined datum" n))))
5235                           			 ;; #<num> handled by parameterized # read-table entry?
5236                               ((and (char? dchar2)
5237                                     (let ((a (assq dchar2 spdrst)))
5238                                       (and a (##sys#slot a 1) a))) =>
5239                                (lambda (h)
5240                                  (##sys#call-with-values
5241                                    (lambda () ((##sys#slot h 1) dchar2 port n))
5242                                    (lambda xs (if (null? xs) (readrec) (car xs))))))
5243                               ;; #<num>
5244			       ((or (eq? dchar2 #\)) (char-whitespace? dchar2))
5245				(##sys#sharp-number-hook port n))
5246			       (else (##sys#read-char-0 port) ; Consume it first
5247				     (##sys#read-error
5248				      port
5249				      "invalid parameterized read syntax"
5250				      c n dchar2) ) ) ))
5251		      (else (let* ((sdrst (##sys#slot crt 2))
5252				   (h (assq dchar sdrst)))
5253			      (if (and h (##sys#slot h 1))
5254                                  ;; then handled by # read-table entry
5255				  (##sys#call-with-values
5256				   (lambda () ((##sys#slot h 1) dchar port))
5257				   (lambda xs (if (null? xs) (readrec) (car xs))))
5258                                  ;; otherwise chicken extended R7RS syntax
5259				  (case (char-downcase dchar)
5260				    ((#\x) (##sys#read-char-0 port) (r-number-with-exactness 16))
5261				    ((#\d) (##sys#read-char-0 port) (r-number-with-exactness 10))
5262				    ((#\o) (##sys#read-char-0 port) (r-number-with-exactness 8))
5263				    ((#\b) (##sys#read-char-0 port) (r-number-with-exactness 2))
5264				    ((#\i) (##sys#read-char-0 port) (r-number-with-radix 'i))
5265				    ((#\e) (##sys#read-char-0 port) (r-number-with-radix 'e))
5266				    ((#\() (r-vector))
5267				    ((#\\) (##sys#read-char-0 port) (r-char))
5268				    ((#\|)
5269				     (##sys#read-char-0 port)
5270				     (r-comment) (readrec) )
5271				    ((#\#)
5272				     (##sys#read-char-0 port)
5273				     (r-ext-symbol) )
5274				    ((#\;)
5275				     (##sys#read-char-0 port)
5276				     (readrec) (readrec) )
5277				    ((#\`)
5278				     (##sys#read-char-0 port)
5279				     (r-quote 'quasisyntax))
5280				    ((#\$)
5281				     (##sys#read-char-0 port)
5282                                     ;; HACK: reuse r-quote to add line number info
5283				     (r-quote 'location))
5284				    ((#\:)
5285				     (##sys#read-char-0 port)
5286				     (let ((c (##sys#peek-char-0 port)))
5287				       (fluid-let ((ksp #f))
5288					 (r-xtoken
5289					  (lambda (str kw)
5290					    (if (and (eq? 0 (string-length str))
5291						     (not (char=? c #\|)))
5292						(##sys#read-error port "empty keyword")
5293						(build-keyword str)))))))
5294				    ((#\+)
5295				     (##sys#read-char-0 port)
5296				     (let* ((ln (##sys#port-line port))
5297					    (tst (readrec)))
5298				       (info 'list-info
5299					     (list 'cond-expand (list tst (readrec)) '(else))
5300					     ln)))
5301				    ((#\!)
5302				     (##sys#read-char-0 port)
5303				     (let ((c (##sys#peek-char-0 port)))
5304				       (cond ((and (char? c)
5305						   (or (char-whitespace? c) (char=? #\/ c)))
5306					      (skip-to-eol)
5307					      (readrec) )
5308					     (else
5309					      (let ([tok (r-token)])
5310						(cond ((string=? "eof" tok) #!eof)
5311						      ((string=? "bwp" tok) #!bwp)
5312                                                      ((string=? "fold-case" tok)
5313                                                       (set! csp #f)
5314                                                       (##sys#setislot port 13 csp)
5315                                                       (readrec))
5316                                                      ((string=? "no-fold-case" tok)
5317                                                       (set! csp #t)
5318                                                       (##sys#setislot port 13 csp)
5319                                                       (readrec))
5320						      ((member tok '("optional" "rest" "key"))
5321						       (build-symbol (##sys#string-append "#!" tok)) )
5322						      (else
5323						       (let ((a (assq (string->symbol tok) ##sys#read-marks)))
5324							 (if a
5325							     ((##sys#slot a 1) port)
5326							     (##sys#read-error
5327							      port
5328							      "invalid `#!' token" tok) ) ) ) ) ) ) ) ) )
5329				    (else
5330				     (##sys#call-with-values (lambda () (##sys#user-read-hook dchar port))
5331							     (lambda xs (if (null? xs) (readrec) (car xs)))) ) ) ) )) ) ) )
5332		  ((#\() (r-list #\( #\)))
5333		  ((#\)) (##sys#read-char-0 port) (container c))
5334		  ((#\") (##sys#read-char-0 port) (r-string #\"))
5335		  ((#\.) (r-number #f #f))
5336		  ((#\- #\+) (r-number #f #f))
5337		  (else
5338		   (cond [(eof-object? c) c]
5339			 [(char-numeric? c) (r-number #f #f)]
5340			 ((memq c reserved-characters)
5341			  (reserved-character c))
5342			 (else
5343			  (case c
5344			    ((#\[) (r-list #\[ #\]))
5345			    ((#\{) (r-list #\{ #\}))
5346			    ((#\] #\}) (##sys#read-char-0 port) (container c))
5347			    (else (r-symbol) ) ) ) ) ) ) ) ) )
5348
5349        (let ((x (readrec)))
5350          (when warn (##sys#read-warning port warn))
5351          (when (pair? shared)
5352            (unthunkify! x (lambda a (apply ##sys#read-error p a))))
5353          x)))))
5354
5355;;; Hooks for user-defined read-syntax:
5356;
5357; - Redefine this to handle new read-syntaxes. If 'char' doesn't match
5358;   your character then call the previous handler.
5359; - Don't forget to read 'char', it's only peeked at this point.
5360
5361(define (##sys#user-read-hook char port)
5362  (define (fail item) (##sys#read-error port "invalid sharp-sign read syntax" item))
5363  (case char
5364    ((#\f #\t #\u)
5365     (let ((sym (##sys#read port ##sys#default-read-info-hook)))
5366       (if (not (symbol? sym))
5367           (fail char)
5368           (case sym
5369             ((t true) #t)
5370             ((f false) #f)
5371             ((u8)
5372              ;; u8vectors, srfi-4 handles this already via read-hook but we reimplement it
5373              ;; here in case srfi-4 is not loaded
5374              (let ((d (##sys#read-numvector-data port)))
5375                (if (or (null? d) (pair? d))
5376                    (##sys#list->bytevector (##sys#canonicalize-number-list! d))
5377                    ;; reuse already created bytevector
5378                    (##core#inline "C_chop_bv" (##sys#slot d 0)))))
5379             (else (fail sym))))))
5380    (else (fail char))))
5381
5382(define (##sys#read-numvector-data port)
5383  (let ((c (##sys#peek-char-0 port)))
5384    (case c
5385      ((#\() (##sys#read port ##sys#default-read-info-hook))
5386      ((#\") (##sys#read port ##sys#default-read-info-hook))
5387      (else (##sys#read-error port "invalid numeric vector syntax" c)))))
5388
5389;; This code is too complicated. We try to avoid mapping over
5390;; a potentially large list and creating lots of garbage in the
5391;; process, therefore the final result list is constructed
5392;; via destructive updates and thus rather inelegant yet avoids
5393;; any re-consing unless elements are non-numeric.
5394(define (##sys#canonicalize-number-list! lst1)
5395  (let loop ((lst lst1) (prev #f))
5396    (if (and (##core#inline "C_blockp" lst)
5397             (##core#inline "C_pairp" lst))
5398        (let retry ((x (##sys#slot lst 0)))
5399          (cond ((char? x) (retry (string x)))
5400                ((string? x)
5401                 (if (zero? (string-length x))
5402                     (loop (##sys#slot lst 1) prev)
5403                     (let loop2 ((ns (string->list x)) (prev prev))
5404                       (let ((n (cons (char->integer (##sys#slot ns 0))
5405                                      (##sys#slot lst 1))))
5406                         (if prev
5407                             (##sys#setslot prev 1 n)
5408                             (set! lst1 n))
5409                         (let ((ns2 (##sys#slot ns 1)))
5410                           (if (null? ns2)
5411                               (loop (##sys#slot lst 1) n)
5412                               (loop2 (##sys#slot ns 1) n)))))))
5413                (else (loop (##sys#slot lst 1) lst))))
5414        (cond (prev (##sys#setslot prev 1 '())
5415                    lst1)
5416              (else '())))))
5417
5418;;; Table for specially-handled read-syntax:
5419;
5420; - entries should be #f or a 256-element vector containing procedures
5421; - each procedure is called with two arguments, a char (peeked) and a
5422;   port, and should return an expression
5423
5424(define ##sys#read-marks '()) ; TODO move to read-syntax module
5425
5426
5427;;; Output:
5428
5429(define (##sys#write-char-0 c p)
5430  ((##sys#slot (##sys#slot p 2) 2) p c)
5431  (##sys#void))
5432
5433(define (##sys#write-char/port c port)
5434  (##sys#check-output-port port #t 'write-char)
5435  (##sys#check-char c 'write-char)
5436  (##sys#write-char-0 c port) )
5437
5438(set! scheme#write-char
5439  (lambda (c #!optional (port ##sys#standard-output))
5440    (##sys#check-char c 'write-char)
5441    (##sys#check-output-port port #t 'write-char)
5442    (##sys#write-char-0 c port) ))
5443
5444(set! scheme#newline
5445  (lambda (#!optional (port ##sys#standard-output))
5446    (##sys#write-char/port #\newline port) ))
5447
5448(set! scheme#write
5449  (lambda (x #!optional (port ##sys#standard-output))
5450    (##sys#check-output-port port #t 'write)
5451    (##sys#print x #t port) ))
5452
5453(set! scheme#display
5454  (lambda (x #!optional (port ##sys#standard-output))
5455    (##sys#check-output-port port #t 'display)
5456    (##sys#print x #f port) ))
5457
5458(define-inline (*print-each lst)
5459  (for-each (cut ##sys#print <> #f ##sys#standard-output) lst) )
5460
5461(set! chicken.base#print
5462  (lambda args
5463    (##sys#check-output-port ##sys#standard-output #t 'print)
5464    (*print-each args)
5465    (##sys#write-char-0 #\newline ##sys#standard-output)
5466    (void)))
5467
5468(set! chicken.base#print*
5469  (lambda args
5470    (##sys#check-output-port ##sys#standard-output #t 'print)
5471    (*print-each args)
5472    (##sys#flush-output ##sys#standard-output)
5473    (void)))
5474
5475(define current-print-length (make-parameter 0))
5476(define ##sys#print-length-limit (make-parameter #f))
5477(define ##sys#print-exit (make-parameter #f))
5478
5479(define ##sys#print
5480  (let ((case-sensitive case-sensitive)
5481        (symbol-escape symbol-escape)
5482	(keyword-style keyword-style))
5483    (lambda (x readable port)
5484      (##sys#check-output-port port #t #f)
5485      (let ((csp (case-sensitive))
5486	    (ksp (keyword-style))
5487            (sep (symbol-escape))
5488	    (length-limit (##sys#print-length-limit))
5489	    (special-characters '(#\( #\) #\, #\[ #\] #\{ #\} #\' #\" #\; #\ #\` #\| #\\)) )
5490
5491	(define (outstr port str)
5492	  (if length-limit
5493	      (let* ((len (string-length str))
5494		     (cpp0 (current-print-length))
5495		     (cpl (fx+ cpp0 len)) )
5496		(if (fx> cpl length-limit)
5497		    (let ((n (fx- length-limit cpp0)))
5498		      (when (fx> n 0) (outstr0 port (##sys#substring str 0 n)))
5499		      (outstr0 port "...")
5500		      ((##sys#print-exit) (##sys#void)))
5501		    (outstr0 port str) )
5502		(current-print-length cpl) )
5503	      (outstr0 port str) ) )
5504
5505	(define (outstr0 port str)
5506          (let ((bv (##sys#slot str 0)))
5507  	    ((##sys#slot (##sys#slot port 2) 3) port bv 0 (fx- (##sys#size bv) 1)))) ; write-bytevector
5508
5509	(define (outchr port chr)
5510	  (when length-limit
5511	    (let ((cpp0 (current-print-length)))
5512	      (current-print-length (fx+ cpp0 1))
5513	      (when (fx>= cpp0 length-limit)
5514		(outstr0 port "...")
5515		((##sys#print-exit) (##sys#void)))))
5516	  ((##sys#slot (##sys#slot port 2) 2) port chr))  ; write-char
5517
5518	(define (specialchar? chr)
5519	  (let ([c (char->integer chr)])
5520	    (or (fx<= c 32)
5521		(memq chr special-characters) ) ) )
5522
5523	(define (outsym port sym)
5524	  (let ((str (##sys#symbol->string/shared sym)))
5525	    (if (or (not sep) (not readable) (sym-is-readable? str))
5526		(outstr port str)
5527		(outreadablesym port str))))
5528
5529	(define (outreadablesym port str)
5530	  (let ((len (string-length str)))
5531	    (outchr port #\|)
5532	    (let loop ((i 0))
5533	      (if (fx>= i len)
5534		  (outchr port #\|)
5535		  (let ((c (string-ref str i)))
5536		    (cond ((or (char<? c #\space) (char>? c #\~))
5537			   (outstr port "\\x")
5538			   (let ((n (char->integer c)))
5539			     (outstr port (##sys#number->string n 16))
5540                             (outchr port #\;)
5541			     (loop (fx+ i 1))))
5542			  (else
5543			   (when (or (eq? c #\|) (eq? c #\\)) (outchr port #\\))
5544			   (outchr port c)
5545			   (loop (fx+ i 1)) ) ) ) ) )))
5546
5547	(define (sym-is-readable? str)
5548	  (let ((len (string-length str)))
5549	    (cond ((eq? len 0) #f)
5550		  ((eq? len 1)
5551		   (let ((c (string-ref str 0)))
5552		     (cond ((or (eq? #\# c) (eq? #\. c)) #f)
5553			   ((specialchar? c) #f)
5554			   ((char-numeric? c) #f)
5555			   (else #t))))
5556		  (else
5557		   (let loop ((i (fx- len 1)))
5558		     (if (eq? i 0)
5559			 (let ((c (string-ref str 0)))
5560			   (cond ((char-numeric? c) #f)
5561                                 ((or (eq? c #\+) (eq? c #\-))
5562				  (or (fx= len 1)
5563                                      (not (char-numeric? (string-ref str 1)))))
5564                                 ((eq? c #\.)
5565				  (and (fx> len 1)
5566                                       (not (char-numeric? (string-ref str 1)))))
5567				 ((eq? c #\:) #f)
5568				 ((and (eq? c #\#)
5569				       ;; Not a qualified symbol?
5570				       (not (and (fx> len 2)
5571						 (eq? (string-ref str 1) #\#)
5572						 (not (eq? (string-ref str 2) #\#)))))
5573				  (member str '("#!rest" "#!key" "#!optional"
5574                                                "#!fold-case" "#!no-fold-case")))
5575				 ((specialchar? c) #f)
5576				 (else #t) ) )
5577			 (let ((c (string-ref str i)))
5578			   (and (or csp (not (char-upper-case? c)))
5579				(not (specialchar? c))
5580				(or (not (eq? c #\:))
5581				    (fx< i (fx- len 1)))
5582				(loop (fx- i 1)) ) ) ) ) ) ) ) )
5583
5584	(let out ([x x])
5585	  (cond ((eq? x '()) (outstr port "()"))
5586		((eq? x #t) (outstr port "#t"))
5587		((eq? x #f) (outstr port "#f"))
5588		((##core#inline "C_eofp" x) (outstr port "#!eof"))
5589		((##core#inline "C_undefinedp" x) (outstr port "#<unspecified>"))
5590		((##core#inline "C_bwpp" x) (outstr port "#!bwp"))
5591		((##core#inline "C_charp" x)
5592		 (cond [readable
5593			(outstr port "#\\")
5594			(let ([code (char->integer x)])
5595			  (cond [(char-name x)
5596				 => (lambda (cn)
5597				      (outstr port (##sys#symbol->string/shared cn)) ) ]
5598				[(or (fx< code 32) (fx> code #x1ffff))
5599				 (outchr port #\x)
5600				 (outstr port (##sys#number->string code 16)) ]
5601				[else (outchr port x)] ) ) ]
5602		       [else (outchr port x)] ) )
5603		((##core#inline "C_fixnump" x) (outstr port (##sys#number->string x)))
5604		((##core#inline "C_unboundvaluep" x) (outstr port "#<unbound value>"))
5605		((not (##core#inline "C_blockp" x)) (outstr port "#<invalid immediate object>"))
5606		((##core#inline "C_forwardedp" x) (outstr port "#<invalid forwarded object>"))
5607		((##core#inline "C_i_keywordp" x)
5608                 ;; Force portable #: style for readable output
5609		 (case (and (not readable) ksp)
5610                   ((#:prefix)
5611                    (outchr port #\:)
5612                    (outsym port x))
5613                   ((#:suffix)
5614                    (outsym port x)
5615                    (outchr port #\:))
5616                   (else
5617                    (outstr port "#:")
5618                    (outsym port x))))
5619		((##core#inline "C_i_symbolp" x) (outsym port x))
5620		((number? x) (outstr port (##sys#number->string x)))
5621		((##core#inline "C_anypointerp" x) (outstr port (##sys#pointer->string x)))
5622		((##core#inline "C_stringp" x)
5623		 (cond (readable
5624			(outchr port #\")
5625			(do ((i 0 (fx+ i 1))
5626			     (c (string-length x) (fx- c 1)) )
5627			    ((eq? c 0)
5628			     (outchr port #\") )
5629			  (let ((chr (char->integer (string-ref x i))))
5630			    (case chr
5631			      ((34) (outstr port "\\\""))
5632			      ((92) (outstr port "\\\\"))
5633			      (else
5634			       (cond ((or (fx< chr 32)
5635					  (fx= chr #x1ffff))
5636				      (outchr port #\\)
5637				      (case chr
5638                                        ((7) (outchr port #\a))
5639					((8) (outchr port #\b))
5640					((9) (outchr port #\t))
5641					((10) (outchr port #\n))
5642					((11) (outchr port #\v))
5643					((12) (outchr port #\f))
5644					((13) (outchr port #\r))
5645					(else
5646					 (outchr port #\x)
5647					 (when (fx< chr 16) (outchr port #\0))
5648					 (outstr port (##sys#number->string chr 16))
5649					 (outchr port #\;) ) ) )
5650				     (else (outchr port (##core#inline "C_fix_to_char" chr)) ) ) ) ) ) ) )
5651		       (else (outstr port x)) ) )
5652		((##core#inline "C_pairp" x)
5653		 (outchr port #\()
5654		 (out (##sys#slot x 0))
5655		 (do ((x (##sys#slot x 1) (##sys#slot x 1)))
5656		     ((or (not (##core#inline "C_blockp" x)) (not (##core#inline "C_pairp" x)))
5657		      (if (not (eq? x '()))
5658			  (begin
5659			    (outstr port " . ")
5660			    (out x) ) )
5661		      (outchr port #\)) )
5662		   (outchr port #\space)
5663		   (out (##sys#slot x 0)) ) )
5664		((##core#inline "C_bytevectorp" x)
5665		 (outstr port "#u8")
5666                 (out (##sys#bytevector->list x)))
5667		((##core#inline "C_structurep" x) (##sys#user-print-hook x readable port))
5668		((##core#inline "C_closurep" x) (outstr port (##sys#procedure->string x)))
5669		((##core#inline "C_locativep" x) (outstr port "#<locative>"))
5670		((##core#inline "C_lambdainfop" x)
5671		 (outstr port "#<lambda info ")
5672		 (outstr port (##sys#lambda-info->string x))
5673		 (outchr port #\>) )
5674		((##core#inline "C_portp" x)
5675		 (case (##sys#slot x 1)
5676		   ((1)  (outstr port "#<input port \""))
5677		   ((2)  (outstr port "#<output port \""))
5678		   (else (outstr port "#<port \"")))
5679		 (outstr port (##sys#slot x 3))
5680		 (outstr port "\">") )
5681		((##core#inline "C_vectorp" x)
5682		 (let ((n (##sys#size x)))
5683		   (cond ((eq? 0 n)
5684			  (outstr port "#()") )
5685			 (else
5686			  (outstr port "#(")
5687			  (out (##sys#slot x 0))
5688			  (do ((i 1 (fx+ i 1))
5689			       (c (fx- n 1) (fx- c 1)) )
5690			      ((eq? c 0)
5691			       (outchr port #\)) )
5692			    (outchr port #\space)
5693			    (out (##sys#slot x i)) ) ) ) ) )
5694		(else (##sys#error "unprintable block object encountered")))))
5695      (##sys#void))))
5696
5697(define ##sys#procedure->string
5698  (let ((string-append string-append))
5699    (lambda (x)
5700      (let ((info (##sys#lambda-info x)))
5701	(if info
5702	    (string-append "#<procedure " (##sys#lambda-info->string info) ">")
5703	    "#<procedure>") ) ) ) )
5704
5705(define ##sys#record-printers '())
5706
5707(set! chicken.base#record-printer
5708  (lambda (type)
5709    (let ((a (assq type ##sys#record-printers)))
5710      (and a (cdr a)))))
5711
5712(set! chicken.base#set-record-printer!
5713  (lambda (type proc)
5714    (##sys#check-closure proc 'set-record-printer!)
5715    (let ((a (assq type ##sys#record-printers)))
5716      (if a
5717	  (##sys#setslot a 1 proc)
5718	  (set! ##sys#record-printers (cons (cons type proc) ##sys#record-printers)))
5719      (##core#undefined))))
5720
5721;; OBSOLETE can be removed after bootstrapping
5722(set! ##sys#register-record-printer chicken.base#set-record-printer!)
5723
5724(set! chicken.base#record-printer
5725  (getter-with-setter record-printer set-record-printer!))
5726
5727(define (##sys#user-print-hook x readable port)
5728  (let* ((type (##sys#slot x 0))
5729	 (a (assq type ##sys#record-printers))
5730         (name (if (vector? type) (##sys#slot type 0) type)))
5731    (cond (a (handle-exceptions ex
5732		(begin
5733		  (##sys#print "#<Error in printer of record type `" #f port)
5734		  (##sys#print name #f port)
5735		  (if (##sys#structure? ex 'condition)
5736		      (and-let* ((a (member '(exn . message) (##sys#slot ex 2))))
5737			(##sys#print "': " #f port)
5738			(##sys#print (cadr a) #f port)
5739			(##sys#write-char-0 #\> port))
5740		      (##sys#print "'>" #f port)))
5741	       ((##sys#slot a 1) x port)))
5742	  (else
5743	   (##sys#print "#<" #f port)
5744	   (##sys#print name #f port)
5745	   (case type
5746	     ((condition)
5747	      (##sys#print ": " #f port)
5748	      (##sys#print (##sys#slot x 1) #f port) )
5749	     ((thread)
5750	      (##sys#print ": " #f port)
5751	      (##sys#print (##sys#slot x 6) #f port) ) )
5752	   (##sys#write-char-0 #\> port) ) ) ) )
5753
5754(define ##sys#with-print-length-limit
5755  (let ([call-with-current-continuation call-with-current-continuation])
5756    (lambda (limit thunk)
5757      (call-with-current-continuation
5758       (lambda (return)
5759	 (parameterize ((##sys#print-length-limit limit)
5760			(##sys#print-exit return)
5761			(current-print-length 0))
5762	   (thunk)))))))
5763
5764
5765;;; String ports:
5766;
5767; - Port-slots:
5768;
5769;   Input:
5770;
5771;   10: position (in bytes)
5772;   11: len
5773;   12: input bytevector
5774;
5775;   Output:
5776;
5777;   10: position (in bytes)
5778;   11: limit
5779;   12: output bytevector
5780
5781(define ##sys#string-port-class
5782  (letrec ((check
5783	    (lambda (p n)
5784	      (let* ((position (##sys#slot p 10))
5785		     (limit (##sys#slot p 11))
5786		     (output (##sys#slot p 12))
5787		     (limit2 (fx+ position n)))
5788		(when (fx>= limit2 limit)
5789		  (when (fx>= limit2 maximal-string-length)
5790		    (##sys#error "string buffer full" p) )
5791		  (let* ([limit3 (fxmin maximal-string-length (fx+ limit limit))]
5792			 [buf (##sys#make-bytevector limit3)] )
5793		    (##core#inline "C_copy_memory_with_offset" buf output 0 0 position)
5794		    (##sys#setslot p 12 buf)
5795		    (##sys#setislot p 11 limit3)
5796		    (check p n) ) ) ) ) ) )
5797    (vector
5798     (lambda (p)			; read-char
5799       (let ((position (##sys#slot p 10))
5800             (input (##sys#slot p 12))
5801             (len (##sys#slot p 11)))
5802         (if (fx>= position len)
5803             #!eof
5804             (let ((c (##core#inline "C_utf_decode" input position)))
5805               (##sys#setislot p 10
5806                               (##core#inline "C_utf_advance" input position))
5807               c))))
5808     (lambda (p)			; peek-char
5809       (let ((position (##sys#slot p 10))
5810             (input (##sys#slot p 12))
5811             (len (##sys#slot p 11)))
5812         (if (fx>= position len)
5813             #!eof
5814             (##core#inline "C_utf_decode" input position))))
5815     (lambda (p c)			; write-char
5816       (check p 1)
5817       (let ([position (##sys#slot p 10)]
5818	     [output (##sys#slot p 12)] )
5819         (##sys#setislot p 10 (##core#inline "C_utf_insert" output position c))))
5820     (lambda (p bv from to)			; write-bytevector
5821       (let ((len (fx- to from)))
5822	 (check p len)
5823	 (let* ((position (##sys#slot p 10))
5824	        (output (##sys#slot p 12)))
5825	   (##core#inline "C_copy_memory_with_offset" output bv position from len)
5826	   (##sys#setislot p 10 (fx+ position len)) ) ) )
5827     void ; close
5828     (lambda (p) #f)			; flush-output
5829     (lambda (p) #t)			; char-ready?
5830     (lambda (p n dest start)		; read-bytevector!
5831       (let* ((pos (##sys#slot p 10))
5832              (input (##sys#slot p 12))
5833	      (n2 (fx- (##sys#slot p 11) pos)))
5834	 (when (or (not n) (fx> n n2)) (set! n n2))
5835	 (##core#inline "C_copy_memory_with_offset" dest input start pos n)
5836	 (##sys#setislot p 10 (fx+ pos n))
5837	 n))
5838     (lambda (p limit)			; read-line
5839       (let* ((pos (##sys#slot p 10))
5840	      (size (##sys#slot p 11))
5841	      (buf (##sys#slot p 12))
5842	      (end (if limit (fx+ pos limit) size)))
5843	 (if (fx>= pos size)
5844	     #!eof
5845	     (receive (next line full-line?)
5846		 (##sys#scan-buffer-line
5847		  buf (if (fx> end size) size end) pos
5848		  (lambda (pos) (values #f pos #f) ) )
5849	       ;; Update row & column position
5850	       (if full-line?
5851		   (begin
5852		     (##sys#setislot p 4 (fx+ (##sys#slot p 4) 1))
5853		     (##sys#setislot p 5 0))
5854		   (##sys#setislot p 5 (fx+ (##sys#slot p 5) (string-length line))))
5855	       (##sys#setislot p 10 next)
5856	       line) ) ) )
5857     (lambda (p)			; read-buffered
5858       (let ((pos (##sys#slot p 10))
5859	     (buf (##sys#slot p 12))
5860	     (len (##sys#slot p 11)) )
5861	 (if (fx>= pos len)
5862	     ""
5863	     (let* ((rest (fx- len pos))
5864                    (buffered (##sys#buffer->string buf pos rest)))
5865	       (##sys#setislot p 10 len)
5866	       buffered))))
5867     )))
5868
5869;; Invokes the eos handler when EOS is reached to get more data.
5870;; The eos-handler is responsible for stopping, either when EOF is hit or
5871;; a user-supplied limit is reached (ie, it's indistinguishable from EOF)
5872(define (##sys#scan-buffer-line buf limit start-pos eos-handler #!optional enc)
5873  (let* ((hold 1024)
5874         (dpos 0)
5875         (line (##sys#make-bytevector hold)))
5876    (define (grow)
5877      (let* ((h2 (fx* hold 2))
5878             (l2 (##sys#make-bytevector h2)))
5879        (##core#inline "C_copy_memory" l2 line dpos)
5880        (set! line l2)
5881        (set! hold h2)))
5882    (define (conc buf from to)
5883      (let ((len (fx- to from)))
5884        (when (fx>= (fx+ dpos len) hold) (grow))
5885        (##core#inline "C_copy_memory_with_offset" line buf dpos from len)
5886        (set! dpos (fx+ dpos len))))
5887    (define (conc1 b)
5888      (when (fx>= (fx+ dpos 1) hold) (grow))
5889      (##core#inline "C_setsubbyte" line dpos b)
5890      (set! dpos (fx+ dpos 1)))
5891    (define (getline)
5892      (if enc
5893          (##sys#buffer->string/encoding line 0 dpos enc)
5894          (##sys#buffer->string line 0 dpos)))
5895    (let loop ((buf buf)
5896               (offset start-pos)
5897               (pos start-pos)
5898               (limit limit))
5899      (cond ((fx= pos limit)
5900             (conc buf offset pos)
5901             (receive (buf offset limit) (eos-handler pos)
5902               (if buf
5903                   (loop buf offset offset limit)
5904                   (values offset (getline) #f))))
5905            (else
5906              (let ((c (##core#inline "C_subbyte" buf pos)))
5907                (cond ((eq? c 10)
5908                       (conc buf offset pos)
5909                       (values (fx+ pos 1) (getline) #t))
5910                      ((and (eq? c 13)	; \r\n -> drop \r from string
5911                            (fx> limit (fx+ pos 1))
5912                            (eq? (##core#inline "C_subbyte" buf (fx+ pos 1)) 10))
5913                       (conc buf offset pos)
5914                       (values (fx+ pos 2) (getline) #t))
5915                      ((and (eq? c 13)	; Edge case (#568): \r{read}[\n|xyz]
5916                            (fx= limit (fx+ pos 1)))
5917                       (conc buf offset pos)
5918                       (receive (buf offset limit) (eos-handler pos)
5919                         (if buf
5920                             (if (eq? (##core#inline "C_subbyte" buf offset) 10)
5921                                 (values (fx+ offset 1) (getline) #t)
5922                                 ;; "Restore" \r we didn't copy, loop w/ new string
5923                                 (begin
5924                                   (conc1 13)
5925                                   (loop buf offset offset limit)))
5926                             ;; Restore \r here, too (when we reached EOF)
5927                             (begin
5928                               (conc1 13)
5929                               (values offset (getline) #t)))))
5930                      ((eq? c 13)
5931                       (conc buf offset pos)
5932                       (values (fx+ pos 1) (getline) #t))
5933                      (else (loop buf offset (fx+ pos 1) limit)) ) ) ) ) )))
5934
5935(define ##sys#print-to-string
5936  (let ([get-output-string get-output-string]
5937	[open-output-string open-output-string] )
5938    (lambda (xs)
5939      (let ([out (open-output-string)])
5940	(for-each (lambda (x) (##sys#print x #f out)) xs)
5941	(get-output-string out) ) ) ) )
5942
5943(define ##sys#pointer->string
5944  (let ((string-append string-append))
5945    (lambda (x)
5946      (if (##core#inline "C_taggedpointerp" x)
5947	  (string-append
5948	   "#<tagged pointer "
5949	   (##sys#print-to-string
5950	    (let ((tag (##sys#slot x 1)))
5951	      (list (if (pair? tag) (car tag) tag) ) ) )
5952	   " "
5953	   (##sys#number->string (##sys#pointer->address x) 16)
5954	   ">")
5955	  (string-append "#<pointer 0x" (##sys#number->string (##sys#pointer->address x) 16) ">") ) ) ) )
5956
5957
5958;;; Access backtrace:
5959
5960(define-constant +trace-buffer-entry-slot-count+ 5)
5961
5962(set! chicken.base#get-call-chain
5963  (let ((extract
5964	 (foreign-lambda* nonnull-c-string ((scheme-object x)) "C_return((C_char *)x);")))
5965    (lambda (#!optional (start 0) (thread ##sys#current-thread))
5966      (let* ((tbl (foreign-value "C_trace_buffer_size" int))
5967	     ;; 5 slots: "raw" location (for compiled code), "cooked" location (for interpreted code), cooked1, cooked2, thread
5968	     (c +trace-buffer-entry-slot-count+)
5969	     (vec (##sys#make-vector (fx* c tbl) #f))
5970	     (r (##core#inline "C_fetch_trace" start vec))
5971	     (n (if (fixnum? r) r (fx* c tbl)))
5972             (t-id (and thread (##sys#slot thread 14))))
5973	(let loop ((i 0))
5974	  (if (fx>= i n)
5975	      '()
5976	      (let ((t (##sys#slot vec (fx+ i 4)))) ; thread id
5977		(if (or (not t) (not thread) (eq? t-id t))
5978		    (cons (vector
5979			   (or (##sys#slot vec (fx+ i 1)) ; cooked_location
5980			       (extract (##sys#slot vec i))) ; raw_location
5981			   (##sys#slot vec (fx+ i 2))   ; cooked1
5982			   (##sys#slot vec (fx+ i 3)))  ; cooked2
5983			  (loop (fx+ i c)))
5984		    (loop (fx+ i c))))))))))
5985
5986(define (##sys#really-print-call-chain port chain header)
5987  (when (pair? chain)
5988    (##sys#print header #f port)
5989    (for-each
5990     (lambda (info)
5991       (let* ((more1 (##sys#slot info 1)) ; cooked1 (expr/form)
5992	      (more2 (##sys#slot info 2)) ; cooked2 (cntr/frameinfo)
5993	      (fi (##sys#structure? more2 'frameinfo)))
5994	 (##sys#print "\n\t" #f port)
5995	 (##sys#print (##sys#slot info 0) #f port) ; raw (mode)
5996	 (##sys#print "\t  " #f port)
5997	 (when (and more2 (if fi (##sys#slot more2 1)))
5998	   (##sys#write-char-0 #\[ port)
5999	   (##sys#print
6000	    (if fi
6001		(##sys#slot more2 1)	; cntr
6002		more2)
6003	    #f port)
6004	   (##sys#print "] " #f port))
6005	 (when more1
6006	   (##sys#with-print-length-limit
6007	    100
6008	    (lambda ()
6009	      (##sys#print more1 #t port))))))
6010     chain)
6011    (##sys#print "\t<--\n" #f port)))
6012
6013(set! chicken.base#print-call-chain
6014  (lambda (#!optional (port ##sys#standard-output) (start 0)
6015		      (thread ##sys#current-thread)
6016		      (header "\n\tCall history:\n"))
6017    (##sys#check-output-port port #t 'print-call-chain)
6018    (##sys#check-fixnum start 'print-call-chain)
6019    (##sys#check-string header 'print-call-chain)
6020    (##sys#really-print-call-chain port (get-call-chain start thread) header)))
6021
6022
6023;;; Interrupt handling:
6024
6025(define (##sys#user-interrupt-hook)
6026  (define (break) (##sys#signal-hook #:user-interrupt #f))
6027  (if (eq? ##sys#current-thread ##sys#primordial-thread)
6028      (break)
6029      (##sys#setslot ##sys#primordial-thread 1 break) ) )
6030
6031
6032;;; Default handlers
6033
6034(define-foreign-variable _ex_software int "EX_SOFTWARE")
6035
6036(define exit-in-progress #f)
6037
6038(define (cleanup-before-exit)
6039  (set! exit-in-progress #t)
6040  (##core#inline "C_flush_all_files" #f)
6041  (when (##core#inline "C_i_dump_heap_on_exitp")
6042    (##sys#print "\n" #f ##sys#standard-error)
6043    (##sys#dump-heap-state))
6044  (when (##core#inline "C_i_profilingp")
6045    (##core#inline "C_i_dump_statistical_profile"))
6046  (let loop ()
6047    (let ((tasks chicken.base#cleanup-tasks))
6048      (set! chicken.base#cleanup-tasks '())
6049      (unless (null? tasks)
6050	(for-each (lambda (t) (t)) tasks)
6051	(loop))))
6052  (when (fx> (##sys#slot ##sys#pending-finalizers 0) 0)
6053    (##sys#run-pending-finalizers #f))
6054  (when (fx> (##core#inline "C_i_live_finalizer_count") 0)
6055    (when (##sys#debug-mode?)
6056      (##sys#print "[debug] forcing finalizers...\n" #f ##sys#standard-error))
6057    (when (chicken.gc#force-finalizers)
6058      (##sys#force-finalizers))))
6059
6060(set! chicken.base#exit-handler
6061  (make-parameter
6062   (lambda (#!optional (code 0))
6063     (##sys#check-fixnum code)
6064     (cond (exit-in-progress
6065	    (##sys#warn "\"exit\" called while processing on-exit tasks"))
6066	   (else
6067	    (cleanup-before-exit)
6068	    (##core#inline "C_exit_runtime" code))))))
6069
6070(set! chicken.base#implicit-exit-handler
6071  (make-parameter
6072   (lambda ()
6073     (cleanup-before-exit))))
6074
6075(define ##sys#reset-handler ; Exposed by chicken.repl
6076  (make-parameter
6077   (lambda ()
6078     ((exit-handler) _ex_software))))
6079
6080(define (##sys#dbg-hook . args)
6081  (##core#inline "C_dbg_hook" #f)
6082  (##core#undefined))
6083
6084
6085;;; Condition handling:
6086
6087(module chicken.condition
6088    ;; NOTE: We don't emit the import lib.  Due to syntax exports, it
6089    ;; has to be a hardcoded primitive module.
6090    (abort signal current-exception-handler
6091     print-error-message with-exception-handler
6092
6093     ;; [syntax] condition-case handle-exceptions
6094
6095     ;; Condition object manipulation
6096     make-property-condition make-composite-condition
6097     condition condition? condition->list condition-predicate
6098     condition-property-accessor get-condition-property)
6099
6100(import scheme chicken.base chicken.fixnum chicken.foreign)
6101(import chicken.internal.syntax)
6102(import (only (scheme base) make-parameter open-output-string get-output-string))
6103
6104(define (##sys#signal-hook/errno mode errno msg . args)
6105  (##core#inline "C_dbg_hook" #f)
6106  (##core#inline "signal_debug_event" mode msg args)
6107  (case mode
6108    [(#:user-interrupt)
6109     (abort
6110      (##sys#make-structure
6111       'condition
6112       '(user-interrupt)
6113       '() ) ) ]
6114    [(#:warning #:notice)
6115     (##sys#print
6116      (if (eq? mode #:warning) "\nWarning: " "\nNote: ")
6117      #f ##sys#standard-error)
6118     (##sys#print msg #f ##sys#standard-error)
6119     (if (or (null? args) (fx> (length args) 1))
6120	 (##sys#write-char-0 #\newline ##sys#standard-error)
6121	 (##sys#print ": " #f ##sys#standard-error))
6122     (for-each
6123      (lambda (x)
6124	(##sys#with-print-length-limit
6125	 400
6126	 (lambda ()
6127	   (##sys#print x #t ##sys#standard-error)
6128	   (##sys#write-char-0 #\newline ##sys#standard-error))))
6129      args)
6130     (##sys#flush-output ##sys#standard-error)]
6131    (else
6132     (when (and (symbol? msg) (null? args))
6133       (set! msg (symbol->string msg)))
6134     (let* ([hasloc (and (or (not msg) (symbol? msg)) (pair? args))]
6135	    [loc (and hasloc msg)]
6136	    [msg (if hasloc (##sys#slot args 0) msg)]
6137	    [args (if hasloc (##sys#slot args 1) args)] )
6138       (abort
6139	(##sys#make-structure
6140	 'condition
6141	 (case mode
6142	   [(#:type-error)		'(exn type)]
6143	   [(#:syntax-error)		'(exn syntax)]
6144	   [(#:bounds-error)		'(exn bounds)]
6145	   [(#:arithmetic-error)	'(exn arithmetic)]
6146	   [(#:file-error)		'(exn i/o file)]
6147	   [(#:runtime-error)		'(exn runtime)]
6148	   [(#:process-error)		'(exn process)]
6149	   [(#:network-error)		'(exn i/o net)]
6150	   [(#:network-timeout-error)   '(exn i/o net timeout)]
6151	   [(#:limit-error)		'(exn runtime limit)]
6152	   [(#:arity-error)		'(exn arity)]
6153	   [(#:access-error)		'(exn access)]
6154	   [(#:domain-error)		'(exn domain)]
6155	   ((#:memory-error)            '(exn memory))
6156	   [else			'(exn)] )
6157         (let ((props
6158                (list '(exn . message) msg
6159                      '(exn . arguments) args
6160                      '(exn . call-chain) (get-call-chain)
6161                      '(exn . location) loc)))
6162           (if errno
6163               (cons '(exn . errno) (cons errno props))
6164               props))))))))
6165
6166(define (##sys#signal-hook mode msg . args)
6167  (if (pair? args)
6168      (apply ##sys#signal-hook/errno mode #f msg args)
6169      (##sys#signal-hook/errno mode #f msg)))
6170
6171(define (abort x)
6172  (##sys#current-exception-handler x)
6173  (abort
6174   (##sys#make-structure
6175    'condition
6176    '(exn)
6177    (list '(exn . message) "exception handler returned"
6178	  '(exn . arguments) '()
6179	  '(exn . location) #f) ) ) )
6180
6181(define (signal x)
6182  (##sys#current-exception-handler x) )
6183
6184(define ##sys#error-handler
6185  (make-parameter
6186   (let ([string-append string-append])
6187     (lambda (msg . args)
6188       (##sys#error-handler (lambda args (##core#inline "C_halt" "error in error")))
6189       (cond ((not (foreign-value "C_gui_mode" bool))
6190	      (##sys#print "\nError" #f ##sys#standard-error)
6191	      (when msg
6192		(##sys#print ": " #f ##sys#standard-error)
6193		(##sys#print msg #f ##sys#standard-error))
6194	      (##sys#with-print-length-limit
6195	       400
6196	       (lambda ()
6197		 (cond [(fx= 1 (length args))
6198			(##sys#print ": " #f ##sys#standard-error)
6199			(##sys#print (##sys#slot args 0) #t ##sys#standard-error)]
6200		       [else
6201			(##sys#for-each
6202			 (lambda (x)
6203			   (##sys#print #\newline #f ##sys#standard-error)
6204			   (##sys#print x #t ##sys#standard-error))
6205			 args)])))
6206	      (##sys#print #\newline #f ##sys#standard-error)
6207	      (print-call-chain ##sys#standard-error)
6208	      (##core#inline "C_halt" #f))
6209	     (else
6210	      (let ((out (open-output-string)))
6211		(when msg (##sys#print msg #f out))
6212		(##sys#print #\newline #f out)
6213		(##sys#for-each (lambda (x) (##sys#print x #t out) (##sys#print #\newline #f out)) args)
6214		(##core#inline "C_halt" (get-output-string out)))))))))
6215
6216
6217(define ##sys#last-exception #f)	; used in csi for ,exn command
6218
6219(define ##sys#current-exception-handler
6220  ;; Exception-handler for the primordial thread:
6221  (let ((string-append string-append))
6222    (lambda (c)
6223      (when (##sys#structure? c 'condition)
6224	(set! ##sys#last-exception c)
6225	(let ((kinds (##sys#slot c 1)))
6226	  (cond ((memq 'exn kinds)
6227		 (let* ((props (##sys#slot c 2))
6228			(msga (member '(exn . message) props))
6229			(argsa (member '(exn . arguments) props))
6230			(loca (member '(exn . location) props)) )
6231		   (apply
6232		    (##sys#error-handler)
6233		    (if msga
6234			(let ((msg (cadr msga))
6235			      (loc (and loca (cadr loca))) )
6236			  (if (and loc (symbol? loc))
6237			      (string-append
6238			       "(" (##sys#symbol->string/shared loc) ") "
6239			       (cond ((symbol? msg) (##sys#slot msg 1))
6240				     ((string? msg) msg)
6241				     (else "") ) ) ; Hm...
6242			      msg) )
6243			"<exn: has no `message' property>")
6244		    (if argsa
6245			(cadr argsa)
6246			'() ) )
6247		   ;; in case error-handler returns, which shouldn't happen:
6248		   ((##sys#reset-handler)) ) )
6249		((eq? 'user-interrupt (##sys#slot kinds 0))
6250		 (##sys#print "\n*** user interrupt ***\n" #f ##sys#standard-error)
6251		 ((##sys#reset-handler)) )
6252		((eq? 'uncaught-exception (##sys#slot kinds 0))
6253		 ((##sys#error-handler)
6254		  "uncaught exception"
6255		  (cadr (member '(uncaught-exception . reason) (##sys#slot c 2))) )
6256		 ((##sys#reset-handler)) ) ) ) )
6257      (abort
6258       (##sys#make-structure
6259	'condition
6260	'(uncaught-exception)
6261	(list '(uncaught-exception . reason) c)) ) ) ) )
6262
6263(define (with-exception-handler handler thunk)
6264  (let ([oldh ##sys#current-exception-handler])
6265    (##sys#dynamic-wind
6266      (lambda () (set! ##sys#current-exception-handler handler))
6267      thunk
6268      (lambda () (set! ##sys#current-exception-handler oldh)) ) ) )
6269
6270;; TODO: Make this a proper parameter
6271(define (current-exception-handler . args)
6272  (if (null? args)
6273      ##sys#current-exception-handler
6274      (let ((proc (car args)))
6275	(##sys#check-closure proc 'current-exception-handler)
6276	(let-optionals (cdr args) ((convert? #t) (set? #t))
6277	  (when set? (set! ##sys#current-exception-handler proc)))
6278	proc)))
6279
6280;;; Condition object manipulation
6281
6282(define (prop-list->kind-prefixed-prop-list loc kind plist)
6283  (let loop ((props plist))
6284    (cond ((null? props) '())
6285	  ((or (not (pair? props)) (not (pair? (cdr props))))
6286	   (##sys#signal-hook
6287	    #:type-error loc "argument is not an even property list" plist))
6288	  (else (cons (cons kind (car props))
6289		      (cons (cadr props)
6290			    (loop (cddr props))))))))
6291
6292(define (make-property-condition kind . props)
6293  (##sys#make-structure
6294   'condition (list kind)
6295   (prop-list->kind-prefixed-prop-list
6296    'make-property-condition kind props)))
6297
6298(define (make-composite-condition c1 . conds)
6299  (let ([conds (cons c1 conds)])
6300    (for-each (lambda (c) (##sys#check-structure c 'condition 'make-composite-condition)) conds)
6301    (##sys#make-structure
6302     'condition
6303     (apply ##sys#append (map (lambda (c) (##sys#slot c 1)) conds))
6304     (apply ##sys#append (map (lambda (c) (##sys#slot c 2)) conds)) ) ) )
6305
6306(define (condition arg1 . args)
6307  (let* ((args (cons arg1 args))
6308	 (keys (apply ##sys#append
6309		      (map (lambda (c)
6310			     (prop-list->kind-prefixed-prop-list
6311			      'condition (car c) (cdr c)))
6312			     args))))
6313    (##sys#make-structure 'condition (map car args) keys)))
6314
6315(define (condition? x) (##sys#structure? x 'condition))
6316
6317(define (condition->list x)
6318  (unless (condition? x)
6319    (##sys#signal-hook
6320     #:type-error 'condition->list
6321     "argument is not a condition object" x))
6322  (map (lambda (k)
6323	 (cons k (let loop ((props (##sys#slot x 2)))
6324		   (cond ((null? props) '())
6325			 ((eq? (caar props) k)
6326			  (cons (cdar props)
6327				(cons (cadr props)
6328				      (loop (cddr props)))))
6329			 (else
6330			  (loop (cddr props)))))))
6331       (##sys#slot x 1)))
6332
6333(define (condition-predicate kind)
6334  (lambda (c)
6335    (and (condition? c)
6336         (if (memv kind (##sys#slot c 1)) #t #f)) ) )
6337
6338(define (condition-property-accessor kind prop . err-def)
6339  (let ((err? (null? err-def))
6340	(k+p (cons kind prop)) )
6341    (lambda (c)
6342      (##sys#check-structure c 'condition)
6343      (and (memv kind (##sys#slot c 1))
6344	   (let ([a (member k+p (##sys#slot c 2))])
6345	     (cond [a (cadr a)]
6346		   [err? (##sys#signal-hook
6347			  #:type-error 'condition-property-accessor
6348			  "condition has no such property" prop) ]
6349		   [else (car err-def)] ) ) ) ) ) )
6350
6351(define get-condition-property
6352  (lambda (c kind prop . err-def)
6353    ((apply condition-property-accessor kind prop err-def) c)))
6354
6355
6356;;; Convenient error printing:
6357
6358(define print-error-message
6359  (let* ((display display)
6360	 (newline newline)
6361	 (write write)
6362	 (string-append string-append)
6363	 (errmsg (condition-property-accessor 'exn 'message #f))
6364	 (errloc (condition-property-accessor 'exn 'location #f))
6365	 (errargs (condition-property-accessor 'exn 'arguments #f))
6366	 (writeargs
6367	  (lambda (args port)
6368	    (##sys#for-each
6369	     (lambda (x)
6370	       (##sys#with-print-length-limit 80 (lambda () (write x port)))
6371	       (newline port) )
6372	     args) ) ) )
6373    (lambda (ex . args)
6374      (let-optionals args ((port ##sys#standard-output)
6375			   (header "Error"))
6376	(##sys#check-output-port port #t 'print-error-message)
6377	(newline port)
6378	(display header port)
6379	(cond ((and (not (##sys#immediate? ex)) (eq? 'condition (##sys#slot ex 0)))
6380	       (cond ((errmsg ex) =>
6381		      (lambda (msg)
6382			(display ": " port)
6383			(let ((loc (errloc ex)))
6384			  (when (and loc (symbol? loc))
6385			    (display (string-append "(" (##sys#symbol->string/shared loc) ") ") port) ) )
6386			(display msg port) ) )
6387		     (else
6388		      (let ((kinds (##sys#slot ex 1)))
6389			(if (equal? '(user-interrupt) kinds)
6390			    (display ": *** user interrupt ***" port)
6391			    (begin
6392			      (display ": <condition> " port)
6393			      (display (##sys#slot ex 1) port) ) ) ) ) )
6394	       (let ((args (errargs ex)))
6395		 (cond
6396		   ((not args))
6397		   ((fx= 1 (length args))
6398		    (display ": " port)
6399		    (writeargs args port))
6400		   (else
6401		    (newline port)
6402		    (writeargs args port)))))
6403	      ((string? ex)
6404	       (display ": " port)
6405	       (display ex port)
6406	       (newline port))
6407	      (else
6408	       (display ": uncaught exception: " port)
6409	       (writeargs (list ex) port) ) ) ) ) ) )
6410
6411
6412;;; Show exception message and backtrace as warning
6413;;; (used for threads and finalizers)
6414
6415(define ##sys#show-exception-warning
6416  (let ((print-error-message print-error-message)
6417	(display display)
6418	(write-char write-char)
6419	(print-call-chain print-call-chain)
6420	(open-output-string open-output-string)
6421	(get-output-string get-output-string) )
6422    (lambda (exn cause #!optional (thread ##sys#current-thread))
6423      (when ##sys#warnings-enabled
6424	(let ((o (open-output-string)))
6425	  (display "Warning" o)
6426	  (when thread
6427	    (display " (" o)
6428	    (display thread o)
6429	    (write-char #\) o))
6430	  (display ": " o)
6431	  (display cause o)
6432	  (print-error-message exn ##sys#standard-error (get-output-string o))
6433	  (print-call-chain ##sys#standard-error 0 thread) ) ))))
6434
6435
6436;;; Error hook (called by runtime-system):
6437
6438(define ##sys#error-hook
6439  (let ([string-append string-append])
6440    (lambda (code loc . args)
6441      (case code
6442	((1) (let ([c (car args)]
6443		   [n (cadr args)]
6444		   [fn (caddr args)] )
6445	       (apply
6446		##sys#signal-hook
6447		#:arity-error loc
6448		(string-append "bad argument count - received " (##sys#number->string n) " but expected "
6449			       (##sys#number->string c) )
6450		(if fn (list fn) '())) ) )
6451	((2) (let ([c (car args)]
6452		   [n (cadr args)]
6453		   [fn (caddr args)] )
6454	       (apply
6455		##sys#signal-hook
6456		#:arity-error loc
6457		(string-append "too few arguments - received " (##sys#number->string n) " but expected "
6458			       (##sys#number->string c) )
6459		(if fn (list fn) '()))))
6460	((3) (apply ##sys#signal-hook #:type-error loc "bad argument type" args))
6461	((4) (apply ##sys#signal-hook #:runtime-error loc "unbound variable" args))
6462	((5) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a keyword" args))
6463	((6) (apply ##sys#signal-hook #:limit-error loc "out of memory" args))
6464	((7) (apply ##sys#signal-hook #:arithmetic-error loc "division by zero" args))
6465	((8) (apply ##sys#signal-hook #:bounds-error loc "out of range" args))
6466	((9) (apply ##sys#signal-hook #:type-error loc "call of non-procedure" args))
6467	((10) (apply ##sys#signal-hook #:arity-error loc "continuation cannot receive multiple values" args))
6468	((11) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a non-cyclic list" args))
6469	((12) (apply ##sys#signal-hook #:limit-error loc "recursion too deep" args))
6470	((13) (apply ##sys#signal-hook #:type-error loc "inexact number cannot be represented as an exact number" args))
6471	((14) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a proper list" args))
6472	((15) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a fixnum" args))
6473	((16) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a number" args))
6474	((17) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a string" args))
6475	((18) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a pair" args))
6476	((19) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a list" args))
6477	((20) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a character" args))
6478	((21) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a vector" args))
6479	((22) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a symbol" args))
6480	((23) (apply ##sys#signal-hook #:limit-error loc "stack overflow" args))
6481	((24) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a structure of the required type" args))
6482	((25) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a bytevector" args))
6483	((26) (apply ##sys#signal-hook #:type-error loc "locative refers to reclaimed object" args))
6484	((27) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a block object" args))
6485	((28) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a number vector" args))
6486	((29) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an integer" args))
6487	((30) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an unsigned integer" args))
6488	((31) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a pointer" args))
6489	((32) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a tagged pointer" args))
6490	((33) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a flonum" args))
6491	((34) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a procedure" args))
6492	((35) (apply ##sys#signal-hook #:type-error loc "bad argument type - invalid base" args))
6493	((36) (apply ##sys#signal-hook #:limit-error loc "recursion too deep or circular data encountered" args))
6494	((37) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a boolean" args))
6495	((38) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a locative" args))
6496	((39) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a port" args))
6497	((40) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a port of the correct type" args))
6498	((41) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an input-port" args))
6499	((42) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an output-port" args))
6500	((43) (apply ##sys#signal-hook #:file-error loc "port already closed" args))
6501	((44) (apply ##sys#signal-hook #:type-error loc "cannot represent string with NUL bytes as C string" args))
6502	((45) (apply ##sys#signal-hook #:memory-error loc "segmentation violation" args))
6503	((46) (apply ##sys#signal-hook #:arithmetic-error loc "floating-point exception" args))
6504	((47) (apply ##sys#signal-hook #:runtime-error loc "illegal instruction" args))
6505	((48) (apply ##sys#signal-hook #:memory-error loc "bus error" args))
6506	((49) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an exact number" args))
6507	((50) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an inexact number" args))
6508	((51) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a real" args))
6509	((52) (apply ##sys#signal-hook #:type-error loc "bad argument type - complex number has no ordering" args))
6510	((53) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an exact integer" args))
6511	((54) (apply ##sys#signal-hook #:type-error loc "number does not fit in foreign type" args))
6512	((55) (apply ##sys#signal-hook #:type-error loc "cannot compute absolute value of complex number" args))
6513	((56) (let ((c (car args))
6514		    (n (cadr args))
6515		    (fn (caddr args)))
6516	        (apply
6517		 ##sys#signal-hook
6518		 #:bounds-error loc
6519		 (string-append "attempted rest argument access at index " (##sys#number->string n)
6520                                " but rest list length is " (##sys#number->string c) )
6521		 (if fn (list fn) '()))))
6522        ((57) (apply ##sys#signal-hook #:type-error loc "string contains invalid UTF-8 sequence" args))
6523        ((58) (apply ##sys#signal-hook #:type-error loc "bad argument type - numeric value exceeds range" args))
6524	(else (apply ##sys#signal-hook #:runtime-error loc "unknown internal error" args)) ) ) ) )
6525
6526) ; chicken.condition
6527
6528(import chicken.condition)
6529
6530;;; R7RS exceptions
6531
6532(define ##sys#r7rs-exn-handlers
6533  (make-parameter
6534    (let ((lst (list ##sys#current-exception-handler)))
6535      (set-cdr! lst lst)
6536      lst)))
6537
6538(define scheme#with-exception-handler
6539  (let ((eh ##sys#r7rs-exn-handlers))
6540    (lambda (handler thunk)
6541      (dynamic-wind
6542       (lambda ()
6543         ;; We might be interoperating with srfi-12 handlers set by intermediate
6544         ;; non-R7RS code, so check if a new handler was set in the meanwhile.
6545         (unless (eq? (car (eh)) ##sys#current-exception-handler)
6546           (eh (cons ##sys#current-exception-handler (eh))))
6547         (eh (cons handler (eh)))
6548         (set! ##sys#current-exception-handler handler))
6549       thunk
6550       (lambda ()
6551         (eh (cdr (eh)))
6552         (set! ##sys#current-exception-handler (car (eh))))))))
6553
6554(define scheme#raise
6555  (let ((eh ##sys#r7rs-exn-handlers))
6556    (lambda (obj)
6557      (scheme#with-exception-handler
6558        (cadr (eh))
6559        (lambda ()
6560          ((cadr (eh)) obj)
6561          ((car (eh))
6562           (make-property-condition
6563            'exn
6564            'message "exception handler returned"
6565            'arguments '()
6566            'location #f)))))))
6567
6568(define scheme#raise-continuable
6569  (let ((eh ##sys#r7rs-exn-handlers))
6570     (lambda (obj)
6571       (scheme#with-exception-handler
6572        (cadr (eh))
6573        (lambda ()
6574          ((cadr (eh)) obj))))))
6575
6576(define scheme#error-object? condition?)
6577(define scheme#error-object-message (condition-property-accessor 'exn 'message))
6578(define scheme#error-object-irritants (condition-property-accessor 'exn 'arguments))
6579
6580(define scheme#read-error?)
6581(define scheme#file-error?)
6582
6583(let ((exn?    (condition-predicate 'exn))
6584      (i/o?    (condition-predicate 'i/o))
6585      (file?   (condition-predicate 'file))
6586      (syntax? (condition-predicate 'syntax)))
6587  (set! scheme#read-error?
6588    (lambda (obj)
6589      (and (exn? obj)
6590           (or (i/o? obj) ; XXX Not fine-grained enough.
6591               (syntax? obj)))))
6592  (set! scheme#file-error?
6593    (lambda (obj)
6594      (and (exn? obj)
6595           (file? obj)))))
6596
6597
6598;;; Miscellaneous low-level routines:
6599
6600(define (##sys#structure? x s) (##core#inline "C_i_structurep" x s))
6601(define (##sys#generic-structure? x) (##core#inline "C_structurep" x))
6602(define (##sys#slot x i) (##core#inline "C_slot" x i))
6603(define (##sys#size x) (##core#inline "C_block_size" x))
6604(define ##sys#make-pointer (##core#primitive "C_make_pointer"))
6605(define ##sys#make-tagged-pointer (##core#primitive "C_make_tagged_pointer"))
6606(define (##sys#pointer? x) (##core#inline "C_anypointerp" x))
6607(define (##sys#set-pointer-address! ptr addr) (##core#inline "C_update_pointer" addr ptr))
6608(define (##sys#bytevector? x) (##core#inline "C_bytevectorp" x))
6609(define (##sys#string->pbytevector s) (##core#inline "C_string_to_pbytevector" s))
6610(define (##sys#permanent? x) (##core#inline "C_permanentp" x))
6611(define (##sys#block-address x) (##core#inline_allocate ("C_block_address" 6) x))
6612(define (##sys#locative? x) (##core#inline "C_locativep" x))
6613
6614(define (##sys#srfi-4-vector? x)
6615  (or (##core#inline "C_i_srfi_4_vectorp" x)
6616      (and (##core#inline "C_blockp" x)
6617           (##core#inline "C_structurep" x)
6618           (let ((t (##sys#slot x 0)))
6619             (or (eq? t 'c64vector) (eq? t 'c128vector))))))
6620
6621(define (##sys#null-pointer)
6622  (let ([ptr (##sys#make-pointer)])
6623    (##core#inline "C_update_pointer" 0 ptr)
6624    ptr) )
6625
6626(define (##sys#null-pointer? x)
6627  (eq? 0 (##sys#pointer->address x)) )
6628
6629(define (##sys#address->pointer addr)
6630  (let ([ptr (##sys#make-pointer)])
6631    (##core#inline "C_update_pointer" addr ptr)
6632    ptr) )
6633
6634(define (##sys#pointer->address ptr)
6635  ;;XXX '6' is platform dependent!
6636  (##core#inline_allocate ("C_a_unsigned_int_to_num" 6) (##sys#slot ptr 0)) )
6637
6638(define (##sys#make-c-string str #!optional loc)
6639  (let ((bv (##sys#slot str 0)))
6640    (if (fx= (##core#inline "C_asciiz_strlen" bv) (fx- (##sys#size bv) 1))
6641        bv
6642        (##sys#error-hook (foreign-value "C_ASCIIZ_REPRESENTATION_ERROR" int)
6643                          loc str))) )
6644
6645(define ##sys#peek-signed-integer (##core#primitive "C_peek_signed_integer"))
6646(define ##sys#peek-unsigned-integer (##core#primitive "C_peek_unsigned_integer"))
6647(define (##sys#peek-fixnum b i) (##core#inline "C_peek_fixnum" b i))
6648(define (##sys#peek-byte ptr i) (##core#inline "C_peek_byte" ptr i))
6649
6650(define (##sys#vector->structure! vec) (##core#inline "C_vector_to_structure" vec))
6651
6652(define (##sys#peek-double b i)
6653  (##core#inline_allocate ("C_a_f64peek" 4) b i))
6654
6655(define (##sys#peek-c-string b i)
6656  (and (not (##sys#null-pointer? b))
6657       (##sys#peek-nonnull-c-string b i)))
6658
6659(define (##sys#peek-nonnull-c-string b i)
6660  (let* ([len (##core#inline "C_fetch_c_strlen" b i)]
6661	 [bv (##sys#make-bytevector (fx+ len 1) 0)] )
6662    (##core#inline "C_peek_c_string" b i bv len)
6663    (##sys#buffer->string! bv len)))
6664
6665(define (##sys#peek-and-free-c-string b i)
6666  (let ((str (##sys#peek-c-string b i)))
6667    (##core#inline "C_free_mptr" b i)
6668    str))
6669
6670(define (##sys#peek-and-free-nonnull-c-string b i)
6671  (let ((str (##sys#peek-nonnull-c-string b i)))
6672    (##core#inline "C_free_mptr" b i)
6673    str))
6674
6675(define (##sys#poke-c-string b i s)
6676  (##core#inline "C_poke_c_string" b i (##sys#make-c-string s) s) )
6677
6678(define (##sys#poke-integer b i n) (##core#inline "C_poke_integer" b i n))
6679(define (##sys#poke-double b i n) (##core#inline "C_poke_double" b i n))
6680
6681(define ##sys#peek-c-string-list
6682  (let ((fetch (foreign-lambda c-string "C_peek_c_string_at" c-pointer int)))
6683    (lambda (ptr n)
6684      (let loop ((i 0))
6685	(if (and n (fx>= i n))
6686	    '()
6687	    (let ((s (fetch ptr i)))
6688	      (if s
6689		  (cons s (loop (fx+ i 1)))
6690		  '() ) ) ) ) ) ) )
6691
6692(define ##sys#peek-and-free-c-string-list
6693  (let ((fetch (foreign-lambda c-string "C_peek_c_string_at" c-pointer int))
6694	(free (foreign-lambda void "C_free" c-pointer)))
6695    (lambda (ptr n)
6696      (let ((lst (let loop ((i 0))
6697		   (if (and n (fx>= i n))
6698		       '()
6699		       (let ((s (fetch ptr i)))
6700			 (cond (s
6701				(##core#inline "C_free_sptr" ptr i)
6702				(cons s (loop (fx+ i 1))) )
6703			       (else '() ) ) ) ) ) ) )
6704	(free ptr)
6705	lst) ) ) )
6706
6707(define (##sys#vector->closure! vec addr)
6708  (##core#inline "C_vector_to_closure" vec)
6709  (##core#inline "C_update_pointer" addr vec) )
6710
6711(define (##sys#symbol-has-toplevel-binding? s)
6712  (##core#inline "C_boundp" s))
6713
6714(define (##sys#block-pointer x)
6715  (let ([ptr (##sys#make-pointer)])
6716    (##core#inline "C_pointer_to_block" ptr x)
6717    ptr) )
6718
6719
6720;;; Support routines for foreign-function calling:
6721
6722(define (##sys#foreign-char-argument x) (##core#inline "C_i_foreign_char_argumentp" x))
6723(define (##sys#foreign-fixnum-argument x) (##core#inline "C_i_foreign_fixnum_argumentp" x))
6724(define (##sys#foreign-flonum-argument x) (##core#inline "C_i_foreign_flonum_argumentp" x))
6725(define (##sys#foreign-block-argument x) (##core#inline "C_i_foreign_block_argumentp" x))
6726
6727(define (##sys#foreign-cplxnum-argument x)
6728  (if (##core#inline "C_i_numberp" x)
6729	  (##core#inline_allocate ("C_a_i_exact_to_inexact" 12) x)
6730   	  (##sys#signal-hook
6731    	#:type-error #f "bad argument type - not a complex number"
6732	    x)))
6733
6734(define (##sys#foreign-struct-wrapper-argument t x)
6735  (##core#inline "C_i_foreign_struct_wrapper_argumentp" t x))
6736
6737(define (##sys#foreign-string-argument x) (##core#inline "C_i_foreign_string_argumentp" x))
6738(define (##sys#foreign-symbol-argument x) (##core#inline "C_i_foreign_symbol_argumentp" x))
6739(define (##sys#foreign-pointer-argument x) (##core#inline "C_i_foreign_pointer_argumentp" x))
6740(define (##sys#foreign-tagged-pointer-argument x tx) (##core#inline "C_i_foreign_tagged_pointer_argumentp" x tx))
6741
6742(define (##sys#foreign-ranged-integer-argument obj size)
6743  (##core#inline "C_i_foreign_ranged_integer_argumentp" obj size))
6744(define (##sys#foreign-unsigned-ranged-integer-argument obj size)
6745  (##core#inline "C_i_foreign_unsigned_ranged_integer_argumentp" obj size))
6746
6747(define (##sys#wrap-struct type rec)
6748  (##sys#setslot rec 0 type)
6749  rec)
6750
6751;;; Low-level threading interface:
6752
6753(define ##sys#default-thread-quantum 10000)
6754
6755(define (##sys#default-exception-handler arg)
6756  (##core#inline "C_halt" "internal error: default exception handler shouldn't be called!") )
6757
6758(define (##sys#make-thread thunk state name q)
6759  (##sys#make-structure
6760   'thread
6761   thunk				; #1 thunk
6762   #f					; #2 result list
6763   state				; #3 state
6764   #f					; #4 block-timeout
6765   (vector				; #5 state buffer
6766    ##sys#dynamic-winds
6767    ##sys#standard-input
6768    ##sys#standard-output
6769    ##sys#standard-error
6770    ##sys#default-exception-handler
6771    (##sys#vector-resize ##sys#current-parameter-vector
6772			 (##sys#size ##sys#current-parameter-vector) #f) )
6773   name					; #6 name
6774   (##core#undefined)			; #7 end-exception
6775   '()					; #8 owned mutexes
6776   q					; #9 quantum
6777   (##core#undefined)			; #10 specific
6778   #f					; #11 block object (type depends on blocking type)
6779   '()					; #12 recipients
6780   #f					; #13 unblocked by timeout?
6781   (cons #f #f)))            		; #14 ID (just needs to be unique)
6782
6783(define ##sys#primordial-thread
6784  (##sys#make-thread #f 'running 'primordial ##sys#default-thread-quantum))
6785
6786(define ##sys#current-thread ##sys#primordial-thread)
6787
6788(define (##sys#make-mutex id owner)
6789  (##sys#make-structure
6790   'mutex
6791   id					; #1 name
6792   owner				; #2 thread or #f
6793   '()					; #3 list of waiting threads
6794   #f					; #4 abandoned
6795   #f					; #5 locked
6796   (##core#undefined) ) )		; #6 specific
6797
6798(define (##sys#schedule) ((##sys#slot ##sys#current-thread 1)))
6799
6800(define (##sys#thread-yield!)
6801  (##sys#call-with-current-continuation
6802   (lambda (return)
6803     (let ((ct ##sys#current-thread))
6804       (##sys#setslot ct 1 (lambda () (return (##core#undefined))))
6805       (##sys#schedule) ) ) ) )
6806
6807(define (##sys#kill-other-threads thunk)
6808  (thunk))	     ; does nothing, will be modified by scheduler.scm
6809
6810;; these two procedures should redefined in thread APIs (e.g. srfi-18):
6811(define (##sys#resume-thread-on-event t) #f)
6812
6813(define (##sys#suspend-thread-on-event t)
6814  ;; wait until signal handler fires. If we are only waiting for a finalizer,
6815  ;; then this will wait forever:
6816  (##sys#sleep-until-interrupt))
6817
6818(define (##sys#sleep-until-interrupt)
6819  (##core#inline "C_i_sleep_until_interrupt" 100)
6820  (##sys#dispatch-interrupt (lambda _ #f)))
6821
6822
6823;;; event queues (for signals and finalizers)
6824
6825(define (##sys#make-event-queue)
6826  (##sys#make-structure 'event-queue
6827                        '() ; head
6828                        '() ; tail
6829                        #f)) ; suspended thread
6830
6831(define (##sys#add-event-to-queue! q e)
6832  (let ((h (##sys#slot q 1))
6833        (t (##sys#slot q 2))
6834        (item (cons e '())))
6835    (if (null? h)
6836        (##sys#setslot q 1 item)
6837        (##sys#setslot t 1 item))
6838    (##sys#setslot q 2 item)
6839    (let ((st (##sys#slot q 3))) ; thread suspended?
6840      (when st
6841        (##sys#setslot q 3 #f)
6842        (##sys#resume-thread-on-event st)))))
6843
6844(define (##sys#get-next-event q)
6845  (let ((st (##sys#slot q 3)))
6846    (and (not st)
6847         (let ((h (##sys#slot q 1)))
6848           (and (not (null? h))
6849                (let ((x (##sys#slot h 0))
6850                      (n (##sys#slot h 1)))
6851                  (##sys#setslot q 1 n)
6852                  (when (null? n) (##sys#setslot q 2 '()))
6853                  x))))))
6854
6855(define (##sys#wait-for-next-event q)
6856  (let ((st (##sys#slot q 3)))
6857    (when st
6858      (##sys#signal-hook #:runtime-error #f "event queue blocked" q))
6859    (let again ()
6860      (let ((h (##sys#slot q 1)))
6861        (cond ((null? h)
6862               (##sys#setslot q 3 ##sys#current-thread)
6863               (##sys#suspend-thread-on-event ##sys#current-thread)
6864               (again))
6865              (else
6866                (let ((x (##sys#slot h 0))
6867                      (n (##sys#slot h 1)))
6868                  (##sys#setslot q 1 n)
6869                  (when (null? n) (##sys#setslot q 2 '()))
6870                  x)))))))
6871
6872
6873;;; Sleeping:
6874
6875(define (chicken.base#sleep-hook n) ; modified by scheduler.scm
6876  (##core#inline "C_i_process_sleep" n))
6877
6878(set! chicken.base#sleep
6879  (lambda (n)
6880    (##sys#check-fixnum n 'sleep)
6881    (chicken.base#sleep-hook n)
6882    (##core#undefined)))
6883
6884
6885;;; Interrupt-handling:
6886
6887(define ##sys#context-switch (##core#primitive "C_context_switch"))
6888
6889(define ##sys#signal-vector (make-vector 256 #f))
6890
6891(define (##sys#interrupt-hook reason state)
6892  (let loop ((reason reason))
6893    (when reason
6894      (let ((handler (##sys#slot ##sys#signal-vector reason)))
6895	(when handler
6896	  (handler reason))
6897	(loop (##core#inline "C_i_pending_interrupt" #f)))))
6898    (cond ((fx> (##sys#slot ##sys#pending-finalizers 0) 0)
6899	   (##sys#run-pending-finalizers state) )
6900	  ((procedure? state) (state))
6901	  (else (##sys#context-switch state) ) ) )
6902
6903(define (##sys#dispatch-interrupt k)
6904  (##sys#interrupt-hook
6905   (##core#inline "C_i_pending_interrupt" #f)
6906   k))
6907
6908
6909;;; Accessing "errno":
6910
6911(define-foreign-variable _errno int "errno")
6912
6913(define ##sys#update-errno)
6914(define ##sys#errno)
6915
6916(let ((n 0))
6917  (set! ##sys#update-errno (lambda () (set! n _errno) n))
6918  (set! ##sys#errno (lambda () n)))
6919
6920
6921;;; Format error string for unterminated here-docs:
6922
6923(define (##sys#format-here-doc-warning end)
6924  (##sys#print-to-string `("unterminated here-doc string literal `" ,end "'")))
6925
6926;;; Special string quoting syntax:
6927
6928(set! ##sys#user-read-hook
6929  (let ([old ##sys#user-read-hook]
6930	[read read]
6931	[display display] )
6932    (define (readln port)
6933      (let ([ln (open-output-string)])
6934	(do ([c (##sys#read-char-0 port) (##sys#read-char-0 port)])
6935	    ((or (eof-object? c) (char=? #\newline c))
6936	     (if (eof-object? c) c (get-output-string ln)))
6937	  (##sys#write-char-0 c ln) ) ) )
6938    (define (read-escaped-sexp port skip-brace?)
6939      (when skip-brace? (##sys#read-char-0 port))
6940      (let* ((form (read port)))
6941	(when skip-brace?
6942	      (let loop ()
6943		;; Skips all characters until #\}
6944		(let ([c (##sys#read-char-0 port)])
6945		  (cond [(eof-object? c)
6946			 (##sys#read-error port "unexpected end of file - unterminated `#{...}' item in `here' string literal") ]
6947			[(not (char=? #\} c)) (loop)] ) ) ) )
6948	form))
6949    (lambda (char port)
6950      (cond [(not (char=? #\< char)) (old char port)]
6951	    [else
6952	     (read-char port)
6953	     (case (##sys#peek-char-0 port)
6954	       [(#\<)
6955		(##sys#read-char-0 port)
6956		(let ([str (open-output-string)]
6957		      [end (readln port)]
6958		      [f #f] )
6959		  (let ((endlen (if (eof-object? end) 0 (string-length end))))
6960		    (cond
6961		     ((fx= endlen 0)
6962		      (##sys#read-warning
6963		       port "Missing tag after #<< here-doc token"))
6964		     ((or (char=? (string-ref end (fx- endlen 1)) #\space)
6965			  (char=? (string-ref end (fx- endlen 1)) #\tab))
6966		      (##sys#read-warning
6967		       port "Whitespace after #<< here-doc tag"))
6968		     ))
6969		  (do ([ln (readln port) (readln port)])
6970		      ((or (eof-object? ln) (string=? end ln))
6971		       (when (eof-object? ln)
6972			 (##sys#read-warning port
6973			  (##sys#format-here-doc-warning end)))
6974		       (get-output-string str) )
6975		    (if f
6976			(##sys#write-char-0 #\newline str)
6977			(set! f #t) )
6978		    (display ln str) ) ) ]
6979	       [(#\#)
6980		(##sys#read-char-0 port)
6981		(let ([end (readln port)]
6982		      [str (open-output-string)] )
6983		  (define (get/clear-str)
6984		    (let ((s (get-output-string str)))
6985		      (set! str (open-output-string))
6986		      s))
6987
6988		  (let ((endlen (if (eof-object? end) 0 (string-length end))))
6989		    (cond
6990		     ((fx= endlen 0)
6991		      (##sys#read-warning
6992		       port "Missing tag after #<# here-doc token"))
6993		     ((or (char=? (string-ref end (fx- endlen 1)) #\space)
6994			  (char=? (string-ref end (fx- endlen 1)) #\tab))
6995		      (##sys#read-warning
6996		       port "Whitespace after #<# here-doc tag"))
6997		     ))
6998
6999		  (let loop [(lst '())]
7000		    (let ([c (##sys#read-char-0 port)])
7001		      (case c
7002			[(#\newline #!eof)
7003			 (let ([s (get/clear-str)])
7004			   (cond [(or (eof-object? c) (string=? end s))
7005				  (when (eof-object? c)
7006				    (##sys#read-warning
7007				     port (##sys#format-here-doc-warning end)))
7008				  `(##sys#print-to-string
7009				    ;;Can't just use `(list ,@lst) because of 126 argument apply limit
7010				    ,(let loop2 ((lst (cdr lst)) (next-string '()) (acc ''())) ; drop last newline
7011				       (cond ((null? lst)
7012					      `(cons ,(##sys#print-to-string next-string) ,acc))
7013					     ((or (string? (car lst)) (char? (car lst)))
7014					      (loop2 (cdr lst) (cons (car lst) next-string) acc))
7015					     (else
7016					      (loop2 (cdr lst)
7017						     '()
7018						     `(cons ,(car lst)
7019							    (cons ,(##sys#print-to-string next-string) ,acc))))))) ]
7020				 [else (loop (cons #\newline (cons s lst)))] ) ) ]
7021			[(#\#)
7022			 (let ([c (##sys#peek-char-0 port)])
7023			   (case c
7024			     [(#\#)
7025			      (##sys#write-char-0 (##sys#read-char-0 port) str)
7026			      (loop lst) ]
7027			     [(#\{) (loop (cons (read-escaped-sexp port #t)
7028						(cons (get/clear-str) lst) ) ) ]
7029			     [else  (loop (cons (read-escaped-sexp port #f)
7030						(cons (get/clear-str) lst) ) ) ] ) ) ]
7031			[else
7032			 (##sys#write-char-0 c str)
7033			 (loop lst) ] ) ) ) ) ]
7034	       [else (##sys#read-error port "unreadable object")] ) ] ) ) ) )
7035
7036
7037;;; Accessing process information (cwd, environ, etc.)
7038
7039#>
7040#if defined(_WIN32) && !defined(__CYGWIN__)
7041#include <direct.h>
7042
7043static C_word C_chdir(C_word str) {
7044	return C_fix(_wchdir(C_utf16(str, 0)));
7045}
7046
7047static C_word C_curdir(C_word buf, C_word size) {
7048	C_WCHAR *cwd = _wgetcwd((C_WCHAR *)C_c_string(buf), C_unfix(size));
7049        if(cwd == NULL) return C_SCHEME_FALSE;
7050	C_char *up = C_utf8(cwd);
7051	C_char *p = up;
7052	while(*p) {
7053		*p = *p == '\\' ? '/' : *p;
7054		++p;
7055	}
7056	int len = C_strlen(up);
7057	C_memcpy(cwd, up, len + 1);
7058        return C_fix(len);
7059}
7060#else
7061# define C_chdir(str) C_fix(chdir(C_c_string(str)))
7062# define C_curdir(buf, size) (getcwd(C_c_string(buf), size) ? C_fix(strlen(C_c_string(buf))) : C_SCHEME_FALSE)
7063#endif
7064
7065<#
7066
7067(module chicken.process-context
7068  (argv argc+argv command-line-arguments
7069   program-name executable-pathname
7070   change-directory current-directory
7071   get-environment-variable get-environment-variables
7072   set-environment-variable! unset-environment-variable!)
7073
7074(import scheme)
7075(import chicken.base chicken.fixnum chicken.foreign)
7076(import chicken.internal.syntax)
7077(import (only (scheme base) make-parameter))
7078
7079;;; Current directory access:
7080
7081(define (change-directory name)
7082  (##sys#check-string name 'change-directory)
7083  (let ((sname (##sys#make-c-string name 'change-directory)))
7084    (unless (fx= (##core#inline "C_chdir" sname) 0)
7085      (##sys#signal-hook/errno #:file-error (##sys#update-errno) 'change-directory
7086       (string-append "cannot change current directory - " strerror) name))
7087    name))
7088
7089(define (##sys#change-directory-hook dir) ; set! by posix for fd support
7090  (change-directory dir))
7091
7092(define current-directory
7093  (getter-with-setter
7094    (lambda ()
7095      (let* ((buffer-size (foreign-value "C_MAX_PATH" size_t))
7096             (buffer (##sys#make-bytevector buffer-size))
7097             (len (##core#inline "C_curdir" buffer buffer-size)))
7098        (unless ##sys#windows-platform ; FIXME need `cond-expand' here
7099          (##sys#update-errno))
7100        (if len
7101            (##sys#buffer->string buffer 0 len)
7102            (##sys#signal-hook/errno
7103             #:file-error
7104             (##sys#errno)
7105             'current-directory "cannot retrieve current directory"))))
7106    (lambda (dir)
7107      (##sys#change-directory-hook dir))
7108    "(chicken.process-context#current-directory)"))
7109
7110
7111;;; Environment access:
7112
7113(define _getenv
7114  (foreign-lambda c-string "C_getenv" scheme-object))
7115
7116(define (get-environment-variable var)
7117  (_getenv (##sys#make-c-string var 'get-environment-variable)))
7118
7119(define get-environment-entry
7120  (foreign-lambda c-string* "C_getenventry" int))
7121
7122(define (set-environment-variable! var val)
7123  (##sys#check-string var 'set-environment-variable!)
7124  (##core#inline "C_i_setenv"
7125   (##sys#make-c-string var 'set-environment-variable!)
7126   (and val
7127        (begin
7128          (##sys#check-string val 'set-environment-variable!)
7129          (##sys#make-c-string val 'set-environment-variable!))))
7130  (##core#undefined))
7131
7132(define (unset-environment-variable! var)
7133  (##sys#check-string var 'unset-environment-variable!)
7134  (##core#inline "C_i_setenv"
7135   (##sys#make-c-string var 'unset-environment-variable!)
7136   #f)
7137  (##core#undefined))
7138
7139(define get-environment-variables
7140   (lambda ()
7141      (let loop ((i 0))
7142        (let ((entry (get-environment-entry i)))
7143          (if entry
7144              (let scan ((j 0))
7145                (if (char=? #\= (string-ref entry j))
7146                    (cons (cons (##sys#substring entry 0 j)
7147                                (##sys#substring entry (fx+ j 1) (string-length entry)))
7148                          (loop (fx+ i 1)))
7149                    (scan (fx+ j 1))))
7150              '())))))
7151
7152
7153;;; Command line handling
7154
7155(define-foreign-variable main_argc int "C_main_argc")
7156(define-foreign-variable main_argv c-pointer "C_main_argv")
7157
7158(define executable-pathname
7159  (foreign-lambda c-string* "C_executable_pathname"))
7160
7161(define (argc+argv)
7162  (##sys#values main_argc main_argv))
7163
7164(define argv				; includes program name
7165  (let ((cache #f)
7166        (fetch-arg (foreign-lambda* c-string ((scheme-object i))
7167                     "C_return(C_main_argv[C_unfix(i)]);")))
7168    (lambda ()
7169      (unless cache
7170        (set! cache (do ((i (fx- main_argc 1) (fx- i 1))
7171                         (v '() (cons (fetch-arg i) v)))
7172                        ((fx< i 0) v))))
7173      cache)))
7174
7175(define program-name
7176  (make-parameter
7177   (if (null? (argv))
7178       "<unknown>" ; may happen if embedded in C application
7179       (car (argv)))
7180   (lambda (x)
7181     (##sys#check-string x 'program-name)
7182     x) ) )
7183
7184(define command-line-arguments
7185  (make-parameter
7186   (let ((args (argv)))
7187     (if (pair? args)
7188	 (let loop ((args (##sys#slot args 1)))	; Skip over program name (argv[0])
7189	   (if (null? args)
7190	       '()
7191	       (let ((arg (##sys#slot args 0))
7192		     (rest (##sys#slot args 1)) )
7193		 (cond
7194		  ((string=? "-:" arg)	; Consume first "empty" runtime options list, return rest
7195		   rest)
7196
7197		  ((and (fx>= (string-length arg) 3)
7198			(string=? "-:" (##sys#substring arg 0 2)))
7199		   (loop rest))
7200
7201		  ;; First non-runtime option and everything following it is returned as-is
7202		  (else args) ) ) ) )
7203	 args) )
7204   (lambda (x)
7205     (##sys#check-list x 'command-line-arguments)
7206     x) ) )
7207
7208) ; chicken.process-context
7209
7210
7211(module chicken.gc
7212    (current-gc-milliseconds gc memory-statistics
7213     set-finalizer! make-finalizer add-to-finalizer
7214     set-gc-report! force-finalizers)
7215
7216(import scheme)
7217(import chicken.base chicken.fixnum chicken.foreign)
7218(import chicken.internal.syntax)
7219(import (only (scheme base) make-parameter))
7220
7221;;; GC info:
7222
7223(define (current-gc-milliseconds)
7224  (##core#inline "C_i_accumulated_gc_time"))
7225
7226(define (set-gc-report! flag)
7227  (##core#inline "C_set_gc_report" flag))
7228
7229;;; Memory info:
7230
7231(define (memory-statistics)
7232  (let* ((free (##sys#gc #t))
7233	 (info (##sys#memory-info))
7234	 (half-size (fx/ (##sys#slot info 0) 2)))
7235    (vector half-size (fx- half-size free) (##sys#slot info 1))))
7236
7237;;; Finalization:
7238
7239(define-foreign-variable _max_pending_finalizers int "C_max_pending_finalizers")
7240
7241(define ##sys#pending-finalizers
7242  (##sys#make-vector (fx+ (fx* 2 _max_pending_finalizers) 1) (##core#undefined)) )
7243
7244(##sys#setislot ##sys#pending-finalizers 0 0)
7245
7246(define ##sys#set-finalizer! (##core#primitive "C_register_finalizer"))
7247
7248(define ##sys#init-finalizer
7249  (let ((string-append string-append))
7250    (lambda (x y)
7251      (when (fx>= (##core#inline "C_i_live_finalizer_count") _max_pending_finalizers)
7252	(cond ((##core#inline "C_resize_pending_finalizers" (fx* 2 _max_pending_finalizers))
7253	       (set! ##sys#pending-finalizers
7254		 (##sys#vector-resize ##sys#pending-finalizers
7255				      (fx+ (fx* 2 _max_pending_finalizers) 1)
7256				      (##core#undefined)))
7257	       (when (##sys#debug-mode?)
7258		 (##sys#print
7259		  (string-append
7260		   "[debug] too many finalizers ("
7261		   (##sys#number->string
7262		    (##core#inline "C_i_live_finalizer_count"))
7263		   "), resized max finalizers to "
7264		   (##sys#number->string _max_pending_finalizers)
7265		   "\n")
7266		  #f ##sys#standard-error)))
7267	      (else
7268	       (when (##sys#debug-mode?)
7269		 (##sys#print
7270		  (string-append
7271		   "[debug] too many finalizers ("
7272		   (##core#inline "C_i_live_finalizer_count")
7273		   "), forcing ...\n")
7274		  #f ##sys#standard-error))
7275	       (##sys#force-finalizers) ) ) )
7276      (##sys#set-finalizer! x y) ) ) )
7277
7278(define set-finalizer! ##sys#init-finalizer)
7279
7280(define finalizer-tag (vector 'finalizer))
7281
7282(define (finalizer? x)
7283  (and (pair? x) (eq? finalizer-tag (##sys#slot x 0))) )
7284
7285(define (make-finalizer . objects)
7286  (let ((q (##sys#make-event-queue)))
7287    (define (handler o) (##sys#add-event-to-queue! q o))
7288    (define (handle o) (##sys#init-finalizer o handler))
7289    (for-each handle objects)
7290    (##sys#decorate-lambda
7291       (lambda (#!optional mode)
7292         (if mode
7293             (##sys#wait-for-next-event q)
7294             (##sys#get-next-event q)))
7295       finalizer?
7296       (lambda (proc i)
7297         (##sys#setslot proc i (cons finalizer-tag handle))
7298         proc))))
7299
7300(define (add-to-finalizer f . objects)
7301  (let ((af (and (procedure? f)
7302                 (##sys#lambda-decoration f finalizer?))))
7303    (unless af
7304      (error 'add-to-finalizer "bad argument type - not a finalizer procedure"
7305             f))
7306    (for-each (cdr af) objects)))
7307
7308(define ##sys#run-pending-finalizers
7309  (let ((vector-fill! vector-fill!)
7310	(string-append string-append)
7311	(working-thread #f) )
7312    (lambda (state)
7313      (cond
7314       ((not working-thread)
7315	(set! working-thread ##sys#current-thread)
7316	(let* ((c (##sys#slot ##sys#pending-finalizers 0)) )
7317	  (when (##sys#debug-mode?)
7318	    (##sys#print
7319	     (string-append "[debug] running " (##sys#number->string c)
7320			    " finalizer(s) ("
7321			    (##sys#number->string
7322			     (##core#inline "C_i_live_finalizer_count"))
7323			    " live, "
7324			    (##sys#number->string
7325			     (##core#inline "C_i_allocated_finalizer_count"))
7326			    " allocated) ...\n")
7327	     #f ##sys#standard-error))
7328	  (do ([i 0 (fx+ i 1)])
7329	      ((fx>= i c))
7330	    (let ([i2 (fx+ 1 (fx* i 2))])
7331	      (handle-exceptions ex
7332		  (##sys#show-exception-warning ex "in finalizer" #f)
7333		((##sys#slot ##sys#pending-finalizers (fx+ i2 1))
7334		 (##sys#slot ##sys#pending-finalizers i2)) ) ))
7335	  (vector-fill! ##sys#pending-finalizers (##core#undefined))
7336	  (##sys#setislot ##sys#pending-finalizers 0 0)
7337	  (set! working-thread #f)))
7338       (state)         ; Got here due to interrupt; continue w/o error
7339       ((eq? working-thread ##sys#current-thread)
7340	 (##sys#signal-hook
7341	  #:error '##sys#run-pending-finalizers
7342	  "re-entry from finalizer thread (maybe (gc #t) was called from a finalizer)"))
7343       (else
7344	;; Give finalizer thread a change to run
7345	(##sys#thread-yield!)))
7346      (cond ((not state))
7347	    ((procedure? state) (state))
7348	    (state (##sys#context-switch state) ) ) ) ))
7349
7350(define force-finalizers (make-parameter #t))
7351
7352(define (##sys#force-finalizers)
7353  (let loop ()
7354    (let ([n (##sys#gc)])
7355      (cond ((fx> (##sys#slot ##sys#pending-finalizers 0) 0)
7356	     (##sys#run-pending-finalizers #f)
7357	     (loop) )
7358	    (else n) ) ) ))
7359
7360(define (gc . arg)
7361  (let ((a (and (pair? arg) (car arg))))
7362    (if a
7363	(##sys#force-finalizers)
7364	(##sys#gc a)))))
7365
7366;;; Auxilliary definitions for safe use in quasiquoted forms and evaluated code:
7367
7368(define ##sys#list->vector list->vector)
7369(define ##sys#list list)
7370(define ##sys#length length)
7371(define ##sys#cons cons)
7372(define ##sys#append append)
7373(define ##sys#vector vector)
7374(define ##sys#apply apply)
7375(define ##sys#values values)
7376(define ##sys#equal? equal?)
7377(define ##sys#car car)
7378(define ##sys#cdr cdr)
7379(define ##sys#pair? pair?)
7380(define ##sys#vector? vector?)
7381(define ##sys#vector->list vector->list)
7382(define ##sys#vector-length vector-length)
7383(define ##sys#vector-ref vector-ref)
7384(define ##sys#>= >=)
7385(define ##sys#= =)
7386(define ##sys#+ +)
7387(define ##sys#eq? eq?)
7388(define ##sys#eqv? eqv?)
7389(define ##sys#list? list?)
7390(define ##sys#null? null?)
7391(define ##sys#map-n map)
7392
7393;;; We need this here so `location' works:
7394
7395(define (##sys#make-locative obj index weak? loc)
7396  (cond [(##sys#immediate? obj)
7397	 (##sys#signal-hook #:type-error loc "locative cannot refer to immediate object" obj) ]
7398	[(or (vector? obj) (pair? obj))
7399	 (##sys#check-range index 0 (##sys#size obj) loc)
7400	 (##core#inline_allocate ("C_a_i_make_locative" 5) 0 obj index weak?) ]
7401	[(and (##core#inline "C_blockp" obj)
7402	      (##core#inline "C_bytevectorp" obj) )
7403	 (##sys#check-range index 0 (##sys#size obj) loc)
7404	 (##core#inline_allocate ("C_a_i_make_locative" 5) 2 obj index weak?) ]
7405	[(##sys#generic-structure? obj)
7406	 (case (##sys#slot obj 0)
7407	   ((u8vector)
7408	    (let ([v (##sys#slot obj 1)])
7409	      (##sys#check-range index 0 (##sys#size v) loc)
7410	      (##core#inline_allocate ("C_a_i_make_locative" 5) 2 v index weak?))  )
7411	   ((s8vector)
7412	    (let ([v (##sys#slot obj 1)])
7413	      (##sys#check-range index 0 (##sys#size v) loc)
7414	      (##core#inline_allocate ("C_a_i_make_locative" 5) 3 v index weak?) ) )
7415	   ((u16vector)
7416	    (let ([v (##sys#slot obj 1)])
7417	      (##sys#check-range index 0 (##sys#size v) loc)
7418	      (##core#inline_allocate ("C_a_i_make_locative" 5) 4 v index weak?) ) )
7419	   ((s16vector)
7420	    (let ([v (##sys#slot obj 1)])
7421	      (##sys#check-range index 0 (##sys#size v) loc)
7422	      (##core#inline_allocate ("C_a_i_make_locative" 5) 5 v index weak?) ) )
7423	   ((u32vector)
7424	    (let ([v (##sys#slot obj 1)])
7425	      (##sys#check-range index 0 (##sys#size v) loc)
7426	      (##core#inline_allocate ("C_a_i_make_locative" 5) 6 v index weak?) ) )
7427	   ((s32vector)
7428	    (let ([v (##sys#slot obj 1)])
7429	      (##sys#check-range index 0 (##sys#size v) loc)
7430	      (##core#inline_allocate ("C_a_i_make_locative" 5) 7 v index weak?) ) )
7431	   ((u64vector)
7432	    (let ([v (##sys#slot obj 1)])
7433	      (##sys#check-range index 0 (##sys#size v) loc)
7434	      (##core#inline_allocate ("C_a_i_make_locative" 5) 8 v index weak?) ) )
7435	   ((s64vector)
7436	    (let ([v (##sys#slot obj 1)])
7437	      (##sys#check-range index 0 (##sys#size v) loc)
7438	      (##core#inline_allocate ("C_a_i_make_locative" 5) 9 v index weak?) ) )
7439	   ((f32vector)
7440	    (let ([v (##sys#slot obj 1)])
7441	      (##sys#check-range index 0 (##sys#size v) loc)
7442	      (##core#inline_allocate ("C_a_i_make_locative" 5) 10 v index weak?) ) )
7443	   ((f64vector)
7444	    (let ([v (##sys#slot obj 1)])
7445	      (##sys#check-range index 0 (##sys#size v) loc)
7446	      (##core#inline_allocate ("C_a_i_make_locative" 5) 11 v index weak?) ) )
7447	   ;;XXX pointer-vector currently not supported
7448	   (else
7449	    (##sys#check-range index 0 (fx- (##sys#size obj) 1) loc)
7450	    (##core#inline_allocate ("C_a_i_make_locative" 5) 0 obj (fx+ index 1) weak?) ) ) ]
7451	((string? obj)
7452	 (let ((bv (##sys#slot obj 0))
7453               (p (##core#inline "C_utf_position" obj index)))
7454           (##sys#check-range index 0 (##sys#slot obj 1) loc)
7455  	   (##core#inline_allocate ("C_a_i_make_locative" 5) 1 bv p weak?) ) )
7456	[else
7457	 (##sys#signal-hook
7458	  #:type-error loc
7459	  "bad argument type - locative cannot refer to objects of this type"
7460	  obj) ] ) )
7461
7462
7463;;; Property lists
7464
7465(module chicken.plist
7466  (get get-properties put! remprop! symbol-plist)
7467
7468(import scheme)
7469(import (only chicken.base getter-with-setter))
7470(import chicken.internal.syntax)
7471
7472(define (put! sym prop val)
7473  (##sys#check-symbol sym 'put!)
7474  (##core#inline_allocate ("C_a_i_putprop" 8) sym prop val) )
7475
7476(define (get sym prop #!optional default)
7477  (##sys#check-symbol sym 'get)
7478  (##core#inline "C_i_getprop" sym prop default))
7479
7480(define ##sys#put! put!)
7481(define ##sys#get get)
7482
7483(set! get (getter-with-setter get put!))
7484
7485(define (remprop! sym prop)
7486  (##sys#check-symbol sym 'remprop!)
7487  (let loop ((plist (##sys#slot sym 2)) (ptl #f))
7488    (and (not (null? plist))
7489	 (let* ((tl (##sys#slot plist 1))
7490		(nxt (##sys#slot tl 1)))
7491	   (or (and (eq? (##sys#slot plist 0) prop)
7492		    (begin
7493		      (if ptl
7494			  (##sys#setslot ptl 1 nxt)
7495			  (##sys#setslot sym 2 nxt) )
7496		      #t ) )
7497	       (loop nxt tl) ) ) ) )
7498  (when (null? (##sys#slot sym 2))
7499    ;; This will only unpersist if symbol is also unbound
7500    (##core#inline "C_i_unpersist_symbol" sym) ) )
7501
7502(define symbol-plist
7503  (getter-with-setter
7504   (lambda (sym)
7505     (##sys#check-symbol sym 'symbol-plist)
7506     (##sys#slot sym 2) )
7507   (lambda (sym lst)
7508     (##sys#check-symbol sym 'symbol-plist)
7509     (##sys#check-list lst 'symbol-plist/setter)
7510     (if (##core#inline "C_i_fixnumevenp" (##core#inline "C_i_length" lst))
7511	 (##sys#setslot sym 2 lst)
7512	 (##sys#signal-hook
7513	  #:type-error "property-list must be of even length"
7514	  lst sym))
7515     (if (null? lst)
7516	 (##core#inline "C_i_unpersist_symbol" sym)
7517	 (##core#inline "C_i_persist_symbol" sym)))
7518   "(chicken.plist#symbol-plist sym)"))
7519
7520(define (get-properties sym props)
7521  (##sys#check-symbol sym 'get-properties)
7522  (unless (pair? props)
7523    (set! props (list props)) )
7524  (let loop ((plist (##sys#slot sym 2)))
7525    (if (null? plist)
7526	(values #f #f #f)
7527	(let* ((prop (##sys#slot plist 0))
7528	       (tl (##sys#slot plist 1))
7529	       (nxt (##sys#slot tl 1)))
7530	  (if (memq prop props)
7531	      (values prop (##sys#slot tl 0) nxt)
7532	      (loop nxt) ) ) ) ) )
7533
7534) ; chicken.plist
7535
7536
7537;;; Print timing information (support for "time" macro):
7538
7539(define (##sys#display-times info)
7540  (define (pstr str) (##sys#print str #f ##sys#standard-error))
7541  (define (pchr chr) (##sys#write-char-0 chr ##sys#standard-error))
7542  (define (pnum num)
7543    (##sys#print (if (zero? num) "0" (##sys#number->string num)) #f ##sys#standard-error))
7544  (define (round-to x y) ; Convert to fp with y digits after the point
7545    (/ (round (* x (expt 10 y))) (expt 10.0 y)))
7546  (define (pmem bytes)
7547    (cond ((> bytes (expt 1024 3))
7548	   (pnum (round-to (/ bytes (expt 1024 3)) 2)) (pstr " GiB"))
7549	  ((> bytes (expt 1024 2))
7550	   (pnum (round-to (/ bytes (expt 1024 2)) 2)) (pstr " MiB"))
7551	  ((> bytes 1024)
7552	   (pnum (round-to (/ bytes 1024) 2)) (pstr " KiB"))
7553	  (else (pnum bytes) (pstr " bytes"))))
7554  (##sys#flush-output ##sys#standard-output)
7555  (pnum (##sys#slot info 0))
7556  (pstr "s CPU time")
7557  (let ((gctime (##sys#slot info 1)))
7558    (when (> gctime 0)
7559      (pstr ", ")
7560      (pnum gctime)
7561      (pstr "s GC time (major)")))
7562  (let ((mut (##sys#slot info 2))
7563	(umut (##sys#slot info 3)))
7564    (when (fx> mut 0)
7565      (pstr ", ")
7566      (pnum mut)
7567      (pchr #\/)
7568      (pnum umut)
7569      (pstr " mutations (total/tracked)")))
7570  (let ((minor (##sys#slot info 4))
7571	(major (##sys#slot info 5)))
7572    (when (or (fx> minor 0) (fx> major 0))
7573      (pstr ", ")
7574      (pnum major)
7575      (pchr #\/)
7576      (pnum minor)
7577      (pstr " GCs (major/minor)")))
7578  (let ((maximum-heap-usage (##sys#slot info 6)))
7579    (pstr ", maximum live heap: ")
7580    (pmem maximum-heap-usage))
7581  (##sys#write-char-0 #\newline ##sys#standard-error)
7582  (##sys#flush-output ##sys#standard-error))
7583
7584
7585;;; Dump heap state to stderr:
7586
7587(define ##sys#dump-heap-state (##core#primitive "C_dump_heap_state"))
7588(define ##sys#filter-heap-objects (##core#primitive "C_filter_heap_objects"))
7589
7590
7591;;; Platform configuration inquiry:
7592
7593(module chicken.platform
7594    (build-platform chicken-version chicken-home
7595     feature? machine-byte-order machine-type
7596     repository-path installation-repository
7597     register-feature! unregister-feature! include-path
7598     software-type software-version return-to-host
7599     system-config-directory system-cache-directory
7600     )
7601
7602(import scheme)
7603(import chicken.fixnum chicken.foreign chicken.keyword chicken.process-context)
7604(import chicken.internal.syntax)
7605(import (only (scheme base) make-parameter))
7606
7607(define software-type
7608  (let ((sym (string->symbol ((##core#primitive "C_software_type")))))
7609    (lambda () sym)))
7610
7611(define machine-type
7612  (let ((sym (string->symbol ((##core#primitive "C_machine_type")))))
7613    (lambda () sym)))
7614
7615(define machine-byte-order
7616  (let ((sym (string->symbol ((##core#primitive "C_machine_byte_order")))))
7617    (lambda () sym)))
7618
7619(define software-version
7620  (let ((sym (string->symbol ((##core#primitive "C_software_version")))))
7621    (lambda () sym)))
7622
7623(define build-platform
7624  (let ((sym (string->symbol ((##core#primitive "C_build_platform")))))
7625    (lambda () sym)))
7626
7627(define ##sys#windows-platform
7628  (and (eq? 'windows (software-type))
7629       ;; Still windows even if 'Linux-like'
7630       (not (eq? 'cygwin (software-version)))))
7631
7632(define (chicken-version #!optional full)
7633  (define (get-config)
7634    (let ((bp (build-platform))
7635	  (st (software-type))
7636	  (sv (software-version))
7637	  (mt (machine-type)))
7638      (define (str x)
7639	(if (eq? 'unknown x)
7640	    ""
7641	    (string-append (symbol->string x) "-")))
7642      (string-append (str sv) (str st) (str bp) (##sys#symbol->string/shared mt))))
7643  (if full
7644      (let ((spec (string-append
7645		   " " (number->string (foreign-value "C_WORD_SIZE" int)) "bit"
7646		   (if (feature? #:dload) " dload" "")
7647		   (if (feature? #:ptables) " ptables" "")
7648		   (if (feature? #:gchooks) " gchooks" "")
7649		   (if (feature? #:cross-chicken) " cross" ""))))
7650	(string-append
7651	 "Version " ##sys#build-version
7652	 (if ##sys#build-branch (string-append " (" ##sys#build-branch ")") "")
7653	 (if ##sys#build-id (string-append " (rev " ##sys#build-id ")") "")
7654	 "\n"
7655	 (get-config)
7656	 (if (zero? (string-length spec))
7657	     ""
7658	     (string-append " [" spec " ]"))))
7659      ##sys#build-version))
7660
7661;;; Installation locations
7662
7663(define-foreign-variable binary-version int "C_BINARY_VERSION")
7664(define-foreign-variable installation-home c-string "C_INSTALL_SHARE_HOME")
7665(define-foreign-variable install-egg-home c-string "C_INSTALL_EGG_HOME")
7666
7667;; DEPRECATED
7668(define (chicken-home) installation-home)
7669
7670(define (include-path #!optional new)
7671  (when new
7672    (##sys#check-list new 'include-path)
7673    (set! ##sys#include-pathnames new))
7674  ##include-pathnames)
7675
7676(define path-list-separator
7677  (if ##sys#windows-platform #\; #\:))
7678
7679(define ##sys#split-path
7680  (let ((cache '(#f)))
7681    (lambda (path)
7682      (cond ((not path) '())
7683            ((equal? path (car cache))
7684             (cdr cache))
7685            (else
7686              (let* ((len (string-length path))
7687                     (lst (let loop ((start 0) (pos 0))
7688                            (cond ((fx>= pos len)
7689                                   (if (fx= pos start)
7690                                       '()
7691                                       (list (substring path start pos))))
7692                                  ((char=? (string-ref path pos)
7693                                           path-list-separator)
7694                                   (cons (substring path start pos)
7695                                         (loop (fx+ pos 1)
7696                                               (fx+ pos 1))))
7697                                  (else
7698                                    (loop start (fx+ pos 1)))))))
7699                (set! cache (cons path lst))
7700                lst))))))
7701
7702(define repository-path
7703  (make-parameter
7704   (cond ((foreign-value "C_private_repository_path()" c-string)
7705           => list)
7706         ((get-environment-variable "CHICKEN_REPOSITORY_PATH")
7707           => ##sys#split-path)
7708         (install-egg-home
7709           => list)
7710         (else #f))
7711   (lambda (new)
7712     (and new
7713          (begin
7714            (##sys#check-list new 'repository-path)
7715            (for-each (lambda (p) (##sys#check-string p 'repository-path)) new)
7716            new)))))
7717
7718(define installation-repository
7719  (make-parameter
7720   (or (foreign-value "C_private_repository_path()" c-string)
7721       (get-environment-variable "CHICKEN_INSTALL_REPOSITORY")
7722       install-egg-home)))
7723
7724(define (chop-separator str)
7725  (let ((len (fx- (string-length str) 1)))
7726    (if (and (> len 0)
7727             (memq (string-ref str len) '(#\\ #\/)))
7728        (substring str 0 len)
7729        str) ) )
7730
7731(define ##sys#include-pathnames
7732  (cond ((get-environment-variable "CHICKEN_INCLUDE_PATH")
7733         => (lambda (p)
7734              (map chop-separator (##sys#split-path p))))
7735        (else (list installation-home))))
7736
7737(define (include-path) ##sys#include-pathnames)
7738
7739
7740;;; Feature identifiers:
7741
7742(define ->feature-id ; TODO: export this?  It might be useful..
7743  (let ()
7744    (define (err . args)
7745      (apply ##sys#signal-hook #:type-error "bad argument type - not a valid feature identifer" args))
7746    (define (prefix s)
7747      (if s (##sys#string-append s "-") ""))
7748    (lambda (x)
7749      (cond ((keyword? x) x)
7750	    ((string? x) (string->keyword x))
7751	    ((symbol? x) (string->keyword (##sys#symbol->string/shared x)))
7752	    (else (err x))))))
7753
7754(define ##sys#features
7755  '(#:chicken
7756    #:srfi-6 #:srfi-12 #:srfi-17 #:srfi-23 #:srfi-30
7757    #:exact-complex #:srfi-39 #:srfi-62 #:srfi-88 #:full-numeric-tower #:full-unicode))
7758
7759;; Add system features:
7760
7761;; all platforms we support have this
7762(set! ##sys#features `(#:posix #:r7rs #:ieee-float #:ratios ,@##sys#features))
7763
7764(let ((check (lambda (f)
7765	       (unless (eq? 'unknown f)
7766		 (set! ##sys#features (cons (->feature-id f) ##sys#features))))))
7767  (check (software-type))
7768  (check (software-version))
7769  (check (build-platform))
7770  (check (machine-type))
7771  (check (machine-byte-order)))
7772
7773(when (foreign-value "HAVE_DLOAD" bool)
7774  (set! ##sys#features (cons #:dload ##sys#features)))
7775(when (foreign-value "HAVE_PTABLES" bool)
7776  (set! ##sys#features (cons #:ptables ##sys#features)))
7777(when (foreign-value "HAVE_GCHOOKS" bool)
7778  (set! ##sys#features (cons #:gchooks ##sys#features)))
7779(when (foreign-value "IS_CROSS_CHICKEN" bool)
7780  (set! ##sys#features (cons #:cross-chicken ##sys#features)))
7781
7782;; Register a feature to represent the word size (e.g., 32bit, 64bit)
7783(set! ##sys#features
7784      (cons (string->keyword
7785             (string-append
7786              (number->string (foreign-value "C_WORD_SIZE" int))
7787              "bit"))
7788            ##sys#features))
7789
7790(set! ##sys#features
7791  (let ((major (##sys#number->string (foreign-value "C_MAJOR_VERSION" int)))
7792	(minor (##sys#number->string (foreign-value "C_MINOR_VERSION" int))))
7793    (cons (->feature-id (string-append "chicken-" major))
7794	  (cons (->feature-id (string-append "chicken-" major "." minor))
7795		##sys#features))))
7796
7797(define (register-feature! . fs)
7798  (for-each
7799   (lambda (f)
7800     (let ((id (->feature-id f)))
7801       (unless (memq id ##sys#features) (set! ##sys#features (cons id ##sys#features)))))
7802   fs)
7803  (##core#undefined))
7804
7805(define (unregister-feature! . fs)
7806  (let ((fs (map ->feature-id fs)))
7807    (set! ##sys#features
7808      (let loop ((ffs ##sys#features))
7809	(if (null? ffs)
7810	    '()
7811	    (let ((f (##sys#slot ffs 0))
7812		  (r (##sys#slot ffs 1)))
7813	      (if (memq f fs)
7814		  (loop r)
7815		  (cons f (loop r)))))))
7816    (##core#undefined)))
7817
7818(define (feature? . ids)
7819  (let loop ((ids ids))
7820    (or (null? ids)
7821	(and (memq (->feature-id (##sys#slot ids 0)) ##sys#features)
7822	     (loop (##sys#slot ids 1))))))
7823
7824(define return-to-host
7825  (##core#primitive "C_return_to_host"))
7826
7827(define (system-config-directory)
7828  (or (get-environment-variable "XDG_CONFIG_HOME")
7829      (if ##sys#windows-platform
7830          (get-environment-variable "APPDATA")
7831          (let ((home (get-environment-variable "HOME")))
7832            (and home (string-append home "/.config"))))))
7833
7834(define (system-cache-directory)
7835  (or (get-environment-variable "XDG_CACHE_HOME")
7836      (if ##sys#windows-platform
7837          (or (get-environment-variable "LOCALAPPDATA")
7838              (get-environment-variable "APPDATA"))
7839          (let ((home (get-environment-variable "HOME")))
7840            (and home (string-append home "/.cache"))))))
7841
7842) ; chicken.platform
7843
7844(set! scheme#features
7845  (lambda ()
7846    (map (lambda (s)
7847         (##sys#string->symbol (##sys#symbol->string s)))
7848       ##sys#features)))
7849
7850(set! scheme#make-list
7851 (lambda (n #!optional fill)
7852  (##sys#check-integer n 'make-list)
7853  (unless (fx>= n 0)
7854    (error 'make-list "not a positive integer" n))
7855  (do ((i n (fx- i 1))
7856       (result '() (cons fill result)))
7857      ((eq? i 0) result))))
7858
7859(set! scheme#list-set!
7860 (lambda (l n obj)
7861  (##sys#check-integer n 'list-set!)
7862  (unless (fx>= n 0)
7863    (error 'list-set! "not a positive integer" n))
7864  (do ((i n (fx- i 1))
7865       (l l (cdr l)))
7866      ((fx= i 0) (set-car! l obj))
7867    (when (null? l)
7868      (error 'list-set! "out of range")))))
7869
7870;; TODO: Test if this is the quickest way to do this, or whether we
7871;; should just cons recursively like our SRFI-1 implementation does.
7872(set! scheme#list-copy
7873 (lambda (lst)
7874  (cond ((pair? lst)
7875         (let lp ((res '())
7876                  (lst lst))
7877           (if (pair? lst)
7878               (lp (cons (car lst) res) (cdr lst))
7879               (append (##sys#fast-reverse res) lst))))
7880        (else lst))))
7881
7882(set! scheme#string->vector
7883 (lambda (s #!optional start end)
7884  (##sys#check-string s 'string->vector)
7885  (let ((s->v (lambda (s start end)
7886                (let* ((len (##sys#slot s 1)))
7887                  (##sys#check-range/including start 0 end 'string->vector)
7888                  (##sys#check-range/including end start len 'string->vector)
7889                  (let ((v (##sys#make-vector (fx- end start))))
7890                    (do ((ti 0 (fx+ ti 1))
7891                         (fi start (fx+ fi 1)))
7892                        ((fx= fi end) v)
7893                      (##sys#setslot v ti (##core#inline "C_utf_subchar" s fi))))))))
7894    (if end
7895        (s->v s start end)
7896        (s->v s (or start 0) (string-length s))))))
7897
7898(set! scheme#vector->string
7899  (lambda (v #!optional start end)
7900    (##sys#check-vector v 'vector->string)
7901    (let ((v->s (lambda (v start end)
7902                  (let ((len (##sys#size v)))
7903                    (##sys#check-range/including start 0 end 'vector->string)
7904                    (##sys#check-range/including end start len 'vector->string)
7905                    (let ((bv (##sys#make-bytevector (fx* (fx- end start) 4))))
7906                      (let loop ((i 0)
7907                                 (p start))
7908                        (if (fx= p end)
7909                            (##sys#buffer->string! bv i)
7910                            (let ((c (##sys#slot v p)))
7911                              (##sys#check-char c 'vector->string)
7912                              (loop (##core#inline "C_utf_insert" bv i c)
7913                                    (fx+ p 1))))))))))
7914      (if end
7915          (v->s v start end)
7916          (v->s v (or start 0) (##sys#size v))))))
7917
7918(set! scheme#string-map
7919  (lambda (proc str . more)
7920    (define (%string-map proc s)
7921      (let* ((len (string-length s))
7922             (ans (##sys#make-bytevector (fx* 4 len))))
7923        (let loop ((i 0)
7924                   (j 0))
7925          (if (fx>= j len)
7926              (##sys#buffer->string! ans i)
7927              (let ((r (proc (string-ref s j))))
7928                (##sys#check-char r 'string-map)
7929                (loop (##core#inline "C_utf_insert" ans i r)
7930                      (fx+ j 1)))))))
7931    (if (null? more)
7932        (%string-map proc str)
7933        (let ((strs (cons str more)))
7934          (##sys#check-closure proc 'string-map)
7935          (##sys#for-each (cut ##sys#check-string <> 'string-map) strs)
7936          (let* ((len (foldl fxmin most-positive-fixnum (map string-length strs)))
7937                 (str (##sys#make-string len)))
7938            (do ((i 0 (fx+ i 1)))
7939                ((fx= i len) str)
7940                (string-set! str i (apply proc (map (cut string-ref <> i) strs)))))))))
7941
7942(set! scheme#string-for-each
7943  (lambda (proc str . more)
7944    (define (%string-for-each proc s)
7945      (let ((len (string-length s)))
7946        (let lp ((i 0))
7947          (if (fx< i len)
7948              (begin (proc (string-ref s i))
7949                (lp (fx+ i 1)))))))
7950    (if (null? more)
7951        (%string-for-each proc str)
7952        (let ((strs (cons str more)))
7953          (##sys#check-closure proc 'string-for-each)
7954          (##sys#for-each (cut ##sys#check-string <> 'string-for-each) strs)
7955          (let* ((len (foldl fxmin most-positive-fixnum (map string-length strs)))
7956                 (str (##sys#make-string len)))
7957            (do ((i 0 (fx+ i 1)))
7958                ((fx= i len))
7959                (apply proc (map (cut string-ref <> i) strs))))))))
7960
7961(set! scheme#vector-map
7962 (lambda (proc v . more)
7963  (cond ((null? more)
7964         (##sys#check-closure proc 'vector-map)
7965         (##sys#check-vector v 'vector-map)
7966         (let* ((len (##sys#size v))
7967                (vec (##sys#make-vector len)))
7968           (do ((i 0 (fx+ i 1)))
7969               ((fx= i len) vec)
7970               (##sys#setslot vec i (proc (##sys#slot v i))))))
7971        (else
7972          (let ((vs (cons v more)))
7973            (##sys#check-closure proc 'vector-map)
7974            (##sys#for-each (cut ##sys#check-vector <> 'vector-map) vs)
7975            (let* ((len (foldl fxmin most-positive-fixnum (map ##sys#size vs)))
7976                   (vec (##sys#make-vector len)))
7977              (do ((i 0 (fx+ i 1)))
7978                  ((fx= i len) vec)
7979                  (##sys#setslot vec i (apply proc (map (cut vector-ref <> i) vs))))))))))
7980
7981(set! scheme#vector-for-each
7982 (lambda (proc v . more)
7983  (cond ((null? more)
7984         (##sys#check-closure proc 'vector-for-each)
7985         (##sys#check-vector v 'vector-for-each)
7986         (let ((len (##sys#size v)))
7987           (do ((i 0 (fx+ i 1)))
7988               ((fx= i len))
7989               (proc (##sys#slot v i)))))
7990        (else
7991          (let ((vs (cons v more)))
7992            (##sys#check-closure proc 'vector-for-each)
7993            (##sys#for-each (cut ##sys#check-vector <> 'vector-for-each) vs)
7994            (let* ((len (foldl fxmin most-positive-fixnum (map ##sys#size vs)))
7995                   (vec (##sys#make-vector len)))
7996              (do ((i 0 (fx+ i 1)))
7997                  ((fx= i len) vec)
7998                  (apply proc (map (cut vector-ref <> i) vs)))))))))
7999
8000(set! scheme#close-port
8001 (lambda (port)
8002  (##sys#check-port port 'close-port)
8003  (when (##core#inline "C_port_openp" port 1)
8004    ((##sys#slot (##sys#slot port 2) 4) port 1))
8005  (when (##core#inline "C_port_openp" port 2)
8006    ((##sys#slot (##sys#slot port 2) 4) port 2))
8007  (##sys#setislot port 8 0)))
8008
8009(set! scheme#call-with-port
8010 (lambda (port proc)
8011  (receive ret
8012      (proc port)
8013    (scheme#close-port port)
8014    (apply values ret))))
8015
8016(set! scheme#eof-object (lambda () #!eof))
8017
8018(set! scheme#peek-u8
8019  (lambda (#!optional (port ##sys#standard-input))
8020    (let ((c (peek-char port)))
8021      (if (eof-object? c)
8022          c
8023          (let ((d (char->integer c)))
8024            (if (fx< d 256) 
8025                d
8026                (let ((bv (##sys#make-bytevector 4)))
8027                  (##sys#encode-char c bv (##sys#slot port 15))
8028                  (##core#inline "C_subbyte" bv 0))))))))
8029
8030(set! scheme#write-string
8031  (lambda (s #!optional (port ##sys#standard-output) start end)
8032    (##sys#check-string s 'write-string)
8033    (##sys#check-output-port port #t 'write-string)
8034    (if start
8035        (##sys#check-fixnum start 'write-string)
8036        (set! start 0))
8037    (if end
8038        (##sys#check-fixnum end 'write-string)
8039        (set! end (string-length s)))
8040    (let* ((part (if start (substring s start end) s))
8041           (bv (##sys#slot part 0))
8042           (len (fx- (##sys#size bv) 1)))
8043      ((##sys#slot (##sys#slot port 2) 3) ; write-bytevector
8044       port bv 0 len))))
8045
8046
8047;; I/O
8048
8049(module chicken.io
8050  (read-list read-buffered read-byte read-line
8051   read-lines read-string read-string! read-token
8052   write-byte write-line write-bytevector read-bytevector
8053   read-bytevector!)
8054
8055(import scheme chicken.base chicken.fixnum)
8056(import chicken.internal.syntax)
8057(import (only (scheme base) open-output-string get-output-string))
8058
8059
8060;;; Read expressions from file:
8061
8062(define read-list
8063  (let ((read read))
8064    (lambda (#!optional (port ##sys#standard-input) (reader read) max)
8065      (##sys#check-input-port port #t 'read-list)
8066      (do ((x (reader port) (reader port))
8067	   (i 0 (fx+ i 1))
8068	   (xs '() (cons x xs)))
8069	  ((or (eof-object? x) (and max (fx>= i max)))
8070	   (##sys#fast-reverse xs))))))
8071
8072
8073;;; Line I/O:
8074
8075(define read-line
8076  (let ()
8077    (lambda args
8078      (let* ([parg (pair? args)]
8079	     [p (if parg (car args) ##sys#standard-input)]
8080	     [limit (and parg (pair? (cdr args)) (cadr args))])
8081	(##sys#check-input-port p #t 'read-line)
8082	(cond ((##sys#slot (##sys#slot p 2) 8) => (lambda (rl) (rl p limit)))
8083	      (else
8084	       (let* ((buffer-len (if limit limit 256))
8085		      (buffer (##sys#make-string buffer-len)))
8086		 (let loop ([i 0])
8087		   (if (and limit (fx>= i limit))
8088		       (##sys#substring buffer 0 i)
8089		       (let ([c (##sys#read-char-0 p)])
8090			 (if (eof-object? c)
8091			     (if (fx= i 0)
8092				 c
8093				 (##sys#substring buffer 0 i) )
8094			     (case c
8095			       [(#\newline) (##sys#substring buffer 0 i)]
8096			       [(#\return)
8097				(let ([c (peek-char p)])
8098				  (if (char=? c #\newline)
8099				      (begin (##sys#read-char-0 p)
8100					     (##sys#substring buffer 0 i))
8101				      (##sys#substring buffer 0 i) ) ) ]
8102			       [else
8103				(when (fx>= i buffer-len)
8104				  (set! buffer
8105				    (##sys#string-append buffer (make-string buffer-len)))
8106				  (set! buffer-len (fx+ buffer-len buffer-len)) )
8107				(string-set! buffer i c)
8108				(loop (fx+ i 1)) ] ) ) ) ) ) ) ) ) ) ) ) )
8109
8110(define read-lines
8111  (lambda (#!optional (port ##sys#standard-input) max)
8112    (##sys#check-input-port port #t 'read-lines)
8113    (when max (##sys#check-fixnum max 'read-lines))
8114    (let loop ((lns '())
8115	       (n (or max most-positive-fixnum)))
8116      (if (eq? n 0)
8117	  (##sys#fast-reverse lns)
8118	  (let ((ln (read-line port)))
8119	    (if (eof-object? ln)
8120		(##sys#fast-reverse lns)
8121		(loop (cons ln lns) (fx- n 1))))))))
8122
8123(define write-line
8124  (lambda (str . port)
8125    (let* ((p (if (##core#inline "C_eqp" port '())
8126                  ##sys#standard-output
8127                  (##sys#slot port 0) ) ))
8128      (##sys#check-output-port p #t 'write-line)
8129      (##sys#check-string str 'write-line)
8130      (let ((bv (##sys#slot str 0)))
8131        ((##sys#slot (##sys#slot p 2) 3)  ; write-bytevector
8132         p
8133         bv
8134         0
8135         (fx- (##sys#size bv) 1)))
8136      (##sys#write-char-0 #\newline p))))
8137
8138
8139;;; Extended I/O
8140
8141(define (read-bytevector!/port n dest port start)
8142  (if (eq? n 0)
8143      0
8144      (let ((rdbvec (##sys#slot (##sys#slot port 2) 7))) ; read-bytevector!
8145        (let loop ((start start) (n n) (m 0))
8146          (let ((n2 (rdbvec port n dest start)))
8147            (##sys#setislot port 5 ; update port-position
8148                            (fx+ (##sys#slot port 5) n2))
8149            (cond ((eq? n2 0) m)
8150                  ((or (not n) (fx< n2 n))
8151                   (loop (fx+ start n2) (and n (fx- n n2)) (fx+ m n2)))
8152                  (else (fx+ n2 m))))))))
8153
8154(define (read-string!/port n dest port start)
8155  (let ((buf (##sys#make-bytevector (fx* n 4)))
8156        (enc (##sys#slot port 15)))
8157    (##sys#encoding-hook
8158     enc
8159     (lambda (decoder _ _)
8160       (define (readb n buf port p)
8161         (let ((bytes (read-bytevector!/port n buf port p)))
8162           (if (eq? enc 'utf-8) ; fast path, avoid copying
8163               bytes
8164               (decoder buf p bytes
8165                        (lambda (dbuf start len)
8166                          (##core#inline "C_copy_memory_with_offset" buf dbuf p start len)
8167                          len)))))
8168       (define (finish un bytes)
8169         (##core#inline "C_utf_overwrite" dest start un buf bytes)
8170         un)
8171       (let loop ((p 0) (n n) (un 0) (bn 0))
8172         (let ((bytes (readb n buf port p)))
8173           (cond ((eq? bytes 0) (finish un bn))
8174                 ((eq? enc 'utf-8)
8175                  ;; read incomplete fragments
8176                  ;; FIXME: hardcoded, should be encoding-specific!
8177                  (let recount ((bytes bytes))
8178                    (let* ((fc (##core#inline "C_utf_fragment_counts" buf p bytes))
8179                           (full (fxshr fc 4))
8180                           (left (fxand fc 15))
8181                           (total (fx+ un full))
8182                           (tbytes (fx+ bn bytes))
8183                           (remain (fx- n full)))
8184                      (cond ((fx> left 0)
8185                             (let ((b2 (readb left buf port (fx+ p bytes))))
8186                               (if (fx< b2 left)
8187                                   (finish total tbytes)
8188                                   (recount (fx+ bytes b2)))))
8189                            ((eq? remain 0) (finish total tbytes))
8190                            (else (loop (fx+ p bytes) remain total
8191                                        tbytes))))))
8192                 ((fx> bytes n)
8193                  (loop (fx+ p bytes) (fx- n bytes)
8194                        (fx+ un bytes) (fx+ bn bytes)))
8195                 (else (finish un bn)))))))))
8196
8197(define (read-string! n dest #!optional (port ##sys#standard-input) (start 0))
8198  (##sys#check-input-port port #t 'read-string!)
8199  (##sys#check-string dest 'read-string!)
8200  (when n (##sys#check-fixnum n 'read-string!))
8201  (let ((dest-size (string-length dest)))
8202    (unless (and n (fx<= (fx+ start n) dest-size))
8203      (set! n (fx- dest-size start))))
8204  (##sys#check-fixnum start 'read-string!)
8205  (read-string!/port n dest port start))
8206
8207(define (read-bytevector! dest #!optional (port ##sys#standard-input) (start 0) end)
8208  (##sys#check-input-port port #t 'read-bytevector!)
8209  (##sys#check-bytevector dest 'read-bytevector!)
8210  (##sys#check-fixnum start 'read-bytevector!)
8211  (when end (##sys#check-fixnum end 'read-bytevector!))
8212  (let* ((size (##sys#size dest))
8213         (n (fx- (or end size) start)))
8214    (read-bytevector!/port n dest port start)))
8215
8216(define read-string/port
8217  (lambda (n p)
8218    (cond ((eq? n 0) "") ; Don't attempt to peek (fd might not be ready)
8219          ((eof-object? (##sys#peek-char-0 p)) #!eof)
8220          (n (let* ((str (##sys#make-string n))
8221                    (n2 (read-string!/port n str p 0)))
8222               (if (eq? n n2)
8223                   str
8224                   (##sys#substring str 0 n2))))
8225          (else
8226            (##sys#read-remaining
8227              p
8228              (lambda (buf len)
8229                (##sys#buffer->string/encoding buf 0 len
8230                                               (##sys#slot p 15))))))))
8231
8232(define (##sys#read-remaining p k)
8233  (let ((len 1024))
8234    (let loop ((buf (##sys#make-bytevector len))
8235               (bsize len)
8236               (pos 0))
8237      (let* ((nr (fx- (##sys#size buf) pos))
8238             (n (read-bytevector!/port nr buf p pos)))
8239        (cond ((eq? n nr)
8240               (let* ((bsize2 (fx* bsize 2))
8241                      (buf2 (##sys#make-bytevector bsize2)))
8242                 (##core#inline "C_copy_memory" buf2 buf bsize)
8243                 (loop buf2 bsize2 (fx+ pos n))))
8244              (else (k buf (fx+ n pos))))))))
8245
8246(define read-bytevector/port
8247  (lambda (n p)
8248    (let* ((bv (##sys#make-bytevector n))
8249           (n2 (read-bytevector!/port n bv p 0)))
8250      (if (eq? n n2)
8251          bv
8252          (let ((bv2 (##sys#make-bytevector n2)))
8253            (##core#inline "C_copy_memory" bv2 bv n2)
8254            bv2)))))
8255
8256(define (read-string #!optional n (port ##sys#standard-input))
8257  (##sys#check-input-port port #t 'read-string)
8258  (when n (##sys#check-fixnum n 'read-string))
8259  (read-string/port n port))
8260
8261(define (read-bytevector #!optional n (port ##sys#standard-input))
8262  (##sys#check-input-port port #t 'read-bytevector)
8263  (cond (n (##sys#check-fixnum n 'read-bytevector)
8264           (let ((r (read-bytevector/port n port)))
8265             (if (eq? (##sys#size r) 0)
8266                 #!eof
8267                 r)))
8268        (else
8269          (##sys#read-remaining
8270            port
8271            (lambda (buf len)
8272              (if (eq? len 0)
8273                  #!eof
8274                  (let ((r (##sys#make-bytevector len)))
8275                    (##core#inline "C_copy_memory" r buf len)
8276                    r)))))))
8277
8278
8279;; Make internal reader procedures available for use in srfi-4.scm:
8280
8281(define chicken.io#read-string/port read-string/port)
8282(define chicken.io#read-string!/port read-string!/port)
8283(define chicken.io#read-bytevector/port read-bytevector/port)
8284(define chicken.io#read-bytevector!/port read-bytevector!/port)
8285
8286(define (read-buffered #!optional (port ##sys#standard-input))
8287  (##sys#check-input-port port #t 'read-buffered)
8288  (let ((rb (##sys#slot (##sys#slot port 2) 9))) ; read-buffered method
8289    (if rb
8290	(rb port)
8291	"")))
8292
8293
8294;;; read token of characters that satisfy a predicate
8295
8296(define read-token
8297  (lambda (pred . port)
8298    (let ([port (optional port ##sys#standard-input)])
8299      (##sys#check-input-port port #t 'read-token)
8300      (let ([out (open-output-string)])
8301	(let loop ()
8302	  (let ([c (##sys#peek-char-0 port)])
8303	    (if (and (not (eof-object? c)) (pred c))
8304		(begin
8305		  (##sys#write-char-0 (##sys#read-char-0 port) out)
8306		  (loop) )
8307		(get-output-string out) ) ) ) ) ) ) )
8308
8309
8310;;; Binary I/O
8311
8312(define (read-byte #!optional (port ##sys#standard-input))
8313  (##sys#check-input-port port #t 'read-byte)
8314  (let* ((bv (##sys#make-bytevector 1))
8315         (n (read-bytevector!/port 1 bv port 0)))
8316    (if (fx< n 1)
8317        #!eof
8318        (##core#inline "C_subbyte" bv 0))))
8319
8320(define (write-byte byte #!optional (port ##sys#standard-output))
8321  (##sys#check-fixnum byte 'write-byte)
8322  (##sys#check-output-port port #t 'write-byte)
8323  (let ((bv (##sys#make-bytevector 1 byte)))
8324    ((##sys#slot (##sys#slot port 2) 3) ; write-bytevector
8325     port bv 0 1)))
8326
8327(define (write-bytevector bv #!optional (port ##sys#standard-output) (start 0)
8328                          end)
8329  (##sys#check-bytevector bv 'write-bytevector)
8330  (##sys#check-output-port port #t 'write-bytevector)
8331  (##sys#check-fixnum start 'write-bytevector)
8332  (let ((len (##sys#size bv)))
8333    (##sys#check-range/including start 0 len 'write-bytevector)
8334    (when end (##sys#check-range/including end 0 len 'write-bytevector))
8335    (let ((end (if end (fxmin end len) len)))
8336      ((##sys#slot (##sys#slot port 2) 3) ; write-bytevector
8337       port bv start end))))
8338
8339) ; module chicken.io
Trap