home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mitsch75.zip / scheme-7_5_17-src.zip / scheme-7.5.17 / src / runtime / load.scm < prev    next >
Text File  |  2001-03-08  |  23KB  |  687 lines

  1. #| -*-Scheme-*-
  2.  
  3. $Id: load.scm,v 14.57 2001/03/08 20:58:23 cph Exp $
  4.  
  5. Copyright (c) 1988-2000 Massachusetts Institute of Technology
  6.  
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or (at
  10. your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful, but
  13. WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15. General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. |#
  21.  
  22. ;;;; Code Loader
  23. ;;; package: (runtime load)
  24.  
  25. (declare (usual-integrations))
  26.  
  27. (define (initialize-package!)
  28.   (set! *purification-root-marker* (intern "#[PURIFICATION-ROOT]"))
  29.   (set! load-noisily? #f)
  30.   (set! load/loading? #f)
  31.   (set! load/suppress-loading-message? #f)
  32.   (set! load/default-types
  33.     `(("com" ,load/internal)
  34.       ("so" ,load-object-file)
  35.       ("sl" ,load-object-file)
  36.       ("bin" ,load/internal)
  37.       ("scm" ,load/internal)))
  38.   (set! fasload/default-types
  39.     `(("com" ,fasload/internal)
  40.       ("bin" ,fasload/internal)))
  41.   (set! load/default-find-pathname-with-type search-types-in-order)
  42.   (set! load/current-pathname)
  43.   (set! condition-type:not-loading
  44.     (make-condition-type 'NOT-LOADING condition-type:error '()
  45.       "No file being loaded."))
  46.   (reset-loaded-object-files!)
  47.   (add-event-receiver! event:after-restart reset-loaded-object-files!)
  48.   (initialize-command-line-parsers)
  49.   (set! hook/process-command-line default/process-command-line)
  50.   (add-event-receiver! event:after-restart process-command-line))
  51.  
  52. (define load-noisily?)
  53. (define load/loading?)
  54. (define load/suppress-loading-message?)
  55. (define load/default-types)
  56. (define load/after-load-hooks)
  57. (define load/current-pathname)
  58. (define condition-type:not-loading)
  59. (define load/default-find-pathname-with-type)
  60. (define fasload/default-types)
  61. (define loaded-object-files)
  62.  
  63. ;;; This is careful to do the minimum number of file existence probes
  64. ;;; before opening the input file.
  65.  
  66. (define (load filename/s #!optional environment syntax-table purify?)
  67.   (let ((environment
  68.      ;; Kludge until optional defaulting fixed.
  69.      (if (or (default-object? environment)
  70.          (eq? environment default-object))
  71.          default-object
  72.          (->environment environment)))
  73.     (syntax-table
  74.      (if (or (default-object? syntax-table)
  75.          (eq? syntax-table default-object))
  76.          default-object
  77.          (guarantee-syntax-table syntax-table 'LOAD)))
  78.     (purify?
  79.      (if (or (default-object? purify?) (eq? purify? default-object))
  80.          #f
  81.          purify?)))
  82.     (handle-load-hooks
  83.      (lambda ()
  84.        (let ((kernel
  85.           (lambda (filename last-file?)
  86.         (call-with-values
  87.             (lambda () (find-pathname filename load/default-types))
  88.           (lambda (pathname loader)
  89.             (fluid-let ((load/current-pathname pathname))
  90.               (let ((load-it
  91.                  (lambda ()
  92.                    (loader pathname
  93.                        environment
  94.                        syntax-table
  95.                        purify?
  96.                        load-noisily?))))
  97.             (cond (last-file? (load-it))
  98.                   (load-noisily? (write-line (load-it)))
  99.                   (else (load-it) unspecific)))))))))
  100.      (if (pair? filename/s)
  101.          (let loop ((filenames filename/s))
  102.            (if (null? (cdr filenames))
  103.            (kernel (car filenames) #t)
  104.            (begin
  105.              (kernel (car filenames) #f)
  106.              (loop (cdr filenames)))))
  107.          (kernel filename/s #t)))))))
  108.  
  109. (define (fasload filename #!optional suppress-loading-message?)
  110.   (call-with-values (lambda () (find-pathname filename fasload/default-types))
  111.     (lambda (pathname loader)
  112.       (loader pathname
  113.           (if (default-object? suppress-loading-message?)
  114.           load/suppress-loading-message?
  115.           suppress-loading-message?)))))
  116.  
  117. (define (current-load-pathname)
  118.   (if (not load/loading?) (error condition-type:not-loading))
  119.   load/current-pathname)
  120.  
  121. (define (load/push-hook! hook)
  122.   (if (not load/loading?) (error condition-type:not-loading))
  123.   (set! load/after-load-hooks (cons hook load/after-load-hooks))
  124.   unspecific)
  125.  
  126. (define (handle-load-hooks thunk)
  127.   (call-with-values
  128.       (lambda ()
  129.     (fluid-let ((load/loading? #t)
  130.             (load/after-load-hooks '()))
  131.       (let ((result (thunk)))
  132.         (values result (reverse load/after-load-hooks)))))
  133.     (lambda (result hooks)
  134.       (for-each (lambda (hook) (hook)) hooks)
  135.       result)))
  136.  
  137. (define default-object
  138.   "default-object")
  139.  
  140. (define (load-noisily filename #!optional environment syntax-table purify?)
  141.   (fluid-let ((load-noisily? #t))
  142.     (load filename
  143.       ;; This defaulting is a kludge until we get the optional
  144.       ;; defaulting fixed.  Right now it must match the defaulting
  145.       ;; of `load'.
  146.       (if (default-object? environment) default-object environment)
  147.       (if (default-object? syntax-table) default-object syntax-table)
  148.       (if (default-object? purify?) default-object purify?))))
  149.  
  150. (define (load-latest . args)
  151.   (fluid-let ((load/default-find-pathname-with-type find-latest-file))
  152.     (apply load args)))
  153.  
  154. (define (fasload-latest . args)
  155.   (fluid-let ((load/default-find-pathname-with-type find-latest-file))
  156.     (apply fasload args)))
  157.  
  158. (define (find-pathname filename default-types)
  159.   (let ((pathname (merge-pathnames filename))
  160.     (fail
  161.      (lambda ()
  162.        (find-pathname (error:file-operation filename
  163.                         "find"
  164.                         "file"
  165.                         "file does not exist"
  166.                         find-pathname
  167.                         (list filename default-types))
  168.               default-types))))
  169.     (cond ((file-exists? pathname)
  170.        (values pathname
  171.            (let ((find-loader
  172.               (lambda (extension)
  173.                 (let ((place (assoc extension default-types)))
  174.                   (and place
  175.                    (cadr place))))))
  176.              (or (and (pathname-type pathname)
  177.                   (find-loader (pathname-type pathname)))
  178.              (find-loader "scm")
  179.              (find-loader "bin")))))
  180.       ((pathname-type pathname)
  181.        (fail))
  182.       (else
  183.        (call-with-values
  184.            (lambda ()
  185.          (load/default-find-pathname-with-type pathname default-types))
  186.          (lambda (pathname loader)
  187.            (if (not pathname)
  188.            (fail)
  189.            (values pathname loader))))))))
  190.  
  191. (define (search-types-in-order pathname default-types)
  192.   (let loop ((types default-types))
  193.     (if (null? types)
  194.     (values #f #f)
  195.      (let ((pathname (pathname-new-type pathname (caar types))))
  196.        (if (file-exists? pathname)
  197.            (values pathname (cadar types))
  198.            (loop (cdr types)))))))
  199.  
  200. (define (find-latest-file pathname default-types)
  201.   (let loop ((types default-types)
  202.          (latest-pathname #f)
  203.          (latest-loader #f)
  204.          (latest-time 0))
  205.     (if (not (pair? types))
  206.     (values latest-pathname latest-loader)
  207.     (let ((pathname (pathname-new-type pathname (caar types)))
  208.           (skip
  209.            (lambda ()
  210.          (loop (cdr types)
  211.                latest-pathname
  212.                latest-loader
  213.                latest-time))))
  214.       (let ((time (file-modification-time-indirect pathname)))
  215.         (if (and time (> time latest-time))
  216.         (loop (cdr types) pathname (cadar types) time)
  217.         (skip)))))))
  218.  
  219. (define (load/internal pathname environment syntax-table purify? load-noisily?)
  220.   (let* ((port (open-input-file pathname))
  221.      (fasl-marker (peek-char port)))
  222.     (if (and (not (eof-object? fasl-marker))
  223.          (= 250 (char->ascii fasl-marker)))
  224.     (begin
  225.       (close-input-port port)
  226.       (load-scode-end (fasload/internal pathname
  227.                         load/suppress-loading-message?)
  228.               environment
  229.               purify?))
  230.     (let ((value-stream
  231.            (lambda ()
  232.          (eval-stream (read-stream port) environment syntax-table))))
  233.       (if load-noisily?
  234.           (write-stream (value-stream)
  235.                 (lambda (exp&value)
  236.                   (hook/repl-write (nearest-repl)
  237.                            (car exp&value)
  238.                            (cdr exp&value))))
  239.           (loading-message load/suppress-loading-message? pathname
  240.         (lambda ()
  241.           (write-stream (value-stream)
  242.                 (lambda (exp&value) exp&value #f)))))))))
  243.  
  244. (define (fasload/internal pathname suppress-loading-message?)
  245.   (let ((value
  246.      (loading-message suppress-loading-message? pathname
  247.        (lambda ()
  248.          ((ucode-primitive binary-fasload) (->namestring pathname))))))
  249.     (fasload/update-debugging-info! value pathname)
  250.     value))
  251.  
  252. (define (load-object-file pathname environment
  253.               syntax-table purify? load-noisily?)
  254.   syntax-table load-noisily?        ; ignored
  255.   (loading-message
  256.    load/suppress-loading-message? pathname
  257.    (lambda ()
  258.      (let* ((handle
  259.          ((ucode-primitive load-object-file 1) (->namestring pathname)))
  260.         (cth
  261.          ((ucode-primitive object-lookup-symbol 3)
  262.           handle "dload_initialize_file" 0)))
  263.        (if (not cth)
  264.        (error "load-object-file: Cannot find init procedure" pathname))
  265.        (let ((scode ((ucode-primitive initialize-c-compiled-block 1)
  266.              ((ucode-primitive address-to-string 1)
  267.               ((ucode-primitive invoke-c-thunk 1)
  268.                cth)))))
  269.      (fasload/update-debugging-info! scode pathname)
  270.      (load-scode-end scode environment purify?))))))
  271.  
  272. (define (load-scode-end scode environment purify?)
  273.   (if purify? (purify (load/purification-root scode)))
  274.   (extended-scode-eval scode
  275.                (if (eq? environment default-object)
  276.                (nearest-repl/environment)
  277.                environment)))
  278.  
  279. (define (load-library-object-file name errors?)
  280.   (let ((directory (system-library-directory-pathname "lib"))
  281.     (nsf
  282.      (lambda ()
  283.        (and errors?
  284.         (error "No library object file of this name:" name)))))
  285.     (if (not directory)
  286.     (nsf))
  287.     (let ((pathname (merge-pathnames name directory)))
  288.       (if (there-exists? loaded-object-files
  289.         (lambda (pathname*)
  290.           (pathname=? pathname pathname*)))
  291.       #t
  292.       (let ((pathname*
  293.          (let ((find
  294.             (lambda (type)
  295.               (let ((pathname (pathname-new-type pathname type)))
  296.                 (and (file-exists? pathname)
  297.                  pathname)))))
  298.            (or (find "so")
  299.                (find "sl")))))
  300.         (cond ((not pathname*)
  301.            (nsf))
  302.           ((ignore-errors (lambda () (load pathname*)))
  303.            => (lambda (condition)
  304.             (if errors?
  305.                 (signal-condition condition)
  306.                 condition)))
  307.           (else
  308.            (set! loaded-object-files
  309.              (cons pathname loaded-object-files))
  310.            #t)))))))
  311.  
  312. (define (reset-loaded-object-files!)
  313.   (set! loaded-object-files '())
  314.   unspecific)
  315.  
  316. (define (loading-message suppress-loading-message? pathname do-it)
  317.   (if suppress-loading-message?
  318.       (do-it)
  319.       (let ((port (notification-output-port)))
  320.     (fresh-line port)
  321.     (write-string ";Loading " port)
  322.     (write (enough-namestring pathname) port)
  323.     (let ((value (do-it)))
  324.       (write-string " -- done" port)
  325.       (newline port)
  326.       value))))
  327.  
  328. (define *purification-root-marker*)
  329.  
  330. (define (load/purification-root object)
  331.   (or (and (comment? object)
  332.        (let ((text (comment-text object)))
  333.          (and (dbg-info-vector? text)
  334.           (dbg-info-vector/purification-root text))))
  335.       (and (object-type? (ucode-type compiled-entry) object)
  336.        (let* ((block ((ucode-primitive compiled-code-address->block 1)
  337.               object))
  338.           (index (- (system-vector-length block) 3)))
  339.          (and (not (negative? index))
  340.           (let ((frob (system-vector-ref block index)))
  341.             (and (pair? frob)
  342.              (eq? (car frob) *purification-root-marker*)
  343.              (cdr frob))))))
  344.       object))
  345.  
  346. (define (read-file filename)
  347.   (call-with-input-file (pathname-default-version filename 'NEWEST)
  348.     (lambda (port)
  349.       (stream->list (read-stream port)))))
  350.  
  351. (define (read-stream port)
  352.   (parse-objects port
  353.          (current-parser-table)
  354.          (lambda (object)
  355.            (and (eof-object? object)
  356.             (begin
  357.               (close-input-port port)
  358.               #t)))))
  359.  
  360. (define (eval-stream stream environment syntax-table)
  361.   (stream-map stream
  362.           (let ((repl (nearest-repl)))
  363.         (let ((environment
  364.                (if (eq? environment default-object)
  365.                (repl/environment repl)
  366.                environment))
  367.               (syntax-table
  368.                (make-syntax-table
  369.             (if (eq? syntax-table default-object)
  370.                 (repl/syntax-table repl)
  371.                 syntax-table))))
  372.           (lambda (s-expression)
  373.             (cons s-expression
  374.               (hook/repl-eval #f
  375.                       s-expression
  376.                       environment
  377.                       syntax-table)))))))
  378.  
  379. (define (write-stream stream write)
  380.   (if (stream-pair? stream)
  381.       (let loop ((exp&value (stream-car stream)) (stream (stream-cdr stream)))
  382.     (if (stream-pair? stream)
  383.         (begin
  384.           (write exp&value)
  385.           (loop (stream-car stream) (stream-cdr stream)))
  386.         (cdr exp&value)))
  387.       unspecific))
  388.  
  389. ;;;; Command Line Parser
  390.  
  391. (define (process-command-line)
  392.   (set! generate-suspend-file? #f)
  393.   (hook/process-command-line ((ucode-primitive get-unused-command-line 0))))
  394.  
  395. (define hook/process-command-line)
  396.  
  397. (define *unused-command-line*)
  398. (define *command-line-parsers* '())
  399.  
  400. (define *load-init-file?*)
  401.  
  402. (define (default/process-command-line unused-command-line)
  403.   (let ((after-parsing-actions '()))
  404.  
  405.     (define (process-keyword command-line unused-options)
  406.       (if (not (null? command-line))
  407.       (let* ((keyword (car command-line))
  408.          (place (assoc keyword *command-line-parsers*)))
  409.         (cond (place
  410.            (call-with-values
  411.                (lambda () ((cdr place) command-line))
  412.              (lambda (next tail-action)
  413.                (if tail-action
  414.                (set! after-parsing-actions
  415.                  (cons tail-action after-parsing-actions)))
  416.                (process-keyword next unused-options))))
  417.           ((zero? (string-length keyword))
  418.            (process-keyword (cdr command-line)
  419.                     unused-options))
  420.           (else
  421.            (if (or (not (char=? (string-ref keyword 0) #\-))
  422.                (= (string-length keyword) 1))
  423.                (warn "process-command-line: Invalid keyword" keyword))
  424.            (find-next-keyword (cdr command-line)
  425.                       (cons (car command-line)
  426.                         unused-options)))))
  427.       (let ((unused (reverse unused-options)))
  428.         (if (not (null? unused))
  429.         (warn "Unhandled command line options:" unused))
  430.         unused)))
  431.  
  432.     (define (find-next-keyword command-line unused-options)
  433.       (if (null? command-line)
  434.       (process-keyword '() unused-options)
  435.       (let ((keyword (car command-line)))
  436.         (if (or (< (string-length keyword) 2)
  437.             (not (char=? (string-ref keyword 0) #\-)))
  438.         (find-next-keyword (cdr command-line)
  439.                    (cons keyword unused-options))
  440.         (process-keyword command-line unused-options)))))
  441.  
  442.     (if (not unused-command-line)
  443.     (begin
  444.       (set! *unused-command-line* #f)
  445.       (load-init-file))
  446.  
  447.     (begin
  448.       (set! *unused-command-line*)
  449.       (fluid-let ((*load-init-file?* #t))
  450.         (set! *unused-command-line*
  451.           (process-keyword (vector->list unused-command-line) '()))
  452.         (for-each (lambda (act) (act))
  453.               (reverse after-parsing-actions))
  454.         (if *load-init-file?* (load-init-file)))))))
  455.  
  456. (define (load-init-file)
  457.   (let ((pathname (init-file-pathname)))
  458.     (if pathname
  459.     (load pathname user-initial-environment)))
  460.   unspecific)
  461.  
  462. ;;   KEYWORD must be a string with at least two characters and the first
  463. ;; being a dash (#\-).
  464. ;;   PROC is a procedure of one argument.  It will be invoked on the
  465. ;; list of command line elements extending to the right of the keyword
  466. ;; (and including it).
  467. ;;   PROC returns two values: the sublist starting with the first
  468. ;; non-handled command-line element (typically the next keyword), and
  469. ;; either #F or a procedure to invoke after the whole command line has
  470. ;; been parsed (and the init file loaded).  Thus PROC has the option
  471. ;; of executing the appropriate action at parsing time, or delaying it
  472. ;; until after the parsing is complete.  The execution of the PROCs
  473. ;; (or their associated delayed actions) is strictly left-to-right,
  474. ;; with the init file loaded between the end of parsing and the
  475. ;; delayed actions.
  476.  
  477. (define (set-command-line-parser! keyword proc)
  478.   (if (not (and (string? keyword)
  479.         (>= (string-length keyword) 2)
  480.         (char=? #\- (string-ref keyword 0))))
  481.       (error:wrong-type-argument keyword
  482.                  "command-line option keyword"
  483.                  'SET-COMMAND-LINE-PARSER!))
  484.   (let ((place (assoc keyword *command-line-parsers*)))
  485.     (if place
  486.     (set-cdr! place proc)
  487.     (begin
  488.       (set! *command-line-parsers*
  489.         (cons (cons keyword proc)
  490.               *command-line-parsers*))
  491.       unspecific))))
  492.  
  493. (define (simple-command-line-parser keyword thunk)
  494.   (set-command-line-parser! keyword
  495.                 (lambda (command-line)
  496.                   (values (cdr command-line) thunk))))
  497.  
  498. ;; Upwards compatibility.
  499. (define simple-option-parser simple-command-line-parser)
  500.  
  501. (define (argument-command-line-parser keyword multiple? procedure)
  502.   (set-command-line-parser!
  503.    keyword
  504.    (if multiple?
  505.        (lambda (command-line)
  506.      (for-each-non-keyword (cdr command-line) procedure))
  507.        (lambda (command-line)
  508.      (if (null? (cdr command-line))
  509.          (values '()
  510.              (lambda ()
  511.                (warn "Missing argument to command-line option:"
  512.                  keyword)))
  513.          (values (cddr command-line)
  514.              (lambda () (procedure (cadr command-line)))))))))
  515.  
  516. (define (for-each-non-keyword command-line processor)
  517.   (let ((end
  518.      (lambda (command-line accum)
  519.        (if (null? accum)
  520.            (values command-line #f)
  521.            (let ((objects (reverse accum)))
  522.          (values command-line
  523.              (lambda () (for-each processor objects))))))))
  524.     (let loop ((command-line command-line) (accum '()))
  525.       (if (null? command-line)
  526.       (end '() accum)
  527.       (let ((next (car command-line)))
  528.         (if (and (> (string-length next) 0)
  529.              (char=? #\- (string-ref next 0)))
  530.         (end command-line accum)
  531.         (loop (cdr command-line) (cons next accum))))))))
  532.  
  533. (define (initialize-command-line-parsers)
  534.   (simple-command-line-parser "-no-init-file"
  535.                   (lambda ()
  536.                 (set! *load-init-file?* #f)
  537.                 unspecific))
  538.   (set! generate-suspend-file? #f)
  539.   (simple-command-line-parser "-suspend-file"
  540.                   (lambda ()
  541.                 (set! generate-suspend-file? #t)
  542.                 unspecific))
  543.   (simple-command-line-parser "-no-suspend-file"
  544.                   (lambda ()
  545.                 (set! generate-suspend-file? #f)
  546.                 unspecific))
  547.   (argument-command-line-parser "-load" #t load)
  548.   (argument-command-line-parser "-eval" #t
  549.                 (lambda (arg)
  550.                   (eval (with-input-from-string arg read)
  551.                     user-initial-environment))))
  552.  
  553. ;;;; Loader for packed binaries
  554.  
  555. (define (load-packed-binaries pathname fname count environment)
  556.   (define (process-bunch alist)
  557.     (let ((real-load load)
  558.       (real-fasload fasload)
  559.       (real-file-exists? file-exists?)
  560.       (real-file-directory? file-directory?)
  561.       (to-purify '()))
  562.       (fluid-let
  563.       ((load
  564.         (lambda (fname #!optional env syntax-table purify?)
  565.           (let ((env (if (default-object? env) default-object env))
  566.             (purify?
  567.              (if (default-object? purify?) default-object purify?)))
  568.         (let ((place (find-filename fname alist)))
  569.           (if (not place)
  570.               (real-load fname
  571.                  env
  572.                  (if (default-object? syntax-table)
  573.                      default-object
  574.                      syntax-table)
  575.                  purify?)
  576.               (handle-load-hooks
  577.                (lambda ()
  578.              (let ((scode (caddr place)))
  579.                (loading-message fname
  580.                         load/suppress-loading-message?
  581.                         ";Pseudo-loading ")
  582.                (if (and (not (eq? purify? default-object)) purify?)
  583.                    (set! to-purify
  584.                      (cons (load/purification-root scode)
  585.                        to-purify)))
  586.                (fluid-let ((load/current-pathname (cadr place)))
  587.                  (extended-scode-eval scode
  588.                           (if (eq? env default-object)
  589.                               environment
  590.                               env)))))))))))
  591.        (fasload
  592.         (lambda (filename #!optional suppress-message?)
  593.           (let ((suppress-message?
  594.              (if (default-object? suppress-message?)
  595.              load/suppress-loading-message?
  596.              suppress-message?))
  597.             (place (find-filename filename alist)))
  598.         (if (not place)
  599.             (real-fasload filename suppress-message?)
  600.             (begin
  601.               (loading-message filename
  602.                                suppress-message?
  603.                        ";Pseudo-fasloading ")
  604.               (caddr place))))))
  605.        (file-exists?
  606.         (lambda (fname)
  607.           (or (find-filename fname alist)
  608.           (real-file-exists? fname))))
  609.        (file-directory?
  610.         (lambda (dname)
  611.           (or (directory-represented? dname alist)
  612.           (real-file-directory? dname)))))
  613.         (load (caar alist)))
  614.       (set! alist)
  615.       (for-each purify (reverse! to-purify)))
  616.     (flush-purification-queue!))
  617.  
  618.   (define (find-filename fname alist)
  619.     (search-alist (->pathname fname) alist
  620.       (lambda (path1 path2)
  621.     (and (equal? (pathname-directory path1)
  622.              (pathname-directory path2))
  623.          (equal? (pathname-name path1)
  624.              (pathname-name path2))
  625.          (or (equal? (pathname-type path1) (pathname-type path2))
  626.          (and (member (pathname-type path1) '(#f "bin" "com"))
  627.               (member (pathname-type path2) '(#f "bin" "com"))))))))
  628.  
  629.   (define (directory-represented? dname alist)
  630.     (search-alist (pathname-as-directory (->pathname dname)) alist
  631.       (lambda (path1 path2)
  632.     (equal? (pathname-directory path1)
  633.         (pathname-directory path2)))))
  634.  
  635.   (define (search-alist path alist predicate?)
  636.     (let loop ((alist alist))
  637.       (and (not (null? alist))
  638.        (if (predicate? path (cadar alist))
  639.            (car alist)
  640.            (loop (cdr alist))))))
  641.  
  642.   (define (loading-message fname suppress? kind)
  643.     (if (not suppress?)
  644.     (let ((port (notification-output-port)))
  645.       (fresh-line port)
  646.       (write-string kind port)
  647.       (write-string (->namestring (->pathname fname)) port)
  648.       (write-string "..." port)
  649.       (newline port))))
  650.  
  651.   (with-binary-input-file (->truename pathname)
  652.     (lambda (channel)
  653.       ((ucode-primitive binary-fasload) channel) ; Dismiss header.
  654.       (let ((process-next-bunch
  655.          (lambda ()
  656.            (process-bunch
  657.         (map (lambda (pair)
  658.                (list (car pair)
  659.                  (->pathname (car pair))
  660.                  (cdr pair)))
  661.              ((ucode-primitive binary-fasload) channel))))))
  662.     (do ((count count (-1+ count)))
  663.         ((= count 1)
  664.          (process-next-bunch))
  665.       (process-next-bunch))))))
  666.  
  667. (define (with-binary-input-file file action)
  668.   (with-binary-file-channel file action
  669.     open-binary-input-file
  670.     port/input-channel
  671.     'with-binary-input-file))
  672.  
  673. (define (with-binary-file-channel file action open extract-channel name)
  674.   (let ((port #f))
  675.     (dynamic-wind
  676.      (lambda ()
  677.        (if port
  678.            (error "cannot re-enter with-binary-file-channel" name)))
  679.      (lambda ()
  680.        (set! port (open file))
  681.        (action (channel-descriptor (extract-channel port))))
  682.      (lambda ()
  683.        (if (and port
  684.                 (not (eq? port #t)))
  685.            (begin
  686.              (close-port port)
  687.              (set! port #t)))))))