xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/asynchat.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker# -*- Mode: Python; tab-width: 4 -*-
2*cda5da8dSAndroid Build Coastguard Worker#       Id: asynchat.py,v 2.26 2000/09/07 22:29:26 rushing Exp
3*cda5da8dSAndroid Build Coastguard Worker#       Author: Sam Rushing <[email protected]>
4*cda5da8dSAndroid Build Coastguard Worker
5*cda5da8dSAndroid Build Coastguard Worker# ======================================================================
6*cda5da8dSAndroid Build Coastguard Worker# Copyright 1996 by Sam Rushing
7*cda5da8dSAndroid Build Coastguard Worker#
8*cda5da8dSAndroid Build Coastguard Worker#                         All Rights Reserved
9*cda5da8dSAndroid Build Coastguard Worker#
10*cda5da8dSAndroid Build Coastguard Worker# Permission to use, copy, modify, and distribute this software and
11*cda5da8dSAndroid Build Coastguard Worker# its documentation for any purpose and without fee is hereby
12*cda5da8dSAndroid Build Coastguard Worker# granted, provided that the above copyright notice appear in all
13*cda5da8dSAndroid Build Coastguard Worker# copies and that both that copyright notice and this permission
14*cda5da8dSAndroid Build Coastguard Worker# notice appear in supporting documentation, and that the name of Sam
15*cda5da8dSAndroid Build Coastguard Worker# Rushing not be used in advertising or publicity pertaining to
16*cda5da8dSAndroid Build Coastguard Worker# distribution of the software without specific, written prior
17*cda5da8dSAndroid Build Coastguard Worker# permission.
18*cda5da8dSAndroid Build Coastguard Worker#
19*cda5da8dSAndroid Build Coastguard Worker# SAM RUSHING DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
20*cda5da8dSAndroid Build Coastguard Worker# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
21*cda5da8dSAndroid Build Coastguard Worker# NO EVENT SHALL SAM RUSHING BE LIABLE FOR ANY SPECIAL, INDIRECT OR
22*cda5da8dSAndroid Build Coastguard Worker# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
23*cda5da8dSAndroid Build Coastguard Worker# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
24*cda5da8dSAndroid Build Coastguard Worker# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
25*cda5da8dSAndroid Build Coastguard Worker# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26*cda5da8dSAndroid Build Coastguard Worker# ======================================================================
27*cda5da8dSAndroid Build Coastguard Worker
28*cda5da8dSAndroid Build Coastguard Workerr"""A class supporting chat-style (command/response) protocols.
29*cda5da8dSAndroid Build Coastguard Worker
30*cda5da8dSAndroid Build Coastguard WorkerThis class adds support for 'chat' style protocols - where one side
31*cda5da8dSAndroid Build Coastguard Workersends a 'command', and the other sends a response (examples would be
32*cda5da8dSAndroid Build Coastguard Workerthe common internet protocols - smtp, nntp, ftp, etc..).
33*cda5da8dSAndroid Build Coastguard Worker
34*cda5da8dSAndroid Build Coastguard WorkerThe handle_read() method looks at the input stream for the current
35*cda5da8dSAndroid Build Coastguard Worker'terminator' (usually '\r\n' for single-line responses, '\r\n.\r\n'
36*cda5da8dSAndroid Build Coastguard Workerfor multi-line output), calling self.found_terminator() on its
37*cda5da8dSAndroid Build Coastguard Workerreceipt.
38*cda5da8dSAndroid Build Coastguard Worker
39*cda5da8dSAndroid Build Coastguard Workerfor example:
40*cda5da8dSAndroid Build Coastguard WorkerSay you build an async nntp client using this class.  At the start
41*cda5da8dSAndroid Build Coastguard Workerof the connection, you'll have self.terminator set to '\r\n', in
42*cda5da8dSAndroid Build Coastguard Workerorder to process the single-line greeting.  Just before issuing a
43*cda5da8dSAndroid Build Coastguard Worker'LIST' command you'll set it to '\r\n.\r\n'.  The output of the LIST
44*cda5da8dSAndroid Build Coastguard Workercommand will be accumulated (using your own 'collect_incoming_data'
45*cda5da8dSAndroid Build Coastguard Workermethod) up to the terminator, and then control will be returned to
46*cda5da8dSAndroid Build Coastguard Workeryou - by calling your self.found_terminator() method.
47*cda5da8dSAndroid Build Coastguard Worker"""
48*cda5da8dSAndroid Build Coastguard Workerimport asyncore
49*cda5da8dSAndroid Build Coastguard Workerfrom collections import deque
50*cda5da8dSAndroid Build Coastguard Worker
51*cda5da8dSAndroid Build Coastguard Workerfrom warnings import _deprecated
52*cda5da8dSAndroid Build Coastguard Worker
53*cda5da8dSAndroid Build Coastguard Worker_DEPRECATION_MSG = ('The {name} module is deprecated and will be removed in '
54*cda5da8dSAndroid Build Coastguard Worker                    'Python {remove}. The recommended replacement is asyncio')
55*cda5da8dSAndroid Build Coastguard Worker_deprecated(__name__, _DEPRECATION_MSG, remove=(3, 12))
56*cda5da8dSAndroid Build Coastguard Worker
57*cda5da8dSAndroid Build Coastguard Worker
58*cda5da8dSAndroid Build Coastguard Worker
59*cda5da8dSAndroid Build Coastguard Workerclass async_chat(asyncore.dispatcher):
60*cda5da8dSAndroid Build Coastguard Worker    """This is an abstract class.  You must derive from this class, and add
61*cda5da8dSAndroid Build Coastguard Worker    the two methods collect_incoming_data() and found_terminator()"""
62*cda5da8dSAndroid Build Coastguard Worker
63*cda5da8dSAndroid Build Coastguard Worker    # these are overridable defaults
64*cda5da8dSAndroid Build Coastguard Worker
65*cda5da8dSAndroid Build Coastguard Worker    ac_in_buffer_size = 65536
66*cda5da8dSAndroid Build Coastguard Worker    ac_out_buffer_size = 65536
67*cda5da8dSAndroid Build Coastguard Worker
68*cda5da8dSAndroid Build Coastguard Worker    # we don't want to enable the use of encoding by default, because that is a
69*cda5da8dSAndroid Build Coastguard Worker    # sign of an application bug that we don't want to pass silently
70*cda5da8dSAndroid Build Coastguard Worker
71*cda5da8dSAndroid Build Coastguard Worker    use_encoding = 0
72*cda5da8dSAndroid Build Coastguard Worker    encoding = 'latin-1'
73*cda5da8dSAndroid Build Coastguard Worker
74*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, sock=None, map=None):
75*cda5da8dSAndroid Build Coastguard Worker        # for string terminator matching
76*cda5da8dSAndroid Build Coastguard Worker        self.ac_in_buffer = b''
77*cda5da8dSAndroid Build Coastguard Worker
78*cda5da8dSAndroid Build Coastguard Worker        # we use a list here rather than io.BytesIO for a few reasons...
79*cda5da8dSAndroid Build Coastguard Worker        # del lst[:] is faster than bio.truncate(0)
80*cda5da8dSAndroid Build Coastguard Worker        # lst = [] is faster than bio.truncate(0)
81*cda5da8dSAndroid Build Coastguard Worker        self.incoming = []
82*cda5da8dSAndroid Build Coastguard Worker
83*cda5da8dSAndroid Build Coastguard Worker        # we toss the use of the "simple producer" and replace it with
84*cda5da8dSAndroid Build Coastguard Worker        # a pure deque, which the original fifo was a wrapping of
85*cda5da8dSAndroid Build Coastguard Worker        self.producer_fifo = deque()
86*cda5da8dSAndroid Build Coastguard Worker        asyncore.dispatcher.__init__(self, sock, map)
87*cda5da8dSAndroid Build Coastguard Worker
88*cda5da8dSAndroid Build Coastguard Worker    def collect_incoming_data(self, data):
89*cda5da8dSAndroid Build Coastguard Worker        raise NotImplementedError("must be implemented in subclass")
90*cda5da8dSAndroid Build Coastguard Worker
91*cda5da8dSAndroid Build Coastguard Worker    def _collect_incoming_data(self, data):
92*cda5da8dSAndroid Build Coastguard Worker        self.incoming.append(data)
93*cda5da8dSAndroid Build Coastguard Worker
94*cda5da8dSAndroid Build Coastguard Worker    def _get_data(self):
95*cda5da8dSAndroid Build Coastguard Worker        d = b''.join(self.incoming)
96*cda5da8dSAndroid Build Coastguard Worker        del self.incoming[:]
97*cda5da8dSAndroid Build Coastguard Worker        return d
98*cda5da8dSAndroid Build Coastguard Worker
99*cda5da8dSAndroid Build Coastguard Worker    def found_terminator(self):
100*cda5da8dSAndroid Build Coastguard Worker        raise NotImplementedError("must be implemented in subclass")
101*cda5da8dSAndroid Build Coastguard Worker
102*cda5da8dSAndroid Build Coastguard Worker    def set_terminator(self, term):
103*cda5da8dSAndroid Build Coastguard Worker        """Set the input delimiter.
104*cda5da8dSAndroid Build Coastguard Worker
105*cda5da8dSAndroid Build Coastguard Worker        Can be a fixed string of any length, an integer, or None.
106*cda5da8dSAndroid Build Coastguard Worker        """
107*cda5da8dSAndroid Build Coastguard Worker        if isinstance(term, str) and self.use_encoding:
108*cda5da8dSAndroid Build Coastguard Worker            term = bytes(term, self.encoding)
109*cda5da8dSAndroid Build Coastguard Worker        elif isinstance(term, int) and term < 0:
110*cda5da8dSAndroid Build Coastguard Worker            raise ValueError('the number of received bytes must be positive')
111*cda5da8dSAndroid Build Coastguard Worker        self.terminator = term
112*cda5da8dSAndroid Build Coastguard Worker
113*cda5da8dSAndroid Build Coastguard Worker    def get_terminator(self):
114*cda5da8dSAndroid Build Coastguard Worker        return self.terminator
115*cda5da8dSAndroid Build Coastguard Worker
116*cda5da8dSAndroid Build Coastguard Worker    # grab some more data from the socket,
117*cda5da8dSAndroid Build Coastguard Worker    # throw it to the collector method,
118*cda5da8dSAndroid Build Coastguard Worker    # check for the terminator,
119*cda5da8dSAndroid Build Coastguard Worker    # if found, transition to the next state.
120*cda5da8dSAndroid Build Coastguard Worker
121*cda5da8dSAndroid Build Coastguard Worker    def handle_read(self):
122*cda5da8dSAndroid Build Coastguard Worker
123*cda5da8dSAndroid Build Coastguard Worker        try:
124*cda5da8dSAndroid Build Coastguard Worker            data = self.recv(self.ac_in_buffer_size)
125*cda5da8dSAndroid Build Coastguard Worker        except BlockingIOError:
126*cda5da8dSAndroid Build Coastguard Worker            return
127*cda5da8dSAndroid Build Coastguard Worker        except OSError:
128*cda5da8dSAndroid Build Coastguard Worker            self.handle_error()
129*cda5da8dSAndroid Build Coastguard Worker            return
130*cda5da8dSAndroid Build Coastguard Worker
131*cda5da8dSAndroid Build Coastguard Worker        if isinstance(data, str) and self.use_encoding:
132*cda5da8dSAndroid Build Coastguard Worker            data = bytes(str, self.encoding)
133*cda5da8dSAndroid Build Coastguard Worker        self.ac_in_buffer = self.ac_in_buffer + data
134*cda5da8dSAndroid Build Coastguard Worker
135*cda5da8dSAndroid Build Coastguard Worker        # Continue to search for self.terminator in self.ac_in_buffer,
136*cda5da8dSAndroid Build Coastguard Worker        # while calling self.collect_incoming_data.  The while loop
137*cda5da8dSAndroid Build Coastguard Worker        # is necessary because we might read several data+terminator
138*cda5da8dSAndroid Build Coastguard Worker        # combos with a single recv(4096).
139*cda5da8dSAndroid Build Coastguard Worker
140*cda5da8dSAndroid Build Coastguard Worker        while self.ac_in_buffer:
141*cda5da8dSAndroid Build Coastguard Worker            lb = len(self.ac_in_buffer)
142*cda5da8dSAndroid Build Coastguard Worker            terminator = self.get_terminator()
143*cda5da8dSAndroid Build Coastguard Worker            if not terminator:
144*cda5da8dSAndroid Build Coastguard Worker                # no terminator, collect it all
145*cda5da8dSAndroid Build Coastguard Worker                self.collect_incoming_data(self.ac_in_buffer)
146*cda5da8dSAndroid Build Coastguard Worker                self.ac_in_buffer = b''
147*cda5da8dSAndroid Build Coastguard Worker            elif isinstance(terminator, int):
148*cda5da8dSAndroid Build Coastguard Worker                # numeric terminator
149*cda5da8dSAndroid Build Coastguard Worker                n = terminator
150*cda5da8dSAndroid Build Coastguard Worker                if lb < n:
151*cda5da8dSAndroid Build Coastguard Worker                    self.collect_incoming_data(self.ac_in_buffer)
152*cda5da8dSAndroid Build Coastguard Worker                    self.ac_in_buffer = b''
153*cda5da8dSAndroid Build Coastguard Worker                    self.terminator = self.terminator - lb
154*cda5da8dSAndroid Build Coastguard Worker                else:
155*cda5da8dSAndroid Build Coastguard Worker                    self.collect_incoming_data(self.ac_in_buffer[:n])
156*cda5da8dSAndroid Build Coastguard Worker                    self.ac_in_buffer = self.ac_in_buffer[n:]
157*cda5da8dSAndroid Build Coastguard Worker                    self.terminator = 0
158*cda5da8dSAndroid Build Coastguard Worker                    self.found_terminator()
159*cda5da8dSAndroid Build Coastguard Worker            else:
160*cda5da8dSAndroid Build Coastguard Worker                # 3 cases:
161*cda5da8dSAndroid Build Coastguard Worker                # 1) end of buffer matches terminator exactly:
162*cda5da8dSAndroid Build Coastguard Worker                #    collect data, transition
163*cda5da8dSAndroid Build Coastguard Worker                # 2) end of buffer matches some prefix:
164*cda5da8dSAndroid Build Coastguard Worker                #    collect data to the prefix
165*cda5da8dSAndroid Build Coastguard Worker                # 3) end of buffer does not match any prefix:
166*cda5da8dSAndroid Build Coastguard Worker                #    collect data
167*cda5da8dSAndroid Build Coastguard Worker                terminator_len = len(terminator)
168*cda5da8dSAndroid Build Coastguard Worker                index = self.ac_in_buffer.find(terminator)
169*cda5da8dSAndroid Build Coastguard Worker                if index != -1:
170*cda5da8dSAndroid Build Coastguard Worker                    # we found the terminator
171*cda5da8dSAndroid Build Coastguard Worker                    if index > 0:
172*cda5da8dSAndroid Build Coastguard Worker                        # don't bother reporting the empty string
173*cda5da8dSAndroid Build Coastguard Worker                        # (source of subtle bugs)
174*cda5da8dSAndroid Build Coastguard Worker                        self.collect_incoming_data(self.ac_in_buffer[:index])
175*cda5da8dSAndroid Build Coastguard Worker                    self.ac_in_buffer = self.ac_in_buffer[index+terminator_len:]
176*cda5da8dSAndroid Build Coastguard Worker                    # This does the Right Thing if the terminator
177*cda5da8dSAndroid Build Coastguard Worker                    # is changed here.
178*cda5da8dSAndroid Build Coastguard Worker                    self.found_terminator()
179*cda5da8dSAndroid Build Coastguard Worker                else:
180*cda5da8dSAndroid Build Coastguard Worker                    # check for a prefix of the terminator
181*cda5da8dSAndroid Build Coastguard Worker                    index = find_prefix_at_end(self.ac_in_buffer, terminator)
182*cda5da8dSAndroid Build Coastguard Worker                    if index:
183*cda5da8dSAndroid Build Coastguard Worker                        if index != lb:
184*cda5da8dSAndroid Build Coastguard Worker                            # we found a prefix, collect up to the prefix
185*cda5da8dSAndroid Build Coastguard Worker                            self.collect_incoming_data(self.ac_in_buffer[:-index])
186*cda5da8dSAndroid Build Coastguard Worker                            self.ac_in_buffer = self.ac_in_buffer[-index:]
187*cda5da8dSAndroid Build Coastguard Worker                        break
188*cda5da8dSAndroid Build Coastguard Worker                    else:
189*cda5da8dSAndroid Build Coastguard Worker                        # no prefix, collect it all
190*cda5da8dSAndroid Build Coastguard Worker                        self.collect_incoming_data(self.ac_in_buffer)
191*cda5da8dSAndroid Build Coastguard Worker                        self.ac_in_buffer = b''
192*cda5da8dSAndroid Build Coastguard Worker
193*cda5da8dSAndroid Build Coastguard Worker    def handle_write(self):
194*cda5da8dSAndroid Build Coastguard Worker        self.initiate_send()
195*cda5da8dSAndroid Build Coastguard Worker
196*cda5da8dSAndroid Build Coastguard Worker    def handle_close(self):
197*cda5da8dSAndroid Build Coastguard Worker        self.close()
198*cda5da8dSAndroid Build Coastguard Worker
199*cda5da8dSAndroid Build Coastguard Worker    def push(self, data):
200*cda5da8dSAndroid Build Coastguard Worker        if not isinstance(data, (bytes, bytearray, memoryview)):
201*cda5da8dSAndroid Build Coastguard Worker            raise TypeError('data argument must be byte-ish (%r)',
202*cda5da8dSAndroid Build Coastguard Worker                            type(data))
203*cda5da8dSAndroid Build Coastguard Worker        sabs = self.ac_out_buffer_size
204*cda5da8dSAndroid Build Coastguard Worker        if len(data) > sabs:
205*cda5da8dSAndroid Build Coastguard Worker            for i in range(0, len(data), sabs):
206*cda5da8dSAndroid Build Coastguard Worker                self.producer_fifo.append(data[i:i+sabs])
207*cda5da8dSAndroid Build Coastguard Worker        else:
208*cda5da8dSAndroid Build Coastguard Worker            self.producer_fifo.append(data)
209*cda5da8dSAndroid Build Coastguard Worker        self.initiate_send()
210*cda5da8dSAndroid Build Coastguard Worker
211*cda5da8dSAndroid Build Coastguard Worker    def push_with_producer(self, producer):
212*cda5da8dSAndroid Build Coastguard Worker        self.producer_fifo.append(producer)
213*cda5da8dSAndroid Build Coastguard Worker        self.initiate_send()
214*cda5da8dSAndroid Build Coastguard Worker
215*cda5da8dSAndroid Build Coastguard Worker    def readable(self):
216*cda5da8dSAndroid Build Coastguard Worker        "predicate for inclusion in the readable for select()"
217*cda5da8dSAndroid Build Coastguard Worker        # cannot use the old predicate, it violates the claim of the
218*cda5da8dSAndroid Build Coastguard Worker        # set_terminator method.
219*cda5da8dSAndroid Build Coastguard Worker
220*cda5da8dSAndroid Build Coastguard Worker        # return (len(self.ac_in_buffer) <= self.ac_in_buffer_size)
221*cda5da8dSAndroid Build Coastguard Worker        return 1
222*cda5da8dSAndroid Build Coastguard Worker
223*cda5da8dSAndroid Build Coastguard Worker    def writable(self):
224*cda5da8dSAndroid Build Coastguard Worker        "predicate for inclusion in the writable for select()"
225*cda5da8dSAndroid Build Coastguard Worker        return self.producer_fifo or (not self.connected)
226*cda5da8dSAndroid Build Coastguard Worker
227*cda5da8dSAndroid Build Coastguard Worker    def close_when_done(self):
228*cda5da8dSAndroid Build Coastguard Worker        "automatically close this channel once the outgoing queue is empty"
229*cda5da8dSAndroid Build Coastguard Worker        self.producer_fifo.append(None)
230*cda5da8dSAndroid Build Coastguard Worker
231*cda5da8dSAndroid Build Coastguard Worker    def initiate_send(self):
232*cda5da8dSAndroid Build Coastguard Worker        while self.producer_fifo and self.connected:
233*cda5da8dSAndroid Build Coastguard Worker            first = self.producer_fifo[0]
234*cda5da8dSAndroid Build Coastguard Worker            # handle empty string/buffer or None entry
235*cda5da8dSAndroid Build Coastguard Worker            if not first:
236*cda5da8dSAndroid Build Coastguard Worker                del self.producer_fifo[0]
237*cda5da8dSAndroid Build Coastguard Worker                if first is None:
238*cda5da8dSAndroid Build Coastguard Worker                    self.handle_close()
239*cda5da8dSAndroid Build Coastguard Worker                    return
240*cda5da8dSAndroid Build Coastguard Worker
241*cda5da8dSAndroid Build Coastguard Worker            # handle classic producer behavior
242*cda5da8dSAndroid Build Coastguard Worker            obs = self.ac_out_buffer_size
243*cda5da8dSAndroid Build Coastguard Worker            try:
244*cda5da8dSAndroid Build Coastguard Worker                data = first[:obs]
245*cda5da8dSAndroid Build Coastguard Worker            except TypeError:
246*cda5da8dSAndroid Build Coastguard Worker                data = first.more()
247*cda5da8dSAndroid Build Coastguard Worker                if data:
248*cda5da8dSAndroid Build Coastguard Worker                    self.producer_fifo.appendleft(data)
249*cda5da8dSAndroid Build Coastguard Worker                else:
250*cda5da8dSAndroid Build Coastguard Worker                    del self.producer_fifo[0]
251*cda5da8dSAndroid Build Coastguard Worker                continue
252*cda5da8dSAndroid Build Coastguard Worker
253*cda5da8dSAndroid Build Coastguard Worker            if isinstance(data, str) and self.use_encoding:
254*cda5da8dSAndroid Build Coastguard Worker                data = bytes(data, self.encoding)
255*cda5da8dSAndroid Build Coastguard Worker
256*cda5da8dSAndroid Build Coastguard Worker            # send the data
257*cda5da8dSAndroid Build Coastguard Worker            try:
258*cda5da8dSAndroid Build Coastguard Worker                num_sent = self.send(data)
259*cda5da8dSAndroid Build Coastguard Worker            except OSError:
260*cda5da8dSAndroid Build Coastguard Worker                self.handle_error()
261*cda5da8dSAndroid Build Coastguard Worker                return
262*cda5da8dSAndroid Build Coastguard Worker
263*cda5da8dSAndroid Build Coastguard Worker            if num_sent:
264*cda5da8dSAndroid Build Coastguard Worker                if num_sent < len(data) or obs < len(first):
265*cda5da8dSAndroid Build Coastguard Worker                    self.producer_fifo[0] = first[num_sent:]
266*cda5da8dSAndroid Build Coastguard Worker                else:
267*cda5da8dSAndroid Build Coastguard Worker                    del self.producer_fifo[0]
268*cda5da8dSAndroid Build Coastguard Worker            # we tried to send some actual data
269*cda5da8dSAndroid Build Coastguard Worker            return
270*cda5da8dSAndroid Build Coastguard Worker
271*cda5da8dSAndroid Build Coastguard Worker    def discard_buffers(self):
272*cda5da8dSAndroid Build Coastguard Worker        # Emergencies only!
273*cda5da8dSAndroid Build Coastguard Worker        self.ac_in_buffer = b''
274*cda5da8dSAndroid Build Coastguard Worker        del self.incoming[:]
275*cda5da8dSAndroid Build Coastguard Worker        self.producer_fifo.clear()
276*cda5da8dSAndroid Build Coastguard Worker
277*cda5da8dSAndroid Build Coastguard Worker
278*cda5da8dSAndroid Build Coastguard Workerclass simple_producer:
279*cda5da8dSAndroid Build Coastguard Worker
280*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, data, buffer_size=512):
281*cda5da8dSAndroid Build Coastguard Worker        self.data = data
282*cda5da8dSAndroid Build Coastguard Worker        self.buffer_size = buffer_size
283*cda5da8dSAndroid Build Coastguard Worker
284*cda5da8dSAndroid Build Coastguard Worker    def more(self):
285*cda5da8dSAndroid Build Coastguard Worker        if len(self.data) > self.buffer_size:
286*cda5da8dSAndroid Build Coastguard Worker            result = self.data[:self.buffer_size]
287*cda5da8dSAndroid Build Coastguard Worker            self.data = self.data[self.buffer_size:]
288*cda5da8dSAndroid Build Coastguard Worker            return result
289*cda5da8dSAndroid Build Coastguard Worker        else:
290*cda5da8dSAndroid Build Coastguard Worker            result = self.data
291*cda5da8dSAndroid Build Coastguard Worker            self.data = b''
292*cda5da8dSAndroid Build Coastguard Worker            return result
293*cda5da8dSAndroid Build Coastguard Worker
294*cda5da8dSAndroid Build Coastguard Worker
295*cda5da8dSAndroid Build Coastguard Worker# Given 'haystack', see if any prefix of 'needle' is at its end.  This
296*cda5da8dSAndroid Build Coastguard Worker# assumes an exact match has already been checked.  Return the number of
297*cda5da8dSAndroid Build Coastguard Worker# characters matched.
298*cda5da8dSAndroid Build Coastguard Worker# for example:
299*cda5da8dSAndroid Build Coastguard Worker# f_p_a_e("qwerty\r", "\r\n") => 1
300*cda5da8dSAndroid Build Coastguard Worker# f_p_a_e("qwertydkjf", "\r\n") => 0
301*cda5da8dSAndroid Build Coastguard Worker# f_p_a_e("qwerty\r\n", "\r\n") => <undefined>
302*cda5da8dSAndroid Build Coastguard Worker
303*cda5da8dSAndroid Build Coastguard Worker# this could maybe be made faster with a computed regex?
304*cda5da8dSAndroid Build Coastguard Worker# [answer: no; circa Python-2.0, Jan 2001]
305*cda5da8dSAndroid Build Coastguard Worker# new python:   28961/s
306*cda5da8dSAndroid Build Coastguard Worker# old python:   18307/s
307*cda5da8dSAndroid Build Coastguard Worker# re:        12820/s
308*cda5da8dSAndroid Build Coastguard Worker# regex:     14035/s
309*cda5da8dSAndroid Build Coastguard Worker
310*cda5da8dSAndroid Build Coastguard Workerdef find_prefix_at_end(haystack, needle):
311*cda5da8dSAndroid Build Coastguard Worker    l = len(needle) - 1
312*cda5da8dSAndroid Build Coastguard Worker    while l and not haystack.endswith(needle[:l]):
313*cda5da8dSAndroid Build Coastguard Worker        l -= 1
314*cda5da8dSAndroid Build Coastguard Worker    return l
315