--- /dev/null
+"""Implements a non-blocking pipe class."""\r
+\r
+# Since it uses thread rather than select, it is portable to at least\r
+# posix and windows environments.\r
+\r
+# Author: Rasjid Wilcox, copyright (c) 2002\r
+# Ideas taken from the Python 2.2 telnetlib.py library.\r
+#\r
+# Last modified: 3 August 2002\r
+# Licence: Python 2.2 Style License. See license.txt.\r
+\r
+# TO DO:\r
+# * Handle excpetions better, particularly Keyboard Interupts.\r
+# * Possibly do a threadless version for posix environments\r
+# where we can use select (is probably more efficient).\r
+# * A test function.\r
+\r
+import Queue\r
+import thread\r
+import os\r
+import time\r
+import types\r
+\r
+#INT_TYPE = type(1)\r
+MIN_TIMEOUT = 0.01\r
+\r
+class nbpipe:\r
+ def __init__(self, readfile, pipesize=0, blocksize=1024):\r
+ """Initialise a non-blocking pipe object, given a real file or file-descriptor.\r
+ pipesize = the size (in blocks) of the queue used to buffer the blocks read\r
+ blocksize = the maximum block size for a raw read."""\r
+ if type(readfile) == types.IntType:\r
+ self.fd = readfile\r
+ else:\r
+ self.fd = readfile.fileno()\r
+ self.pipesize = pipesize\r
+ self.blocksize = blocksize\r
+ self.eof = 0\r
+ self._q = Queue.Queue(self.pipesize)\r
+ self.data = ''\r
+ thread.start_new_thread(self._readtoq, ())\r
+ def _readtoq(self):\r
+ finish = 0\r
+ while (1):\r
+ try:\r
+ item = os.read(self.fd, self.blocksize)\r
+ except (IOError, OSError):\r
+ finish = 1\r
+ if (item == '') or finish:\r
+ # Wait until everything has been read from the queue before\r
+ # setting eof = 1 and exiting.\r
+ while not self._q.empty():\r
+ time.sleep(MIN_TIMEOUT)\r
+ self.eof = 1\r
+ thread.exit()\r
+ else:\r
+ self._q.put(item)\r
+ def has_data(self):\r
+ return self.data\r
+ def eof(self):\r
+ return self.eof\r
+ def read_lazy(self):\r
+ """Process and return data that's already in the queues (lazy).\r
+\r
+ Return '' if no data available. Don't block.\r
+\r
+ """\r
+ while not self._q.empty():\r
+ self.data += self._q.get()\r
+ data = self.data\r
+ self.data = ''\r
+ return data\r
+ def read_some(self, until_eof=False):\r
+ """Read at least one byte of cooked data unless EOF is hit.\r
+\r
+ Return '' if EOF is hit. Block if no data is immediately\r
+ available.\r
+\r
+ """\r
+ data = ''\r
+ while (until_eof or not data) and not self.eof:\r
+ data += self.read_lazy()\r
+ time.sleep(MIN_TIMEOUT)\r
+ return data\r
+ def read_until(self, match, timeout=None):\r
+ """Read until a given string is encountered or until timeout.\r
+\r
+ If no match is found or EOF is hit, return whatever is\r
+ available instead, possibly the empty string.\r
+ """\r
+ if timeout is not None:\r
+ timeout = timeout / MIN_TIMEOUT\r
+ else:\r
+ timeout = 1\r
+ n = len(match)\r
+ data = self.read_lazy()\r
+ i = 0\r
+ while timeout >= 0 and not self.eof:\r
+ i = data.find(match, i)\r
+ if i >= 0:\r
+ i += n\r
+ self.data = data[i:]\r
+ return data[:i]\r
+ time.sleep(MIN_TIMEOUT)\r
+ timeout -= 1\r
+ i = max(0, len(data) - n)\r
+ data += self.read_lazy()\r
+ return data\r
+ def read_all(self):\r
+ """Read until the EOF. May block."""\r
+ return read_some(until_eof=True)\r