The contents of a file (or part of it) as a string
When this macro is passed a valid filename and the ACL2 state, it generally returns the contents of the file (or a specified part of
the file) as a string. Otherwise, it returns
Example Forms: (read-file-into-string "foo.lisp") (read-file-into-string "foo.lisp" :start 0 :bytes nil) ; same as above (read-file-into-string "foo.lisp" :start 20000 :bytes 10000) (read-file-into-string "foo.lisp" :start 20000 :bytes 10000 :close t) General Form: (read-file-into-string filename ; a filename relative to the current directory :start s ; default 0 :bytes b ; default nil :close c ; default :default )
where
For examples, see community-books file
The result, when not
Note that ACL2 characters always fit into a single byte, which is why we can talk about ``bytes'' here.
The
(time$ (read-file-into-string "<file>" :start 0 :bytes 0 :close t))
Compared with the usual io routines provided by ACL2,
The constant
There are two checks to guarantee that
(increment-file-clock state)
If however you make illegal successive reads as described above, a Lisp error will occur with a message of the following form.
*********************************************** ************ ABORTING from raw Lisp *********** ********** (see :DOC raw-lisp-error) ********** Error: Illegal consecutive reads from file "<some_filename>", which appears to have been written between the two reads. Execute (INCREMENT-FILE-CLOCK STATE) to avoid this error. See :DOC read-file-into-string. While executing: READ-FILE-INTO-STRING2 ***********************************************
A similar error may occur when a call of
The other check ensures that the write date of the file has not changed while a call is in progress. When that check fails the corresponding Lisp error is of the following form.
************ ABORTING from raw Lisp *********** ********** (see :DOC raw-lisp-error) ********** Error: Illegal attempt to call READ-FILE-INTO-STRING concurrently with some write to that file! See :DOC read-file-into-string. ***********************************************
We close by showing the relevant ACL2 definitions in the logic, that is,
not including the special raw Lisp (under the hood) code in the definition of
Function:
(defun read-file-into-string1 (channel state ans bound) (declare (xargs :stobjs state :guard (and (symbolp channel) (open-input-channel-p channel :character state) (character-listp ans) (natp bound)))) (cond ((zp bound) (mv nil state)) (t (mv-let (val state) (read-char$ channel state) (cond ((not (characterp val)) (mv (coerce (reverse ans) 'string) state)) (t (read-file-into-string1 channel state (cons val ans) (1- bound))))))))
Definition:
(defconst *read-file-into-string-bound* (1- (ash 1 60)))
Function:
(defun read-file-into-string2-logical (filename start bytes state) (declare (xargs :stobjs state :guard (and (stringp filename) (natp start) (or (null bytes) (natp bytes))))) (non-exec (mv-let (erp val state) (mv-let (chan state) (open-input-channel filename :character state) (cond ((or (null chan) (not (state-p state))) (mv nil nil state)) (t (mv-let (val state) (read-file-into-string1 chan state nil *read-file-into-string-bound*) (pprogn (ec-call (close-input-channel chan state)) (mv nil val state)))))) (declare (ignore erp state)) (and (stringp val) (<= start (length val)) (subseq val start (if bytes (min (+ start bytes) (length val)) (length val)))))))
Function:
(defun read-file-into-string2 (filename start bytes close state) (declare (xargs :stobjs state :guard (and (stringp filename) (natp start) (or (null bytes) (natp bytes)))) (ignore close)) (read-file-into-string2-logical filename start bytes state))
Macro:
(defmacro read-file-into-string (filename &key (start '0) bytes (close ':default)) (cons 'read-file-into-string2 (cons filename (cons start (cons bytes (cons close '(state)))))))