Major Section: IO
Use this function in place of open-output-channel
if you want to open a
channel for output at times this would otherwise be prohibited, for example
during make-event
expansion and clause-processor
hints. If
this functionality doesn't quite seem like what you need, take a look at the
definition of open-output-channel!
in axioms.lisp, specifically the
binding of state
global variable writes-okp
. The following
example, taken from books/hons-archive/hons-archive.lisp
, illustrates
the latter approach.
(defmacro har-zip! (x filename &key sortp) "See :doc hons-archive" `(mv-let (erp val state) (progn! :state-global-bindings ((temp-touchable-vars t set-temp-touchable-vars)) (state-global-let* ((writes-okp t)) (let ((state (har-zip-fn ,x ,filename ,sortp state))) (mv nil nil state)))) (declare (ignore erp val)) state))
The book below illustrates the soundness loophole plugged in ACL2 Version_3.2 related to file writes during book certification.
; The following example is adapted (with only very slight changes) ; from one written by Peter Dillinger. It illustrates the prohibition ; against writing files enforced by with-output-channel during book ; certification (more specifically, during make-event expansion).; This book certifies in ACL2 Version_3.1 before the fix discussed in the ; paragraph about it being ``possible to write files during book ; certification'' in :DOC NOTE-3-2. The fix was actually made to ACL2 ; function open-output-channel.
; After the fix, in order for certification to succeed one needs to do ; two things. First, in raw lisp: ; (push :after-writes-okp-fix *features*) ; Second, certify with this command: ; (certify-book "writes-okp" 0 nil :ttags (:writes-okp))
(in-package "ACL2")
(local (defun write-objects-to-channel (obj-lst chan state) (declare (xargs :mode :program :stobjs state :guard (true-listp obj-lst))) (if (consp obj-lst) (pprogn (print-object$ (car obj-lst) chan state) (write-objects-to-channel (cdr obj-lst) chan state) state) state)))
#+after-writes-okp-fix (defttag :writes-okp)
(local (defun write-objects-to-file (obj-lst filename state) (declare (xargs :mode :program :stobjs state :guard (and (stringp filename) (true-listp obj-lst)))) (mv-let (chan state) #-after-writes-okp-fix (open-output-channel filename :object state) #+after-writes-okp-fix (open-output-channel! filename :object state) (if chan (pprogn (write-objects-to-channel obj-lst chan state) (close-output-channel chan state) (value :done)) (er soft 'write-object-to-file "Could not open for writing: ~x0" filename)))))
(local (defconst *nil.lisp* '((in-package "ACL2") (defthm bad nil :rule-classes nil))))
(local (defconst *nil.cert* '((IN-PACKAGE "ACL2") "ACL2 Version 3.1" :BEGIN-PORTCULLIS-CMDS :END-PORTCULLIS-CMDS NIL (("/home/peterd/test/nil.lisp" "nil" "nil" ((:SKIPPED-PROOFSP) (:AXIOMSP) (:TTAGS)) . 134094174)) 62589544 )))
(local (make-event (er-progn (write-objects-to-file *nil.lisp* "nil.lisp" state) (write-objects-to-file *nil.cert* "nil.cert" state) (value '(value-triple :invisible)))))
(local (include-book "nil" :load-compiled-file nil))
(defthm bad nil :rule-classes nil)