Raymond Toy pushed to branch issue-373-handle-temp-files at cmucl / cmucl

Commits:

3 changed files:

Changes:

  • src/code/exports.lisp
    ... ... @@ -1569,7 +1569,10 @@
    1569 1569
     
    
    1570 1570
     	     "*TRUST-DYNAMIC-EXTENT-DECLARATIONS*"
    
    1571 1571
     
    
    1572
    -	     "INVALID-FASL")
    
    1572
    +	     "INVALID-FASL"
    
    1573
    +	     "WITH-TEMPORARY-DIRECTORY"
    
    1574
    +	     "WITH-TEMPORARY-FILE"
    
    1575
    +	     "WITH-TEMPORARY-STREAM")
    
    1573 1576
       ;; gencgc features
    
    1574 1577
       #+gencgc
    
    1575 1578
       (:export "GET-GC-ASSERTIONS"
    

  • src/code/extensions.lisp
    ... ... @@ -627,22 +627,29 @@
    627 627
     	(filename (gensym "FILENAME-"))
    
    628 628
     	(dir (gensym "DIRECTION-"))
    
    629 629
     	(okay (gensym "OKAY-"))
    
    630
    -	(err (gensym "ERR-")))
    
    630
    +	(err (gensym "ERR-"))
    
    631
    +	(file-template (gensym "FILE-TEMPLATE-")))
    
    631 632
         `(progn
    
    632 633
            (unless (member ,direction '(:output :io))
    
    633 634
     	 (error ":direction must be one of :output or :io, not ~S"
    
    634 635
     		,direction))
    
    635
    -       (let (,fd ,filename ,s)
    
    636
    +       (let ((,file-template (concatenate 'string
    
    637
    +					  "/tmp/cmucl-temp-stream-"
    
    638
    +					  "XXXXXX"))
    
    639
    +	     ,fd ,filename ,s)
    
    636 640
     	 (unwind-protect
    
    637 641
     	      (progn
    
    638 642
     		(multiple-value-setq (,fd ,filename)
    
    639
    -		  (unix::unix-mkstemp "/tmp/temp-stream-XXXXXX"))
    
    643
    +		  (unix::unix-mkstemp ,file-template))
    
    644
    +		(unless ,fd
    
    645
    +		  (error "Unable to create temporary stream at ~S: ~A~%"
    
    646
    +			 ,file-template
    
    647
    +			 (unix:get-unix-error-msg ,filename)))
    
    640 648
     		(let* ((,dir ,direction))
    
    641 649
     		  (setf ,s (make-fd-stream ,fd
    
    642 650
     					   :input (member ,dir '(:input :io))
    
    643 651
     					   :output (member ,dir '(:output :io))
    
    644 652
     					   :element-type ',element-type
    
    645
    -					   :name ,filename
    
    646 653
     					   :external-format ,external-format
    
    647 654
     					   :decoding-error ,decoding-error
    
    648 655
     					   :encoding-error ,encoding-error)))
    
    ... ... @@ -654,47 +661,62 @@
    654 661
     			   ,filename (unix:get-unix-error-msg ,err))))
    
    655 662
     		(locally ,@decls
    
    656 663
     		  ,@forms))
    
    657
    -	   ;; Close the stream and the fd now that we're done.
    
    658
    -	   (close ,s)
    
    659
    -	   (unix:unix-close ,fd))))))
    
    664
    +	   ;; Close the stream which will close the fd now that we're
    
    665
    +	   ;; done.
    
    666
    +	   (when ,s
    
    667
    +	     (close ,s)))))))
    
    660 668
     
    
    661 669
     ;;; WITH-TEMPORARY-FILE  -- Public
    
    662
    -(defmacro with-temporary-file ((filename)
    
    670
    +(defmacro with-temporary-file ((filename &key prefix)
    
    663 671
     			       &parse-body (forms decls))
    
    664
    -  (let ((fd (gensym "FD-")))
    
    665
    -    `(let (,filename)
    
    672
    +  (let ((fd (gensym "FD-"))
    
    673
    +	(file-template (gensym "TEMP-PATH-")))
    
    674
    +    `(let ((,file-template (concatenate 'string
    
    675
    +					(or ,prefix
    
    676
    +					    "/tmp/cmucl-temp-file-")
    
    677
    +					"XXXXXX"))
    
    678
    +	   ,filename)
    
    666 679
            (unwind-protect
    
    667 680
     	    (let (,fd)
    
    668 681
     	      (multiple-value-setq (,fd ,filename)
    
    669
    -		(unix::unix-mkstemp "/tmp/cmucl-temp-file-XXXXXX"))
    
    682
    +		(unix::unix-mkstemp ,file-template))
    
    683
    +	      (unless ,fd
    
    684
    +		(error "Unable to create temporary file with template ~S: ~A~%"
    
    685
    +		       ,file-template
    
    686
    +		       (unix:get-unix-error-msg ,filename)))
    
    670 687
     	      (unix:unix-close ,fd)
    
    671 688
     	      (locally ,@decls
    
    672 689
     		,@forms))
    
    673
    -	 (delete-file ,filename)))))
    
    674
    -	
    
    690
    +	 ;; We're done so delete the temp file, if one was created.
    
    691
    +	 (when (stringp ,filename)
    
    692
    +	   (delete-file ,filename))))))
    
    675 693
     
    
    676 694
     ;;; WITH-TEMPORARY-DIRECTORY  -- Public
    
    677
    -(defmacro with-temporary-directory ((dirname template)
    
    695
    +(defmacro with-temporary-directory ((dirname &key prefix)
    
    678 696
     				    &parse-body (forms decls))
    
    679 697
       "Return a pathname to a temporary directory.  TEMPLATE is a string that
    
    680 698
       is used as a prefix for the name of the temporary directory.  The
    
    681 699
       directory and all its contents are automatically removed afterward."
    
    682
    -  (let ((err (gensym "ERR-")))
    
    683
    -    `(let (,dirname ,err)
    
    700
    +  (let ((err (gensym "ERR-"))
    
    701
    +	(dir-path (gensym "DIR-PATH"))
    
    702
    +	(dir-template (gensym "DIR-TEMPLATE-")))
    
    703
    +    `(let ((,dir-template (concatenate 'string
    
    704
    +				       (or ,prefix
    
    705
    +					   "/tmp/cmucl-temp-dir")
    
    706
    +				       "XXXXXX"))
    
    707
    +	   ,dirname ,err)
    
    684 708
            (unwind-protect
    
    685 709
     	    (progn
    
    686 710
     	      (multiple-value-setq (,dirname ,err)
    
    687
    -		(unix::unix-mkdtemp (concatenate 'string ,template
    
    688
    -						 "XXXXXX")))
    
    711
    +		(unix::unix-mkdtemp ,dir-template))
    
    689 712
     	      (unless ,dirname
    
    690
    -		(error "Unable to create temporary directory: ~A"
    
    713
    +		(error "Unable to create temporary directory at ~S: ~A"
    
    714
    +		       ,dir-template
    
    691 715
     		       (unix:get-unix-error-msg ,err)))
    
    692 716
     	      (setf ,dirname (concatenate 'string ,dirname "/"))
    
    693 717
     	      (locally ,@decls
    
    694 718
     		,@forms))
    
    695
    -	 ;; Remove the temp directory and all its contents.  Is there a
    
    696
    -	 ;; better way?
    
    719
    +	 ;; If a temp directory was created, remove it and all its
    
    720
    +	 ;; contents.  Is there a better way?
    
    697 721
     	 (when ,dirname
    
    698 722
     	   (ext:run-program "/bin/rm" (list "-rf" ,dirname)))))))
    699
    -     
    
    700
    -	  

  • tests/trac.lisp
    ... ... @@ -127,16 +127,17 @@
    127 127
       (:tag :trac)
    
    128 128
       (flet ((bug (&optional (format :utf16))
    
    129 129
     	   (ext::with-temporary-stream (s :direction :io :external-format format)
    
    130
    -				       (format s "Hello~%")
    
    131
    -				       (format t "posn = ~A~%" (file-position s))
    
    132
    -				       (file-position s 0)
    
    133
    -				       (let ((ch (read-char s)))
    
    134
    -					 (values ch (file-position s))))))
    
    130
    +	     (format s "Hello~%")
    
    131
    +	     (format t "posn = ~A~%" (file-position s))
    
    132
    +	     (file-position s 0)
    
    133
    +	     (let ((ch (read-char s)))
    
    134
    +	       (values ch (file-position s))))))
    
    135 135
         (assert-equal (values #\H 4)
    
    136 136
     		  (bug :utf16))
    
    137 137
         (assert-equal (values #\H 8)
    
    138 138
     		  (bug :utf32))))
    
    139 139
     
    
    140
    +#+nil
    
    140 141
     (define-test trac.43
    
    141 142
       (:tag :trac)
    
    142 143
       (assert-true
    
    ... ... @@ -156,6 +157,23 @@
    156 157
     		(let ((p0* (file-position stream)))
    
    157 158
     		  (eql p0* p0)))))))))
    
    158 159
     
    
    160
    +(define-test trac.43
    
    161
    +    (:tag :trac)
    
    162
    +  (assert-true
    
    163
    +   (ext:with-temporary-file (path)
    
    164
    +     (with-open-file (ostream path :direction :output
    
    165
    +				   :external-format :utf-8)
    
    166
    +       (dotimes (i 1000)
    
    167
    +	 (write-char (code-char #x1234) ostream)))
    
    168
    +
    
    169
    +     (with-open-file (stream path :direction :input
    
    170
    +				  :external-format :utf-8)
    
    171
    +       (let ((p0 (file-position stream))
    
    172
    +	     (ch (read-char stream)))
    
    173
    +	 (unread-char ch stream)
    
    174
    +	 (let ((p0* (file-position stream)))
    
    175
    +	   (eql p0* p0)))))))
    
    176
    +
    
    159 177
     (define-test trac.50
    
    160 178
       (:tag :trac)
    
    161 179
       (assert-equal "#P(:DIRECTORY (:ABSOLUTE \"tmp\" \"\" \"a\" \"\" \"b\"))"