diff --git a/pcl_expect.py b/pcl_expect.py
index 4265bf55718fb42d31891d216695b9ae4cc39437..bff35fe78ba56a4d39cc76c06e6ad5a0483d0fb3 100644
--- a/pcl_expect.py
+++ b/pcl_expect.py
@@ -1,6 +1,9 @@
-import sets
-import select
 import os
+import re
+import select
+import sets
+import sys
+import types
 
 #
 # Global variables.  The user are supposed to change these.
@@ -21,24 +24,33 @@ timeout_raises_exception = True
 class Timeout(Exception): pass
 
 class expectable:
-    def __init__(self):
+    def __init__(self, fileno):
+        self.__fileno = fileno
+        self.__buffer = ""
         self.__eof_seen = False
 
     def fileno(self):
         return self.__fileno
 
     def fill_buffer(self):
-        s = os.read(self.fileno(), 8192)
-        if s == "":
-            self.__eof_seen = True
+        if not self.__eof_seen:
+            s = os.read(self.fileno(), 8192)
+            if s == "":
+                debug("got eof from fd %d" % self.fileno())
+                self.__eof_seen = True
+            else:
+                debug("got %d bytes from fd %d" % (len(s), self.fileno()))
+                self.__buffer = self.__buffer + s
         else:
-            self.__buffer = self.__buffer + s
+            debug("eof already seen on fd %d; not reading" % self.fileno())
+        return self.__eof_seen
 
     def eof(self):
         """Return True if end-of-file has been seen.
 
         There might still be pending data in the buffer, though.
         """
+        return self.__eof_seen
 
     def buffer(self):
         return self.__buffer
@@ -46,6 +58,14 @@ class expectable:
     def remove_first(self, n):
         self.__buffer = self.__buffer[n:]
 
+class popen(expectable):
+    def __init__(self, cmd):
+        self.__cmd = os.popen(cmd, "r")
+        expectable.__init__(self, self.__cmd.fileno())
+
+    def close(self):
+        return self.__cmd.close()
+
 class impl:
     def __init__(self, timeout = None):
         self.__first = True
@@ -56,21 +76,29 @@ class impl:
         self.__timeout_active = False
         self.__acted = False
         self.__all_inputs_seen = False
+        debug("START")
 
     def loop(self):
+        debug("at top of loop")
         if self.__done:
+            debug("done -- exiting expect")
             return False
 
         if self.__first:
             self.__first = False
-            if __expect_before():
+            debug("first time round")
+            self.__acted = False
+            if _expect_before():
                 return False
             return True
         elif not self.__acted:
+            debug("no action taken during previous loop")
             self.__all_inputs_seen = True
-            if __expect_after():
+            if _expect_after():
                 return False
 
+        self.__acted = False
+
         # Nothing handled the timeout event.
         if self.__timeout_active:
             debug("Unhandled timeout")
@@ -79,6 +107,7 @@ class impl:
             else:
                 return False
 
+        r = ", ".join([str(x.fileno()) for x in self.__inputs])
         if not self.__all_inputs_seen:
             t = 0
         elif self.__timeout == None:
@@ -86,7 +115,9 @@ class impl:
         else:
             t = self.__timeout
         if t > 0:
-            debug("Waiting for input")
+            debug("Waiting for input on %s" % r)
+        else:
+            debug("Polling for input on %s" % r)
         (r, w, e) = select.select([x for x in self.__inputs], [], [], t)
         self.__readable = sets.Set(r)
         if len(self.__readable) == 0:
@@ -95,11 +126,19 @@ class impl:
                 self.__timeout_active = True
         else:
             debug("Input available")
-        if __expect_before():
+        if _expect_before():
             return False
         return True
 
 
+    def __fill_buffer(self, exp):
+        if exp in self.__readable:
+            debug("reading from fd %d" % exp.fileno())
+            self.__readable.remove(exp)
+            if exp.fill_buffer():
+                debug("got eof on fd %d" % exp.fileno())
+                self.__inputs.discard(exp)
+
     def re(self, exp, regexp):
         """Implement "when re foo, foo_re".
 
@@ -119,9 +158,10 @@ class impl:
         if self.__done:
             raise "foo! me bad!"
 
-        if exp in self.__readable:
-            self.__readable.remove(exp)
-            exp.fill_buffer()
+        self.__fill_buffer(exp)
+
+        debug("does \"%s\" match \"%s\" (fd %d)?" % (
+            exp.buffer(), regexp, exp.fileno()))
 
         # Doing this compilation again and again could be a problem.
         # I rely on the cache in module re.  I hope it exists...
@@ -130,16 +170,43 @@ class impl:
 
         match = regexp.search(exp.buffer())
         if match != None:
+            debug("yes")
             exp.match = match
             exp.remove_first(match.end())
             self.__done = True
             self.__acted = True
             return True
         else:
+            debug("no")
             if not exp.eof():
+                debug("adding fd %d to rd-set" % exp.fileno())
                 self.__inputs.add(exp)
             return False
 
+    def eof(self, exp):
+        """Implement "when eof foo".
+        """
+        if self.__acted:
+            return False
+        
+        if self.__done:
+            raise "foo! me bad!"
+
+        self.__fill_buffer(exp)
+
+        if exp.eof():
+            debug("eof seen on fd %d" % exp.fileno())
+            exp.match = exp.buffer()
+            exp.remove_first(len(exp.match))
+            self.__done = True
+            self.__acted = True
+            return True
+        else:
+            debug("no eof on fd %d" % exp.fileno())
+            debug("adding fd %d to rd-set" % exp.fileno())
+            self.__inputs.add(exp)
+            return False
+
     def timeout(self):
         """Implement "when timeout".
 
@@ -153,14 +220,56 @@ class impl:
             raise "foo! me bad!"
 
         if self.__timeout_active:
+            debug("eof pending")
             self.__timeout_active = False
             self.__done = True
             self.__acted = True
             return True
         else:
+            debug("no eof pending")
             return False
 
     def cont(self):
+        debug("cont called")
         self.__done = False
         self.__first = True
         # Don't touch self.__acted
+
+def _expect_before():
+    return False
+
+def _expect_after():
+    return False
+
+def debug(s):
+    if 0:
+        sys.stderr.write("pcl-expect: %s\n" % s)
+
+if __name__ == '__main__':
+    df = popen("df -k")
+
+    x = impl()
+    while x.loop():
+        if x.re(df, "Filesystem.*\n"):
+            print "Header:", df.match.group()
+
+    x = impl()
+    while x.loop():
+        if x.re(df, "^/.* .*\n"):
+            print "Normal line:", df.match.group()
+            x.cont()
+            continue
+        elif x.re(df, "^/.*\n"):
+            print "Mount point only:", df.match.group()
+            x.cont()
+            continue
+        elif x.re(df, "^ .*\n"):
+            print "Info only:", df.match.group()
+            x.cont()
+            continue
+        elif x.re(df, "^.*\n"):
+            print "Unexpected line", df.match.group()
+            x.cont()
+            continue
+        elif x.eof(df):
+            print "And that's all, folks!"