<br><br><div class="gmail_quote">On Wed, Mar 31, 2010 at 12:02 PM, Gregory Collins <span dir="ltr">&lt;<a href="mailto:greg@gregorycollins.net">greg@gregorycollins.net</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div class="im">David Leimbach &lt;<a href="mailto:leimy2k@gmail.com">leimy2k@gmail.com</a>&gt; writes:<br>
<br>
&gt; to block or perhaps timeout, depending on the environment, looking for<br>
&gt; &quot;some String&quot; on an input Handle, and it appears that iteratee works<br>
&gt; in a very fixed block size.  While a fixed block size is ok, if I can<br>
&gt; put back unused bytes into the enumerator somehow (I may need to put a<br>
&gt; LOT back in some cases, but in the common case I will not need to put<br>
&gt; any back as most expect-like scripts typically catch the last few<br>
&gt; bytes of data sent before the peer is blocked waiting for a<br>
&gt; response...)<br>
<br>
</div>See IterGV from the iteratee lib:<br>
<br>
<a href="http://hackage.haskell.org/packages/archive/iteratee/0.3.1/doc/html/Data-Iteratee-Base.html#t%3AIterGV" target="_blank">http://hackage.haskell.org/packages/archive/iteratee/0.3.1/doc/html/Data-Iteratee-Base.html#t%3AIterGV</a><br>

<br>
The second argument to the &quot;Done&quot; constructor is for the portion of the<br>
input that you didn&#39;t use. If you use the Monad instance, the unused<br>
input is passed on (transparently) to the next iteratee in the chain.</blockquote><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<br>
If you use attoparsec-iteratee<br>
(<a href="http://hackage.haskell.org/packages/archive/attoparsec-iteratee/0.1/doc/html/Data-Attoparsec-Iteratee.html" target="_blank">http://hackage.haskell.org/packages/archive/attoparsec-iteratee/0.1/doc/html/Data-Attoparsec-Iteratee.html</a>),<br>

you could write &quot;expect&quot; as an attoparsec parser:<br></blockquote><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"><br>
------------------------------------------------------------------------<br>
{-# LANGUAGE OverloadedStrings #-}<br>
<br>
import Control.Applicative<br>
import Control.Monad.Trans (lift)<br>
import Data.Attoparsec hiding (Done)<br>
import Data.Attoparsec.Iteratee<br>
import qualified Data.ByteString as S<br>
import Data.ByteString (ByteString)<br>
import Data.Iteratee<br>
import Data.Iteratee.IO.Fd<br>
import Data.Iteratee.WrappedByteString<br>
import Data.Word (Word8)<br>
import System.IO<br>
import <a href="http://System.Posix.IO" target="_blank">System.Posix.IO</a><br>
<br>
expect :: (Monad m) =&gt; ByteString<br>
                    -&gt; IterateeG WrappedByteString Word8 m ()<br>
expect s = parserToIteratee (p &gt;&gt; return ())<br>
  where<br>
    p = string s &lt;|&gt; (anyWord8 &gt;&gt; p)<br>
<br>
<br>
dialog :: (Monad m) =&gt;<br>
          IterateeG WrappedByteString Word8 m a   -- ^ output end<br>
       -&gt; IterateeG WrappedByteString Word8 m ()<br>
dialog outIter = do<br>
    expect &quot;login:&quot;<br>
    respond &quot;foo\n&quot;<br>
    expect &quot;password:&quot;<br>
    respond &quot;bar\n&quot;<br>
    return ()<br>
<br>
  where<br>
    respond s = do<br>
        _ &lt;- lift $ enumPure1Chunk (WrapBS s) outIter &gt;&gt;= run<br>
        return ()<br>
<br>
<br>
main :: IO ()<br>
main = do<br>
    hSetBuffering stdin NoBuffering<br>
    hSetBuffering stdout NoBuffering<br>
    enumFd stdInput (dialog output) &gt;&gt;= run<br>
  where<br>
    output = IterateeG $ \chunk -&gt;<br>
             case chunk of<br>
               (EOF _)            -&gt; return $ Done () chunk<br>
               (Chunk (WrapBS s)) -&gt; S.putStr s &gt;&gt;<br>
                                     hFlush stdout &gt;&gt;<br>
                                     return (Cont output Nothing)<br>
------------------------------------------------------------------------<br>
<br>
Usage example:<br>
<br>
    $ awk &#39;BEGIN { print &quot;login:&quot;; fflush(); system(&quot;sleep 2&quot;); \<br>
                   print &quot;password:&quot;; fflush(); }&#39; | runhaskell Expect.hs<br>
    foo<br>
    bar<br>
<br>
N.B. for some reason &quot;enumHandle&quot; doesn&#39;t work here w.r.t buffering, had<br>
to go to POSIX i/o to get the proper buffering behaviour.<br>
<br></blockquote><div>That&#39;s pretty neat actually.  I&#39;m going to have to incorporate timeouts into something like that (and attoparsec-iteratee doesn&#39;t install for me for some reason, I&#39;ll try again today).</div>
<div><br></div><div>That leads me to another question in another thread I&#39;m about to start.</div><div><br></div><div>Dave</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">

G<br>
<font color="#888888">--<br>
Gregory Collins &lt;<a href="mailto:greg@gregorycollins.net">greg@gregorycollins.net</a>&gt;<br>
</font></blockquote></div><br>