This is a discussion on Re: macro equivalent to "format" but with changed line endings - lisp ; bufie <bufie@spamneggs.com> writes: > I currently have some code that needs to write an output file for use > on windows systems that the users can edit with notepad (yes, that > awful thing that doesn't understand <lf> line endings). ...
bufie <bufie@spamneggs.com> writes:
> I currently have some code that needs to write an output file for use
> on windows systems that the users can edit with notepad (yes, that
> awful thing that doesn't understand <lf> line endings).
>
> I want to use essentially something like:
>
> (with-open-file (o "myfile.txt" :directionutput)
> (dotimes (i 2)
> (format o "This is line ~D.~%~%" (1+ i))))
My first advice would be to use an (unfortunately implementation
specific) external format such as:
(with-open-file (o "myfile.txt"
:directionutput
:external-format #+clisp (ext:make-encoding
:charset charset:windows-1252
:line-terminator :dos)
#-clisp (error "How do you specify an ~
external format encoding WINDOWS-1252 with CR-LF line ~
terminators in ~A" (lisp-implementation-type)))
(dotimes (i 2)
(format o "This is line ~D.~2%" (1+ i))))
> I figured I could write a macro to send <cr><lf> instead of just <lf>,
> perhaps something like this:
>
> (defmacro format-crlf (mystream &rest args)
You don't need a macro for this.
> (let (mystring newstring)
> (setq mystring (apply 'format nil args))
> (setq newstring (string-replace mystring
> (format nil "~A" #\Newline)
> (format nil "~A~A" #\Return #\Newline)))
> `(format ,mystream ,newstring)))
This is wrong, because #\newline may be converted to either #\return,
#\linefeed or #(#\return #\linefeed). At the very least, you should
write:
(format nil "~C~C" #\return #\linefeed)
But since the presence of #\return and #\linefeed is implementation
dependant, you should really guard it with:
#+#.(cl:if (cl:ignore-errors (cl:read-from-string "(#\\Return #\\Linefeed)"))
'(:and) '(r))
(format nil "~C~C" #\return #\linefeed)
#-#.(cl:if (cl:ignore-errors (cl:read-from-string "(#\\Return #\\Linefeed)"))
'(:and) '(r))
(error "There are no #\\Return or #\\Linefeed in ~A"
(lisp-implementation-type))
Therefore, to handle properly the second case, I would advise to treat
this output for what it is: a binary format:
(with-open-file (o "myfile.txt"
:directionutput
:element-type '(unsigned-byte 8))
(let ((ascii:*newline* :crlf))
(dotimes (i 2)
(ascii:ascii-format o "This is line ~D.~2%" (1+ i)))))
;; See: http://darcs.informatimago.com/publi...isp/ascii.lisp
;; and: http://www.informatimago.com/develop/lisp
Now, if the file you write is not encoded in ASCII but in WINDOWS-1252
or something else, you'll have to convert your non ASCII strings
explicitely, and the problem is that encoding/decoding operators are
implementation specific or inexistant.
(with-open-file (o "myfile.txt"
:directionutput
:element-type '(unsigned-byte 8))
(dotimes (i 2)
(write-sequence
(encode-in-windows-1252 (format nil "Thís îs line ~D." (1+ i))) o)
(write-sequence (vector ascii:cr ascii:lf) o)))
Up to you to implement encode-in-windows-1252. If you're lucky, your
implementation will allow you to do it easily:
(defun encode-in-windows-1252 (string)
(assert (not (find #\newline string)))
;; Note, AFAIK there's now way to specify the line-terminator encoding
;; to sbcl, so we don't treat newlines in this function.
#+clisp (ext:convert-string-to-bytes charset:windows-1252)
#+sbcl (sb-ext:string-to-octets string :external-format :windows-1252)
#-(or clisp sbcl)
(error "How do I convert strings to windows-1252 byte sequences in ~A?"
(lisp-implementation-type)))
Of course, you can hide all this in a function notepad-format and a
macro with-notepad-file:
(with-notepad-file (o "myfile.txt" :directionutput)
(dotimes (i 2)
(notepad-format o "Thís îs line ~D.~%" (1+ i))))
And perhaps notepad expects utf-8 instead of windows-1252, I don't
really know anything about MS-Windows...
--
__Pascal Bourguignon__ http://www.informatimago.com/
NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.