From: ···········@gmail.com
Subject: How to write binary data to standard out?
Date: 
Message-ID: <1151979067.117352.39090@m79g2000cwm.googlegroups.com>
If I try:

(write-byte 128 *standard-output*)

I get:

*** - WRITE-BYTE on #<OUTPUT BUFFERED FILE-STREAM CHARACTER
#P"/dev/fd/1"> is
      illegal

How can I change the :element-type of *standard-output*?

From: Rob Warnock
Subject: Re: How to write binary data to standard out?
Date: 
Message-ID: <9_ydnRao3om7RzTZnZ2dnUVZ_radnZ2d@speakeasy.net>
<···········@gmail.com> wrote:
+---------------
| If I try:
|    (write-byte 128 *standard-output*)
| I get:
|    *** - WRITE-BYTE on #<OUTPUT BUFFERED FILE-STREAM CHARACTER
|    #P"/dev/fd/1"> is illegal
| How can I change the :element-type of *standard-output*?
+---------------

Whether you can at all is implementation-dependent; it may very well
be the case that you can't. However, given that you're obviously
running on a system which supports "/dev/fd/1", why not simply do this?

    (with-open-file (s "/dev/fd/1" :direction :output
				   :if-exists :append
				   :element-type '(unsigned-byte 8))
      (write-byte 128 s))

[Works in CMUCL & CLISP, at least.]


-Rob

p.s. In CMUCL, one could also do it this way:

    (let* ((sym (synonym-stream-symbol *standard-output*))
           (fd1 (system:fd-stream-fd (symbol-value sym)))
           (fd (unix:unix-dup fd1))         ; avoid closing fd1 !!
           (s (system:make-fd-stream fd :output t
                                        :element-type '(unsigned-byte 8))))
      (with-open-stream (s s)
        (write-byte 128 s)))

But that's just UG-lee...  ;-}  ;-}

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: goose
Subject: Re: How to write binary data to standard out?
Date: 
Message-ID: <1151991638.116355.78530@a14g2000cwb.googlegroups.com>
Rob Warnock wrote:
> <···········@gmail.com> wrote:
> +---------------
> | If I try:
> |    (write-byte 128 *standard-output*)
> | I get:
> |    *** - WRITE-BYTE on #<OUTPUT BUFFERED FILE-STREAM CHARACTER
> |    #P"/dev/fd/1"> is illegal
> | How can I change the :element-type of *standard-output*?
> +---------------
>
> Whether you can at all is implementation-dependent; it may very well
> be the case that you can't. However, given that you're obviously
> running on a system which supports "/dev/fd/1", why not simply do this?
>
>     (with-open-file (s "/dev/fd/1" :direction :output
>                                  :if-exists :append
>                                  :element-type '(unsigned-byte 8))
>       (write-byte 128 s))
>

Quick question: How can I write a string to that output?
format and print both fail. I'd like to mix raw bytes and
common strings on the same output (and input).

tia
goose,
From: Pascal Bourguignon
Subject: Re: How to write binary data to standard out?
Date: 
Message-ID: <87bqs5vrw2.fsf@thalassa.informatimago.com>
"goose" <····@webmail.co.za> writes:

> Rob Warnock wrote:
>> <···········@gmail.com> wrote:
>> +---------------
>> | If I try:
>> |    (write-byte 128 *standard-output*)
>> | I get:
>> |    *** - WRITE-BYTE on #<OUTPUT BUFFERED FILE-STREAM CHARACTER
>> |    #P"/dev/fd/1"> is illegal
>> | How can I change the :element-type of *standard-output*?
>> +---------------
>>
>> Whether you can at all is implementation-dependent; it may very well
>> be the case that you can't. However, given that you're obviously
>> running on a system which supports "/dev/fd/1", why not simply do this?
>>
>>     (with-open-file (s "/dev/fd/1" :direction :output
>>                                  :if-exists :append
>>                                  :element-type '(unsigned-byte 8))
>>       (write-byte 128 s))
>>
>
> Quick question: How can I write a string to that output?
> format and print both fail. I'd like to mix raw bytes and
> common strings on the same output (and input).

You cannot.  Strings contain characters, not bytes.
Well, you can encode a string into a byte sequence.


For example:

(defvar *ascii* " !\"#$%&'()*+,-./0123456789:;<=>·@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~")

(defun string-encode-ascii (string)
  (coerce
   (loop
      :for ch :across string
      :for code = (position ch *ascii* :test (function char=))
      :when (null code)
      :do (error "~S contains an non-ASCII-encodable character: ~C" string ch)
      :when (not (null code))  :collect (+ 32 code)) 'vector))


(string-encode-ascii "Hello World!")
--> #(72 101 108 108 111 32 87 111 114 108 100 33)

(string-encode-ascii "Enchant�!")
ERROR: *** - "Enchant�!" contains an non-ASCII-encodable character: �



Some implementations have non standard functions to encode and decode
strings.  Eg. clisp has EXT:CONVERT-STRING-TO-BYTES and
EXT:CONVERT-STRING-FROM-BYTES.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

READ THIS BEFORE OPENING PACKAGE: According to certain suggested
versions of the Grand Unified Theory, the primary particles
constituting this product may decay to nothingness within the next
four hundred million years.
From: Rob Warnock
Subject: Re: How to write binary data to standard out?
Date: 
Message-ID: <SLWdnR-FQpujvDfZnZ2dnUVZ_oSdnZ2d@speakeasy.net>
Pascal Bourguignon  <···@informatimago.com> wrote:
+---------------
| "goose" <····@webmail.co.za> writes:
| > Quick question: How can I write a string to that output?
| > format and print both fail. I'd like to mix raw bytes and
| > common strings on the same output (and input).
| 
| You cannot.  Strings contain characters, not bytes.
| Well, you can encode a string into a byte sequence.
| For example: ...
| (defun string-encode-ascii (string)
|   (coerce (loop :for ch :across string ...)
|           'vector))
| (string-encode-ascii "Hello World!")
| --> #(72 101 108 108 111 32 87 111 114 108 100 33)
+---------------

Plain ol' MAP should also work:

    > (map 'vector 'char-code "Hello World!")

    #(72 101 108 108 111 32 87 111 114 108 100 33)
    > 

And then one should able to use WRITE-SEQUENCE on the resulting vector.
WITH-OUTPUT-TO-STRING is handy for capturing the text to MAP. Putting it
all together:

    > (with-open-file (s "/dev/fd/1" :direction :output
				     :if-exists :append
				     :element-type '(unsigned-byte 8))
	(write-byte 128 s)
	(write-sequence (map 'vector 'char-code
			     (with-output-to-string (str)
			       (format str "Hello, world!")
			       (print 'a-symbol str)
			       (terpri str)))  
			s)
	(write-byte 129 s))
    Hello, world!
    A-SYMBOL 

    129
    > 


-Rob

p.s. The #x80 & #x81 bytes didn't cut & paste above, but they were there:

$ cmucl -quiet -load foo.lisp -eval '(quit)' | hexdump -C
00000000  80 48 65 6c 6c 6f 2c 20  77 6f 72 6c 64 21 0a 41  |.Hello, world!.A|
00000010  2d 53 59 4d 42 4f 4c 20  0a 81                    |-SYMBOL ..|
0000001a
$ 

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Pascal Bourguignon
Subject: Re: How to write binary data to standard out?
Date: 
Message-ID: <87u05xtysk.fsf@thalassa.informatimago.com>
····@rpw3.org (Rob Warnock) writes:
> Plain ol' MAP should also work:
>
>     > (map 'vector 'char-code "Hello World!")
>
>     #(72 101 108 108 111 32 87 111 114 108 100 33)
>     > 

Beware, CHAR-CODE is not ASCII-CODE (nor UTF-8-CODE or anything else specified)!

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

PLEASE NOTE: Some quantum physics theories suggest that when the
consumer is not directly observing this product, it may cease to
exist or will exist only in a vague and undetermined state.
From: Rob Warnock
Subject: Re: How to write binary data to standard out?
Date: 
Message-ID: <f4ednaNXZo-I0jfZnZ2dnUVZ_vSdnZ2d@speakeasy.net>
Pascal Bourguignon  <···@informatimago.com> wrote:
+---------------
| ····@rpw3.org (Rob Warnock) writes:
| > Plain ol' MAP should also work:
| >     > (map 'vector 'char-code "Hello World!")
| >     #(72 101 108 108 111 32 87 111 114 108 100 33)
| >     > 
| 
| Beware, CHAR-CODE is not ASCII-CODE (nor UTF-8-CODE or
| anything else specified)!
+---------------

Good point.


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Tayssir John Gabbour
Subject: Re: How to write binary data to standard out?
Date: 
Message-ID: <1152010656.254636.289140@h44g2000cwa.googlegroups.com>
Pascal Bourguignon wrote:
> "goose" <····@webmail.co.za> writes:
> > Quick question: How can I write a string to that output?
> > format and print both fail. I'd like to mix raw bytes and
> > common strings on the same output (and input).
>
> You cannot.  Strings contain characters, not bytes.
> Well, you can encode a string into a byte sequence.

I believe Edi Weitz's Flexi-Streams does this? I just looked at it
yesterday:
http://www.weitz.de/flexi-streams/


Tayssir
--
Pro-globalization anarchist from Yale interviewed by Charlie Rose:
http://youtube.com/watch?v=uajHCIU876I&search=anthropology
From: Thomas A. Russ
Subject: Re: How to write binary data to standard out?
Date: 
Message-ID: <ymihd1v3nab.fsf@sevak.isi.edu>
Pascal Bourguignon <···@informatimago.com> writes:

> "goose" <····@webmail.co.za> writes:
> > Quick question: How can I write a string to that output?
> > format and print both fail. I'd like to mix raw bytes and
> > common strings on the same output (and input).
> 
> You cannot.  Strings contain characters, not bytes.
> Well, you can encode a string into a byte sequence.

Some lisp implementations support so-called BI-VALENT streams.  They
allow both binary and character input or output.  I know that ACL has
them under that name.  This actually turns out to be quite useful for
writing web applications, since the headers are all ASCII characters,
even for transfering binary data like, for example GIF files.

That makes it useful to be able to mix reading and writing character and
binary data on the same stream.

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Pascal Bourguignon
Subject: Re: How to write binary data to standard out?
Date: 
Message-ID: <87k66uuis3.fsf@thalassa.informatimago.com>
···········@gmail.com writes:

> If I try:
>
> (write-byte 128 *standard-output*)
>
> I get:
>
> *** - WRITE-BYTE on #<OUTPUT BUFFERED FILE-STREAM CHARACTER
> #P"/dev/fd/1"> is
>       illegal
>
> How can I change the :element-type of *standard-output*?

(setf (stream-element-type *standard-output*) '(unsigned-byte 8))

This is not supported by all stream types though: you cannot send
binary data to a "terminal" designed to display characters, or to a
_text_ file.  But if you're on a system that allow to store both bytes
and characters to a file, you ought to have no problem.


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

NEW GRAND UNIFIED THEORY DISCLAIMER: The manufacturer may
technically be entitled to claim that this product is
ten-dimensional. However, the consumer is reminded that this
confers no legal rights above and beyond those applicable to
three-dimensional objects, since the seven new dimensions are
"rolled up" into such a small "area" that they cannot be
detected.
From: Juho Snellman
Subject: Re: How to write binary data to standard out?
Date: 
Message-ID: <slrneaklso.9ba.jsnell@sbz-30.cs.Helsinki.FI>
Pascal Bourguignon <···@informatimago.com> wrote:
> (setf (stream-element-type *standard-output*) '(unsigned-byte 8))
> 
> This is not supported by all stream types though:

It's also not a part of Common Lisp, and thus unlikely to be supported
on most implementations.

-- 
Juho Snellman