| 1 | ;;;-*- Mode: Lisp; Package: ccl -*-
|
|---|
| 2 |
|
|---|
| 3 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|---|
| 4 | ;;
|
|---|
| 5 | ;; block-io-mcl.lisp
|
|---|
| 6 | ;; low-level block I/O - MCL version.
|
|---|
| 7 | ;;
|
|---|
| 8 | ;; Copyright © 1996-1999 Digitool, Inc.
|
|---|
| 9 | ;; Copyright © 1992-1995 Apple Computer, Inc.
|
|---|
| 10 | ;; All rights reserved.
|
|---|
| 11 | ;; Permission is given to use, copy, and modify this software provided
|
|---|
| 12 | ;; that Digitool is given credit in all derivative works.
|
|---|
| 13 | ;; This software is provided "as is". Digitool makes no warranty or
|
|---|
| 14 | ;; representation, either express or implied, with respect to this software,
|
|---|
| 15 | ;; its quality, accuracy, merchantability, or fitness for a particular
|
|---|
| 16 | ;; purpose.
|
|---|
| 17 | ;;
|
|---|
| 18 |
|
|---|
| 19 | ;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|---|
| 20 | ;;
|
|---|
| 21 | ;; Modification history
|
|---|
| 22 | ;;
|
|---|
| 23 | ;; 01/29/00 akh fix example at end of this file
|
|---|
| 24 | ;; 01/10/00 akh fix for possible non fixnum file address
|
|---|
| 25 | ;; ------------- 0.96
|
|---|
| 26 | ;; 07/20/96 bill databases-locked-p, with-databases-unlocked, & funcall-with-databases-unlocked
|
|---|
| 27 | ;; are already part of CCL 4.0. Bind *warn-if-redefine*, etc. appropriately.
|
|---|
| 28 | ;; 07/06/96 bill provide block-io-mcl, not block-io.
|
|---|
| 29 | ;; 05/21/96 bill PPC versions of %fread-bytes & %fwrite-bytes now work correctly
|
|---|
| 30 | ;; if the starting file or buffer position is odd.
|
|---|
| 31 | ;; They use %copy-ivector-to-ivector instead of local code.
|
|---|
| 32 | ;; ------------- 0.95
|
|---|
| 33 | ;; 05/09/96 bill databases-locked-p
|
|---|
| 34 | ;; funcall-with-databases-locked-p comes out-of-line from with-databases-unlocked.
|
|---|
| 35 | ;; It now binds *database-locked-p* nil during its body.
|
|---|
| 36 | ;; 05/03/96 bill multi-process with-databases-locked
|
|---|
| 37 | ;; 05/01/96 slh don't require lapmacros on PPC
|
|---|
| 38 | ;; ------------- 0.94 = MCL-PPC 3.9
|
|---|
| 39 | ;; 03/09/96 bill Eliminate LAP for ppc-target
|
|---|
| 40 | ;; ------------- 0.93
|
|---|
| 41 | ;; 07/21/95 bill inhibited-event-dispatch now processes *inhibited-foreground-switch*
|
|---|
| 42 | ;; 05/31/95 bill wood:with-database-locked now calls new inhibted-event-dispatch
|
|---|
| 43 | ;; function if event processing happenned while it was inhibited.
|
|---|
| 44 | ;; This makes interactive response time as good as it can be
|
|---|
| 45 | ;; given this locking mechanism.
|
|---|
| 46 | ;; 05/25/95 bill %fread-bytes & %fwrite-bytes use #_BlockMove instead
|
|---|
| 47 | ;; of a move.b loop; it's faster.
|
|---|
| 48 | ;; set-minimum-file-length never makes the file shorter.
|
|---|
| 49 | ;; ------------- 0.9
|
|---|
| 50 | ;; 03/13/95 bill byte-array-p and ensure-byte-array move here from "disk-cache-accessors.lisp"
|
|---|
| 51 | ;; byte-array-p updated to work in MCL 3.0.
|
|---|
| 52 | ;; Former lap uses of $v_subtype changed to calls of ensure-byte-array
|
|---|
| 53 | ;; 10/25/94 Moon without-interrupts -> with-databases-locked
|
|---|
| 54 | ;; 09/21/94 bill without-interrupts around part of %fread-bytes and %fwrite-bytes
|
|---|
| 55 | ;; 01/31/94 bill %fread-bytes & %fwrite-bytes support offsets > 64K and
|
|---|
| 56 | ;; will read/write more than just the first 512 bytes.
|
|---|
| 57 | ;; ------------ 0.8
|
|---|
| 58 | ;; ------------ 0.6
|
|---|
| 59 | ;; ------------ 0.5
|
|---|
| 60 | ;; 03/05/92 bill New file
|
|---|
| 61 | ;;
|
|---|
| 62 |
|
|---|
| 63 | (in-package :ccl)
|
|---|
| 64 |
|
|---|
| 65 | (export '(stream-read-bytes stream-write-bytes set-minimum-file-length))
|
|---|
| 66 |
|
|---|
| 67 | (provide :block-io-mcl)
|
|---|
| 68 |
|
|---|
| 69 | (defvar *inhibit-event-dispatch* nil)
|
|---|
| 70 | (defvar *event-dispatch-inhibited* nil)
|
|---|
| 71 |
|
|---|
| 72 | ; Set non-NIL if a suspend or resume event comes in while
|
|---|
| 73 | ; *event-dispatch-inhibited* is true. 0 means it was
|
|---|
| 74 | ; suspend, non-zero means resume.
|
|---|
| 75 | (defvar *inhibited-foreground-switch* nil)
|
|---|
| 76 |
|
|---|
| 77 | ;;; This macro provides the interlocking so the WOOD database
|
|---|
| 78 | ;;; doesn't get screwed up by being used reentrantly by an event
|
|---|
| 79 | ;;; handler. Change this macro and recompile to change the
|
|---|
| 80 | ;;; implementation of the interlocking.
|
|---|
| 81 | ;;; Defined here since WOOD doesn't seem to have
|
|---|
| 82 | ;;; a file specifically for macros like this.
|
|---|
| 83 | #-ccl-3
|
|---|
| 84 | (progn
|
|---|
| 85 |
|
|---|
| 86 | (defmacro wood::with-databases-locked (&body body)
|
|---|
| 87 | ;; The following is surprisingly slow on 68040s
|
|---|
| 88 | ;`(without-interrupts ,@body)
|
|---|
| 89 | ;; So do it this way instead.
|
|---|
| 90 | `(multiple-value-prog1 ; Wish this could be prog1
|
|---|
| 91 | (let ((*inhibit-event-dispatch* t))
|
|---|
| 92 | ,@body)
|
|---|
| 93 | (locally (declare (optimize (speed 3) (safety 0))) ; force inline value cell reference
|
|---|
| 94 | (when (and *event-dispatch-inhibited*
|
|---|
| 95 | (not *inhibit-event-dispatch*))
|
|---|
| 96 | (inhibited-event-dispatch)))))
|
|---|
| 97 |
|
|---|
| 98 | (defmacro wood::with-databases-unlocked (&body body)
|
|---|
| 99 | `(let ((ccl::*inhibit-event-dispatch* nil))
|
|---|
| 100 | (declare (special ccl::*inhibit-event-dispatch*)) ; fix build problem
|
|---|
| 101 | ,@body))
|
|---|
| 102 |
|
|---|
| 103 | (defun wood::databases-locked-p (&optional by-locker)
|
|---|
| 104 | (declare (ignore by-locker))
|
|---|
| 105 | (and (boundp 'ccl::*inhibit-event-dispatch*)
|
|---|
| 106 | ccl::*inhibit-event-dispatch*))
|
|---|
| 107 |
|
|---|
| 108 | ) ; end of #-ccl-3 progn
|
|---|
| 109 |
|
|---|
| 110 | ; with-databases-(un)locked is a NOP is CCL 3.0, since store-conditional
|
|---|
| 111 | ; doesn't exists there yet.
|
|---|
| 112 | #+(and ccl-3 (not ppc-target))
|
|---|
| 113 | (progn
|
|---|
| 114 |
|
|---|
| 115 | (defmacro wood:with-databases-locked (&body body)
|
|---|
| 116 | `(progn ,@body))
|
|---|
| 117 |
|
|---|
| 118 | (defmacro wood:with-databases-unlocked (&body body)
|
|---|
| 119 | `(progn ,@body))
|
|---|
| 120 |
|
|---|
| 121 | (defun wood::databases-locked-p (&optional by-locker)
|
|---|
| 122 | (declare (ignore by-locker))
|
|---|
| 123 | nil)
|
|---|
| 124 |
|
|---|
| 125 | ) ; end of #+(and ccl-3 (not ppc-target)) progn
|
|---|
| 126 |
|
|---|
| 127 | #+ppc-target
|
|---|
| 128 | (progn
|
|---|
| 129 |
|
|---|
| 130 | (defvar *database-lock* (make-lock))
|
|---|
| 131 | (defvar *database-queue* (make-process-queue "*database-queue*"))
|
|---|
| 132 | (defvar *database-locked-p* nil)
|
|---|
| 133 |
|
|---|
| 134 | (declaim (type lock *database-lock)
|
|---|
| 135 | (type boolean *database-locked-p*))
|
|---|
| 136 |
|
|---|
| 137 | (declaim (inline lock-databases unlock-databases))
|
|---|
| 138 |
|
|---|
| 139 | ; You should only call this inside a binding of *database-locked-p* to true.
|
|---|
| 140 | ; Otherwise, another process will steal the lock from you.
|
|---|
| 141 | ; with-databases-locked uses it correctly.
|
|---|
| 142 | ; Returns when it has the *database-lock*.
|
|---|
| 143 | ; A true value means that it is newly grabbed.
|
|---|
| 144 | ; NIL means that this process already had the lock when lock-databases was called.
|
|---|
| 145 | (defun lock-databases ()
|
|---|
| 146 | (declare (type process *current-process*))
|
|---|
| 147 | (let ((process *current-process*)
|
|---|
| 148 | (lock *database-lock*))
|
|---|
| 149 | (declare (type lock lock))
|
|---|
| 150 | (unless (eq (lock.value lock) process)
|
|---|
| 151 | (unless (store-conditional lock nil process)
|
|---|
| 152 | (lock-databases-out-of-line))
|
|---|
| 153 | t)))
|
|---|
| 154 |
|
|---|
| 155 | (defun unlock-databases ()
|
|---|
| 156 | (declare (type lock *database-lock*)
|
|---|
| 157 | (type process *current-process*))
|
|---|
| 158 | (unless (store-conditional *database-lock* *current-process* nil)
|
|---|
| 159 | (error "~s not held by ~s" '*database-lock* *current-process*)))
|
|---|
| 160 |
|
|---|
| 161 | (declaim (ftype (function (&optional t)) wood::with-databases-locked-p))
|
|---|
| 162 |
|
|---|
| 163 | (let ((*warn-if-redefine* nil)
|
|---|
| 164 | (*warn-if-redefine-kernel* nil))
|
|---|
| 165 |
|
|---|
| 166 | (defun wood::databases-locked-p (&optional by-locker)
|
|---|
| 167 | (without-interrupts
|
|---|
| 168 | (let* ((lock *database-lock*)
|
|---|
| 169 | (locker (lock.value lock)))
|
|---|
| 170 | (cond ((null locker) nil)
|
|---|
| 171 | ((or (process-exhausted-p locker)
|
|---|
| 172 | (not (symbol-value-in-process '*database-locked-p* locker)))
|
|---|
| 173 | (setf (lock.value lock) nil))
|
|---|
| 174 | (by-locker (eq locker by-locker))
|
|---|
| 175 | (t t)))))
|
|---|
| 176 |
|
|---|
| 177 | )
|
|---|
| 178 |
|
|---|
| 179 | ; This is so hairy because we're trying to avoid an unwind-protect (too slow)
|
|---|
| 180 | ; yet we still want to notice when the holder of the *database-lock*
|
|---|
| 181 | ; has thrown out of wood::with-databases-locked.
|
|---|
| 182 | (defun lock-databases-out-of-line ()
|
|---|
| 183 | (let ((lock *database-lock*)
|
|---|
| 184 | (queue *database-queue*)
|
|---|
| 185 | (enqueued nil))
|
|---|
| 186 | (declare (type lock lock))
|
|---|
| 187 | ; In case we threw out of a with-databases-locked
|
|---|
| 188 | (unwind-protect
|
|---|
| 189 | (loop
|
|---|
| 190 | (wood::databases-locked-p) ; clear lock.value if it's not really locked
|
|---|
| 191 | (unless enqueued
|
|---|
| 192 | (setq enqueued (process-enqueue-with-timeout queue 30)))
|
|---|
| 193 | (when enqueued
|
|---|
| 194 | (when (store-conditional lock nil *current-process*)
|
|---|
| 195 | (return t))
|
|---|
| 196 | (process-wait-with-timeout "Lock"
|
|---|
| 197 | 30
|
|---|
| 198 | #'(lambda (lock)
|
|---|
| 199 | (null (lock.value lock)))
|
|---|
| 200 | lock)))
|
|---|
| 201 | (when enqueued
|
|---|
| 202 | (process-dequeue queue)))))
|
|---|
| 203 |
|
|---|
| 204 | (defmacro wood::with-databases-locked (&body body)
|
|---|
| 205 | (let ((needs-unlocking-p (gensym)))
|
|---|
| 206 | `(let* ((*database-locked-p* t)
|
|---|
| 207 | (,needs-unlocking-p (lock-databases)))
|
|---|
| 208 | (multiple-value-prog1
|
|---|
| 209 | (progn ,@body)
|
|---|
| 210 | (when ,needs-unlocking-p
|
|---|
| 211 | (unlock-databases))))))
|
|---|
| 212 |
|
|---|
| 213 | ;;; Undo the effect of with-databases-locked temporarily, if possible
|
|---|
| 214 | (eval-when (:compile-toplevel :execute :load-toplevel)
|
|---|
| 215 | (unless (fboundp 'wood::with-databases-unlocked)
|
|---|
| 216 |
|
|---|
| 217 | (defmacro wood::with-databases-unlocked (&body body)
|
|---|
| 218 | (let ((thunk (gensym)))
|
|---|
| 219 | `(let ((,thunk #'(lambda () ,@body)))
|
|---|
| 220 | (declare (dynamic-extent ,thunk))
|
|---|
| 221 | (funcall-with-databases-unlocked ,thunk))))
|
|---|
| 222 |
|
|---|
| 223 | ))
|
|---|
| 224 |
|
|---|
| 225 | (let ((*warn-if-redefine* nil)
|
|---|
| 226 | (*warn-if-redefine-kernel* nil))
|
|---|
| 227 |
|
|---|
| 228 | (defun funcall-with-databases-unlocked (thunk)
|
|---|
| 229 | (let ((was-locked? nil))
|
|---|
| 230 | (unwind-protect
|
|---|
| 231 | (let ((*database-locked-p* *database-locked-p*))
|
|---|
| 232 | (when (setq was-locked? (wood::databases-locked-p *current-process*))
|
|---|
| 233 | (unlock-databases)
|
|---|
| 234 | (setq *database-locked-p* nil))
|
|---|
| 235 | (funcall thunk))
|
|---|
| 236 | (when was-locked?
|
|---|
| 237 | (lock-databases)))))
|
|---|
| 238 |
|
|---|
| 239 | )
|
|---|
| 240 |
|
|---|
| 241 | ) ; end of #+ppc-target progn
|
|---|
| 242 |
|
|---|
| 243 | ; Separate function mostly so we can meter it
|
|---|
| 244 | (defun inhibited-event-dispatch ()
|
|---|
| 245 | (setq *event-dispatch-inhibited* nil)
|
|---|
| 246 | (let ((switch *inhibited-foreground-switch*))
|
|---|
| 247 | (when switch
|
|---|
| 248 | (setq *inhibited-foreground-switch* nil)
|
|---|
| 249 | (unless (eq *foreground*
|
|---|
| 250 | (setq *foreground* (not (eql switch 0))))
|
|---|
| 251 | (when (fboundp 'establish-*foreground*)
|
|---|
| 252 | (funcall 'establish-*foreground*)))))
|
|---|
| 253 | (event-dispatch))
|
|---|
| 254 |
|
|---|
| 255 | ;; (stream-read-bytes stream address vector offset length)
|
|---|
| 256 | ;; read length bytes into vector at offset from stream at address.
|
|---|
| 257 | ;;
|
|---|
| 258 | ;; (stream-write-bytes stream address vector offset length)
|
|---|
| 259 | ;; write length bytes from stream at address into vector at offset.
|
|---|
| 260 | ;; Extend the length of the file if necessary.
|
|---|
| 261 | ;;
|
|---|
| 262 | ;; (set-minimum-file-length stream length)
|
|---|
| 263 | ;; Set the file length of stream to >= length.
|
|---|
| 264 | ;;
|
|---|
| 265 | ;; This implementation only supports vectors of type
|
|---|
| 266 | ;; (array (unsigned-byte 8)), (array (signed-byte 8)), or simple-string
|
|---|
| 267 |
|
|---|
| 268 | (eval-when (eval compile)
|
|---|
| 269 | #-ppc-target
|
|---|
| 270 | (require 'lapmacros)
|
|---|
| 271 | (require 'lispequ)
|
|---|
| 272 |
|
|---|
| 273 | ;structure of fblock
|
|---|
| 274 | ;from "ccl:level-1;l1-sysio.lisp"
|
|---|
| 275 |
|
|---|
| 276 | (let ((*warn-if-redefine* nil))
|
|---|
| 277 |
|
|---|
| 278 | (def-accessors (fblock) %svref
|
|---|
| 279 | nil ; 'fblock
|
|---|
| 280 | fblock.pb ; a parameter block; nil if closed.
|
|---|
| 281 | fblock.lastchar ; untyi char or nil
|
|---|
| 282 | fblock.dirty ; non-nil when dirty
|
|---|
| 283 | fblock.buffer ; macptr to buffer; nil when closed
|
|---|
| 284 | fblock.bufvec ; buffer vector; nil when closed
|
|---|
| 285 | fblock.bufsize ; size (in 8-bit bytes) of buffer
|
|---|
| 286 | fblock.bufidx ; index of next element to read/write
|
|---|
| 287 | fblock.bufcount ; # of elements in buffer
|
|---|
| 288 | fblock.filepos ; 8-bit position at last read/write
|
|---|
| 289 | fblock.fileeof ; file's logical eof.
|
|---|
| 290 | fblock.stream ; backptr to file stream
|
|---|
| 291 | fblock.element-type ; typespec
|
|---|
| 292 | fblock.nbits-per-element ; # of bits per element
|
|---|
| 293 | fblock.elements-per-buffer ; 512 or whatever
|
|---|
| 294 | fblock.minval ; minimum value of element type or nil: < 0
|
|---|
| 295 | fblock.maxval ; maximum value or nil
|
|---|
| 296 | fblock.element-bit-offset ; for non-arefable n-bit elements
|
|---|
| 297 | )
|
|---|
| 298 |
|
|---|
| 299 | ) ; end of let
|
|---|
| 300 |
|
|---|
| 301 | ) ; end of eval-when
|
|---|
| 302 |
|
|---|
| 303 | ; Read length bytes into array at offset from stream at address.
|
|---|
| 304 | ; Array must be a simple (byte 8) array.
|
|---|
| 305 | ; stream must be an input stream for 8 bit elements.
|
|---|
| 306 | (defmethod stream-read-bytes ((stream input-file-stream)
|
|---|
| 307 | address array offset length)
|
|---|
| 308 | (%fread-bytes (slot-value stream 'fblock)
|
|---|
| 309 | #+:wood-fixnum-addresses
|
|---|
| 310 | (require-type address 'fixnum)
|
|---|
| 311 | #-:wood-fixnum-addresses
|
|---|
| 312 | (require-type address 'integer)
|
|---|
| 313 | array
|
|---|
| 314 | (require-type offset 'fixnum)
|
|---|
| 315 | (require-type length 'fixnum)))
|
|---|
| 316 |
|
|---|
| 317 | #-ppc-target
|
|---|
| 318 | (defun %fread-bytes (fblock address array offset length)
|
|---|
| 319 | (declare (fixnum offset length))
|
|---|
| 320 | #+:wood-fixnum-addresses (declare (fixnum address))
|
|---|
| 321 | (unless (eql 8 (fblock.nbits-per-element fblock))
|
|---|
| 322 | (error "%fread-bytes only implemented for 8-bit bytes"))
|
|---|
| 323 | (unless (>= (length array) (the fixnum (+ offset length)))
|
|---|
| 324 | (error "array too small"))
|
|---|
| 325 | (ensure-byte-array array)
|
|---|
| 326 | (let ((max-length (- (%fsize fblock) address)))
|
|---|
| 327 | #+:wood-fixnum-addresses (declare (fixnum max-length))
|
|---|
| 328 | (if (< max-length length) (setq length max-length))
|
|---|
| 329 | (if (< length 0) (setq length 0)))
|
|---|
| 330 | (let ((bytes length)
|
|---|
| 331 | (bufvec (fblock.bufvec fblock)))
|
|---|
| 332 | (declare (fixnum bytes))
|
|---|
| 333 | (loop
|
|---|
| 334 | (when (<= length 0) (return bytes))
|
|---|
| 335 | (wood::with-databases-locked
|
|---|
| 336 | (%fpos fblock address)
|
|---|
| 337 | (let* ((vec-index (- address (the #+:wood-fixnum-addresses fixnum
|
|---|
| 338 | #-:wood-fixnum-addresses integer
|
|---|
| 339 | (fblock.filepos fblock))))
|
|---|
| 340 | (vec-left (- (the fixnum (fblock.bufcount fblock)) vec-index)))
|
|---|
| 341 | (declare (fixnum vec-index vec-left))
|
|---|
| 342 | ; (print-db vec-index vec-left)
|
|---|
| 343 | (if (> vec-left length) (setq vec-left length))
|
|---|
| 344 | (lap-inline ()
|
|---|
| 345 | (:variable bufvec array offset vec-index vec-left)
|
|---|
| 346 | (move.l (varg bufvec) atemp0)
|
|---|
| 347 | (move.l (varg vec-index) acc)
|
|---|
| 348 | (getint acc)
|
|---|
| 349 | (lea (atemp0 acc.l $v_data) atemp0)
|
|---|
| 350 | (move.l (varg array) atemp1)
|
|---|
| 351 | (move.l (varg offset) acc)
|
|---|
| 352 | (getint acc)
|
|---|
| 353 | (lea (atemp1 acc.l $v_data) atemp1)
|
|---|
| 354 | (move.l (varg vec-left) acc)
|
|---|
| 355 | (getint acc)
|
|---|
| 356 | (dc.w #_BlockMove)
|
|---|
| 357 | )
|
|---|
| 358 | (incf address vec-left)
|
|---|
| 359 | (incf offset vec-left)
|
|---|
| 360 | (decf length vec-left))))))
|
|---|
| 361 |
|
|---|
| 362 | #+ppc-target
|
|---|
| 363 | (defun %fread-bytes (fblock address array offset length)
|
|---|
| 364 | (declare (fixnum offset length))
|
|---|
| 365 | #+:wood-fixnum-addresses (declare (fixnum address))
|
|---|
| 366 | (unless (eql 8 (fblock.nbits-per-element fblock))
|
|---|
| 367 | (error "%fread-bytes only implemented for 8-bit bytes"))
|
|---|
| 368 | (unless (>= (length array) (the fixnum (+ offset length)))
|
|---|
| 369 | (error "array too small"))
|
|---|
| 370 | (ensure-byte-array array)
|
|---|
| 371 | (let ((max-length (- (%fsize fblock) address)))
|
|---|
| 372 | #+:wood-fixnum-addresses (declare (fixnum max-length))
|
|---|
| 373 | (if (< max-length length) (setq length max-length))
|
|---|
| 374 | (if (< length 0) (setq length 0)))
|
|---|
| 375 | (let ((bytes length)
|
|---|
| 376 | (bufvec (fblock.bufvec fblock)))
|
|---|
| 377 | (declare (fixnum bytes))
|
|---|
| 378 | (loop
|
|---|
| 379 | (when (<= length 0) (return bytes))
|
|---|
| 380 | (without-interrupts
|
|---|
| 381 | (%fpos fblock address)
|
|---|
| 382 | (let* ((vec-index (fblock.bufidx fblock))
|
|---|
| 383 | (vec-left (- (the fixnum (fblock.bufcount fblock)) vec-index)))
|
|---|
| 384 | (declare (fixnum vec-index vec-left))
|
|---|
| 385 | (if (> vec-left length) (setq vec-left length))
|
|---|
| 386 | (%copy-ivector-to-ivector bufvec vec-index array offset vec-left)
|
|---|
| 387 | (incf address vec-left)
|
|---|
| 388 | (incf offset vec-left)
|
|---|
| 389 | (decf length vec-left))))))
|
|---|
| 390 |
|
|---|
| 391 | ; same, but other direction
|
|---|
| 392 | (defmethod stream-write-bytes ((stream output-file-stream)
|
|---|
| 393 | address array offset length)
|
|---|
| 394 | (%fwrite-bytes (slot-value stream 'fblock)
|
|---|
| 395 | #+:wood-fixnum-addresses (require-type address 'fixnum)
|
|---|
| 396 | #-:wood-fixnum-addresses (require-type address 'integer)
|
|---|
| 397 | array
|
|---|
| 398 | (require-type offset 'fixnum)
|
|---|
| 399 | (require-type length 'fixnum)))
|
|---|
| 400 |
|
|---|
| 401 | #-ppc-target
|
|---|
| 402 | (defun %fwrite-bytes (fblock address array offset length)
|
|---|
| 403 | (declare (fixnum offset length))
|
|---|
| 404 | #+:wood-fixnum-addresses (declare (fixnum address))
|
|---|
| 405 | (unless (eql 8 (fblock.nbits-per-element fblock))
|
|---|
| 406 | (error "%fwrite-bytes only implemented for 8-bit bytes"))
|
|---|
| 407 | (unless (>= (length array) (the fixnum (+ offset length)))
|
|---|
| 408 | (error "array too small"))
|
|---|
| 409 | (ensure-byte-array array)
|
|---|
| 410 | (let ((min-size (+ address length)))
|
|---|
| 411 | #+:wood-fixnum-addresses (declare (fixnum min-size))
|
|---|
| 412 | (when (> min-size (%fsize fblock))
|
|---|
| 413 | (%fsize fblock min-size)))
|
|---|
| 414 | (let ((bytes length)
|
|---|
| 415 | (bufvec (fblock.bufvec fblock)))
|
|---|
| 416 | (declare (fixnum bytes))
|
|---|
| 417 | (loop
|
|---|
| 418 | (when (<= length 0) (return bytes))
|
|---|
| 419 | (wood::with-databases-locked
|
|---|
| 420 | (%fpos fblock address)
|
|---|
| 421 | (let* ((vec-index (- address (the #+:wood-fixnum-addresses fixnum
|
|---|
| 422 | #-:wood-fixnum-addresses integer
|
|---|
| 423 | (fblock.filepos fblock))))
|
|---|
| 424 | (vec-left (- (the fixnum (fblock.elements-per-buffer fblock))
|
|---|
| 425 | vec-index)))
|
|---|
| 426 | (declare (fixnum vec-index vec-left))
|
|---|
| 427 | (if (> vec-left length) (setq vec-left length))
|
|---|
| 428 | (lap-inline ()
|
|---|
| 429 | (:variable bufvec array offset vec-index vec-left)
|
|---|
| 430 | (move.l (varg bufvec) atemp1)
|
|---|
| 431 | (move.l (varg vec-index) acc)
|
|---|
| 432 | (getint acc)
|
|---|
| 433 | (lea (atemp1 acc.l $v_data) atemp1)
|
|---|
| 434 | (move.l (varg array) atemp0)
|
|---|
| 435 | (move.l (varg offset) acc)
|
|---|
| 436 | (getint acc)
|
|---|
| 437 | (lea (atemp0 acc.l $v_data) atemp0)
|
|---|
| 438 | (move.l (varg vec-left) acc)
|
|---|
| 439 | (getint acc)
|
|---|
| 440 | (dc.w #_BlockMove))
|
|---|
| 441 | (let ((index (+ vec-index vec-left))
|
|---|
| 442 | (bufcount (fblock.bufcount fblock)))
|
|---|
| 443 | (declare (fixnum index bufcount))
|
|---|
| 444 | (if (> index bufcount)
|
|---|
| 445 | (setf (fblock.bufcount fblock) index))
|
|---|
| 446 | (setf (fblock.bufidx fblock) index
|
|---|
| 447 | (fblock.dirty fblock) t))
|
|---|
| 448 | (incf address vec-left)
|
|---|
| 449 | (incf offset vec-left)
|
|---|
| 450 | (decf length vec-left))))))
|
|---|
| 451 |
|
|---|
| 452 | #+ppc-target
|
|---|
| 453 | (defun %fwrite-bytes (fblock address array offset length)
|
|---|
| 454 | (declare (fixnum offset length))
|
|---|
| 455 | #+:wood-fixnum-addresses (declare (fixnum address))
|
|---|
| 456 | (unless (eql 8 (fblock.nbits-per-element fblock))
|
|---|
| 457 | (error "%fwrite-bytes only implemented for 8-bit bytes"))
|
|---|
| 458 | (unless (>= (length array) (the fixnum (+ offset length)))
|
|---|
| 459 | (error "array too small"))
|
|---|
| 460 | (ensure-byte-array array)
|
|---|
| 461 | (let ((min-size (+ address length)))
|
|---|
| 462 | #+:wood-fixnum-addresses (declare (fixnum min-size))
|
|---|
| 463 | (when (> min-size (%fsize fblock))
|
|---|
| 464 | (%fsize fblock min-size)))
|
|---|
| 465 | (let ((bytes length)
|
|---|
| 466 | (bufvec (fblock.bufvec fblock)))
|
|---|
| 467 | (declare (fixnum bytes))
|
|---|
| 468 | (loop
|
|---|
| 469 | (when (<= length 0) (return bytes))
|
|---|
| 470 | (wood::with-databases-locked
|
|---|
| 471 | (%fpos fblock address)
|
|---|
| 472 | (let* ((vec-index (fblock.bufidx fblock))
|
|---|
| 473 | (vec-left (- (the fixnum (fblock.elements-per-buffer fblock))
|
|---|
| 474 | vec-index)))
|
|---|
| 475 | (declare (fixnum vec-index vec-left))
|
|---|
| 476 | (if (> vec-left length) (setq vec-left length))
|
|---|
| 477 | (%copy-ivector-to-ivector array offset bufvec vec-index vec-left)
|
|---|
| 478 | (let ((index (+ vec-index vec-left))
|
|---|
| 479 | (bufcount (fblock.bufcount fblock)))
|
|---|
| 480 | (declare (fixnum index bufcount))
|
|---|
| 481 | (if (> index bufcount)
|
|---|
| 482 | (setf (fblock.bufcount fblock) index))
|
|---|
| 483 | (setf (fblock.bufidx fblock) index
|
|---|
| 484 | (fblock.dirty fblock) t))
|
|---|
| 485 | (incf address vec-left)
|
|---|
| 486 | (incf offset vec-left)
|
|---|
| 487 | (decf length vec-left))))))
|
|---|
| 488 |
|
|---|
| 489 | (defun set-minimum-file-length (stream length)
|
|---|
| 490 | (unless (>= (file-length stream) length)
|
|---|
| 491 | (file-length stream length)))
|
|---|
| 492 |
|
|---|
| 493 | #|
|
|---|
| 494 | (setq s (open "temp.lisp" :direction :io :if-exists :overwrite))
|
|---|
| 495 |
|
|---|
| 496 | (defun r (address length)
|
|---|
| 497 | (declare (special s))
|
|---|
| 498 | (let ((v (make-string length :element-type 'base-character)))
|
|---|
| 499 | (let ((real-length (stream-read-bytes s address v 0 length)))
|
|---|
| 500 | (if (eql length real-length)
|
|---|
| 501 | (values v length)
|
|---|
| 502 | (let ((res (make-string real-length)))
|
|---|
| 503 | (dotimes (i real-length)
|
|---|
| 504 | (setf (aref res i) (aref v i)))
|
|---|
| 505 | (values res real-length))))))
|
|---|
| 506 |
|
|---|
| 507 | (defun w (string address &optional
|
|---|
| 508 | (offset 0) (length (- (length string) offset)))
|
|---|
| 509 | (declare (special s))
|
|---|
| 510 | (stream-write-bytes s address string offset length))
|
|---|
| 511 |
|
|---|
| 512 | |#
|
|---|
| 513 | ;;; 1 3/10/94 bill 1.8d247
|
|---|
| 514 | ;;; 2 10/04/94 bill 1.9d071
|
|---|
| 515 | ;;; 3 11/03/94 Moon 1.9d086
|
|---|
| 516 | ;;; 2 3/23/95 bill 1.11d010
|
|---|
| 517 | ;;; 3 6/02/95 bill 1.11d040
|
|---|
| 518 | ;;; 4 8/01/95 bill 1.11d065
|
|---|