From: dpapathanasiou
Subject: Problems using handler-case inside a do loop
Date: 
Message-ID: <1139258374.618122.86210@o13g2000cwo.googlegroups.com>
I have a utility function which reads a stream and returns the entire
contents as a string:

(defun stream-to-string (str)
  "Convert the contents of stream to a single string."
  (when (streamp str)
    (with-output-to-string (s)
      (do ((l (read-line str nil 'eof)
	      (read-line str nil 'eof)))
	  ((eql l 'eof))
	(format s "~A~%" l)))))

It breaks down, though, when there's a problem with the stream, most
commonly if the stream gets cut off and doesn't return a proper EOF
marker.

In those cases I get this error message, and I'm thrown into the
debugger:

End-of-File on #<Stream for descriptor 5>
   [Condition of type END-OF-FILE]

To remedy that, I've rewritten the function to use a (handler-case)
like this:

(defun read-my-stream (str)
  (handler-case
    (read str nil 'eof)
    (error () 'eof)))

(defun stream-to-string (str)
  "Convert the contents of stream to a single string."
  (when (streamp str)
    (with-output-to-string (s)
      (do ((l (read-my-stream str)
	      (read-my-stream str)))
	  ((eql l 'eof))
	(format s "~A~%" l)))))

>From what I understand about (handler-case), it'll attempt the first
statement -- in this example: (read str nil 'eof) -- but if there's an
error of any kind, it will return the symbol 'eof instead.

Unfortunately, what I'm finding is that the do loop inside
stream-to-string never breaks!

In other words, handler-case does trap the error -- I do not see those
"End-of-File on #<Stream for descriptor 5>" messages any more -- but it
does not set l to 'eof as I expect.

I rewrote the functions like this:

(defun read-my-stream (str)
  (handler-case
    (read str nil 'eof)
    (error () nil)))

(defun stream-to-string (str)
  "Convert the contents of stream to a single string."
  (when (streamp str)
    (with-output-to-string (s)
      (do ((l (read-my-stream str)
	      (read-my-stream str)))
	  ((or (null l) (eql l 'eof)))
	(format s "~A~%" l)))))

but that did not solve the problem either -- in the case of a stream
error, l never gets set to nil.

Just to make sure handler-case is working, I rewrote it like this:

(defun read-my-stream (str)
  (handler-case
    (read str nil 'eof)
    (error () (progn (format t "ERROR~%") nil))))

Sure enough, I saw the text "ERROR" flash when the stream broke, but
the stream-to-string function never finished its do loop -- l was never
set to nil, and the do loop just kept going.

What can I do to correct this?

From: Ulrich Hobelmann
Subject: Re: Problems using handler-case inside a do loop
Date: 
Message-ID: <44prvoF3e0g2U2@individual.net>
dpapathanasiou wrote:
> I have a utility function which reads a stream and returns the entire
> contents as a string:

I hope this will help you:
http://www.emmett.ca/~sabetts/slurp.html

Some of the functions used, such as READ-LINE, usually terminate on EOF.

-- 
Suffering from Gates-induced brain leakage...
From: Brian Downing
Subject: Re: Problems using handler-case inside a do loop
Date: 
Message-ID: <%1QFf.537475$084.318216@attbi_s22>
In article <·······················@o13g2000cwo.googlegroups.com>,
dpapathanasiou <···················@gmail.com> wrote:
> It breaks down, though, when there's a problem with the stream, most
> commonly if the stream gets cut off and doesn't return a proper EOF
> marker.
> 
> In those cases I get this error message, and I'm thrown into the
> debugger:
> 
> End-of-File on #<Stream for descriptor 5>
>    [Condition of type END-OF-FILE]

This is a good indication your implementation is broken.  This should
not happen.

> To remedy that, I've rewritten the function to use a (handler-case)
> like this:
> 
> (defun read-my-stream (str)
>   (handler-case
>     (read str nil 'eof)
>     (error () 'eof)))

I assume you meant READ-LINE here - it shouldn't change the fact that
your loop doesn't end, though.

> (defun stream-to-string (str)
>   "Convert the contents of stream to a single string."
>   (when (streamp str)
>     (with-output-to-string (s)
>       (do ((l (read-my-stream str)
> 	      (read-my-stream str)))
> 	  ((eql l 'eof))
> 	(format s "~A~%" l)))))
> 
> >From what I understand about (handler-case), it'll attempt the first
> statement -- in this example: (read str nil 'eof) -- but if there's an
> error of any kind, it will return the symbol 'eof instead.
> 
> Unfortunately, what I'm finding is that the do loop inside
> stream-to-string never breaks!
> 
> What can I do to correct this?

I tried your code above on SBCL, CMUCL, and Lispworks, and all work as
expected.  What implementation are you using?

-bcd
-- 
*** Brian Downing <bdowning at lavos dot net> 
From: dpapathanasiou
Subject: Re: Problems using handler-case inside a do loop
Date: 
Message-ID: <1139265849.433458.60650@g14g2000cwa.googlegroups.com>
Brian,

> I assume you meant READ-LINE here

Yes, the first expression in the handler-case structure is: (read-line
str nil 'eof).

Here's that function copied from my source file:

(defun read-my-stream (str)
  (handler-case
    (read-line str nil 'eof)
    (error () 'eof)))

> I tried your code above on SBCL, CMUCL, and Lispworks, and all work as
> expected.  What implementation are you using?

It's CMUCL 19c on a Debian Sarge (x86) box.

What I want to confirm is:

My expectation, based on my understanding of handler-case, is that if
the call to (read-my-stream) results in an error, then the variable l
in (stream-to-string) gets set to the symbol 'eof -- is that correct?

If that's so, then, by extention, the do loop in (stream-to-string)
should stop b/c the do loop's terminating condition will have been met,
correct?

Or, is it like ignore-error which returns two values, and I need to use
something like (multiple-value-bind ...) ?
From: Brian Downing
Subject: Re: Problems using handler-case inside a do loop
Date: 
Message-ID: <NGQFf.780566$xm3.326749@attbi_s21>
In article <·······················@g14g2000cwa.googlegroups.com>,
dpapathanasiou <···················@gmail.com> wrote:
> Here's that function copied from my source file:
> 
> (defun read-my-stream (str)
>   (handler-case
>       (read-line str nil 'eof)
>     (error () 'eof)))
> 
> What I want to confirm is:
> 
> My expectation, based on my understanding of handler-case, is that if
> the call to (read-my-stream) results in an error, then the variable l
> in (stream-to-string) gets set to the symbol 'eof -- is that correct?

Yes, the code above will return the value of (read-line str nil 'eof),
but if a condition that is a subclass of ERROR is signaled, it will
return EOF instead.

The catch would be if for some strange reason END-OF-FILE is not a
subclass of ERROR for some reason (in violation of the spec), it would
not be caught by that HANDLER-CASE.  However, if it was signaled with
ERROR it would still hit the debugger.

You may want to explicitly check for END-OF-FILE instead of ERROR.

> Or, is it like ignore-error which returns two values, and I need to use
> something like (multiple-value-bind ...) ?

No.

I don't know what could be causing your behavior.

-bcd
-- 
*** Brian Downing <bdowning at lavos dot net> 
From: dpapathanasiou
Subject: Re: Problems using handler-case inside a do loop
Date: 
Message-ID: <1139269359.187974.29580@g43g2000cwa.googlegroups.com>
Brian,

Thanks for that clarification -- I thought I'd read the section on
handler-case correctly, but I wasn't sure.

Actually, the source of the stream fed into (stream-to-string) comes
from an ext:run-program call, so it looks like I'll have to dig deeper
into those parameters.

Right now, I'm calling ext:run-program with :output :stream :wait nil
-- i.e. using the default :error setting.

When the underlying process succeeds (and writes all its output to
stdout), there are no problems in (stream-to-string).

But when the child fails (and writes to stderr), either the content of
stderr or how that stderr content gets fed into the stream I'm trying
to read (etc., or something else along those lines) is probably what's
fooling handler-case.
From: Brian Downing
Subject: Re: Problems using handler-case inside a do loop
Date: 
Message-ID: <6jRFf.537549$084.42432@attbi_s22>
In article <·······················@g43g2000cwa.googlegroups.com>,
dpapathanasiou <···················@gmail.com> wrote:
> Actually, the source of the stream fed into (stream-to-string) comes
> from an ext:run-program call, so it looks like I'll have to dig deeper
> into those parameters.

Ah, that could definitely make things strange.

> Right now, I'm calling ext:run-program with :output :stream :wait nil
> -- i.e. using the default :error setting.
> 
> When the underlying process succeeds (and writes all its output to
> stdout), there are no problems in (stream-to-string).
> 
> But when the child fails (and writes to stderr), either the content of
> stderr or how that stderr content gets fed into the stream I'm trying
> to read (etc., or something else along those lines) is probably what's
> fooling handler-case.

The CMUCL mailing list may be a good place to go with these issues.

-bcd
-- 
*** Brian Downing <bdowning at lavos dot net>