2 # -*- coding: utf-8 -*-
4 # codimension - graphics python two-way code editor and analyzer
5 # Copyright (C) 2010 Sergey Satskiy <sergey.satskiy@gmail.com>
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # The file was taken from eric 4 and adopted for codimension.
26 # Copyright (c) 2002 - 2012 Detlev Offenbach <detlev@die-offenbachs.de>
30 Module implementing an asynchronous
31 file like socket interface for the debugger.
36 from protocol_cdm_dbg
import EOT
39 def AsyncPendingWrite( fileObj
):
41 Checks for data to be written
43 @param fileObj The file object to be checked (file)
44 @return Flag indicating if there is data wating (int)
48 pending
= fileObj
.pendingWrite()
54 class AsyncFile( object ):
55 " Wrapps a socket object with a file interface "
58 maxbuffersize
= 1024 * 1024 * 4
60 def __init__( self
, sock
, mode
, name
):
62 @param sock the socket object being wrapped
63 @param mode mode of this file (string)
64 @param name name of this file (string)
67 # Initialise the attributes.
77 def __checkMode( self
, mode
):
81 This method checks, if an operation is permitted according to
82 the mode of the file. If it is not, an IOError is raised.
84 @param mode the mode to be checked (string)
88 raise IOError, '[Errno 9] Bad file descriptor'
91 def __nWrite( self
, n
):
93 Writes a specific number of pending bytes
95 @param n the number of bytes to be written (int)
100 buf
= "%s%s" % ( self
.wpending
[ : n
], EOT
)
102 buf
= buf
.encode( 'utf8' )
103 except ( UnicodeEncodeError, UnicodeDecodeError ):
105 self
.sock
.sendall( buf
)
106 self
.wpending
= self
.wpending
[ n
: ]
107 self
.nWriteErrors
= 0
109 self
.nWriteErrors
+= 1
110 if self
.nWriteErrors
> self
.maxtries
:
111 self
.wpending
= u
'' # delete all output
114 def pendingWrite( self
):
116 Returns the number of bytes waiting to be written
118 @return the number of bytes to be written (int)
120 return len( self
.wpending
)
121 # return self.wpending.rfind( '\n' ) + 1
123 def close( self
, closeit
= 0 ):
127 @param closeit flag to indicate a close ordered by
128 the debugger code (boolean)
131 if closeit
and not self
.closed
:
138 " Writes all pending bytes "
140 self
.__nWrite
( len( self
.wpending
) )
145 Indicates whether a tty interface is supported.
153 Public method returning the file number.
155 @return file number (int)
158 return self
.sock
.fileno()
162 def read_p( self
, size
= -1 ):
164 Reads bytes from this file
166 @param size maximum number of bytes to be read (int)
167 @return the bytes read (any)
169 self
.__checkMode
( 'r' )
174 return self
.sock
.recv(size
).decode( 'utf8' )
176 def read( self
, size
= -1 ):
178 Reads bytes from this file
180 @param size maximum number of bytes to be read (int)
181 @return the bytes read (any)
183 self
.__checkMode
( 'r' )
190 def readline_p( self
, size
= -1 ):
192 Reads a line from this file.
194 <b>Note</b>: This method will not block and may return
195 only a part of a line if that is all that is available.
197 @param size maximum number of bytes to be read (int)
198 @return one line of text up to size bytes (string)
200 self
.__checkMode
( 'r' )
205 # The integration of the debugger client event loop and the connection
206 # to the debugger relies on the two lines of the debugger command being
207 # delivered as two separate events. Therefore we make sure we only
208 # read a line at a time.
209 line
= self
.sock
.recv( size
, socket
.MSG_PEEK
)
211 eol
= line
.find( '\n' )
218 # Now we know how big the line is, read it for real.
219 return self
.sock
.recv( size
).decode( 'utf8' )
221 def readlines( self
, sizehint
= -1 ):
223 Reads all lines from this file.
225 @param sizehint hint of the numbers of bytes to be read (int)
226 @return list of lines read (list of strings)
228 self
.__checkMode
( 'r' )
233 line
= self
.readline_p( room
)
234 linelen
= len( line
)
240 room
= room
- linelen
245 line
= self
.readline_p( room
)
246 linelen
= len( line
)
250 def readline( self
, sizehint
= -1 ):
252 Reads one line from this file.
254 @param sizehint hint of the numbers of bytes to be read (int)
255 @return one line read (string)
257 self
.__checkMode
( 'r' )
259 line
= raw_input() + '\n'
261 line
= line
[ : sizehint
]
264 def seek( self
, offset
, whence
= 0 ):
266 Moves the filepointer
268 @exception IOError This method is not supported and always raises an
271 raise IOError, '[Errno 29] Illegal seek'
275 Provides the filepointer position
277 @exception IOError This method is not supported and always raises an
280 raise IOError, '[Errno 29] Illegal seek'
282 def truncate( self
, size
= -1 ):
286 @exception IOError This method is not supported and always raises an
289 raise IOError, '[Errno 29] Illegal seek'
291 def write( self
, s
):
293 Writes a string to the file
295 @param s bytes to be written (string)
298 self
.__checkMode
( 'w' )
300 if not self
.wpending
:
302 elif type( self
.wpending
) != type( s
) or \
303 len( self
.wpending
) + len( s
) > self
.maxbuffersize
:
304 # flush wpending so that different string types
305 # are not concatenated
307 # if we have a persistent error in sending the data,
308 # an exception will be raised in __nWrite
311 if tries
> self
.maxtries
:
312 raise socket
.error( "Too many attempts to send data" )
316 self
.__nWrite
( self
.pendingWrite() )
319 def writelines( self
, lines
):
321 Writes a list of strings to the file.
323 @param lines the list to be written (list of string)
325 map( self
.write
, lines
)