~ chicken-core (master) /library.scm


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