~ chicken-core (chicken-5) /library.scm


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