summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xLib/dos-8x3/arrayio.py142
-rwxr-xr-xLib/dos-8x3/ast.py224
-rwxr-xr-xLib/dos-8x3/basehttp.py482
-rwxr-xr-xLib/dos-8x3/bastion.py162
-rwxr-xr-xLib/dos-8x3/cgihttps.py203
-rwxr-xr-xLib/dos-8x3/compilea.py70
-rwxr-xr-xLib/dos-8x3/complex.py275
-rwxr-xr-xLib/dos-8x3/formatte.py399
-rwxr-xr-xLib/dos-8x3/gopherli.py191
-rwxr-xr-xLib/dos-8x3/htmlenti.py105
-rwxr-xr-xLib/dos-8x3/importal.py36
-rwxr-xr-xLib/dos-8x3/linecach.py90
-rwxr-xr-xLib/dos-8x3/macurl2p.py76
-rwxr-xr-xLib/dos-8x3/mimetool.py187
-rwxr-xr-xLib/dos-8x3/multifil.py128
-rwxr-xr-xLib/dos-8x3/nturl2pa.py52
-rwxr-xr-xLib/dos-8x3/para.py409
-rwxr-xr-xLib/dos-8x3/posixfil.py207
-rwxr-xr-xLib/dos-8x3/posixpat.py307
-rwxr-xr-xLib/dos-8x3/py_compi.py31
-rwxr-xr-xLib/dos-8x3/queue.py121
-rwxr-xr-xLib/dos-8x3/regex_sy.py41
-rwxr-xr-xLib/dos-8x3/simpleht.py168
-rwxr-xr-xLib/dos-8x3/socketse.py413
-rwxr-xr-xLib/dos-8x3/statcach.py82
-rwxr-xr-xLib/dos-8x3/stringio.py156
-rwxr-xr-xLib/dos-8x3/test_aud.py202
-rwxr-xr-xLib/dos-8x3/test_bui.py13
-rwxr-xr-xLib/dos-8x3/test_exc.py92
-rwxr-xr-xLib/dos-8x3/test_gra.py513
-rwxr-xr-xLib/dos-8x3/test_opc.py59
-rwxr-xr-xLib/dos-8x3/test_ope.py5
-rwxr-xr-xLib/dos-8x3/test_rgb.py49
-rwxr-xr-xLib/dos-8x3/test_sel.py23
-rwxr-xr-xLib/dos-8x3/test_sig.py50
-rwxr-xr-xLib/dos-8x3/test_sup.py41
-rwxr-xr-xLib/dos-8x3/test_thr.py106
-rwxr-xr-xLib/dos-8x3/test_typ.py182
-rwxr-xr-xLib/dos-8x3/tracebac.py125
-rwxr-xr-xLib/dos-8x3/userdict.py18
-rwxr-xr-xLib/dos-8x3/userlist.py50
-rwxr-xr-xLib/dos-8x3/whatsoun.py270
-rwxr-xr-xLib/dos_8x3/arrayio.py142
-rwxr-xr-xLib/dos_8x3/ast.py224
-rwxr-xr-xLib/dos_8x3/basehttp.py482
-rwxr-xr-xLib/dos_8x3/bastion.py162
-rwxr-xr-xLib/dos_8x3/cgihttps.py203
-rwxr-xr-xLib/dos_8x3/compilea.py70
-rwxr-xr-xLib/dos_8x3/complex.py275
-rwxr-xr-xLib/dos_8x3/formatte.py399
-rwxr-xr-xLib/dos_8x3/gopherli.py191
-rwxr-xr-xLib/dos_8x3/htmlenti.py105
-rwxr-xr-xLib/dos_8x3/importal.py36
-rwxr-xr-xLib/dos_8x3/linecach.py90
-rwxr-xr-xLib/dos_8x3/macurl2p.py76
-rwxr-xr-xLib/dos_8x3/mimetool.py187
-rwxr-xr-xLib/dos_8x3/multifil.py128
-rwxr-xr-xLib/dos_8x3/nturl2pa.py52
-rwxr-xr-xLib/dos_8x3/para.py409
-rwxr-xr-xLib/dos_8x3/posixfil.py207
-rwxr-xr-xLib/dos_8x3/posixpat.py307
-rwxr-xr-xLib/dos_8x3/py_compi.py31
-rwxr-xr-xLib/dos_8x3/queue.py121
-rwxr-xr-xLib/dos_8x3/regex_sy.py41
-rwxr-xr-xLib/dos_8x3/simpleht.py168
-rwxr-xr-xLib/dos_8x3/socketse.py413
-rwxr-xr-xLib/dos_8x3/statcach.py82
-rwxr-xr-xLib/dos_8x3/stringio.py156
-rwxr-xr-xLib/dos_8x3/test_aud.py202
-rwxr-xr-xLib/dos_8x3/test_bui.py13
-rwxr-xr-xLib/dos_8x3/test_exc.py92
-rwxr-xr-xLib/dos_8x3/test_gra.py513
-rwxr-xr-xLib/dos_8x3/test_opc.py59
-rwxr-xr-xLib/dos_8x3/test_ope.py5
-rwxr-xr-xLib/dos_8x3/test_rgb.py49
-rwxr-xr-xLib/dos_8x3/test_sel.py23
-rwxr-xr-xLib/dos_8x3/test_sig.py50
-rwxr-xr-xLib/dos_8x3/test_sup.py41
-rwxr-xr-xLib/dos_8x3/test_thr.py106
-rwxr-xr-xLib/dos_8x3/test_typ.py182
-rwxr-xr-xLib/dos_8x3/tracebac.py125
-rwxr-xr-xLib/dos_8x3/userdict.py18
-rwxr-xr-xLib/dos_8x3/userlist.py50
-rwxr-xr-xLib/dos_8x3/whatsoun.py270
84 files changed, 13110 insertions, 0 deletions
diff --git a/Lib/dos-8x3/arrayio.py b/Lib/dos-8x3/arrayio.py
new file mode 100755
index 0000000..5b06f92
--- /dev/null
+++ b/Lib/dos-8x3/arrayio.py
@@ -0,0 +1,142 @@
+"""File-like objects that read/write an array buffer.
+
+This implements (nearly) all stdio methods.
+
+f = ArrayIO() # ready for writing
+f = ArrayIO(buf) # ready for reading
+f.close() # explicitly release resources held
+flag = f.isatty() # always false
+pos = f.tell() # get current position
+f.seek(pos) # set current position
+f.seek(pos, mode) # mode 0: absolute; 1: relative; 2: relative to EOF
+buf = f.read() # read until EOF
+buf = f.read(n) # read up to n bytes
+buf = f.readline() # read until end of line ('\n') or EOF
+list = f.readlines()# list of f.readline() results until EOF
+f.write(buf) # write at current position
+f.writelines(list) # for line in list: f.write(line)
+f.getvalue() # return whole file's contents as a string
+
+Notes:
+- This is very similar to StringIO. StringIO is faster for reading,
+ but ArrayIO is faster for writing.
+- ArrayIO uses an array object internally, but all its interfaces
+ accept and return strings.
+- Using a real file is often faster (but less convenient).
+- fileno() is left unimplemented so that code which uses it triggers
+ an exception early.
+- Seeking far beyond EOF and then writing will insert real null
+ bytes that occupy space in the buffer.
+- There's a simple test set (see end of this file).
+"""
+
+import string
+from array import array
+
+class ArrayIO:
+ def __init__(self, buf = ''):
+ self.buf = array('c', buf)
+ self.pos = 0
+ self.closed = 0
+ self.softspace = 0
+ def close(self):
+ if not self.closed:
+ self.closed = 1
+ del self.buf, self.pos
+ def isatty(self):
+ return 0
+ def seek(self, pos, mode = 0):
+ if mode == 1:
+ pos = pos + self.pos
+ elif mode == 2:
+ pos = pos + len(self.buf)
+ self.pos = max(0, pos)
+ def tell(self):
+ return self.pos
+ def read(self, n = -1):
+ if n < 0:
+ newpos = len(self.buf)
+ else:
+ newpos = min(self.pos+n, len(self.buf))
+ r = self.buf[self.pos:newpos].tostring()
+ self.pos = newpos
+ return r
+ def readline(self):
+ i = string.find(self.buf[self.pos:].tostring(), '\n')
+ if i < 0:
+ newpos = len(self.buf)
+ else:
+ newpos = self.pos+i+1
+ r = self.buf[self.pos:newpos].tostring()
+ self.pos = newpos
+ return r
+ def readlines(self):
+ lines = string.splitfields(self.read(), '\n')
+ if not lines:
+ return lines
+ for i in range(len(lines)-1):
+ lines[i] = lines[i] + '\n'
+ if not lines[-1]:
+ del lines[-1]
+ return lines
+ def write(self, s):
+ if not s: return
+ a = array('c', s)
+ n = self.pos - len(self.buf)
+ if n > 0:
+ self.buf[len(self.buf):] = array('c', '\0')*n
+ newpos = self.pos + len(a)
+ self.buf[self.pos:newpos] = a
+ self.pos = newpos
+ def writelines(self, list):
+ self.write(string.joinfields(list, ''))
+ def flush(self):
+ pass
+ def getvalue(self):
+ return self.buf.tostring()
+
+
+# A little test suite
+
+def test():
+ import sys
+ if sys.argv[1:]:
+ file = sys.argv[1]
+ else:
+ file = '/etc/passwd'
+ lines = open(file, 'r').readlines()
+ text = open(file, 'r').read()
+ f = ArrayIO()
+ for line in lines[:-2]:
+ f.write(line)
+ f.writelines(lines[-2:])
+ if f.getvalue() != text:
+ raise RuntimeError, 'write failed'
+ length = f.tell()
+ print 'File length =', length
+ f.seek(len(lines[0]))
+ f.write(lines[1])
+ f.seek(0)
+ print 'First line =', `f.readline()`
+ here = f.tell()
+ line = f.readline()
+ print 'Second line =', `line`
+ f.seek(-len(line), 1)
+ line2 = f.read(len(line))
+ if line != line2:
+ raise RuntimeError, 'bad result after seek back'
+ f.seek(len(line2), 1)
+ list = f.readlines()
+ line = list[-1]
+ f.seek(f.tell() - len(line))
+ line2 = f.read()
+ if line != line2:
+ raise RuntimeError, 'bad result after seek back from EOF'
+ print 'Read', len(list), 'more lines'
+ print 'File length =', f.tell()
+ if f.tell() != length:
+ raise RuntimeError, 'bad length'
+ f.close()
+
+if __name__ == '__main__':
+ test()
diff --git a/Lib/dos-8x3/ast.py b/Lib/dos-8x3/ast.py
new file mode 100755
index 0000000..6f92bee
--- /dev/null
+++ b/Lib/dos-8x3/ast.py
@@ -0,0 +1,224 @@
+"""Object-oriented interface to the parser module.
+
+This module exports three classes which together provide an interface
+to the parser module. Together, the three classes represent two ways
+to create parsed representations of Python source and the two starting
+data types (source text and tuple representations). Each class
+provides interfaces which are identical other than the constructors.
+The constructors are described in detail in the documentation for each
+class and the remaining, shared portion of the interface is documented
+below. Briefly, the three classes provided are:
+
+AST
+ Defines the primary interface to the AST objects and supports creation
+ from the tuple representation of the parse tree.
+
+ExpressionAST
+ Supports creation of expression constructs from source text.
+
+SuiteAST
+ Supports creation of statement suites from source text.
+
+FileSuiteAST
+ Convenience subclass of the `SuiteAST' class; loads source text of the
+ suite from an external file.
+
+Aside from the constructors, several methods are provided to allow
+access to the various interpretations of the parse tree and to check
+conditions of the construct represented by the parse tree.
+
+ast()
+ Returns the corresponding `parser.ASTType' object.
+
+code()
+ Returns the compiled code object.
+
+filename()
+ Returns the name of the associated source file, if known.
+
+isExpression()
+ Returns true value if parse tree represents an expression, or a false
+ value otherwise.
+
+isSuite()
+ Returns true value if parse tree represents a suite of statements, or
+ a false value otherwise.
+
+text()
+ Returns the source text, or None if not available.
+
+tuple()
+ Returns the tuple representing the parse tree.
+"""
+
+__version__ = '$Revision$'
+__copyright__ = """Copyright (c) 1995, 1996 by Fred L. Drake, Jr.
+
+This software may be used and distributed freely for any purpose provided
+that this notice is included unchanged on any and all copies. The author
+does not warrant or guarantee this software in any way.
+"""
+
+class AST:
+ """Base class for Abstract Syntax Tree objects.
+
+ Creates an Abstract Syntax Tree based on the tuple representation
+ of the parse tree. The parse tree can represent either an
+ expression or a suite; which will be recognized automatically.
+ This base class provides all of the query methods for subclass
+ objects defined in this module.
+ """
+ _p = __import__('parser') # import internally to avoid
+ # namespace pollution at the
+ # top level
+ _text = None
+ _code = None
+ _ast = None
+ _type = 'unknown'
+ _tupl = None
+
+ def __init__(self, tuple):
+ """Create an `AST' instance from a tuple-tree representation.
+
+ tuple
+ The tuple tree to convert.
+
+ The tuple-tree may represent either an expression or a suite; the
+ type will be determined automatically.
+ """
+ if type(tuple) is not type(()):
+ raise TypeError, 'Base AST class requires tuple parameter.'
+
+ self._tupl = tuple
+ self._ast = self._p.tuple2ast(tuple)
+ self._type = (self._p.isexpr(self._ast) and 'expression') or 'suite'
+
+ def tuple(self):
+ """Returns the tuple representing the parse tree.
+ """
+ if self._tupl is None:
+ self._tupl = self._p.ast2tuple(self._ast)
+ return self._tupl
+
+ def code(self):
+ """Returns the compiled code object.
+
+ The code object returned by this method may be passed to the
+ exec statement if `AST.isSuite()' is true or to the eval()
+ function if `AST.isExpression()' is true. All the usual rules
+ regarding execution of code objects apply.
+ """
+ if not self._code:
+ self._code = self._p.compileast(self._ast)
+ return self._code
+
+ def ast(self):
+ """Returns the corresponding `parser.ASTType' object.
+ """
+ return self._ast
+
+ def filename(self):
+ """Returns the name of the source file if known, or None.
+ """
+ return None
+
+ def text(self):
+ """Returns the source text, or None if not available.
+
+ If the instance is of class `AST', None is returned since no
+ source text is available. If of class `ExpressionAST' or
+ `SuiteAST', the source text passed to the constructor is
+ returned.
+ """
+ return self._text
+
+ def isSuite(self):
+ """Determine if `AST' instance represents a suite of statements.
+ """
+ return self._type == 'suite'
+
+ def isExpression(self):
+ """Determine if `AST' instance represents an expression.
+ """
+ return self._type == 'expression'
+
+
+
+class SuiteAST(AST):
+ """Statement suite parse tree representation.
+
+ This subclass of the `AST' base class represents statement suites
+ parsed from the source text of a Python suite. If the source text
+ does not represent a parsable suite of statements, the appropriate
+ exception is raised by the parser.
+ """
+ _type = 'suite'
+
+ def __init__(self, text):
+ """Initialize a `SuiteAST' from source text.
+
+ text
+ Source text to parse.
+ """
+ if type(text) is not type(''):
+ raise TypeError, 'SuiteAST requires source text parameter.'
+ self._text = text
+ self._ast = self._p.suite(text)
+
+ def isSuite(self):
+ return 1
+
+ def isExpression(self):
+ return 0
+
+
+class FileSuiteAST(SuiteAST):
+ """Representation of a python source file syntax tree.
+
+ This provides a convenience wrapper around the `SuiteAST' class to
+ load the source text from an external file.
+ """
+ def __init__(self, fileName):
+ """Initialize a `SuiteAST' from a source file.
+
+ fileName
+ Name of the external source file.
+ """
+ self._fileName = fileName
+ SuiteAST.__init__(self, open(fileName).read())
+
+ def filename(self):
+ return self._fileName
+
+
+
+class ExpressionAST(AST):
+ """Expression parse tree representation.
+
+ This subclass of the `AST' base class represents expression
+ constructs parsed from the source text of a Python expression. If
+ the source text does not represent a parsable expression, the
+ appropriate exception is raised by the Python parser.
+ """
+ _type = 'expression'
+
+ def __init__(self, text):
+ """Initialize an expression AST from source text.
+
+ text
+ Source text to parse.
+ """
+ if type(text) is not type(''):
+ raise TypeError, 'ExpressionAST requires source text parameter.'
+ self._text = text
+ self._ast = self._p.expr(text)
+
+ def isSuite(self):
+ return 0
+
+ def isExpression(self):
+ return 1
+
+
+#
+# end of file
diff --git a/Lib/dos-8x3/basehttp.py b/Lib/dos-8x3/basehttp.py
new file mode 100755
index 0000000..281ddf6
--- /dev/null
+++ b/Lib/dos-8x3/basehttp.py
@@ -0,0 +1,482 @@
+"""HTTP server base class.
+
+Note: the class in this module doesn't implement any HTTP request; see
+SimpleHTTPServer for simple implementations of GET, HEAD and POST
+(including CGI scripts).
+
+Contents:
+
+- BaseHTTPRequestHandler: HTTP request handler base class
+- test: test function
+
+XXX To do:
+
+- send server version
+- log requests even later (to capture byte count)
+- log user-agent header and other interesting goodies
+- send error log to separate file
+- are request names really case sensitive?
+
+"""
+
+
+# See also:
+#
+# HTTP Working Group T. Berners-Lee
+# INTERNET-DRAFT R. T. Fielding
+# <draft-ietf-http-v10-spec-00.txt> H. Frystyk Nielsen
+# Expires September 8, 1995 March 8, 1995
+#
+# URL: http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-v10-spec-00.txt
+
+
+# Log files
+# ---------
+#
+# Here's a quote from the NCSA httpd docs about log file format.
+#
+# | The logfile format is as follows. Each line consists of:
+# |
+# | host rfc931 authuser [DD/Mon/YYYY:hh:mm:ss] "request" ddd bbbb
+# |
+# | host: Either the DNS name or the IP number of the remote client
+# | rfc931: Any information returned by identd for this person,
+# | - otherwise.
+# | authuser: If user sent a userid for authentication, the user name,
+# | - otherwise.
+# | DD: Day
+# | Mon: Month (calendar name)
+# | YYYY: Year
+# | hh: hour (24-hour format, the machine's timezone)
+# | mm: minutes
+# | ss: seconds
+# | request: The first line of the HTTP request as sent by the client.
+# | ddd: the status code returned by the server, - if not available.
+# | bbbb: the total number of bytes sent,
+# | *not including the HTTP/1.0 header*, - if not available
+# |
+# | You can determine the name of the file accessed through request.
+#
+# (Actually, the latter is only true if you know the server configuration
+# at the time the request was made!)
+
+
+__version__ = "0.2"
+
+
+import sys
+import time
+import socket # For gethostbyaddr()
+import string
+import rfc822
+import mimetools
+import SocketServer
+
+# Default error message
+DEFAULT_ERROR_MESSAGE = """\
+<head>
+<title>Error response</title>
+</head>
+<body>
+<h1>Error response</h1>
+<p>Error code %(code)d.
+<p>Message: %(message)s.
+<p>Error code explanation: %(code)s = %(explain)s.
+</body>
+"""
+
+
+class HTTPServer(SocketServer.TCPServer):
+
+ def server_bind(self):
+ """Override server_bind to store the server name."""
+ SocketServer.TCPServer.server_bind(self)
+ host, port = self.socket.getsockname()
+ if not host or host == '0.0.0.0':
+ host = socket.gethostname()
+ hostname, hostnames, hostaddrs = socket.gethostbyaddr(host)
+ if '.' not in hostname:
+ for host in hostnames:
+ if '.' in host:
+ hostname = host
+ break
+ self.server_name = hostname
+ self.server_port = port
+
+
+class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler):
+
+ """HTTP request handler base class.
+
+ The following explanation of HTTP serves to guide you through the
+ code as well as to expose any misunderstandings I may have about
+ HTTP (so you don't need to read the code to figure out I'm wrong
+ :-).
+
+ HTTP (HyperText Transfer Protocol) is an extensible protocol on
+ top of a reliable stream transport (e.g. TCP/IP). The protocol
+ recognizes three parts to a request:
+
+ 1. One line identifying the request type and path
+ 2. An optional set of RFC-822-style headers
+ 3. An optional data part
+
+ The headers and data are separated by a blank line.
+
+ The first line of the request has the form
+
+ <command> <path> <version>
+
+ where <command> is a (case-sensitive) keyword such as GET or POST,
+ <path> is a string containing path information for the request,
+ and <version> should be the string "HTTP/1.0". <path> is encoded
+ using the URL encoding scheme (using %xx to signify the ASCII
+ character with hex code xx).
+
+ The protocol is vague about whether lines are separated by LF
+ characters or by CRLF pairs -- for compatibility with the widest
+ range of clients, both should be accepted. Similarly, whitespace
+ in the request line should be treated sensibly (allowing multiple
+ spaces between components and allowing trailing whitespace).
+
+ Similarly, for output, lines ought to be separated by CRLF pairs
+ but most clients grok LF characters just fine.
+
+ If the first line of the request has the form
+
+ <command> <path>
+
+ (i.e. <version> is left out) then this is assumed to be an HTTP
+ 0.9 request; this form has no optional headers and data part and
+ the reply consists of just the data.
+
+ The reply form of the HTTP 1.0 protocol again has three parts:
+
+ 1. One line giving the response code
+ 2. An optional set of RFC-822-style headers
+ 3. The data
+
+ Again, the headers and data are separated by a blank line.
+
+ The response code line has the form
+
+ <version> <responsecode> <responsestring>
+
+ where <version> is the protocol version (always "HTTP/1.0"),
+ <responsecode> is a 3-digit response code indicating success or
+ failure of the request, and <responsestring> is an optional
+ human-readable string explaining what the response code means.
+
+ This server parses the request and the headers, and then calls a
+ function specific to the request type (<command>). Specifically,
+ a request SPAM will be handled by a method handle_SPAM(). If no
+ such method exists the server sends an error response to the
+ client. If it exists, it is called with no arguments:
+
+ do_SPAM()
+
+ Note that the request name is case sensitive (i.e. SPAM and spam
+ are different requests).
+
+ The various request details are stored in instance variables:
+
+ - client_address is the client IP address in the form (host,
+ port);
+
+ - command, path and version are the broken-down request line;
+
+ - headers is an instance of mimetools.Message (or a derived
+ class) containing the header information;
+
+ - rfile is a file object open for reading positioned at the
+ start of the optional input data part;
+
+ - wfile is a file object open for writing.
+
+ IT IS IMPORTANT TO ADHERE TO THE PROTOCOL FOR WRITING!
+
+ The first thing to be written must be the response line. Then
+ follow 0 or more header lines, then a blank line, and then the
+ actual data (if any). The meaning of the header lines depends on
+ the command executed by the server; in most cases, when data is
+ returned, there should be at least one header line of the form
+
+ Content-type: <type>/<subtype>
+
+ where <type> and <subtype> should be registered MIME types,
+ e.g. "text/html" or "text/plain".
+
+ """
+
+ # The Python system version, truncated to its first component.
+ sys_version = "Python/" + string.split(sys.version)[0]
+
+ # The server software version. You may want to override this.
+ # The format is multiple whitespace-separated strings,
+ # where each string is of the form name[/version].
+ server_version = "BaseHTTP/" + __version__
+
+ def handle(self):
+ """Handle a single HTTP request.
+
+ You normally don't need to override this method; see the class
+ __doc__ string for information on how to handle specific HTTP
+ commands such as GET and POST.
+
+ """
+
+ self.raw_requestline = self.rfile.readline()
+ self.request_version = version = "HTTP/0.9" # Default
+ requestline = self.raw_requestline
+ if requestline[-2:] == '\r\n':
+ requestline = requestline[:-2]
+ elif requestline[-1:] == '\n':
+ requestline = requestline[:-1]
+ self.requestline = requestline
+ words = string.split(requestline)
+ if len(words) == 3:
+ [command, path, version] = words
+ if version != self.protocol_version:
+ self.send_error(400, "Bad request version (%s)" % `version`)
+ return
+ elif len(words) == 2:
+ [command, path] = words
+ if command != 'GET':
+ self.send_error(400,
+ "Bad HTTP/0.9 request type (%s)" % `command`)
+ return
+ else:
+ self.send_error(400, "Bad request syntax (%s)" % `requestline`)
+ return
+ self.command, self.path, self.request_version = command, path, version
+ self.headers = self.MessageClass(self.rfile, 0)
+ mname = 'do_' + command
+ if not hasattr(self, mname):
+ self.send_error(501, "Unsupported method (%s)" % `mname`)
+ return
+ method = getattr(self, mname)
+ method()
+
+ def send_error(self, code, message=None):
+ """Send and log an error reply.
+
+ Arguments are the error code, and a detailed message.
+ The detailed message defaults to the short entry matching the
+ response code.
+
+ This sends an error response (so it must be called before any
+ output has been generated), logs the error, and finally sends
+ a piece of HTML explaining the error to the user.
+
+ """
+
+ try:
+ short, long = self.responses[code]
+ except KeyError:
+ short, long = '???', '???'
+ if not message:
+ message = short
+ explain = long
+ self.log_error("code %d, message %s", code, message)
+ self.send_response(code, message)
+ self.end_headers()
+ self.wfile.write(self.error_message_format %
+ {'code': code,
+ 'message': message,
+ 'explain': explain})
+
+ error_message_format = DEFAULT_ERROR_MESSAGE
+
+ def send_response(self, code, message=None):
+ """Send the response header and log the response code.
+
+ Also send two standard headers with the server software
+ version and the current date.
+
+ """
+ self.log_request(code)
+ if message is None:
+ if self.responses.has_key(code):
+ message = self.responses[code][1]
+ else:
+ message = ''
+ if self.request_version != 'HTTP/0.9':
+ self.wfile.write("%s %s %s\r\n" %
+ (self.protocol_version, str(code), message))
+ self.send_header('Server', self.version_string())
+ self.send_header('Date', self.date_time_string())
+
+ def send_header(self, keyword, value):
+ """Send a MIME header."""
+ if self.request_version != 'HTTP/0.9':
+ self.wfile.write("%s: %s\r\n" % (keyword, value))
+
+ def end_headers(self):
+ """Send the blank line ending the MIME headers."""
+ if self.request_version != 'HTTP/0.9':
+ self.wfile.write("\r\n")
+
+ def log_request(self, code='-', size='-'):
+ """Log an accepted request.
+
+ This is called by send_reponse().
+
+ """
+
+ self.log_message('"%s" %s %s',
+ self.requestline, str(code), str(size))
+
+ def log_error(self, *args):
+ """Log an error.
+
+ This is called when a request cannot be fulfilled. By
+ default it passes the message on to log_message().
+
+ Arguments are the same as for log_message().
+
+ XXX This should go to the separate error log.
+
+ """
+
+ apply(self.log_message, args)
+
+ def log_message(self, format, *args):
+ """Log an arbitrary message.
+
+ This is used by all other logging functions. Override
+ it if you have specific logging wishes.
+
+ The first argument, FORMAT, is a format string for the
+ message to be logged. If the format string contains
+ any % escapes requiring parameters, they should be
+ specified as subsequent arguments (it's just like
+ printf!).
+
+ The client host and current date/time are prefixed to
+ every message.
+
+ """
+
+ sys.stderr.write("%s - - [%s] %s\n" %
+ (self.address_string(),
+ self.log_date_time_string(),
+ format%args))
+
+ def version_string(self):
+ """Return the server software version string."""
+ return self.server_version + ' ' + self.sys_version
+
+ def date_time_string(self):
+ """Return the current date and time formatted for a message header."""
+ now = time.time()
+ year, month, day, hh, mm, ss, wd, y, z = time.gmtime(now)
+ s = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
+ self.weekdayname[wd],
+ day, self.monthname[month], year,
+ hh, mm, ss)
+ return s
+
+ def log_date_time_string(self):
+ """Return the current time formatted for logging."""
+ now = time.time()
+ year, month, day, hh, mm, ss, x, y, z = time.localtime(now)
+ s = "%02d/%3s/%04d %02d:%02d:%02d" % (
+ day, self.monthname[month], year, hh, mm, ss)
+ return s
+
+ weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+
+ monthname = [None,
+ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
+ 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
+
+ def address_string(self):
+ """Return the client address formatted for logging.
+
+ This version looks up the full hostname using gethostbyaddr(),
+ and tries to find a name that contains at least one dot.
+
+ """
+
+ (host, port) = self.client_address
+ try:
+ name, names, addresses = socket.gethostbyaddr(host)
+ except socket.error, msg:
+ return host
+ names.insert(0, name)
+ for name in names:
+ if '.' in name: return name
+ return names[0]
+
+
+ # Essentially static class variables
+
+ # The version of the HTTP protocol we support.
+ # Don't override unless you know what you're doing (hint: incoming
+ # requests are required to have exactly this version string).
+ protocol_version = "HTTP/1.0"
+
+ # The Message-like class used to parse headers
+ MessageClass = mimetools.Message
+
+ # Table mapping response codes to messages; entries have the
+ # form {code: (shortmessage, longmessage)}.
+ # See http://www.w3.org/hypertext/WWW/Protocols/HTTP/HTRESP.html
+ responses = {
+ 200: ('OK', 'Request fulfilled, document follows'),
+ 201: ('Created', 'Document created, URL follows'),
+ 202: ('Accepted',
+ 'Request accepted, processing continues off-line'),
+ 203: ('Partial information', 'Request fulfilled from cache'),
+ 204: ('No response', 'Request fulfilled, nothing follows'),
+
+ 301: ('Moved', 'Object moved permanently -- see URI list'),
+ 302: ('Found', 'Object moved temporarily -- see URI list'),
+ 303: ('Method', 'Object moved -- see Method and URL list'),
+ 304: ('Not modified',
+ 'Document has not changed singe given time'),
+
+ 400: ('Bad request',
+ 'Bad request syntax or unsupported method'),
+ 401: ('Unauthorized',
+ 'No permission -- see authorization schemes'),
+ 402: ('Payment required',
+ 'No payment -- see charging schemes'),
+ 403: ('Forbidden',
+ 'Request forbidden -- authorization will not help'),
+ 404: ('Not found', 'Nothing matches the given URI'),
+
+ 500: ('Internal error', 'Server got itself in trouble'),
+ 501: ('Not implemented',
+ 'Server does not support this operation'),
+ 502: ('Service temporarily overloaded',
+ 'The server cannot process the request due to a high load'),
+ 503: ('Gateway timeout',
+ 'The gateway server did not receive a timely response'),
+
+ }
+
+
+def test(HandlerClass = BaseHTTPRequestHandler,
+ ServerClass = HTTPServer):
+ """Test the HTTP request handler class.
+
+ This runs an HTTP server on port 8000 (or the first command line
+ argument).
+
+ """
+
+ if sys.argv[1:]:
+ port = string.atoi(sys.argv[1])
+ else:
+ port = 8000
+ server_address = ('', port)
+
+ httpd = ServerClass(server_address, HandlerClass)
+
+ print "Serving HTTP on port", port, "..."
+ httpd.serve_forever()
+
+
+if __name__ == '__main__':
+ test()
diff --git a/Lib/dos-8x3/bastion.py b/Lib/dos-8x3/bastion.py
new file mode 100755
index 0000000..7ddd93e
--- /dev/null
+++ b/Lib/dos-8x3/bastion.py
@@ -0,0 +1,162 @@
+"""Bastionification utility.
+
+A bastion (for another object -- the 'original') is an object that has
+the same methods as the original but does not give access to its
+instance variables. Bastions have a number of uses, but the most
+obvious one is to provide code executing in restricted mode with a
+safe interface to an object implemented in unrestricted mode.
+
+The bastionification routine has an optional second argument which is
+a filter function. Only those methods for which the filter method
+(called with the method name as argument) returns true are accessible.
+The default filter method returns true unless the method name begins
+with an underscore.
+
+There are a number of possible implementations of bastions. We use a
+'lazy' approach where the bastion's __getattr__() discipline does all
+the work for a particular method the first time it is used. This is
+usually fastest, especially if the user doesn't call all available
+methods. The retrieved methods are stored as instance variables of
+the bastion, so the overhead is only occurred on the first use of each
+method.
+
+Detail: the bastion class has a __repr__() discipline which includes
+the repr() of the original object. This is precomputed when the
+bastion is created.
+
+"""
+
+__version__ = '$Revision$'
+# $Source$
+
+
+from types import MethodType
+
+
+class BastionClass:
+
+ """Helper class used by the Bastion() function.
+
+ You could subclass this and pass the subclass as the bastionclass
+ argument to the Bastion() function, as long as the constructor has
+ the same signature (a get() function and a name for the object).
+
+ """
+
+ def __init__(self, get, name):
+ """Constructor.
+
+ Arguments:
+
+ get - a function that gets the attribute value (by name)
+ name - a human-readable name for the original object
+ (suggestion: use repr(object))
+
+ """
+ self._get_ = get
+ self._name_ = name
+
+ def __repr__(self):
+ """Return a representation string.
+
+ This includes the name passed in to the constructor, so that
+ if you print the bastion during debugging, at least you have
+ some idea of what it is.
+
+ """
+ return "<Bastion for %s>" % self._name_
+
+ def __getattr__(self, name):
+ """Get an as-yet undefined attribute value.
+
+ This calls the get() function that was passed to the
+ constructor. The result is stored as an instance variable so
+ that the next time the same attribute is requested,
+ __getattr__() won't be invoked.
+
+ If the get() function raises an exception, this is simply
+ passed on -- exceptions are not cached.
+
+ """
+ attribute = self._get_(name)
+ self.__dict__[name] = attribute
+ return attribute
+
+
+def Bastion(object, filter = lambda name: name[:1] != '_',
+ name=None, bastionclass=BastionClass):
+ """Create a bastion for an object, using an optional filter.
+
+ See the Bastion module's documentation for background.
+
+ Arguments:
+
+ object - the original object
+ filter - a predicate that decides whether a function name is OK;
+ by default all names are OK that don't start with '_'
+ name - the name of the object; default repr(object)
+ bastionclass - class used to create the bastion; default BastionClass
+
+ """
+
+ # Note: we define *two* ad-hoc functions here, get1 and get2.
+ # Both are intended to be called in the same way: get(name).
+ # It is clear that the real work (getting the attribute
+ # from the object and calling the filter) is done in get1.
+ # Why can't we pass get1 to the bastion? Because the user
+ # would be able to override the filter argument! With get2,
+ # overriding the default argument is no security loophole:
+ # all it does is call it.
+ # Also notice that we can't place the object and filter as
+ # instance variables on the bastion object itself, since
+ # the user has full access to all instance variables!
+
+ def get1(name, object=object, filter=filter):
+ """Internal function for Bastion(). See source comments."""
+ if filter(name):
+ attribute = getattr(object, name)
+ if type(attribute) == MethodType:
+ return attribute
+ raise AttributeError, name
+
+ def get2(name, get1=get1):
+ """Internal function for Bastion(). See source comments."""
+ return get1(name)
+
+ if name is None:
+ name = `object`
+ return bastionclass(get2, name)
+
+
+def _test():
+ """Test the Bastion() function."""
+ class Original:
+ def __init__(self):
+ self.sum = 0
+ def add(self, n):
+ self._add(n)
+ def _add(self, n):
+ self.sum = self.sum + n
+ def total(self):
+ return self.sum
+ o = Original()
+ b = Bastion(o)
+ b.add(81)
+ b.add(18)
+ print "b.total() =", b.total()
+ try:
+ print "b.sum =", b.sum,
+ except:
+ print "inaccessible"
+ else:
+ print "accessible"
+ try:
+ print "b._add =", b._add,
+ except:
+ print "inaccessible"
+ else:
+ print "accessible"
+
+
+if __name__ == '__main__':
+ _test()
diff --git a/Lib/dos-8x3/cgihttps.py b/Lib/dos-8x3/cgihttps.py
new file mode 100755
index 0000000..837f7c2
--- /dev/null
+++ b/Lib/dos-8x3/cgihttps.py
@@ -0,0 +1,203 @@
+"""CGI-savvy HTTP Server.
+
+This module builds on SimpleHTTPServer by implementing GET and POST
+requests to cgi-bin scripts.
+
+"""
+
+
+__version__ = "0.3"
+
+
+import os
+import sys
+import time
+import socket
+import string
+import urllib
+import BaseHTTPServer
+import SimpleHTTPServer
+
+
+class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
+
+ """Complete HTTP server with GET, HEAD and POST commands.
+
+ GET and HEAD also support running CGI scripts.
+
+ The POST command is *only* implemented for CGI scripts.
+
+ """
+
+ def do_POST(self):
+ """Serve a POST request.
+
+ This is only implemented for CGI scripts.
+
+ """
+
+ if self.is_cgi():
+ self.run_cgi()
+ else:
+ self.send_error(501, "Can only POST to CGI scripts")
+
+ def send_head(self):
+ """Version of send_head that support CGI scripts"""
+ if self.is_cgi():
+ return self.run_cgi()
+ else:
+ return SimpleHTTPServer.SimpleHTTPRequestHandler.send_head(self)
+
+ def is_cgi(self):
+ """test whether PATH corresponds to a CGI script.
+
+ Return a tuple (dir, rest) if PATH requires running a
+ CGI script, None if not. Note that rest begins with a
+ slash if it is not empty.
+
+ The default implementation tests whether the path
+ begins with one of the strings in the list
+ self.cgi_directories (and the next character is a '/'
+ or the end of the string).
+
+ """
+
+ path = self.path
+
+ for x in self.cgi_directories:
+ i = len(x)
+ if path[:i] == x and (not path[i:] or path[i] == '/'):
+ self.cgi_info = path[:i], path[i+1:]
+ return 1
+ return 0
+
+ cgi_directories = ['/cgi-bin', '/htbin']
+
+ def run_cgi(self):
+ """Execute a CGI script."""
+ dir, rest = self.cgi_info
+ i = string.rfind(rest, '?')
+ if i >= 0:
+ rest, query = rest[:i], rest[i+1:]
+ else:
+ query = ''
+ i = string.find(rest, '/')
+ if i >= 0:
+ script, rest = rest[:i], rest[i:]
+ else:
+ script, rest = rest, ''
+ scriptname = dir + '/' + script
+ scriptfile = self.translate_path(scriptname)
+ if not os.path.exists(scriptfile):
+ self.send_error(404, "No such CGI script (%s)" % `scriptname`)
+ return
+ if not os.path.isfile(scriptfile):
+ self.send_error(403, "CGI script is not a plain file (%s)" %
+ `scriptname`)
+ return
+ if not executable(scriptfile):
+ self.send_error(403, "CGI script is not executable (%s)" %
+ `scriptname`)
+ return
+ nobody = nobody_uid()
+ self.send_response(200, "Script output follows")
+ self.wfile.flush() # Always flush before forking
+ pid = os.fork()
+ if pid != 0:
+ # Parent
+ pid, sts = os.waitpid(pid, 0)
+ if sts:
+ self.log_error("CGI script exit status x%x" % sts)
+ return
+ # Child
+ try:
+ # Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html
+ # XXX Much of the following could be prepared ahead of time!
+ env = {}
+ env['SERVER_SOFTWARE'] = self.version_string()
+ env['SERVER_NAME'] = self.server.server_name
+ env['GATEWAY_INTERFACE'] = 'CGI/1.1'
+ env['SERVER_PROTOCOL'] = self.protocol_version
+ env['SERVER_PORT'] = str(self.server.server_port)
+ env['REQUEST_METHOD'] = self.command
+ uqrest = urllib.unquote(rest)
+ env['PATH_INFO'] = uqrest
+ env['PATH_TRANSLATED'] = self.translate_path(uqrest)
+ env['SCRIPT_NAME'] = scriptname
+ if query:
+ env['QUERY_STRING'] = query
+ host = self.address_string()
+ if host != self.client_address[0]:
+ env['REMOTE_HOST'] = host
+ env['REMOTE_ADDR'] = self.client_address[0]
+ # AUTH_TYPE
+ # REMOTE_USER
+ # REMOTE_IDENT
+ env['CONTENT_TYPE'] = self.headers.type
+ length = self.headers.getheader('content-length')
+ if length:
+ env['CONTENT_LENGTH'] = length
+ accept = []
+ for line in self.headers.getallmatchingheaders('accept'):
+ if line[:1] in string.whitespace:
+ accept.append(string.strip(line))
+ else:
+ accept = accept + string.split(line[7:])
+ env['HTTP_ACCEPT'] = string.joinfields(accept, ',')
+ ua = self.headers.getheader('user-agent')
+ if ua:
+ env['HTTP_USER_AGENT'] = ua
+ # XXX Other HTTP_* headers
+ import regsub
+ decoded_query = regsub.gsub('+', ' ', query)
+ try:
+ os.setuid(nobody)
+ except os.error:
+ pass
+ os.dup2(self.rfile.fileno(), 0)
+ os.dup2(self.wfile.fileno(), 1)
+ print scriptfile, script, decoded_query
+ os.execve(scriptfile,
+ [script, decoded_query],
+ env)
+ except:
+ self.server.handle_error(self.request, self.client_address)
+ os._exit(127)
+
+
+nobody = None
+
+def nobody_uid():
+ """Internal routine to get nobody's uid"""
+ global nobody
+ if nobody:
+ return nobody
+ import pwd
+ try:
+ nobody = pwd.getpwnam('nobody')[2]
+ except pwd.error:
+ nobody = 1 + max(map(lambda x: x[2], pwd.getpwall()))
+ return nobody
+
+
+def executable(path):
+ """Test for executable file."""
+ try:
+ st = os.stat(path)
+ except os.error:
+ return 0
+ return st[0] & 0111 != 0
+
+
+def test(HandlerClass = CGIHTTPRequestHandler,
+ ServerClass = BaseHTTPServer.HTTPServer):
+ import sys
+ if sys.argv[1:2] == ['-r']:
+ db = MyArchive()
+ db.regenindices()
+ return
+ SimpleHTTPServer.test(HandlerClass, ServerClass)
+
+
+if __name__ == '__main__':
+ test()
diff --git a/Lib/dos-8x3/compilea.py b/Lib/dos-8x3/compilea.py
new file mode 100755
index 0000000..3120284
--- /dev/null
+++ b/Lib/dos-8x3/compilea.py
@@ -0,0 +1,70 @@
+# Routines to force "compilation" of all .py files in a directory
+# tree or on sys.path. By default recursion is pruned at a depth of
+# 10 and the current directory, if it occurs in sys.path, is skipped.
+# When called as a script, compiles argument directories, or sys.path
+# if no arguments.
+# After a similar module by Sjoerd Mullender.
+
+import os
+import sys
+import py_compile
+
+def compile_dir(dir, maxlevels = 10):
+ print 'Listing', dir, '...'
+ try:
+ names = os.listdir(dir)
+ except os.error:
+ print "Can't list", dir
+ names = []
+ names.sort()
+ for name in names:
+ fullname = os.path.join(dir, name)
+ if os.path.isfile(fullname):
+ head, tail = name[:-3], name[-3:]
+ if tail == '.py':
+ print 'Compiling', fullname, '...'
+ try:
+ py_compile.compile(fullname)
+ except KeyboardInterrupt:
+ del names[:]
+ print '\n[interrupt]'
+ break
+ except:
+ if type(sys.exc_type) == type(''):
+ exc_type_name = sys.exc_type
+ else: exc_type_name = sys.exc_type.__name__
+ print 'Sorry:', exc_type_name + ':',
+ print sys.exc_value
+ elif maxlevels > 0 and \
+ name != os.curdir and name != os.pardir and \
+ os.path.isdir(fullname) and \
+ not os.path.islink(fullname):
+ compile_dir(fullname, maxlevels - 1)
+
+def compile_path(skip_curdir = 1):
+ for dir in sys.path:
+ if dir == os.curdir and skip_curdir:
+ print 'Skipping current directory'
+ else:
+ compile_dir(dir, 0)
+
+def main():
+ import getopt
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], 'l')
+ except getopt.error, msg:
+ print msg
+ print "usage: compileall [-l] [directory ...]"
+ print "-l: don't recurse down"
+ print "if no arguments, -l sys.path is assumed"
+ maxlevels = 10
+ for o, a in opts:
+ if o == '-l': maxlevels = 0
+ if args:
+ for dir in sys.argv[1:]:
+ compile_dir(dir, maxlevels)
+ else:
+ compile_path()
+
+if __name__ == '__main__':
+ main()
diff --git a/Lib/dos-8x3/complex.py b/Lib/dos-8x3/complex.py
new file mode 100755
index 0000000..f4892f3
--- /dev/null
+++ b/Lib/dos-8x3/complex.py
@@ -0,0 +1,275 @@
+# Complex numbers
+# ---------------
+
+# This module represents complex numbers as instances of the class Complex.
+# A Complex instance z has two data attribues, z.re (the real part) and z.im
+# (the imaginary part). In fact, z.re and z.im can have any value -- all
+# arithmetic operators work regardless of the type of z.re and z.im (as long
+# as they support numerical operations).
+#
+# The following functions exist (Complex is actually a class):
+# Complex([re [,im]) -> creates a complex number from a real and an imaginary part
+# IsComplex(z) -> true iff z is a complex number (== has .re and .im attributes)
+# Polar([r [,phi [,fullcircle]]]) ->
+# the complex number z for which r == z.radius() and phi == z.angle(fullcircle)
+# (r and phi default to 0)
+#
+# Complex numbers have the following methods:
+# z.abs() -> absolute value of z
+# z.radius() == z.abs()
+# z.angle([fullcircle]) -> angle from positive X axis; fullcircle gives units
+# z.phi([fullcircle]) == z.angle(fullcircle)
+#
+# These standard functions and unary operators accept complex arguments:
+# abs(z)
+# -z
+# +z
+# not z
+# repr(z) == `z`
+# str(z)
+# hash(z) -> a combination of hash(z.re) and hash(z.im) such that if z.im is zero
+# the result equals hash(z.re)
+# Note that hex(z) and oct(z) are not defined.
+#
+# These conversions accept complex arguments only if their imaginary part is zero:
+# int(z)
+# long(z)
+# float(z)
+#
+# The following operators accept two complex numbers, or one complex number
+# and one real number (int, long or float):
+# z1 + z2
+# z1 - z2
+# z1 * z2
+# z1 / z2
+# pow(z1, z2)
+# cmp(z1, z2)
+# Note that z1 % z2 and divmod(z1, z2) are not defined,
+# nor are shift and mask operations.
+#
+# The standard module math does not support complex numbers.
+# (I suppose it would be easy to implement a cmath module.)
+#
+# Idea:
+# add a class Polar(r, phi) and mixed-mode arithmetic which
+# chooses the most appropriate type for the result:
+# Complex for +,-,cmp
+# Polar for *,/,pow
+
+
+import types, math
+
+if not hasattr(math, 'hypot'):
+ def hypot(x, y):
+ # XXX I know there's a way to compute this without possibly causing
+ # overflow, but I can't remember what it is right now...
+ return math.sqrt(x*x + y*y)
+ math.hypot = hypot
+
+twopi = math.pi*2.0
+halfpi = math.pi/2.0
+
+def IsComplex(obj):
+ return hasattr(obj, 're') and hasattr(obj, 'im')
+
+def Polar(r = 0, phi = 0, fullcircle = twopi):
+ phi = phi * (twopi / fullcircle)
+ return Complex(math.cos(phi)*r, math.sin(phi)*r)
+
+class Complex:
+
+ def __init__(self, re=0, im=0):
+ if IsComplex(re):
+ im = im + re.im
+ re = re.re
+ if IsComplex(im):
+ re = re - im.im
+ im = im.re
+ self.re = re
+ self.im = im
+
+ def __setattr__(self, name, value):
+ if hasattr(self, name):
+ raise TypeError, "Complex numbers have set-once attributes"
+ self.__dict__[name] = value
+
+ def __repr__(self):
+ if not self.im:
+ return 'Complex(%s)' % `self.re`
+ else:
+ return 'Complex(%s, %s)' % (`self.re`, `self.im`)
+
+ def __str__(self):
+ if not self.im:
+ return `self.re`
+ else:
+ return 'Complex(%s, %s)' % (`self.re`, `self.im`)
+
+ def __coerce__(self, other):
+ if IsComplex(other):
+ return self, other
+ return self, Complex(other) # May fail
+
+ def __cmp__(self, other):
+ return cmp(self.re, other.re) or cmp(self.im, other.im)
+
+ def __hash__(self):
+ if not self.im: return hash(self.re)
+ mod = sys.maxint + 1L
+ return int((hash(self.re) + 2L*hash(self.im) + mod) % (2L*mod) - mod)
+
+ def __neg__(self):
+ return Complex(-self.re, -self.im)
+
+ def __pos__(self):
+ return self
+
+ def __abs__(self):
+ return math.hypot(self.re, self.im)
+ ##return math.sqrt(self.re*self.re + self.im*self.im)
+
+
+ def __int__(self):
+ if self.im:
+ raise ValueError, "can't convert Complex with nonzero im to int"
+ return int(self.re)
+
+ def __long__(self):
+ if self.im:
+ raise ValueError, "can't convert Complex with nonzero im to long"
+ return long(self.re)
+
+ def __float__(self):
+ if self.im:
+ raise ValueError, "can't convert Complex with nonzero im to float"
+ return float(self.re)
+
+ def __nonzero__(self):
+ return not (self.re == self.im == 0)
+
+ abs = radius = __abs__
+
+ def angle(self, fullcircle = twopi):
+ return (fullcircle/twopi) * ((halfpi - math.atan2(self.re, self.im)) % twopi)
+
+ phi = angle
+
+ def __add__(self, other):
+ return Complex(self.re + other.re, self.im + other.im)
+
+ __radd__ = __add__
+
+ def __sub__(self, other):
+ return Complex(self.re - other.re, self.im - other.im)
+
+ def __rsub__(self, other):
+ return Complex(other.re - self.re, other.im - self.im)
+
+ def __mul__(self, other):
+ return Complex(self.re*other.re - self.im*other.im,
+ self.re*other.im + self.im*other.re)
+
+ __rmul__ = __mul__
+
+ def __div__(self, other):
+ # Deviating from the general principle of not forcing re or im
+ # to be floats, we cast to float here, otherwise division
+ # of Complex numbers with integer re and im parts would use
+ # the (truncating) integer division
+ d = float(other.re*other.re + other.im*other.im)
+ if not d: raise ZeroDivisionError, 'Complex division'
+ return Complex((self.re*other.re + self.im*other.im) / d,
+ (self.im*other.re - self.re*other.im) / d)
+
+ def __rdiv__(self, other):
+ return other / self
+
+ def __pow__(self, n, z=None):
+ if z is not None:
+ raise TypeError, 'Complex does not support ternary pow()'
+ if IsComplex(n):
+ if n.im: raise TypeError, 'Complex to the Complex power'
+ n = n.re
+ r = pow(self.abs(), n)
+ phi = n*self.angle()
+ return Complex(math.cos(phi)*r, math.sin(phi)*r)
+
+ def __rpow__(self, base):
+ return pow(base, self)
+
+
+# Everything below this point is part of the test suite
+
+def checkop(expr, a, b, value, fuzz = 1e-6):
+ import sys
+ print ' ', a, 'and', b,
+ try:
+ result = eval(expr)
+ except:
+ result = sys.exc_type
+ print '->', result
+ if (type(result) == type('') or type(value) == type('')):
+ ok = result == value
+ else:
+ ok = abs(result - value) <= fuzz
+ if not ok:
+ print '!!\t!!\t!! should be', value, 'diff', abs(result - value)
+
+
+def test():
+ testsuite = {
+ 'a+b': [
+ (1, 10, 11),
+ (1, Complex(0,10), Complex(1,10)),
+ (Complex(0,10), 1, Complex(1,10)),
+ (Complex(0,10), Complex(1), Complex(1,10)),
+ (Complex(1), Complex(0,10), Complex(1,10)),
+ ],
+ 'a-b': [
+ (1, 10, -9),
+ (1, Complex(0,10), Complex(1,-10)),
+ (Complex(0,10), 1, Complex(-1,10)),
+ (Complex(0,10), Complex(1), Complex(-1,10)),
+ (Complex(1), Complex(0,10), Complex(1,-10)),
+ ],
+ 'a*b': [
+ (1, 10, 10),
+ (1, Complex(0,10), Complex(0, 10)),
+ (Complex(0,10), 1, Complex(0,10)),
+ (Complex(0,10), Complex(1), Complex(0,10)),
+ (Complex(1), Complex(0,10), Complex(0,10)),
+ ],
+ 'a/b': [
+ (1., 10, 0.1),
+ (1, Complex(0,10), Complex(0, -0.1)),
+ (Complex(0, 10), 1, Complex(0, 10)),
+ (Complex(0, 10), Complex(1), Complex(0, 10)),
+ (Complex(1), Complex(0,10), Complex(0, -0.1)),
+ ],
+ 'pow(a,b)': [
+ (1, 10, 1),
+ (1, Complex(0,10), 'TypeError'),
+ (Complex(0,10), 1, Complex(0,10)),
+ (Complex(0,10), Complex(1), Complex(0,10)),
+ (Complex(1), Complex(0,10), 'TypeError'),
+ (2, Complex(4,0), 16),
+ ],
+ 'cmp(a,b)': [
+ (1, 10, -1),
+ (1, Complex(0,10), 1),
+ (Complex(0,10), 1, -1),
+ (Complex(0,10), Complex(1), -1),
+ (Complex(1), Complex(0,10), 1),
+ ],
+ }
+ exprs = testsuite.keys()
+ exprs.sort()
+ for expr in exprs:
+ print expr + ':'
+ t = (expr,)
+ for item in testsuite[expr]:
+ apply(checkop, t+item)
+
+
+if __name__ == '__main__':
+ test()
diff --git a/Lib/dos-8x3/formatte.py b/Lib/dos-8x3/formatte.py
new file mode 100755
index 0000000..0266379
--- /dev/null
+++ b/Lib/dos-8x3/formatte.py
@@ -0,0 +1,399 @@
+import regex
+import regsub
+import string
+import sys
+from types import StringType
+
+
+AS_IS = None
+
+
+class NullFormatter:
+
+ def __init__(self): pass
+ def end_paragraph(self, blankline): pass
+ def add_line_break(self): pass
+ def add_hor_rule(self, abswidth=None, percentwidth=1.0,
+ height=None, align=None): pass
+ def add_label_data(self, format, counter): pass
+ def add_flowing_data(self, data): pass
+ def add_literal_data(self, data): pass
+ def flush_softspace(self): pass
+ def push_alignment(self, align): pass
+ def pop_alignment(self): pass
+ def push_font(self, x): pass
+ def pop_font(self): pass
+ def push_margin(self, margin): pass
+ def pop_margin(self): pass
+ def set_spacing(self, spacing): pass
+ def push_style(self, *styles): pass
+ def pop_style(self, n=1): pass
+ def assert_line_data(self, flag=1): pass
+
+
+class AbstractFormatter:
+
+ def __init__(self, writer):
+ self.writer = writer # Output device
+ self.align = None # Current alignment
+ self.align_stack = [] # Alignment stack
+ self.font_stack = [] # Font state
+ self.margin_stack = [] # Margin state
+ self.spacing = None # Vertical spacing state
+ self.style_stack = [] # Other state, e.g. color
+ self.nospace = 1 # Should leading space be suppressed
+ self.softspace = 0 # Should a space be inserted
+ self.para_end = 1 # Just ended a paragraph
+ self.parskip = 0 # Skipped space between paragraphs?
+ self.hard_break = 1 # Have a hard break
+ self.have_label = 0
+
+ def end_paragraph(self, blankline):
+ if not self.hard_break:
+ self.writer.send_line_break()
+ self.have_label = 0
+ if self.parskip < blankline and not self.have_label:
+ self.writer.send_paragraph(blankline - self.parskip)
+ self.parskip = blankline
+ self.have_label = 0
+ self.hard_break = self.nospace = self.para_end = 1
+ self.softspace = 0
+
+ def add_line_break(self):
+ if not (self.hard_break or self.para_end):
+ self.writer.send_line_break()
+ self.have_label = self.parskip = 0
+ self.hard_break = self.nospace = 1
+ self.softspace = 0
+
+ def add_hor_rule(self, *args, **kw):
+ if not self.hard_break:
+ self.writer.send_line_break()
+ apply(self.writer.send_hor_rule, args, kw)
+ self.hard_break = self.nospace = 1
+ self.have_label = self.para_end = self.softspace = self.parskip = 0
+
+ def add_label_data(self, format, counter, blankline = None):
+ if self.have_label or not self.hard_break:
+ self.writer.send_line_break()
+ if not self.para_end:
+ self.writer.send_paragraph((blankline and 1) or 0)
+ if type(format) is StringType:
+ self.writer.send_label_data(self.format_counter(format, counter))
+ else:
+ self.writer.send_label_data(format)
+ self.nospace = self.have_label = self.hard_break = self.para_end = 1
+ self.softspace = self.parskip = 0
+
+ def format_counter(self, format, counter):
+ label = ''
+ for c in format:
+ try:
+ if c == '1':
+ label = label + ('%d' % counter)
+ elif c in 'aA':
+ if counter > 0:
+ label = label + self.format_letter(c, counter)
+ elif c in 'iI':
+ if counter > 0:
+ label = label + self.format_roman(c, counter)
+ else:
+ label = label + c
+ except:
+ label = label + c
+ return label
+
+ def format_letter(self, case, counter):
+ label = ''
+ while counter > 0:
+ counter, x = divmod(counter-1, 26)
+ s = chr(ord(case) + x)
+ label = s + label
+ return label
+
+ def format_roman(self, case, counter):
+ ones = ['i', 'x', 'c', 'm']
+ fives = ['v', 'l', 'd']
+ label, index = '', 0
+ # This will die of IndexError when counter is too big
+ while counter > 0:
+ counter, x = divmod(counter, 10)
+ if x == 9:
+ label = ones[index] + ones[index+1] + label
+ elif x == 4:
+ label = ones[index] + fives[index] + label
+ else:
+ if x >= 5:
+ s = fives[index]
+ x = x-5
+ else:
+ s = ''
+ s = s + ones[index]*x
+ label = s + label
+ index = index + 1
+ if case == 'I':
+ return string.upper(label)
+ return label
+
+ def add_flowing_data(self, data,
+ # These are only here to load them into locals:
+ whitespace = string.whitespace,
+ join = string.join, split = string.split):
+ if not data: return
+ # The following looks a bit convoluted but is a great improvement over
+ # data = regsub.gsub('[' + string.whitespace + ']+', ' ', data)
+ prespace = data[:1] in whitespace
+ postspace = data[-1:] in whitespace
+ data = join(split(data))
+ if self.nospace and not data:
+ return
+ elif prespace or self.softspace:
+ if not data:
+ if not self.nospace:
+ self.softspace = 1
+ self.parskip = 0
+ return
+ if not self.nospace:
+ data = ' ' + data
+ self.hard_break = self.nospace = self.para_end = \
+ self.parskip = self.have_label = 0
+ self.softspace = postspace
+ self.writer.send_flowing_data(data)
+
+ def add_literal_data(self, data):
+ if not data: return
+ # Caller is expected to cause flush_softspace() if needed.
+ self.hard_break = data[-1:] == '\n'
+ self.nospace = self.para_end = self.softspace = \
+ self.parskip = self.have_label = 0
+ self.writer.send_literal_data(data)
+
+ def flush_softspace(self):
+ if self.softspace:
+ self.hard_break = self.nospace = self.para_end = self.parskip = \
+ self.have_label = self.softspace = 0
+ self.writer.send_flowing_data(' ')
+
+ def push_alignment(self, align):
+ if align and align != self.align:
+ self.writer.new_alignment(align)
+ self.align = align
+ self.align_stack.append(align)
+ else:
+ self.align_stack.append(self.align)
+
+ def pop_alignment(self):
+ if self.align_stack:
+ del self.align_stack[-1]
+ if self.align_stack:
+ self.align = align = self.align_stack[-1]
+ self.writer.new_alignment(align)
+ else:
+ self.align = None
+ self.writer.new_alignment(None)
+
+ def push_font(self, (size, i, b, tt)):
+ if self.softspace:
+ self.hard_break = self.nospace = self.para_end = self.softspace = 0
+ self.writer.send_flowing_data(' ')
+ if self.font_stack:
+ csize, ci, cb, ctt = self.font_stack[-1]
+ if size is AS_IS: size = csize
+ if i is AS_IS: i = ci
+ if b is AS_IS: b = cb
+ if tt is AS_IS: tt = ctt
+ font = (size, i, b, tt)
+ self.font_stack.append(font)
+ self.writer.new_font(font)
+
+ def pop_font(self):
+ if self.softspace:
+ self.hard_break = self.nospace = self.para_end = self.softspace = 0
+ self.writer.send_flowing_data(' ')
+ if self.font_stack:
+ del self.font_stack[-1]
+ if self.font_stack:
+ font = self.font_stack[-1]
+ else:
+ font = None
+ self.writer.new_font(font)
+
+ def push_margin(self, margin):
+ self.margin_stack.append(margin)
+ fstack = filter(None, self.margin_stack)
+ if not margin and fstack:
+ margin = fstack[-1]
+ self.writer.new_margin(margin, len(fstack))
+
+ def pop_margin(self):
+ if self.margin_stack:
+ del self.margin_stack[-1]
+ fstack = filter(None, self.margin_stack)
+ if fstack:
+ margin = fstack[-1]
+ else:
+ margin = None
+ self.writer.new_margin(margin, len(fstack))
+
+ def set_spacing(self, spacing):
+ self.spacing = spacing
+ self.writer.new_spacing(spacing)
+
+ def push_style(self, *styles):
+ if self.softspace:
+ self.hard_break = self.nospace = self.para_end = self.softspace = 0
+ self.writer.send_flowing_data(' ')
+ for style in styles:
+ self.style_stack.append(style)
+ self.writer.new_styles(tuple(self.style_stack))
+
+ def pop_style(self, n=1):
+ if self.softspace:
+ self.hard_break = self.nospace = self.para_end = self.softspace = 0
+ self.writer.send_flowing_data(' ')
+ del self.style_stack[-n:]
+ self.writer.new_styles(tuple(self.style_stack))
+
+ def assert_line_data(self, flag=1):
+ self.nospace = self.hard_break = not flag
+ self.para_end = self.have_label = 0
+
+
+class NullWriter:
+ """Minimal writer interface to use in testing.
+ """
+ def __init__(self): pass
+ def new_alignment(self, align): pass
+ def new_font(self, font): pass
+ def new_margin(self, margin, level): pass
+ def new_spacing(self, spacing): pass
+ def new_styles(self, styles): pass
+ def send_paragraph(self, blankline): pass
+ def send_line_break(self): pass
+ def send_hor_rule(self, *args, **kw): pass
+ def send_label_data(self, data): pass
+ def send_flowing_data(self, data): pass
+ def send_literal_data(self, data): pass
+
+
+class AbstractWriter(NullWriter):
+
+ def __init__(self):
+ pass
+
+ def new_alignment(self, align):
+ print "new_alignment(%s)" % `align`
+
+ def new_font(self, font):
+ print "new_font(%s)" % `font`
+
+ def new_margin(self, margin, level):
+ print "new_margin(%s, %d)" % (`margin`, level)
+
+ def new_spacing(self, spacing):
+ print "new_spacing(%s)" % `spacing`
+
+ def new_styles(self, styles):
+ print "new_styles(%s)" % `styles`
+
+ def send_paragraph(self, blankline):
+ print "send_paragraph(%s)" % `blankline`
+
+ def send_line_break(self):
+ print "send_line_break()"
+
+ def send_hor_rule(self, *args, **kw):
+ print "send_hor_rule()"
+
+ def send_label_data(self, data):
+ print "send_label_data(%s)" % `data`
+
+ def send_flowing_data(self, data):
+ print "send_flowing_data(%s)" % `data`
+
+ def send_literal_data(self, data):
+ print "send_literal_data(%s)" % `data`
+
+
+class DumbWriter(NullWriter):
+
+ def __init__(self, file=None, maxcol=72):
+ self.file = file or sys.stdout
+ self.maxcol = maxcol
+ NullWriter.__init__(self)
+ self.reset()
+
+ def reset(self):
+ self.col = 0
+ self.atbreak = 0
+
+ def send_paragraph(self, blankline):
+ self.file.write('\n' + '\n'*blankline)
+ self.col = 0
+ self.atbreak = 0
+
+ def send_line_break(self):
+ self.file.write('\n')
+ self.col = 0
+ self.atbreak = 0
+
+ def send_hor_rule(self, *args, **kw):
+ self.file.write('\n')
+ self.file.write('-'*self.maxcol)
+ self.file.write('\n')
+ self.col = 0
+ self.atbreak = 0
+
+ def send_literal_data(self, data):
+ self.file.write(data)
+ i = string.rfind(data, '\n')
+ if i >= 0:
+ self.col = 0
+ data = data[i+1:]
+ data = string.expandtabs(data)
+ self.col = self.col + len(data)
+ self.atbreak = 0
+
+ def send_flowing_data(self, data):
+ if not data: return
+ atbreak = self.atbreak or data[0] in string.whitespace
+ col = self.col
+ maxcol = self.maxcol
+ write = self.file.write
+ for word in string.split(data):
+ if atbreak:
+ if col + len(word) >= maxcol:
+ write('\n')
+ col = 0
+ else:
+ write(' ')
+ col = col + 1
+ write(word)
+ col = col + len(word)
+ atbreak = 1
+ self.col = col
+ self.atbreak = data[-1] in string.whitespace
+
+
+def test(file = None):
+ w = DumbWriter()
+ f = AbstractFormatter(w)
+ if file:
+ fp = open(file)
+ elif sys.argv[1:]:
+ fp = open(sys.argv[1])
+ else:
+ fp = sys.stdin
+ while 1:
+ line = fp.readline()
+ if not line:
+ break
+ if line == '\n':
+ f.end_paragraph(1)
+ else:
+ f.add_flowing_data(line)
+ f.end_paragraph(0)
+
+
+if __name__ == '__main__':
+ test()
diff --git a/Lib/dos-8x3/gopherli.py b/Lib/dos-8x3/gopherli.py
new file mode 100755
index 0000000..cf06e95
--- /dev/null
+++ b/Lib/dos-8x3/gopherli.py
@@ -0,0 +1,191 @@
+# Gopher protocol client interface
+
+import string
+
+# Default selector, host and port
+DEF_SELECTOR = '1/'
+DEF_HOST = 'gopher.micro.umn.edu'
+DEF_PORT = 70
+
+# Recognized file types
+A_TEXT = '0'
+A_MENU = '1'
+A_CSO = '2'
+A_ERROR = '3'
+A_MACBINHEX = '4'
+A_PCBINHEX = '5'
+A_UUENCODED = '6'
+A_INDEX = '7'
+A_TELNET = '8'
+A_BINARY = '9'
+A_DUPLICATE = '+'
+A_SOUND = 's'
+A_EVENT = 'e'
+A_CALENDAR = 'c'
+A_HTML = 'h'
+A_TN3270 = 'T'
+A_MIME = 'M'
+A_IMAGE = 'I'
+A_WHOIS = 'w'
+A_QUERY = 'q'
+A_GIF = 'g'
+A_HTML = 'h' # HTML file
+A_WWW = 'w' # WWW address
+A_PLUS_IMAGE = ':'
+A_PLUS_MOVIE = ';'
+A_PLUS_SOUND = '<'
+
+
+# Function mapping all file types to strings; unknown types become TYPE='x'
+_names = dir()
+_type_to_name_map = None
+def type_to_name(gtype):
+ global _type_to_name_map
+ if not _type_to_name_map:
+ for name in _names:
+ if name[:2] == 'A_':
+ _type_to_name_map[eval(name)] = name[2:]
+ if _type_to_name_map.has_key(gtype):
+ return _type_to_name_map[gtype]
+ return 'TYPE=' + `gtype`
+
+# Names for characters and strings
+CRLF = '\r\n'
+TAB = '\t'
+
+# Send a selector to a given host and port, return a file with the reply
+def send_selector(selector, host, port = 0):
+ import socket
+ import string
+ if not port:
+ i = string.find(host, ':')
+ if i >= 0:
+ host, port = host[:i], string.atoi(host[i+1:])
+ if not port:
+ port = DEF_PORT
+ elif type(port) == type(''):
+ port = string.atoi(port)
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ s.connect(host, port)
+ s.send(selector + CRLF)
+ s.shutdown(1)
+ return s.makefile('rb')
+
+# Send a selector and a query string
+def send_query(selector, query, host, port = 0):
+ return send_selector(selector + '\t' + query, host, port)
+
+# The following functions interpret the data returned by the gopher
+# server according to the expected type, e.g. textfile or directory
+
+# Get a directory in the form of a list of entries
+def get_directory(f):
+ import string
+ list = []
+ while 1:
+ line = f.readline()
+ if not line:
+ print '(Unexpected EOF from server)'
+ break
+ if line[-2:] == CRLF:
+ line = line[:-2]
+ elif line[-1:] in CRLF:
+ line = line[:-1]
+ if line == '.':
+ break
+ if not line:
+ print '(Empty line from server)'
+ continue
+ gtype = line[0]
+ parts = string.splitfields(line[1:], TAB)
+ if len(parts) < 4:
+ print '(Bad line from server:', `line`, ')'
+ continue
+ if len(parts) > 4:
+ if parts[4:] != ['+']:
+ print '(Extra info from server:', parts[4:], ')'
+ else:
+ parts.append('')
+ parts.insert(0, gtype)
+ list.append(parts)
+ return list
+
+# Get a text file as a list of lines, with trailing CRLF stripped
+def get_textfile(f):
+ list = []
+ get_alt_textfile(f, list.append)
+ return list
+
+# Get a text file and pass each line to a function, with trailing CRLF stripped
+def get_alt_textfile(f, func):
+ while 1:
+ line = f.readline()
+ if not line:
+ print '(Unexpected EOF from server)'
+ break
+ if line[-2:] == CRLF:
+ line = line[:-2]
+ elif line[-1:] in CRLF:
+ line = line[:-1]
+ if line == '.':
+ break
+ if line[:2] == '..':
+ line = line[1:]
+ func(line)
+
+# Get a binary file as one solid data block
+def get_binary(f):
+ data = f.read()
+ return data
+
+# Get a binary file and pass each block to a function
+def get_alt_binary(f, func, blocksize):
+ while 1:
+ data = f.read(blocksize)
+ if not data:
+ break
+ func(data)
+
+# Trivial test program
+def test():
+ import sys
+ import getopt
+ opts, args = getopt.getopt(sys.argv[1:], '')
+ selector = DEF_SELECTOR
+ type = selector[0]
+ host = DEF_HOST
+ port = DEF_PORT
+ if args:
+ host = args[0]
+ args = args[1:]
+ if args:
+ type = args[0]
+ args = args[1:]
+ if len(type) > 1:
+ type, selector = type[0], type
+ else:
+ selector = ''
+ if args:
+ selector = args[0]
+ args = args[1:]
+ query = ''
+ if args:
+ query = args[0]
+ args = args[1:]
+ if type == A_INDEX:
+ f = send_query(selector, query, host)
+ else:
+ f = send_selector(selector, host)
+ if type == A_TEXT:
+ list = get_textfile(f)
+ for item in list: print item
+ elif type in (A_MENU, A_INDEX):
+ list = get_directory(f)
+ for item in list: print item
+ else:
+ data = get_binary(f)
+ print 'binary data:', len(data), 'bytes:', `data[:100]`[:40]
+
+# Run the test when run as script
+if __name__ == '__main__':
+ test()
diff --git a/Lib/dos-8x3/htmlenti.py b/Lib/dos-8x3/htmlenti.py
new file mode 100755
index 0000000..55aefaa
--- /dev/null
+++ b/Lib/dos-8x3/htmlenti.py
@@ -0,0 +1,105 @@
+# Proposed entity definitions for HTML, taken from
+# http://www.w3.org/hypertext/WWW/MarkUp/html-spec/html-spec_14.html
+
+entitydefs = {
+ 'lt': '<',
+ 'gt': '>',
+ 'amp': '&',
+ 'quot': '"',
+ 'nbsp': chr(160), # no-break space
+ 'iexcl': chr(161), # inverted exclamation mark
+ 'cent': chr(162), # cent sign
+ 'pound': chr(163), # pound sterling sign
+ 'curren': chr(164), # general currency sign
+ 'yen': chr(165), # yen sign
+ 'brvbar': chr(166), # broken (vertical) bar
+ 'sect': chr(167), # section sign
+ 'uml': chr(168), # umlaut (dieresis)
+ 'copy': chr(169), # copyright sign
+ 'ordf': chr(170), # ordinal indicator, feminine
+ 'laquo': chr(171), # angle quotation mark, left
+ 'not': chr(172), # not sign
+ 'shy': chr(173), # soft hyphen
+ 'reg': chr(174), # registered sign
+ 'macr': chr(175), # macron
+ 'deg': chr(176), # degree sign
+ 'plusmn': chr(177), # plus-or-minus sign
+ 'sup2': chr(178), # superscript two
+ 'sup3': chr(179), # superscript three
+ 'acute': chr(180), # acute accent
+ 'micro': chr(181), # micro sign
+ 'para': chr(182), # pilcrow (paragraph sign)
+ 'middot': chr(183), # middle dot
+ 'cedil': chr(184), # cedilla
+ 'sup1': chr(185), # superscript one
+ 'ordm': chr(186), # ordinal indicator, masculine
+ 'raquo': chr(187), # angle quotation mark, right
+ 'frac14': chr(188), # fraction one-quarter
+ 'frac12': chr(189), # fraction one-half
+ 'frac34': chr(190), # fraction three-quarters
+ 'iquest': chr(191), # inverted question mark
+ 'Agrave': chr(192), # capital A, grave accent
+ 'Aacute': chr(193), # capital A, acute accent
+ 'Acirc': chr(194), # capital A, circumflex accent
+ 'Atilde': chr(195), # capital A, tilde
+ 'Auml': chr(196), # capital A, dieresis or umlaut mark
+ 'Aring': chr(197), # capital A, ring
+ 'AElig': chr(198), # capital AE diphthong (ligature)
+ 'Ccedil': chr(199), # capital C, cedilla
+ 'Egrave': chr(200), # capital E, grave accent
+ 'Eacute': chr(201), # capital E, acute accent
+ 'Ecirc': chr(202), # capital E, circumflex accent
+ 'Euml': chr(203), # capital E, dieresis or umlaut mark
+ 'Igrave': chr(204), # capital I, grave accent
+ 'Iacute': chr(205), # capital I, acute accent
+ 'Icirc': chr(206), # capital I, circumflex accent
+ 'Iuml': chr(207), # capital I, dieresis or umlaut mark
+ 'ETH': chr(208), # capital Eth, Icelandic
+ 'Ntilde': chr(209), # capital N, tilde
+ 'Ograve': chr(210), # capital O, grave accent
+ 'Oacute': chr(211), # capital O, acute accent
+ 'Ocirc': chr(212), # capital O, circumflex accent
+ 'Otilde': chr(213), # capital O, tilde
+ 'Ouml': chr(214), # capital O, dieresis or umlaut mark
+ 'times': chr(215), # multiply sign
+ 'Oslash': chr(216), # capital O, slash
+ 'Ugrave': chr(217), # capital U, grave accent
+ 'Uacute': chr(218), # capital U, acute accent
+ 'Ucirc': chr(219), # capital U, circumflex accent
+ 'Uuml': chr(220), # capital U, dieresis or umlaut mark
+ 'Yacute': chr(221), # capital Y, acute accent
+ 'THORN': chr(222), # capital THORN, Icelandic
+ 'szlig': chr(223), # small sharp s, German (sz ligature)
+ 'agrave': chr(224), # small a, grave accent
+ 'aacute': chr(225), # small a, acute accent
+ 'acirc': chr(226), # small a, circumflex accent
+ 'atilde': chr(227), # small a, tilde
+ 'auml': chr(228), # small a, dieresis or umlaut mark
+ 'aring': chr(229), # small a, ring
+ 'aelig': chr(230), # small ae diphthong (ligature)
+ 'ccedil': chr(231), # small c, cedilla
+ 'egrave': chr(232), # small e, grave accent
+ 'eacute': chr(233), # small e, acute accent
+ 'ecirc': chr(234), # small e, circumflex accent
+ 'euml': chr(235), # small e, dieresis or umlaut mark
+ 'igrave': chr(236), # small i, grave accent
+ 'iacute': chr(237), # small i, acute accent
+ 'icirc': chr(238), # small i, circumflex accent
+ 'iuml': chr(239), # small i, dieresis or umlaut mark
+ 'eth': chr(240), # small eth, Icelandic
+ 'ntilde': chr(241), # small n, tilde
+ 'ograve': chr(242), # small o, grave accent
+ 'oacute': chr(243), # small o, acute accent
+ 'ocirc': chr(244), # small o, circumflex accent
+ 'otilde': chr(245), # small o, tilde
+ 'ouml': chr(246), # small o, dieresis or umlaut mark
+ 'divide': chr(247), # divide sign
+ 'oslash': chr(248), # small o, slash
+ 'ugrave': chr(249), # small u, grave accent
+ 'uacute': chr(250), # small u, acute accent
+ 'ucirc': chr(251), # small u, circumflex accent
+ 'uuml': chr(252), # small u, dieresis or umlaut mark
+ 'yacute': chr(253), # small y, acute accent
+ 'thorn': chr(254), # small thorn, Icelandic
+ 'yuml': chr(255), # small y, dieresis or umlaut mark
+}
diff --git a/Lib/dos-8x3/importal.py b/Lib/dos-8x3/importal.py
new file mode 100755
index 0000000..780862c
--- /dev/null
+++ b/Lib/dos-8x3/importal.py
@@ -0,0 +1,36 @@
+# THIS IS OBSOLETE -- USE MODULE 'compileall' INSTEAD!
+
+# Utility module to import all modules in the path, in the hope
+# that this will update their ".pyc" files.
+
+import os
+import sys
+
+# Sabotage 'gl' and 'stdwin' to prevent windows popping up...
+for m in 'gl', 'stdwin', 'fl', 'fm':
+ sys.modules[m] = sys
+
+exceptions = ['importall']
+
+for dir in sys.path:
+ print 'Listing', dir
+ try:
+ names = os.listdir(dir)
+ except os.error:
+ print 'Can\'t list', dir
+ names = []
+ names.sort()
+ for name in names:
+ head, tail = name[:-3], name[-3:]
+ if tail == '.py' and head not in exceptions:
+ s = 'import ' + head
+ print s
+ try:
+ exec s + '\n'
+ except KeyboardInterrupt:
+ del names[:]
+ print '\n[interrupt]'
+ break
+ except:
+ print 'Sorry:', sys.exc_type + ':',
+ print sys.exc_value
diff --git a/Lib/dos-8x3/linecach.py b/Lib/dos-8x3/linecach.py
new file mode 100755
index 0000000..7de373f
--- /dev/null
+++ b/Lib/dos-8x3/linecach.py
@@ -0,0 +1,90 @@
+# Cache lines from files.
+# This is intended to read lines from modules imported -- hence if a filename
+# is not found, it will look down the module search path for a file by
+# that name.
+
+import sys
+import os
+from stat import *
+
+def getline(filename, lineno):
+ lines = getlines(filename)
+ if 1 <= lineno <= len(lines):
+ return lines[lineno-1]
+ else:
+ return ''
+
+
+# The cache
+
+cache = {} # The cache
+
+
+# Clear the cache entirely
+
+def clearcache():
+ global cache
+ cache = {}
+
+
+# Get the lines for a file from the cache.
+# Update the cache if it doesn't contain an entry for this file already.
+
+def getlines(filename):
+ if cache.has_key(filename):
+ return cache[filename][2]
+ else:
+ return updatecache(filename)
+
+
+# Discard cache entries that are out of date.
+# (This is not checked upon each call!)
+
+def checkcache():
+ for filename in cache.keys():
+ size, mtime, lines, fullname = cache[filename]
+ try:
+ stat = os.stat(fullname)
+ except os.error:
+ del cache[filename]
+ continue
+ if size <> stat[ST_SIZE] or mtime <> stat[ST_MTIME]:
+ del cache[filename]
+
+
+# Update a cache entry and return its list of lines.
+# If something's wrong, print a message, discard the cache entry,
+# and return an empty list.
+
+def updatecache(filename):
+ if cache.has_key(filename):
+ del cache[filename]
+ if not filename or filename[0] + filename[-1] == '<>':
+ return []
+ fullname = filename
+ try:
+ stat = os.stat(fullname)
+ except os.error, msg:
+ # Try looking through the module search path
+ basename = os.path.split(filename)[1]
+ for dirname in sys.path:
+ fullname = os.path.join(dirname, basename)
+ try:
+ stat = os.stat(fullname)
+ break
+ except os.error:
+ pass
+ else:
+ # No luck
+## print '*** Cannot stat', filename, ':', msg
+ return []
+ try:
+ fp = open(fullname, 'r')
+ lines = fp.readlines()
+ fp.close()
+ except IOError, msg:
+## print '*** Cannot open', fullname, ':', msg
+ return []
+ size, mtime = stat[ST_SIZE], stat[ST_MTIME]
+ cache[filename] = size, mtime, lines, fullname
+ return lines
diff --git a/Lib/dos-8x3/macurl2p.py b/Lib/dos-8x3/macurl2p.py
new file mode 100755
index 0000000..65afe69
--- /dev/null
+++ b/Lib/dos-8x3/macurl2p.py
@@ -0,0 +1,76 @@
+"""Mac specific module for conversion between pathnames and URLs."""
+
+import string
+import urllib
+import os
+
+def url2pathname(pathname):
+ "Convert /-delimited pathname to mac pathname"
+ #
+ # XXXX The .. handling should be fixed...
+ #
+ tp = urllib.splittype(pathname)[0]
+ if tp and tp <> 'file':
+ raise RuntimeError, 'Cannot convert non-local URL to pathname'
+ components = string.split(pathname, '/')
+ # Remove . and embedded ..
+ i = 0
+ while i < len(components):
+ if components[i] == '.':
+ del components[i]
+ elif components[i] == '..' and i > 0 and \
+ components[i-1] not in ('', '..'):
+ del components[i-1:i+1]
+ i = i-1
+ elif components[i] == '' and i > 0 and components[i-1] <> '':
+ del components[i]
+ else:
+ i = i+1
+ if not components[0]:
+ # Absolute unix path, don't start with colon
+ return string.join(components[1:], ':')
+ else:
+ # relative unix path, start with colon. First replace
+ # leading .. by empty strings (giving ::file)
+ i = 0
+ while i < len(components) and components[i] == '..':
+ components[i] = ''
+ i = i + 1
+ return ':' + string.join(components, ':')
+
+def pathname2url(pathname):
+ "convert mac pathname to /-delimited pathname"
+ if '/' in pathname:
+ raise RuntimeError, "Cannot convert pathname containing slashes"
+ components = string.split(pathname, ':')
+ # Replace empty string ('::') by .. (will result in '/../' later)
+ for i in range(1, len(components)):
+ if components[i] == '':
+ components[i] = '..'
+ # Truncate names longer than 31 bytes
+ components = map(lambda x: x[:31], components)
+
+ if os.path.isabs(pathname):
+ return '/' + string.join(components, '/')
+ else:
+ return string.join(components, '/')
+
+def test():
+ for url in ["index.html",
+ "bar/index.html",
+ "/foo/bar/index.html",
+ "/foo/bar/",
+ "/"]:
+ print `url`, '->', `url2pathname(url)`
+ for path in ["drive:",
+ "drive:dir:",
+ "drive:dir:file",
+ "drive:file",
+ "file",
+ ":file",
+ ":dir:",
+ ":dir:file"]:
+ print `path`, '->', `pathname2url(path)`
+
+if __name__ == '__main__':
+ test()
diff --git a/Lib/dos-8x3/mimetool.py b/Lib/dos-8x3/mimetool.py
new file mode 100755
index 0000000..da33a77
--- /dev/null
+++ b/Lib/dos-8x3/mimetool.py
@@ -0,0 +1,187 @@
+# Various tools used by MIME-reading or MIME-writing programs.
+
+
+import os
+import rfc822
+import string
+import tempfile
+
+
+# A derived class of rfc822.Message that knows about MIME headers and
+# contains some hooks for decoding encoded and multipart messages.
+
+class Message(rfc822.Message):
+
+ def __init__(self, fp, seekable = 1):
+ rfc822.Message.__init__(self, fp, seekable)
+ self.encodingheader = \
+ self.getheader('content-transfer-encoding')
+ self.typeheader = \
+ self.getheader('content-type')
+ self.parsetype()
+ self.parseplist()
+
+ def parsetype(self):
+ str = self.typeheader
+ if str == None:
+ str = 'text/plain'
+ if ';' in str:
+ i = string.index(str, ';')
+ self.plisttext = str[i:]
+ str = str[:i]
+ else:
+ self.plisttext = ''
+ fields = string.splitfields(str, '/')
+ for i in range(len(fields)):
+ fields[i] = string.lower(string.strip(fields[i]))
+ self.type = string.joinfields(fields, '/')
+ self.maintype = fields[0]
+ self.subtype = string.joinfields(fields[1:], '/')
+
+ def parseplist(self):
+ str = self.plisttext
+ self.plist = []
+ while str[:1] == ';':
+ str = str[1:]
+ if ';' in str:
+ # XXX Should parse quotes!
+ end = string.index(str, ';')
+ else:
+ end = len(str)
+ f = str[:end]
+ if '=' in f:
+ i = string.index(f, '=')
+ f = string.lower(string.strip(f[:i])) + \
+ '=' + string.strip(f[i+1:])
+ self.plist.append(string.strip(f))
+ str = str[end:]
+
+ def getplist(self):
+ return self.plist
+
+ def getparam(self, name):
+ name = string.lower(name) + '='
+ n = len(name)
+ for p in self.plist:
+ if p[:n] == name:
+ return rfc822.unquote(p[n:])
+ return None
+
+ def getencoding(self):
+ if self.encodingheader == None:
+ return '7bit'
+ return string.lower(self.encodingheader)
+
+ def gettype(self):
+ return self.type
+
+ def getmaintype(self):
+ return self.maintype
+
+ def getsubtype(self):
+ return self.subtype
+
+
+
+
+# Utility functions
+# -----------------
+
+
+# Return a random string usable as a multipart boundary.
+# The method used is so that it is *very* unlikely that the same
+# string of characters will every occur again in the Universe,
+# so the caller needn't check the data it is packing for the
+# occurrence of the boundary.
+#
+# The boundary contains dots so you have to quote it in the header.
+
+_prefix = None
+
+def choose_boundary():
+ global _prefix
+ import time
+ import rand
+ if _prefix == None:
+ import socket
+ import os
+ hostid = socket.gethostbyname(socket.gethostname())
+ uid = `os.getuid()`
+ pid = `os.getpid()`
+ seed = `rand.rand()`
+ _prefix = hostid + '.' + uid + '.' + pid
+ timestamp = `int(time.time())`
+ seed = `rand.rand()`
+ return _prefix + '.' + timestamp + '.' + seed
+
+
+# Subroutines for decoding some common content-transfer-types
+
+# XXX This requires that uudecode and mmencode are in $PATH
+
+def decode(input, output, encoding):
+ if decodetab.has_key(encoding):
+ pipethrough(input, decodetab[encoding], output)
+ else:
+ raise ValueError, \
+ 'unknown Content-Transfer-Encoding: %s' % encoding
+
+def encode(input, output, encoding):
+ if encodetab.has_key(encoding):
+ pipethrough(input, encodetab[encoding], output)
+ else:
+ raise ValueError, \
+ 'unknown Content-Transfer-Encoding: %s' % encoding
+
+uudecode_pipe = '''(
+TEMP=/tmp/@uu.$$
+sed "s%^begin [0-7][0-7]* .*%begin 600 $TEMP%" | uudecode
+cat $TEMP
+rm $TEMP
+)'''
+
+decodetab = {
+ 'uuencode': uudecode_pipe,
+ 'x-uuencode': uudecode_pipe,
+ 'quoted-printable': 'mmencode -u -q',
+ 'base64': 'mmencode -u -b',
+}
+
+encodetab = {
+ 'x-uuencode': 'uuencode tempfile',
+ 'uuencode': 'uuencode tempfile',
+ 'quoted-printable': 'mmencode -q',
+ 'base64': 'mmencode -b',
+}
+
+def pipeto(input, command):
+ pipe = os.popen(command, 'w')
+ copyliteral(input, pipe)
+ pipe.close()
+
+def pipethrough(input, command, output):
+ tempname = tempfile.mktemp()
+ try:
+ temp = open(tempname, 'w')
+ except IOError:
+ print '*** Cannot create temp file', `tempname`
+ return
+ copyliteral(input, temp)
+ temp.close()
+ pipe = os.popen(command + ' <' + tempname, 'r')
+ copybinary(pipe, output)
+ pipe.close()
+ os.unlink(tempname)
+
+def copyliteral(input, output):
+ while 1:
+ line = input.readline()
+ if not line: break
+ output.write(line)
+
+def copybinary(input, output):
+ BUFSIZE = 8192
+ while 1:
+ line = input.read(BUFSIZE)
+ if not line: break
+ output.write(line)
diff --git a/Lib/dos-8x3/multifil.py b/Lib/dos-8x3/multifil.py
new file mode 100755
index 0000000..71e0dd0
--- /dev/null
+++ b/Lib/dos-8x3/multifil.py
@@ -0,0 +1,128 @@
+# A class that makes each part of a multipart message "feel" like an
+# ordinary file, as long as you use fp.readline(). Allows recursive
+# use, for nested multipart messages. Probably best used together
+# with module mimetools.
+#
+# Suggested use:
+#
+# real_fp = open(...)
+# fp = MultiFile(real_fp)
+#
+# "read some lines from fp"
+# fp.push(separator)
+# while 1:
+# "read lines from fp until it returns an empty string" (A)
+# if not fp.next(): break
+# fp.pop()
+# "read remaining lines from fp until it returns an empty string"
+#
+# The latter sequence may be used recursively at (A).
+# It is also allowed to use multiple push()...pop() sequences.
+# Note that if a nested multipart message is terminated by a separator
+# for an outer message, this is not reported, even though it is really
+# illegal input.
+
+import sys
+import string
+
+err = sys.stderr.write
+
+Error = 'multifile.Error'
+
+class MultiFile:
+ #
+ def __init__(self, fp):
+ self.fp = fp
+ self.stack = [] # Grows down
+ self.level = 0
+ self.last = 0
+ self.start = self.fp.tell()
+ self.posstack = [] # Grows down
+ #
+ def tell(self):
+ if self.level > 0:
+ return self.lastpos
+ return self.fp.tell() - self.start
+ #
+ def seek(self, pos):
+ if not 0 <= pos <= self.tell() or \
+ self.level > 0 and pos > self.lastpos:
+ raise Error, 'bad MultiFile.seek() call'
+ self.fp.seek(pos + self.start)
+ self.level = 0
+ self.last = 0
+ #
+ def readline(self):
+ if self.level > 0: return ''
+ line = self.fp.readline()
+ if not line:
+ self.level = len(self.stack)
+ self.last = (self.level > 0)
+ if self.last:
+ err('*** Sudden EOF in MultiFile.readline()\n')
+ return ''
+ if line[:2] <> '--': return line
+ n = len(line)
+ k = n
+ while k > 0 and line[k-1] in string.whitespace: k = k-1
+ mark = line[2:k]
+ if mark[-2:] == '--': mark1 = mark[:-2]
+ else: mark1 = None
+ for i in range(len(self.stack)):
+ sep = self.stack[i]
+ if sep == mark:
+ self.last = 0
+ break
+ elif mark1 <> None and sep == mark1:
+ self.last = 1
+ break
+ else:
+ return line
+ # Get here after break out of loop
+ self.lastpos = self.tell() - len(line)
+ self.level = i+1
+ if self.level > 1:
+ err('*** Missing endmarker in MultiFile.readline()\n')
+ return ''
+ #
+ def readlines(self):
+ list = []
+ while 1:
+ line = self.readline()
+ if not line: break
+ list.append(line)
+ return list
+ #
+ def read(self): # Note: no size argument -- read until EOF only!
+ return string.joinfields(self.readlines(), '')
+ #
+ def next(self):
+ while self.readline(): pass
+ if self.level > 1 or self.last:
+ return 0
+ self.level = 0
+ self.last = 0
+ self.start = self.fp.tell()
+ return 1
+ #
+ def push(self, sep):
+ if self.level > 0:
+ raise Error, 'bad MultiFile.push() call'
+ self.stack.insert(0, sep)
+ self.posstack.insert(0, self.start)
+ self.start = self.fp.tell()
+ #
+ def pop(self):
+ if self.stack == []:
+ raise Error, 'bad MultiFile.pop() call'
+ if self.level <= 1:
+ self.last = 0
+ else:
+ abslastpos = self.lastpos + self.start
+ self.level = max(0, self.level - 1)
+ del self.stack[0]
+ self.start = self.posstack[0]
+ del self.posstack[0]
+ if self.level > 0:
+ self.lastpos = abslastpos - self.start
+ #
diff --git a/Lib/dos-8x3/nturl2pa.py b/Lib/dos-8x3/nturl2pa.py
new file mode 100755
index 0000000..17f01f5
--- /dev/null
+++ b/Lib/dos-8x3/nturl2pa.py
@@ -0,0 +1,52 @@
+#
+# nturl2path convert a NT pathname to a file URL and
+# vice versa
+
+def url2pathname(url):
+ """ Convert a URL to a DOS path...
+ Currently only works for absolute paths
+
+ ///C|/foo/bar/spam.foo
+
+ becomes
+
+ C:\foo\bar\spam.foo
+ """
+ import string
+ comp = string.splitfields(url, '|')
+ if len(comp) != 2 or comp[0][-1] not in string.letters:
+ error = 'Bad URL: ' + url
+ raise IOError, error
+ drive = string.upper(comp[0][-1])
+ components = string.splitfields(comp[1], '/')
+ path = drive + ':'
+ for comp in components:
+ if comp:
+ path = path + '\\' + comp
+ return path
+
+def pathname2url(p):
+
+ """ Convert a DOS path name to a file url...
+ Currently only works for absolute paths
+
+ C:\foo\bar\spam.foo
+
+ becomes
+
+ ///C|/foo/bar/spam.foo
+ """
+
+ import string
+ comp = string.splitfields(p, ':')
+ if len(comp) != 2 or len(comp[0]) > 1:
+ error = 'Bad path: ' + p
+ raise IOError, error
+
+ drive = string.upper(comp[0])
+ components = string.splitfields(comp[1], '\\')
+ path = '///' + drive + '|'
+ for comp in components:
+ if comp:
+ path = path + '/' + comp
+ return path
diff --git a/Lib/dos-8x3/para.py b/Lib/dos-8x3/para.py
new file mode 100755
index 0000000..c9b3bdd
--- /dev/null
+++ b/Lib/dos-8x3/para.py
@@ -0,0 +1,409 @@
+# Text formatting abstractions
+# Note -- this module is obsolete, it's too slow anyway
+
+
+# Oft-used type object
+Int = type(0)
+
+
+# Represent a paragraph. This is a list of words with associated
+# font and size information, plus indents and justification for the
+# entire paragraph.
+# Once the words have been added to a paragraph, it can be laid out
+# for different line widths. Once laid out, it can be rendered at
+# different screen locations. Once rendered, it can be queried
+# for mouse hits, and parts of the text can be highlighted
+class Para:
+ #
+ def __init__(self):
+ self.words = [] # The words
+ self.just = 'l' # Justification: 'l', 'r', 'lr' or 'c'
+ self.indent_left = self.indent_right = self.indent_hang = 0
+ # Final lay-out parameters, may change
+ self.left = self.top = self.right = self.bottom = \
+ self.width = self.height = self.lines = None
+ #
+ # Add a word, computing size information for it.
+ # Words may also be added manually by appending to self.words
+ # Each word should be a 7-tuple:
+ # (font, text, width, space, stretch, ascent, descent)
+ def addword(self, d, font, text, space, stretch):
+ if font <> None:
+ d.setfont(font)
+ width = d.textwidth(text)
+ ascent = d.baseline()
+ descent = d.lineheight() - ascent
+ spw = d.textwidth(' ')
+ space = space * spw
+ stretch = stretch * spw
+ tuple = (font, text, width, space, stretch, ascent, descent)
+ self.words.append(tuple)
+ #
+ # Hooks to begin and end anchors -- insert numbers in the word list!
+ def bgn_anchor(self, id):
+ self.words.append(id)
+ #
+ def end_anchor(self, id):
+ self.words.append(0)
+ #
+ # Return the total length (width) of the text added so far, in pixels
+ def getlength(self):
+ total = 0
+ for word in self.words:
+ if type(word) <> Int:
+ total = total + word[2] + word[3]
+ return total
+ #
+ # Tab to a given position (relative to the current left indent):
+ # remove all stretch, add fixed space up to the new indent.
+ # If the current position is already beying the tab stop,
+ # don't add any new space (but still remove the stretch)
+ def tabto(self, tab):
+ total = 0
+ as, de = 1, 0
+ for i in range(len(self.words)):
+ word = self.words[i]
+ if type(word) == Int: continue
+ fo, te, wi, sp, st, as, de = word
+ self.words[i] = fo, te, wi, sp, 0, as, de
+ total = total + wi + sp
+ if total < tab:
+ self.words.append(None, '', 0, tab-total, 0, as, de)
+ #
+ # Make a hanging tag: tab to hang, increment indent_left by hang,
+ # and reset indent_hang to -hang
+ def makehangingtag(self, hang):
+ self.tabto(hang)
+ self.indent_left = self.indent_left + hang
+ self.indent_hang = -hang
+ #
+ # Decide where the line breaks will be given some screen width
+ def layout(self, linewidth):
+ self.width = linewidth
+ height = 0
+ self.lines = lines = []
+ avail1 = self.width - self.indent_left - self.indent_right
+ avail = avail1 - self.indent_hang
+ words = self.words
+ i = 0
+ n = len(words)
+ lastfont = None
+ while i < n:
+ firstfont = lastfont
+ charcount = 0
+ width = 0
+ stretch = 0
+ ascent = 0
+ descent = 0
+ lsp = 0
+ j = i
+ while i < n:
+ word = words[i]
+ if type(word) == Int:
+ if word > 0 and width >= avail:
+ break
+ i = i+1
+ continue
+ fo, te, wi, sp, st, as, de = word
+ if width + wi > avail and width > 0 and wi > 0:
+ break
+ if fo <> None:
+ lastfont = fo
+ if width == 0:
+ firstfont = fo
+ charcount = charcount + len(te) + (sp > 0)
+ width = width + wi + sp
+ lsp = sp
+ stretch = stretch + st
+ lst = st
+ ascent = max(ascent, as)
+ descent = max(descent, de)
+ i = i+1
+ while i > j and type(words[i-1]) == Int and \
+ words[i-1] > 0: i = i-1
+ width = width - lsp
+ if i < n:
+ stretch = stretch - lst
+ else:
+ stretch = 0
+ tuple = i-j, firstfont, charcount, width, stretch, \
+ ascent, descent
+ lines.append(tuple)
+ height = height + ascent + descent
+ avail = avail1
+ self.height = height
+ #
+ # Call a function for all words in a line
+ def visit(self, wordfunc, anchorfunc):
+ avail1 = self.width - self.indent_left - self.indent_right
+ avail = avail1 - self.indent_hang
+ v = self.top
+ i = 0
+ for tuple in self.lines:
+ wordcount, firstfont, charcount, width, stretch, \
+ ascent, descent = tuple
+ h = self.left + self.indent_left
+ if i == 0: h = h + self.indent_hang
+ extra = 0
+ if self.just == 'r': h = h + avail - width
+ elif self.just == 'c': h = h + (avail - width) / 2
+ elif self.just == 'lr' and stretch > 0:
+ extra = avail - width
+ v2 = v + ascent + descent
+ for j in range(i, i+wordcount):
+ word = self.words[j]
+ if type(word) == Int:
+ ok = anchorfunc(self, tuple, word, \
+ h, v)
+ if ok <> None: return ok
+ continue
+ fo, te, wi, sp, st, as, de = word
+ if extra > 0 and stretch > 0:
+ ex = extra * st / stretch
+ extra = extra - ex
+ stretch = stretch - st
+ else:
+ ex = 0
+ h2 = h + wi + sp + ex
+ ok = wordfunc(self, tuple, word, h, v, \
+ h2, v2, (j==i), (j==i+wordcount-1))
+ if ok <> None: return ok
+ h = h2
+ v = v2
+ i = i + wordcount
+ avail = avail1
+ #
+ # Render a paragraph in "drawing object" d, using the rectangle
+ # given by (left, top, right) with an unspecified bottom.
+ # Return the computed bottom of the text.
+ def render(self, d, left, top, right):
+ if self.width <> right-left:
+ self.layout(right-left)
+ self.left = left
+ self.top = top
+ self.right = right
+ self.bottom = self.top + self.height
+ self.anchorid = 0
+ try:
+ self.d = d
+ self.visit(self.__class__._renderword, \
+ self.__class__._renderanchor)
+ finally:
+ self.d = None
+ return self.bottom
+ #
+ def _renderword(self, tuple, word, h, v, h2, v2, isfirst, islast):
+ if word[0] <> None: self.d.setfont(word[0])
+ baseline = v + tuple[5]
+ self.d.text((h, baseline - word[5]), word[1])
+ if self.anchorid > 0:
+ self.d.line((h, baseline+2), (h2, baseline+2))
+ #
+ def _renderanchor(self, tuple, word, h, v):
+ self.anchorid = word
+ #
+ # Return which anchor(s) was hit by the mouse
+ def hitcheck(self, mouseh, mousev):
+ self.mouseh = mouseh
+ self.mousev = mousev
+ self.anchorid = 0
+ self.hits = []
+ self.visit(self.__class__._hitcheckword, \
+ self.__class__._hitcheckanchor)
+ return self.hits
+ #
+ def _hitcheckword(self, tuple, word, h, v, h2, v2, isfirst, islast):
+ if self.anchorid > 0 and h <= self.mouseh <= h2 and \
+ v <= self.mousev <= v2:
+ self.hits.append(self.anchorid)
+ #
+ def _hitcheckanchor(self, tuple, word, h, v):
+ self.anchorid = word
+ #
+ # Return whether the given anchor id is present
+ def hasanchor(self, id):
+ return id in self.words or -id in self.words
+ #
+ # Extract the raw text from the word list, substituting one space
+ # for non-empty inter-word space, and terminating with '\n'
+ def extract(self):
+ text = ''
+ for w in self.words:
+ if type(w) <> Int:
+ word = w[1]
+ if w[3]: word = word + ' '
+ text = text + word
+ return text + '\n'
+ #
+ # Return which character position was hit by the mouse, as
+ # an offset in the entire text as returned by extract().
+ # Return None if the mouse was not in this paragraph
+ def whereis(self, d, mouseh, mousev):
+ if mousev < self.top or mousev > self.bottom:
+ return None
+ self.mouseh = mouseh
+ self.mousev = mousev
+ self.lastfont = None
+ self.charcount = 0
+ try:
+ self.d = d
+ return self.visit(self.__class__._whereisword, \
+ self.__class__._whereisanchor)
+ finally:
+ self.d = None
+ #
+ def _whereisword(self, tuple, word, h1, v1, h2, v2, isfirst, islast):
+ fo, te, wi, sp, st, as, de = word
+ if fo <> None: self.lastfont = fo
+ h = h1
+ if isfirst: h1 = 0
+ if islast: h2 = 999999
+ if not (v1 <= self.mousev <= v2 and h1 <= self.mouseh <= h2):
+ self.charcount = self.charcount + len(te) + (sp > 0)
+ return
+ if self.lastfont <> None:
+ self.d.setfont(self.lastfont)
+ cc = 0
+ for c in te:
+ cw = self.d.textwidth(c)
+ if self.mouseh <= h + cw/2:
+ return self.charcount + cc
+ cc = cc+1
+ h = h+cw
+ self.charcount = self.charcount + cc
+ if self.mouseh <= (h+h2) / 2:
+ return self.charcount
+ else:
+ return self.charcount + 1
+ #
+ def _whereisanchor(self, tuple, word, h, v):
+ pass
+ #
+ # Return screen position corresponding to position in paragraph.
+ # Return tuple (h, vtop, vbaseline, vbottom).
+ # This is more or less the inverse of whereis()
+ def screenpos(self, d, pos):
+ if pos < 0:
+ ascent, descent = self.lines[0][5:7]
+ return self.left, self.top, self.top + ascent, \
+ self.top + ascent + descent
+ self.pos = pos
+ self.lastfont = None
+ try:
+ self.d = d
+ ok = self.visit(self.__class__._screenposword, \
+ self.__class__._screenposanchor)
+ finally:
+ self.d = None
+ if ok == None:
+ ascent, descent = self.lines[-1][5:7]
+ ok = self.right, self.bottom - ascent - descent, \
+ self.bottom - descent, self.bottom
+ return ok
+ #
+ def _screenposword(self, tuple, word, h1, v1, h2, v2, isfirst, islast):
+ fo, te, wi, sp, st, as, de = word
+ if fo <> None: self.lastfont = fo
+ cc = len(te) + (sp > 0)
+ if self.pos > cc:
+ self.pos = self.pos - cc
+ return
+ if self.pos < cc:
+ self.d.setfont(self.lastfont)
+ h = h1 + self.d.textwidth(te[:self.pos])
+ else:
+ h = h2
+ ascent, descent = tuple[5:7]
+ return h, v1, v1+ascent, v2
+ #
+ def _screenposanchor(self, tuple, word, h, v):
+ pass
+ #
+ # Invert the stretch of text between pos1 and pos2.
+ # If pos1 is None, the beginning is implied;
+ # if pos2 is None, the end is implied.
+ # Undoes its own effect when called again with the same arguments
+ def invert(self, d, pos1, pos2):
+ if pos1 == None:
+ pos1 = self.left, self.top, self.top, self.top
+ else:
+ pos1 = self.screenpos(d, pos1)
+ if pos2 == None:
+ pos2 = self.right, self.bottom,self.bottom,self.bottom
+ else:
+ pos2 = self.screenpos(d, pos2)
+ h1, top1, baseline1, bottom1 = pos1
+ h2, top2, baseline2, bottom2 = pos2
+ if bottom1 <= top2:
+ d.invert((h1, top1), (self.right, bottom1))
+ h1 = self.left
+ if bottom1 < top2:
+ d.invert((h1, bottom1), (self.right, top2))
+ top1, bottom1 = top2, bottom2
+ d.invert((h1, top1), (h2, bottom2))
+
+
+# Test class Para
+# XXX This was last used on the Mac, hence the weird fonts...
+def test():
+ import stdwin
+ from stdwinevents import *
+ words = 'The', 'quick', 'brown', 'fox', 'jumps', 'over', \
+ 'the', 'lazy', 'dog.'
+ paralist = []
+ for just in 'l', 'r', 'lr', 'c':
+ p = Para()
+ p.just = just
+ p.addword(stdwin, ('New York', 'p', 12), words[0], 1, 1)
+ for word in words[1:-1]:
+ p.addword(stdwin, None, word, 1, 1)
+ p.addword(stdwin, None, words[-1], 2, 4)
+ p.addword(stdwin, ('New York', 'b', 18), 'Bye!', 0, 0)
+ p.addword(stdwin, ('New York', 'p', 10), 'Bye!', 0, 0)
+ paralist.append(p)
+ window = stdwin.open('Para.test()')
+ start = stop = selpara = None
+ while 1:
+ etype, win, detail = stdwin.getevent()
+ if etype == WE_CLOSE:
+ break
+ if etype == WE_SIZE:
+ window.change((0, 0), (1000, 1000))
+ if etype == WE_DRAW:
+ width, height = window.getwinsize()
+ d = None
+ try:
+ d = window.begindrawing()
+ d.cliprect(detail)
+ d.erase(detail)
+ v = 0
+ for p in paralist:
+ v = p.render(d, 0, v, width)
+ if p == selpara and \
+ start <> None and stop <> None:
+ p.invert(d, start, stop)
+ finally:
+ if d: d.close()
+ if etype == WE_MOUSE_DOWN:
+ if selpara and start <> None and stop <> None:
+ d = window.begindrawing()
+ selpara.invert(d, start, stop)
+ d.close()
+ start = stop = selpara = None
+ mouseh, mousev = detail[0]
+ for p in paralist:
+ start = p.whereis(stdwin, mouseh, mousev)
+ if start <> None:
+ selpara = p
+ break
+ if etype == WE_MOUSE_UP and start <> None and selpara:
+ mouseh, mousev = detail[0]
+ stop = selpara.whereis(stdwin, mouseh, mousev)
+ if stop == None: start = selpara = None
+ else:
+ if start > stop:
+ start, stop = stop, start
+ d = window.begindrawing()
+ selpara.invert(d, start, stop)
+ d.close()
+ window.close()
diff --git a/Lib/dos-8x3/posixfil.py b/Lib/dos-8x3/posixfil.py
new file mode 100755
index 0000000..459cd52
--- /dev/null
+++ b/Lib/dos-8x3/posixfil.py
@@ -0,0 +1,207 @@
+#
+# Start of posixfile.py
+#
+
+#
+# Extended file operations
+#
+# f = posixfile.open(filename, [mode, [bufsize]])
+# will create a new posixfile object
+#
+# f = posixfile.fileopen(fileobject)
+# will create a posixfile object from a builtin file object
+#
+# f.file()
+# will return the original builtin file object
+#
+# f.dup()
+# will return a new file object based on a new filedescriptor
+#
+# f.dup2(fd)
+# will return a new file object based on the given filedescriptor
+#
+# f.flags(mode)
+# will turn on the associated flag (merge)
+# mode can contain the following characters:
+#
+# (character representing a flag)
+# a append only flag
+# c close on exec flag
+# n no delay flag
+# s synchronization flag
+# (modifiers)
+# ! turn flags 'off' instead of default 'on'
+# = copy flags 'as is' instead of default 'merge'
+# ? return a string in which the characters represent the flags
+# that are set
+#
+# note: - the '!' and '=' modifiers are mutually exclusive.
+# - the '?' modifier will return the status of the flags after they
+# have been changed by other characters in the mode string
+#
+# f.lock(mode [, len [, start [, whence]]])
+# will (un)lock a region
+# mode can contain the following characters:
+#
+# (character representing type of lock)
+# u unlock
+# r read lock
+# w write lock
+# (modifiers)
+# | wait until the lock can be granted
+# ? return the first lock conflicting with the requested lock
+# or 'None' if there is no conflict. The lock returned is in the
+# format (mode, len, start, whence, pid) where mode is a
+# character representing the type of lock ('r' or 'w')
+#
+# note: - the '?' modifier prevents a region from being locked; it is
+# query only
+#
+
+class _posixfile_:
+ states = ['open', 'closed']
+
+ #
+ # Internal routines
+ #
+ def __repr__(self):
+ file = self._file_
+ return "<%s posixfile '%s', mode '%s' at %s>" % \
+ (self.states[file.closed], file.name, file.mode, \
+ hex(id(self))[2:])
+
+ def __del__(self):
+ self._file_.close()
+
+ #
+ # Initialization routines
+ #
+ def open(self, name, mode='r', bufsize=-1):
+ import __builtin__
+ return self.fileopen(__builtin__.open(name, mode, bufsize))
+
+ def fileopen(self, file):
+ if `type(file)` != "<type 'file'>":
+ raise TypeError, 'posixfile.fileopen() arg must be file object'
+ self._file_ = file
+ # Copy basic file methods
+ for method in file.__methods__:
+ setattr(self, method, getattr(file, method))
+ return self
+
+ #
+ # New methods
+ #
+ def file(self):
+ return self._file_
+
+ def dup(self):
+ import posix
+
+ try: ignore = posix.fdopen
+ except: raise AttributeError, 'dup() method unavailable'
+
+ return posix.fdopen(posix.dup(self._file_.fileno()), self._file_.mode)
+
+ def dup2(self, fd):
+ import posix
+
+ try: ignore = posix.fdopen
+ except: raise AttributeError, 'dup() method unavailable'
+
+ posix.dup2(self._file_.fileno(), fd)
+ return posix.fdopen(fd, self._file_.mode)
+
+ def flags(self, *which):
+ import fcntl, FCNTL
+
+ if which:
+ if len(which) > 1:
+ raise TypeError, 'Too many arguments'
+ which = which[0]
+ else: which = '?'
+
+ l_flags = 0
+ if 'n' in which: l_flags = l_flags | FCNTL.O_NDELAY
+ if 'a' in which: l_flags = l_flags | FCNTL.O_APPEND
+ if 's' in which: l_flags = l_flags | FCNTL.O_SYNC
+
+ file = self._file_
+
+ if '=' not in which:
+ cur_fl = fcntl.fcntl(file.fileno(), FCNTL.F_GETFL, 0)
+ if '!' in which: l_flags = cur_fl & ~ l_flags
+ else: l_flags = cur_fl | l_flags
+
+ l_flags = fcntl.fcntl(file.fileno(), FCNTL.F_SETFL, l_flags)
+
+ if 'c' in which:
+ arg = ('!' not in which) # 0 is don't, 1 is do close on exec
+ l_flags = fcntl.fcntl(file.fileno(), FCNTL.F_SETFD, arg)
+
+ if '?' in which:
+ which = '' # Return current flags
+ l_flags = fcntl.fcntl(file.fileno(), FCNTL.F_GETFL, 0)
+ if FCNTL.O_APPEND & l_flags: which = which + 'a'
+ if fcntl.fcntl(file.fileno(), FCNTL.F_GETFD, 0) & 1:
+ which = which + 'c'
+ if FCNTL.O_NDELAY & l_flags: which = which + 'n'
+ if FCNTL.O_SYNC & l_flags: which = which + 's'
+ return which
+
+ def lock(self, how, *args):
+ import struct, fcntl, FCNTL
+
+ if 'w' in how: l_type = FCNTL.F_WRLCK
+ elif 'r' in how: l_type = FCNTL.F_RDLCK
+ elif 'u' in how: l_type = FCNTL.F_UNLCK
+ else: raise TypeError, 'no type of lock specified'
+
+ if '|' in how: cmd = FCNTL.F_SETLKW
+ elif '?' in how: cmd = FCNTL.F_GETLK
+ else: cmd = FCNTL.F_SETLK
+
+ l_whence = 0
+ l_start = 0
+ l_len = 0
+
+ if len(args) == 1:
+ l_len = args[0]
+ elif len(args) == 2:
+ l_len, l_start = args
+ elif len(args) == 3:
+ l_len, l_start, l_whence = args
+ elif len(args) > 3:
+ raise TypeError, 'too many arguments'
+
+ flock = struct.pack('hhllhh', l_type, l_whence, l_start, l_len, 0, 0)
+ flock = fcntl.fcntl(self._file_.fileno(), cmd, flock)
+
+ if '?' in how:
+ l_type, l_whence, l_start, l_len, l_sysid, l_pid = \
+ struct.unpack('hhllhh', flock)
+ if l_type != FCNTL.F_UNLCK:
+ if l_type == FCNTL.F_RDLCK:
+ return 'r', l_len, l_start, l_whence, l_pid
+ else:
+ return 'w', l_len, l_start, l_whence, l_pid
+
+#
+# Public routine to obtain a posixfile object
+#
+def open(name, mode='r', bufsize=-1):
+ return _posixfile_().open(name, mode, bufsize)
+
+def fileopen(file):
+ return _posixfile_().fileopen(file)
+
+#
+# Constants
+#
+SEEK_SET = 0
+SEEK_CUR = 1
+SEEK_END = 2
+
+#
+# End of posixfile.py
+#
diff --git a/Lib/dos-8x3/posixpat.py b/Lib/dos-8x3/posixpat.py
new file mode 100755
index 0000000..d284834
--- /dev/null
+++ b/Lib/dos-8x3/posixpat.py
@@ -0,0 +1,307 @@
+# Module 'posixpath' -- common operations on POSIX pathnames
+
+import posix
+import stat
+
+
+# Normalize the case of a pathname. Trivial in Posix, string.lower on Mac.
+# On MS-DOS this may also turn slashes into backslashes; however, other
+# normalizations (such as optimizing '../' away) are not allowed
+# (another function should be defined to do that).
+
+def normcase(s):
+ return s
+
+
+# Return wheter a path is absolute.
+# Trivial in Posix, harder on the Mac or MS-DOS.
+
+def isabs(s):
+ return s[:1] == '/'
+
+
+# Join two pathnames.
+# Ignore the first part if the second part is absolute.
+# Insert a '/' unless the first part is empty or already ends in '/'.
+
+def join(a, b):
+ if b[:1] == '/': return b
+ if a == '' or a[-1:] == '/': return a + b
+ # Note: join('x', '') returns 'x/'; is this what we want?
+ return a + '/' + b
+
+
+# Split a path in head (everything up to the last '/') and tail (the
+# rest). If the path ends in '/', tail will be empty. If there is no
+# '/' in the path, head will be empty.
+# Trailing '/'es are stripped from head unless it is the root.
+
+def split(p):
+ import string
+ i = string.rfind(p, '/') + 1
+ head, tail = p[:i], p[i:]
+ if head and head <> '/'*len(head):
+ while head[-1] == '/':
+ head = head[:-1]
+ return head, tail
+
+
+# Split a path in root and extension.
+# The extension is everything starting at the first dot in the last
+# pathname component; the root is everything before that.
+# It is always true that root + ext == p.
+
+def splitext(p):
+ root, ext = '', ''
+ for c in p:
+ if c == '/':
+ root, ext = root + ext + c, ''
+ elif c == '.':
+ if ext:
+ root, ext = root + ext, c
+ else:
+ ext = c
+ elif ext:
+ ext = ext + c
+ else:
+ root = root + c
+ return root, ext
+
+
+# Split a pathname into a drive specification and the rest of the
+# path. Useful on DOS/Windows/NT; on Unix, the drive is always empty.
+
+def splitdrive(p):
+ return '', p
+
+
+# Return the tail (basename) part of a path.
+
+def basename(p):
+ return split(p)[1]
+
+
+# Return the head (dirname) part of a path.
+
+def dirname(p):
+ return split(p)[0]
+
+
+# Return the longest prefix of all list elements.
+
+def commonprefix(m):
+ if not m: return ''
+ prefix = m[0]
+ for item in m:
+ for i in range(len(prefix)):
+ if prefix[:i+1] <> item[:i+1]:
+ prefix = prefix[:i]
+ if i == 0: return ''
+ break
+ return prefix
+
+
+# Is a path a symbolic link?
+# This will always return false on systems where posix.lstat doesn't exist.
+
+def islink(path):
+ try:
+ st = posix.lstat(path)
+ except (posix.error, AttributeError):
+ return 0
+ return stat.S_ISLNK(st[stat.ST_MODE])
+
+
+# Does a path exist?
+# This is false for dangling symbolic links.
+
+def exists(path):
+ try:
+ st = posix.stat(path)
+ except posix.error:
+ return 0
+ return 1
+
+
+# Is a path a posix directory?
+# This follows symbolic links, so both islink() and isdir() can be true
+# for the same path.
+
+def isdir(path):
+ try:
+ st = posix.stat(path)
+ except posix.error:
+ return 0
+ return stat.S_ISDIR(st[stat.ST_MODE])
+
+
+# Is a path a regular file?
+# This follows symbolic links, so both islink() and isfile() can be true
+# for the same path.
+
+def isfile(path):
+ try:
+ st = posix.stat(path)
+ except posix.error:
+ return 0
+ return stat.S_ISREG(st[stat.ST_MODE])
+
+
+# Are two filenames really pointing to the same file?
+
+def samefile(f1, f2):
+ s1 = posix.stat(f1)
+ s2 = posix.stat(f2)
+ return samestat(s1, s2)
+
+
+# Are two open files really referencing the same file?
+# (Not necessarily the same file descriptor!)
+# XXX Oops, posix.fstat() doesn't exist yet!
+
+def sameopenfile(fp1, fp2):
+ s1 = posix.fstat(fp1)
+ s2 = posix.fstat(fp2)
+ return samestat(s1, s2)
+
+
+# Are two stat buffers (obtained from stat, fstat or lstat)
+# describing the same file?
+
+def samestat(s1, s2):
+ return s1[stat.ST_INO] == s2[stat.ST_INO] and \
+ s1[stat.ST_DEV] == s2[stat.ST_DEV]
+
+
+# Is a path a mount point?
+# (Does this work for all UNIXes? Is it even guaranteed to work by POSIX?)
+
+def ismount(path):
+ try:
+ s1 = posix.stat(path)
+ s2 = posix.stat(join(path, '..'))
+ except posix.error:
+ return 0 # It doesn't exist -- so not a mount point :-)
+ dev1 = s1[stat.ST_DEV]
+ dev2 = s2[stat.ST_DEV]
+ if dev1 != dev2:
+ return 1 # path/.. on a different device as path
+ ino1 = s1[stat.ST_INO]
+ ino2 = s2[stat.ST_INO]
+ if ino1 == ino2:
+ return 1 # path/.. is the same i-node as path
+ return 0
+
+
+# Directory tree walk.
+# For each directory under top (including top itself, but excluding
+# '.' and '..'), func(arg, dirname, filenames) is called, where
+# dirname is the name of the directory and filenames is the list
+# files files (and subdirectories etc.) in the directory.
+# The func may modify the filenames list, to implement a filter,
+# or to impose a different order of visiting.
+
+def walk(top, func, arg):
+ try:
+ names = posix.listdir(top)
+ except posix.error:
+ return
+ func(arg, top, names)
+ exceptions = ('.', '..')
+ for name in names:
+ if name not in exceptions:
+ name = join(top, name)
+ if isdir(name) and not islink(name):
+ walk(name, func, arg)
+
+
+# Expand paths beginning with '~' or '~user'.
+# '~' means $HOME; '~user' means that user's home directory.
+# If the path doesn't begin with '~', or if the user or $HOME is unknown,
+# the path is returned unchanged (leaving error reporting to whatever
+# function is called with the expanded path as argument).
+# See also module 'glob' for expansion of *, ? and [...] in pathnames.
+# (A function should also be defined to do full *sh-style environment
+# variable expansion.)
+
+def expanduser(path):
+ if path[:1] <> '~':
+ return path
+ i, n = 1, len(path)
+ while i < n and path[i] <> '/':
+ i = i+1
+ if i == 1:
+ if not posix.environ.has_key('HOME'):
+ return path
+ userhome = posix.environ['HOME']
+ else:
+ import pwd
+ try:
+ pwent = pwd.getpwnam(path[1:i])
+ except KeyError:
+ return path
+ userhome = pwent[5]
+ if userhome[-1:] == '/': i = i+1
+ return userhome + path[i:]
+
+
+# Expand paths containing shell variable substitutions.
+# This expands the forms $variable and ${variable} only.
+# Non-existant variables are left unchanged.
+
+_varprog = None
+
+def expandvars(path):
+ global _varprog
+ if '$' not in path:
+ return path
+ if not _varprog:
+ import regex
+ _varprog = regex.compile('$\([a-zA-Z0-9_]+\|{[^}]*}\)')
+ i = 0
+ while 1:
+ i = _varprog.search(path, i)
+ if i < 0:
+ break
+ name = _varprog.group(1)
+ j = i + len(_varprog.group(0))
+ if name[:1] == '{' and name[-1:] == '}':
+ name = name[1:-1]
+ if posix.environ.has_key(name):
+ tail = path[j:]
+ path = path[:i] + posix.environ[name]
+ i = len(path)
+ path = path + tail
+ else:
+ i = j
+ return path
+
+
+# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
+# It should be understood that this may change the meaning of the path
+# if it contains symbolic links!
+
+def normpath(path):
+ import string
+ # Treat initial slashes specially
+ slashes = ''
+ while path[:1] == '/':
+ slashes = slashes + '/'
+ path = path[1:]
+ comps = string.splitfields(path, '/')
+ i = 0
+ while i < len(comps):
+ if comps[i] == '.':
+ del comps[i]
+ elif comps[i] == '..' and i > 0 and \
+ comps[i-1] not in ('', '..'):
+ del comps[i-1:i+1]
+ i = i-1
+ elif comps[i] == '' and i > 0 and comps[i-1] <> '':
+ del comps[i]
+ else:
+ i = i+1
+ # If the path is now empty, substitute '.'
+ if not comps and not slashes:
+ comps.append('.')
+ return slashes + string.joinfields(comps, '/')
diff --git a/Lib/dos-8x3/py_compi.py b/Lib/dos-8x3/py_compi.py
new file mode 100755
index 0000000..2e68ba8
--- /dev/null
+++ b/Lib/dos-8x3/py_compi.py
@@ -0,0 +1,31 @@
+# Routine to "compile" a .py file to a .pyc file.
+# This has intimate knowledge of how Python/import.c does it.
+# By Sjoerd Mullender (I forced him to write it :-).
+
+import imp
+MAGIC = imp.get_magic()
+
+def wr_long(f, x):
+ f.write(chr( x & 0xff))
+ f.write(chr((x >> 8) & 0xff))
+ f.write(chr((x >> 16) & 0xff))
+ f.write(chr((x >> 24) & 0xff))
+
+def compile(file, cfile = None):
+ import os, marshal, __builtin__
+ f = open(file)
+ codestring = f.read()
+ f.close()
+ timestamp = os.stat(file)[8]
+ codeobject = __builtin__.compile(codestring, file, 'exec')
+ if not cfile:
+ cfile = file + 'c'
+ fc = open(cfile, 'wb')
+ fc.write(MAGIC)
+ wr_long(fc, timestamp)
+ marshal.dump(codeobject, fc)
+ fc.close()
+ if os.name == 'mac':
+ import macfs
+ macfs.FSSpec(cfile).SetCreatorType('Pyth', 'PYC ')
+ macfs.FSSpec(file).SetCreatorType('Pyth', 'TEXT')
diff --git a/Lib/dos-8x3/queue.py b/Lib/dos-8x3/queue.py
new file mode 100755
index 0000000..5125fd5
--- /dev/null
+++ b/Lib/dos-8x3/queue.py
@@ -0,0 +1,121 @@
+# A multi-producer, multi-consumer queue.
+
+Empty = 'Queue.Empty' # Exception raised by get_nowait()
+
+class Queue:
+
+ # Initialize a queue object with a given maximum size
+ # (If maxsize is <= 0, the maximum size is infinite)
+ def __init__(self, maxsize):
+ import thread
+ self._init(maxsize)
+ self.mutex = thread.allocate_lock()
+ self.esema = thread.allocate_lock()
+ self.esema.acquire_lock()
+ self.fsema = thread.allocate_lock()
+
+ # Get an approximation of the queue size (not reliable!)
+ def qsize(self):
+ self.mutex.acquire_lock()
+ n = self._qsize()
+ self.mutex.release_lock()
+ return n
+
+ # Check if the queue is empty (not reliable!)
+ def empty(self):
+ self.mutex.acquire_lock()
+ n = self._empty()
+ self.mutex.release_lock()
+ return n
+
+ # Check if the queue is full (not reliable!)
+ def full(self):
+ self.mutex.acquire_lock()
+ n = self._full()
+ self.mutex.release_lock()
+ return n
+
+ # Put a new item into the queue
+ def put(self, item):
+ self.fsema.acquire_lock()
+ self.mutex.acquire_lock()
+ was_empty = self._empty()
+ self._put(item)
+ if was_empty:
+ self.esema.release_lock()
+ if not self._full():
+ self.fsema.release_lock()
+ self.mutex.release_lock()
+
+ # Get an item from the queue,
+ # blocking if necessary until one is available
+ def get(self):
+ self.esema.acquire_lock()
+ self.mutex.acquire_lock()
+ was_full = self._full()
+ item = self._get()
+ if was_full:
+ self.fsema.release_lock()
+ if not self._empty():
+ self.esema.release_lock()
+ self.mutex.release_lock()
+ return item
+
+ # Get an item from the queue if one is immediately available,
+ # raise Empty if the queue is empty or temporarily unavailable
+ def get_nowait(self):
+ locked = self.esema.acquire_lock(0)
+ self.mutex.acquire_lock()
+ if self._empty():
+ # The queue is empyt -- we can't have esema
+ self.mutex.release_lock()
+ raise Empty
+ if not locked:
+ locked = self.esema.acquire_lock(0)
+ if not locked:
+ # Somebody else has esema
+ # but we have mutex --
+ # go out of their way
+ self.mutex.release_lock()
+ raise Empty
+ was_full = self._full()
+ item = self._get()
+ if was_full:
+ self.fsema.release_lock()
+ if not self._empty():
+ self.esema.release_lock()
+ self.mutex.release_lock()
+ return item
+
+ # XXX Need to define put_nowait() as well.
+
+
+ # Override these methods to implement other queue organizations
+ # (e.g. stack or priority queue).
+ # These will only be called with appropriate locks held
+
+ # Initialize the queue representation
+ def _init(self, maxsize):
+ self.maxsize = maxsize
+ self.queue = []
+
+ def _qsize(self):
+ return len(self.queue)
+
+ # Check wheter the queue is empty
+ def _empty(self):
+ return not self.queue
+
+ # Check whether the queue is full
+ def _full(self):
+ return self.maxsize > 0 and len(self.queue) == self.maxsize
+
+ # Put a new item in the queue
+ def _put(self, item):
+ self.queue.append(item)
+
+ # Get an item from the queue
+ def _get(self):
+ item = self.queue[0]
+ del self.queue[0]
+ return item
diff --git a/Lib/dos-8x3/regex_sy.py b/Lib/dos-8x3/regex_sy.py
new file mode 100755
index 0000000..bb80f4e
--- /dev/null
+++ b/Lib/dos-8x3/regex_sy.py
@@ -0,0 +1,41 @@
+# These bits are passed to regex.set_syntax() to choose among
+# alternative regexp syntaxes.
+
+# 1 means plain parentheses serve as grouping, and backslash
+# parentheses are needed for literal searching.
+# 0 means backslash-parentheses are grouping, and plain parentheses
+# are for literal searching.
+RE_NO_BK_PARENS = 1
+
+# 1 means plain | serves as the "or"-operator, and \| is a literal.
+# 0 means \| serves as the "or"-operator, and | is a literal.
+RE_NO_BK_VBAR = 2
+
+# 0 means plain + or ? serves as an operator, and \+, \? are literals.
+# 1 means \+, \? are operators and plain +, ? are literals.
+RE_BK_PLUS_QM = 4
+
+# 1 means | binds tighter than ^ or $.
+# 0 means the contrary.
+RE_TIGHT_VBAR = 8
+
+# 1 means treat \n as an _OR operator
+# 0 means treat it as a normal character
+RE_NEWLINE_OR = 16
+
+# 0 means that a special characters (such as *, ^, and $) always have
+# their special meaning regardless of the surrounding context.
+# 1 means that special characters may act as normal characters in some
+# contexts. Specifically, this applies to:
+# ^ - only special at the beginning, or after ( or |
+# $ - only special at the end, or before ) or |
+# *, +, ? - only special when not after the beginning, (, or |
+RE_CONTEXT_INDEP_OPS = 32
+
+# Now define combinations of bits for the standard possibilities.
+RE_SYNTAX_AWK = (RE_NO_BK_PARENS | RE_NO_BK_VBAR | RE_CONTEXT_INDEP_OPS)
+RE_SYNTAX_EGREP = (RE_SYNTAX_AWK | RE_NEWLINE_OR)
+RE_SYNTAX_GREP = (RE_BK_PLUS_QM | RE_NEWLINE_OR)
+RE_SYNTAX_EMACS = 0
+
+# (Python's obsolete "regexp" module used a syntax similar to awk.)
diff --git a/Lib/dos-8x3/simpleht.py b/Lib/dos-8x3/simpleht.py
new file mode 100755
index 0000000..dd3107a
--- /dev/null
+++ b/Lib/dos-8x3/simpleht.py
@@ -0,0 +1,168 @@
+"""Simple HTTP Server.
+
+This module builds on BaseHTTPServer by implementing the standard GET
+and HEAD requests in a fairly straightforward manner.
+
+"""
+
+
+__version__ = "0.3"
+
+
+import os
+import pwd
+import sys
+import time
+import socket
+import string
+import posixpath
+import SocketServer
+import BaseHTTPServer
+
+
+def nobody_uid():
+ """Internal routine to get nobody's uid"""
+ try:
+ nobody = pwd.getpwnam('nobody')[2]
+ except pwd.error:
+ nobody = 1 + max(map(lambda x: x[2], pwd.getpwall()))
+ return nobody
+
+nobody = nobody_uid()
+
+
+class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+
+ """Simple HTTP request handler with GET and HEAD commands.
+
+ This serves files from the current directory and any of its
+ subdirectories. It assumes that all files are plain text files
+ unless they have the extension ".html" in which case it assumes
+ they are HTML files.
+
+ The GET and HEAD requests are identical except that the HEAD
+ request omits the actual contents of the file.
+
+ """
+
+ server_version = "SimpleHTTP/" + __version__
+
+ def do_GET(self):
+ """Serve a GET request."""
+ f = self.send_head()
+ if f:
+ self.copyfile(f, self.wfile)
+ f.close()
+
+ def do_HEAD(self):
+ """Serve a HEAD request."""
+ f = self.send_head()
+ if f:
+ f.close()
+
+ def send_head(self):
+ """Common code for GET and HEAD commands.
+
+ This sends the response code and MIME headers.
+
+ Return value is either a file object (which has to be copied
+ to the outputfile by the caller unless the command was HEAD,
+ and must be closed by the caller under all circumstances), or
+ None, in which case the caller has nothing further to do.
+
+ """
+ path = self.translate_path(self.path)
+ if os.path.isdir(path):
+ self.send_error(403, "Directory listing not supported")
+ return None
+ try:
+ f = open(path)
+ except IOError:
+ self.send_error(404, "File not found")
+ return None
+ self.send_response(200)
+ self.send_header("Content-type", self.guess_type(path))
+ self.end_headers()
+ return f
+
+ def translate_path(self, path):
+ """Translate a /-separated PATH to the local filename syntax.
+
+ Components that mean special things to the local file system
+ (e.g. drive or directory names) are ignored. (XXX They should
+ probably be diagnosed.)
+
+ """
+ path = posixpath.normpath(path)
+ words = string.splitfields(path, '/')
+ words = filter(None, words)
+ path = os.getcwd()
+ for word in words:
+ drive, word = os.path.splitdrive(word)
+ head, word = os.path.split(word)
+ if word in (os.curdir, os.pardir): continue
+ path = os.path.join(path, word)
+ return path
+
+ def copyfile(self, source, outputfile):
+ """Copy all data between two file objects.
+
+ The SOURCE argument is a file object open for reading
+ (or anything with a read() method) and the DESTINATION
+ argument is a file object open for writing (or
+ anything with a write() method).
+
+ The only reason for overriding this would be to change
+ the block size or perhaps to replace newlines by CRLF
+ -- note however that this the default server uses this
+ to copy binary data as well.
+
+ """
+
+ BLOCKSIZE = 8192
+ while 1:
+ data = source.read(BLOCKSIZE)
+ if not data: break
+ outputfile.write(data)
+
+ def guess_type(self, path):
+ """Guess the type of a file.
+
+ Argument is a PATH (a filename).
+
+ Return value is a string of the form type/subtype,
+ usable for a MIME Content-type header.
+
+ The default implementation looks the file's extension
+ up in the table self.extensions_map, using text/plain
+ as a default; however it would be permissible (if
+ slow) to look inside the data to make a better guess.
+
+ """
+
+ base, ext = posixpath.splitext(path)
+ if self.extensions_map.has_key(ext):
+ return self.extensions_map[ext]
+ ext = string.lower(ext)
+ if self.extensions_map.has_key(ext):
+ return self.extensions_map[ext]
+ else:
+ return self.extensions_map['']
+
+ extensions_map = {
+ '': 'text/plain', # Default, *must* be present
+ '.html': 'text/html',
+ '.htm': 'text/html',
+ '.gif': 'image/gif',
+ '.jpg': 'image/jpeg',
+ '.jpeg': 'image/jpeg',
+ }
+
+
+def test(HandlerClass = SimpleHTTPRequestHandler,
+ ServerClass = SocketServer.TCPServer):
+ BaseHTTPServer.test(HandlerClass, ServerClass)
+
+
+if __name__ == '__main__':
+ test()
diff --git a/Lib/dos-8x3/socketse.py b/Lib/dos-8x3/socketse.py
new file mode 100755
index 0000000..9a646ab
--- /dev/null
+++ b/Lib/dos-8x3/socketse.py
@@ -0,0 +1,413 @@
+"""Generic socket server classes.
+
+This module tries to capture the various aspects of defining a server:
+
+- address family:
+ - AF_INET: IP (Internet Protocol) sockets (default)
+ - AF_UNIX: Unix domain sockets
+ - others, e.g. AF_DECNET are conceivable (see <socket.h>
+- socket type:
+ - SOCK_STREAM (reliable stream, e.g. TCP)
+ - SOCK_DGRAM (datagrams, e.g. UDP)
+- client address verification before further looking at the request
+ (This is actually a hook for any processing that needs to look
+ at the request before anything else, e.g. logging)
+- how to handle multiple requests:
+ - synchronous (one request is handled at a time)
+ - forking (each request is handled by a new process)
+ - threading (each request is handled by a new thread)
+
+The classes in this module favor the server type that is simplest to
+write: a synchronous TCP/IP server. This is bad class design, but
+save some typing. (There's also the issue that a deep class hierarchy
+slows down method lookups.)
+
+There are four classes in an inheritance diagram that represent
+synchronous servers of four types:
+
+ +-----------+ +------------------+
+ | TCPServer |------->| UnixStreamServer |
+ +-----------+ +------------------+
+ |
+ v
+ +-----------+ +--------------------+
+ | UDPServer |------->| UnixDatagramServer |
+ +-----------+ +--------------------+
+
+(Note that UnixDatagramServer derives from UDPServer, not from
+UnixStreamServer -- the only difference between an IP and a Unix
+stream server is the address family, which is simply repeated in both
+unix server classes.)
+
+Forking and threading versions of each type of server can be created
+using the ForkingServer and ThreadingServer mix-in classes. For
+instance, a threading UDP server class is created as follows:
+
+ class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
+
+(The Mix-in class must come first, since it overrides a method defined
+in UDPServer!)
+
+To implement a service, you must derive a class from
+BaseRequestHandler and redefine its handle() method. You can then run
+various versions of the service by combining one of the server classes
+with your request handler class.
+
+The request handler class must be different for datagram or stream
+services. This can be hidden by using the mix-in request handler
+classes StreamRequestHandler or DatagramRequestHandler.
+
+Of course, you still have to use your head!
+
+For instance, it makes no sense to use a forking server if the service
+contains state in memory that can be modified by requests (since the
+modifications in the child process would never reach the initial state
+kept in the parent process and passed to each child). In this case,
+you can use a threading server, but you will probably have to use
+locks to avoid two requests that come in nearly simultaneous to apply
+conflicting changes to the server state.
+
+On the other hand, if you are building e.g. an HTTP server, where all
+data is stored externally (e.g. in the file system), a synchronous
+class will essentially render the service "deaf" while one request is
+being handled -- which may be for a very long time if a client is slow
+to reqd all the data it has requested. Here a threading or forking
+server is appropriate.
+
+In some cases, it may be appropriate to process part of a request
+synchronously, but to finish processing in a forked child depending on
+the request data. This can be implemented by using a synchronous
+server and doing an explicit fork in the request handler class's
+handle() method.
+
+Another approach to handling multiple simultaneous requests in an
+environment that supports neither threads nor fork (or where these are
+too expensive or inappropriate for the service) is to maintain an
+explicit table of partially finished requests and to use select() to
+decide which request to work on next (or whether to handle a new
+incoming request). This is particularly important for stream services
+where each client can potentially be connected for a long time (if
+threads or subprocesses can't be used).
+
+Future work:
+- Standard classes for Sun RPC (which uses either UDP or TCP)
+- Standard mix-in classes to implement various authentication
+ and encryption schemes
+- Standard framework for select-based multiplexing
+
+XXX Open problems:
+- What to do with out-of-band data?
+
+"""
+
+
+__version__ = "0.2"
+
+
+import socket
+import sys
+import os
+
+
+class TCPServer:
+
+ """Base class for various socket-based server classes.
+
+ Defaults to synchronous IP stream (i.e., TCP).
+
+ Methods for the caller:
+
+ - __init__(server_address, RequestHandlerClass)
+ - serve_forever()
+ - handle_request() # if you don't use serve_forever()
+ - fileno() -> int # for select()
+
+ Methods that may be overridden:
+
+ - server_bind()
+ - server_activate()
+ - get_request() -> request, client_address
+ - verify_request(request, client_address)
+ - process_request(request, client_address)
+ - handle_error()
+
+ Methods for derived classes:
+
+ - finish_request(request, client_address)
+
+ Class variables that may be overridden by derived classes or
+ instances:
+
+ - address_family
+ - socket_type
+ - request_queue_size (only for stream sockets)
+
+ Instance variables:
+
+ - server_address
+ - RequestHandlerClass
+ - socket
+
+ """
+
+ address_family = socket.AF_INET
+
+ socket_type = socket.SOCK_STREAM
+
+ request_queue_size = 5
+
+ def __init__(self, server_address, RequestHandlerClass):
+ """Constructor. May be extended, do not override."""
+ self.server_address = server_address
+ self.RequestHandlerClass = RequestHandlerClass
+ self.socket = socket.socket(self.address_family,
+ self.socket_type)
+ self.server_bind()
+ self.server_activate()
+
+ def server_bind(self):
+ """Called by constructor to bind the socket.
+
+ May be overridden.
+
+ """
+ self.socket.bind(self.server_address)
+
+ def server_activate(self):
+ """Called by constructor to activate the server.
+
+ May be overridden.
+
+ """
+ self.socket.listen(self.request_queue_size)
+
+ def fileno(self):
+ """Return socket file number.
+
+ Interface required by select().
+
+ """
+ return self.socket.fileno()
+
+ def serve_forever(self):
+ """Handle one request at a time until doomsday."""
+ while 1:
+ self.handle_request()
+
+ # The distinction between handling, getting, processing and
+ # finishing a request is fairly arbitrary. Remember:
+ #
+ # - handle_request() is the top-level call. It calls
+ # get_request(), verify_request() and process_request()
+ # - get_request() is different for stream or datagram sockets
+ # - process_request() is the place that may fork a new process
+ # or create a new thread to finish the request
+ # - finish_request() instantiates the request handler class;
+ # this constructor will handle the request all by itself
+
+ def handle_request(self):
+ """Handle one request, possibly blocking."""
+ request, client_address = self.get_request()
+ if self.verify_request(request, client_address):
+ try:
+ self.process_request(request, client_address)
+ except:
+ self.handle_error(request, client_address)
+
+ def get_request(self):
+ """Get the request and client address from the socket.
+
+ May be overridden.
+
+ """
+ return self.socket.accept()
+
+ def verify_request(self, request, client_address):
+ """Verify the request. May be overridden.
+
+ Return true if we should proceed with this request.
+
+ """
+ return 1
+
+ def process_request(self, request, client_address):
+ """Call finish_request.
+
+ Overridden by ForkingMixIn and ThreadingMixIn.
+
+ """
+ self.finish_request(request, client_address)
+
+ def finish_request(self, request, client_address):
+ """Finish one request by instantiating RequestHandlerClass."""
+ self.RequestHandlerClass(request, client_address, self)
+
+ def handle_error(self, request, client_address):
+ """Handle an error gracefully. May be overridden.
+
+ The default is to print a traceback and continue.
+
+ """
+ exc, value, tb = sys.exc_type, sys.exc_value, sys.exc_traceback
+ print '-'*40
+ print 'Exception happened during processing of request from',
+ print client_address
+ import traceback
+ traceback.print_exception(exc, value, tb)
+ print '-'*40
+
+
+class UDPServer(TCPServer):
+
+ """UDP server class."""
+
+ socket_type = socket.SOCK_DGRAM
+
+ max_packet_size = 8192
+
+ def get_request(self):
+ return self.socket.recvfrom(max_packet_size)
+
+
+if hasattr(socket, 'AF_UNIX'):
+
+ class UnixStreamServer(TCPServer):
+
+ address_family = socket.AF_UNIX
+
+
+ class UnixDatagramServer(UDPServer):
+
+ address_family = socket.AF_UNIX
+
+
+class ForkingMixIn:
+
+ """Mix-in class to handle each request in a new process."""
+
+ active_children = None
+
+ def collect_children(self):
+ """Internal routine to wait for died children."""
+ while self.active_children:
+ pid, status = os.waitpid(0, os.WNOHANG)
+ if not pid: break
+ self.active_children.remove(pid)
+
+ def process_request(self, request, client_address):
+ """Fork a new subprocess to process the request."""
+ self.collect_children()
+ pid = os.fork()
+ if pid:
+ # Parent process
+ if self.active_children is None:
+ self.active_children = []
+ self.active_children.append(pid)
+ return
+ else:
+ # Child process.
+ # This must never return, hence os._exit()!
+ try:
+ self.finish_request(request, client_address)
+ os._exit(0)
+ except:
+ try:
+ self.handle_error(request,
+ client_address)
+ finally:
+ os._exit(1)
+
+
+class ThreadingMixIn:
+
+ """Mix-in class to handle each request in a new thread."""
+
+ def process_request(self, request, client_address):
+ """Start a new thread to process the request."""
+ import thread
+ thread.start_new_thread(self.finish_request,
+ (request, client_address))
+
+
+class ForkingUDPServer(ForkingMixIn, UDPServer): pass
+class ForkingTCPServer(ForkingMixIn, TCPServer): pass
+
+class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
+class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
+
+
+class BaseRequestHandler:
+
+ """Base class for request handler classes.
+
+ This class is instantiated for each request to be handled. The
+ constructor sets the instance variables request, client_address
+ and server, and then calls the handle() method. To implement a
+ specific service, all you need to do is to derive a class which
+ defines a handle() method.
+
+ The handle() method can find the request as self.request, the
+ client address as self.client_request, and the server (in case it
+ needs access to per-server information) as self.server. Since a
+ separate instance is created for each request, the handle() method
+ can define arbitrary other instance variariables.
+
+ """
+
+ def __init__(self, request, client_address, server):
+ self.request = request
+ self.client_address = client_address
+ self.server = server
+ try:
+ self.setup()
+ self.handle()
+ self.finish()
+ finally:
+ sys.exc_traceback = None # Help garbage collection
+
+ def setup(self):
+ pass
+
+ def __del__(self):
+ pass
+
+ def handle(self):
+ pass
+
+ def finish(self):
+ pass
+
+
+# The following two classes make it possible to use the same service
+# class for stream or datagram servers.
+# Each class sets up these instance variables:
+# - rfile: a file object from which receives the request is read
+# - wfile: a file object to which the reply is written
+# When the handle() method returns, wfile is flushed properly
+
+
+class StreamRequestHandler(BaseRequestHandler):
+
+ """Define self.rfile and self.wfile for stream sockets."""
+
+ def setup(self):
+ self.connection = self.request
+ self.rfile = self.connection.makefile('rb')
+ self.wfile = self.connection.makefile('wb', 0)
+
+ def finish(self):
+ self.wfile.flush()
+
+
+class DatagramRequestHandler(BaseRequestHandler):
+
+ """Define self.rfile and self.wfile for datagram sockets."""
+
+ def setup(self):
+ import StringIO
+ self.packet, self.socket = self.request
+ self.rfile = StringIO.StringIO(self.packet)
+ self.wfile = StringIO.StringIO(self.packet)
+
+ def finish(self):
+ self.socket.send(self.wfile.getvalue())
diff --git a/Lib/dos-8x3/statcach.py b/Lib/dos-8x3/statcach.py
new file mode 100755
index 0000000..770aef0
--- /dev/null
+++ b/Lib/dos-8x3/statcach.py
@@ -0,0 +1,82 @@
+# Module 'statcache'
+#
+# Maintain a cache of file stats.
+# There are functions to reset the cache or to selectively remove items.
+
+import os
+from stat import *
+
+# The cache.
+# Keys are pathnames, values are `os.stat' outcomes.
+#
+cache = {}
+
+
+# Stat a file, possibly out of the cache.
+#
+def stat(path):
+ if cache.has_key(path):
+ return cache[path]
+ cache[path] = ret = os.stat(path)
+ return ret
+
+
+# Reset the cache completely.
+#
+def reset():
+ global cache
+ cache = {}
+
+
+# Remove a given item from the cache, if it exists.
+#
+def forget(path):
+ if cache.has_key(path):
+ del cache[path]
+
+
+# Remove all pathnames with a given prefix.
+#
+def forget_prefix(prefix):
+ n = len(prefix)
+ for path in cache.keys():
+ if path[:n] == prefix:
+ del cache[path]
+
+
+# Forget about a directory and all entries in it, but not about
+# entries in subdirectories.
+#
+def forget_dir(prefix):
+ if prefix[-1:] == '/' and prefix <> '/':
+ prefix = prefix[:-1]
+ forget(prefix)
+ if prefix[-1:] <> '/':
+ prefix = prefix + '/'
+ n = len(prefix)
+ for path in cache.keys():
+ if path[:n] == prefix:
+ rest = path[n:]
+ if rest[-1:] == '/': rest = rest[:-1]
+ if '/' not in rest:
+ del cache[path]
+
+
+# Remove all pathnames except with a given prefix.
+# Normally used with prefix = '/' after a chdir().
+#
+def forget_except_prefix(prefix):
+ n = len(prefix)
+ for path in cache.keys():
+ if path[:n] <> prefix:
+ del cache[path]
+
+
+# Check for directory.
+#
+def isdir(path):
+ try:
+ st = stat(path)
+ except os.error:
+ return 0
+ return S_ISDIR(st[ST_MODE])
diff --git a/Lib/dos-8x3/stringio.py b/Lib/dos-8x3/stringio.py
new file mode 100755
index 0000000..bbd9428
--- /dev/null
+++ b/Lib/dos-8x3/stringio.py
@@ -0,0 +1,156 @@
+# class StringIO implements file-like objects that read/write a
+# string buffer (a.k.a. "memory files").
+#
+# This implements (nearly) all stdio methods.
+#
+# f = StringIO() # ready for writing
+# f = StringIO(buf) # ready for reading
+# f.close() # explicitly release resources held
+# flag = f.isatty() # always false
+# pos = f.tell() # get current position
+# f.seek(pos) # set current position
+# f.seek(pos, mode) # mode 0: absolute; 1: relative; 2: relative to EOF
+# buf = f.read() # read until EOF
+# buf = f.read(n) # read up to n bytes
+# buf = f.readline() # read until end of line ('\n') or EOF
+# list = f.readlines()# list of f.readline() results until EOF
+# f.write(buf) # write at current position
+# f.writelines(list) # for line in list: f.write(line)
+# f.getvalue() # return whole file's contents as a string
+#
+# Notes:
+# - Using a real file is often faster (but less convenient).
+# - fileno() is left unimplemented so that code which uses it triggers
+# an exception early.
+# - Seeking far beyond EOF and then writing will insert real null
+# bytes that occupy space in the buffer.
+# - There's a simple test set (see end of this file).
+
+import string
+
+class StringIO:
+ def __init__(self, buf = ''):
+ self.buf = buf
+ self.len = len(buf)
+ self.buflist = []
+ self.pos = 0
+ self.closed = 0
+ self.softspace = 0
+ def close(self):
+ if not self.closed:
+ self.closed = 1
+ del self.buf, self.pos
+ def isatty(self):
+ return 0
+ def seek(self, pos, mode = 0):
+ if self.buflist:
+ self.buf = self.buf + string.joinfields(self.buflist, '')
+ self.buflist = []
+ if mode == 1:
+ pos = pos + self.pos
+ elif mode == 2:
+ pos = pos + self.len
+ self.pos = max(0, pos)
+ def tell(self):
+ return self.pos
+ def read(self, n = -1):
+ if self.buflist:
+ self.buf = self.buf + string.joinfields(self.buflist, '')
+ self.buflist = []
+ if n < 0:
+ newpos = self.len
+ else:
+ newpos = min(self.pos+n, self.len)
+ r = self.buf[self.pos:newpos]
+ self.pos = newpos
+ return r
+ def readline(self):
+ if self.buflist:
+ self.buf = self.buf + string.joinfields(self.buflist, '')
+ self.buflist = []
+ i = string.find(self.buf, '\n', self.pos)
+ if i < 0:
+ newpos = self.len
+ else:
+ newpos = i+1
+ r = self.buf[self.pos:newpos]
+ self.pos = newpos
+ return r
+ def readlines(self):
+ lines = []
+ line = self.readline()
+ while line:
+ lines.append(line)
+ line = self.readline()
+ return lines
+ def write(self, s):
+ if not s: return
+ if self.pos > self.len:
+ self.buflist.append('\0'*(self.pos - self.len))
+ self.len = self.pos
+ newpos = self.pos + len(s)
+ if self.pos < self.len:
+ if self.buflist:
+ self.buf = self.buf + string.joinfields(self.buflist, '')
+ self.buflist = []
+ self.buflist = [self.buf[:self.pos], s, self.buf[newpos:]]
+ self.buf = ''
+ else:
+ self.buflist.append(s)
+ self.len = newpos
+ self.pos = newpos
+ def writelines(self, list):
+ self.write(string.joinfields(list, ''))
+ def flush(self):
+ pass
+ def getvalue(self):
+ if self.buflist:
+ self.buf = self.buf + string.joinfields(self.buflist, '')
+ self.buflist = []
+ return self.buf
+
+
+# A little test suite
+
+def test():
+ import sys
+ if sys.argv[1:]:
+ file = sys.argv[1]
+ else:
+ file = '/etc/passwd'
+ lines = open(file, 'r').readlines()
+ text = open(file, 'r').read()
+ f = StringIO()
+ for line in lines[:-2]:
+ f.write(line)
+ f.writelines(lines[-2:])
+ if f.getvalue() != text:
+ raise RuntimeError, 'write failed'
+ length = f.tell()
+ print 'File length =', length
+ f.seek(len(lines[0]))
+ f.write(lines[1])
+ f.seek(0)
+ print 'First line =', `f.readline()`
+ here = f.tell()
+ line = f.readline()
+ print 'Second line =', `line`
+ f.seek(-len(line), 1)
+ line2 = f.read(len(line))
+ if line != line2:
+ raise RuntimeError, 'bad result after seek back'
+ f.seek(len(line2), 1)
+ list = f.readlines()
+ line = list[-1]
+ f.seek(f.tell() - len(line))
+ line2 = f.read()
+ if line != line2:
+ raise RuntimeError, 'bad result after seek back from EOF'
+ print 'Read', len(list), 'more lines'
+ print 'File length =', f.tell()
+ if f.tell() != length:
+ raise RuntimeError, 'bad length'
+ f.close()
+
+if __name__ == '__main__':
+ test()
diff --git a/Lib/dos-8x3/test_aud.py b/Lib/dos-8x3/test_aud.py
new file mode 100755
index 0000000..3acf1bf
--- /dev/null
+++ b/Lib/dos-8x3/test_aud.py
@@ -0,0 +1,202 @@
+# Test audioop.
+import audioop
+
+def gendata1():
+ return '\0\1\2'
+
+def gendata2():
+ if audioop.getsample('\0\1', 2, 0) == 1:
+ return '\0\0\0\1\0\2'
+ else:
+ return '\0\0\1\0\2\0'
+
+def gendata4():
+ if audioop.getsample('\0\0\0\1', 4, 0) == 1:
+ return '\0\0\0\0\0\0\0\1\0\0\0\2'
+ else:
+ return '\0\0\0\0\1\0\0\0\2\0\0\0'
+
+def testmax(data):
+ if audioop.max(data[0], 1) <> 2 or \
+ audioop.max(data[1], 2) <> 2 or \
+ audioop.max(data[2], 4) <> 2:
+ return 0
+ return 1
+
+def testmaxpp(data):
+ if audioop.maxpp(data[0], 1) <> 0 or \
+ audioop.maxpp(data[1], 2) <> 0 or \
+ audioop.maxpp(data[2], 4) <> 0:
+ return 0
+ return 1
+
+def testavg(data):
+ if audioop.avg(data[0], 1) <> 1 or \
+ audioop.avg(data[1], 2) <> 1 or \
+ audioop.avg(data[2], 4) <> 1:
+ return 0
+ return 1
+
+def testavgpp(data):
+ if audioop.avgpp(data[0], 1) <> 0 or \
+ audioop.avgpp(data[1], 2) <> 0 or \
+ audioop.avgpp(data[2], 4) <> 0:
+ return 0
+ return 1
+
+def testrms(data):
+ if audioop.rms(data[0], 1) <> 1 or \
+ audioop.rms(data[1], 2) <> 1 or \
+ audioop.rms(data[2], 4) <> 1:
+ return 0
+ return 1
+
+def testcross(data):
+ if audioop.cross(data[0], 1) <> 0 or \
+ audioop.cross(data[1], 2) <> 0 or \
+ audioop.cross(data[2], 4) <> 0:
+ return 0
+ return 1
+
+def testadd(data):
+ data2 = []
+ for d in data:
+ str = ''
+ for s in d:
+ str = str + chr(ord(s)*2)
+ data2.append(str)
+ if audioop.add(data[0], data[0], 1) <> data2[0] or \
+ audioop.add(data[1], data[1], 2) <> data2[1] or \
+ audioop.add(data[2], data[2], 4) <> data2[2]:
+ return 0
+ return 1
+
+def testbias(data):
+ # Note: this test assumes that avg() works
+ d1 = audioop.bias(data[0], 1, 100)
+ d2 = audioop.bias(data[1], 2, 100)
+ d4 = audioop.bias(data[2], 4, 100)
+ if audioop.avg(d1, 1) <> 101 or \
+ audioop.avg(d2, 2) <> 101 or \
+ audioop.avg(d4, 4) <> 101:
+ return 0
+ return 1
+
+def testlin2lin(data):
+ # too simple: we test only the size
+ for d1 in data:
+ for d2 in data:
+ got = len(d1)/3
+ wtd = len(d2)/3
+ if len(audioop.lin2lin(d1, got, wtd)) <> len(d2):
+ return 0
+ return 1
+
+def testadpcm2lin(data):
+ # Very cursory test
+ if audioop.adpcm2lin('\0\0', 1, None) <> ('\0\0\0\0', (0,0)):
+ return 0
+ return 1
+
+def testlin2adpcm(data):
+ # Very cursory test
+ if audioop.lin2adpcm('\0\0\0\0', 1, None) <> ('\0\0', (0,0)):
+ return 0
+ return 1
+
+def testlin2ulaw(data):
+ if audioop.lin2ulaw(data[0], 1) <> '\377\347\333' or \
+ audioop.lin2ulaw(data[1], 2) <> '\377\377\377' or \
+ audioop.lin2ulaw(data[2], 4) <> '\377\377\377':
+ return 0
+ return 1
+
+def testulaw2lin(data):
+ # Cursory
+ d = audioop.lin2ulaw(data[0], 1)
+ if audioop.ulaw2lin(d, 1) <> data[0]:
+ return 0
+ return 1
+
+def testmul(data):
+ data2 = []
+ for d in data:
+ str = ''
+ for s in d:
+ str = str + chr(ord(s)*2)
+ data2.append(str)
+ if audioop.mul(data[0], 1, 2) <> data2[0] or \
+ audioop.mul(data[1],2, 2) <> data2[1] or \
+ audioop.mul(data[2], 4, 2) <> data2[2]:
+ return 0
+ return 1
+
+def testreverse(data):
+ if audioop.reverse(data[0], 1) <> '\2\1\0':
+ return 0
+ return 1
+
+def testtomono(data):
+ data2 = ''
+ for d in data[0]:
+ data2 = data2 + d + d
+ if audioop.tomono(data2, 1, 0.5, 0.5) <> data[0]:
+ return 0
+ return 1
+
+def testtostereo(data):
+ data2 = ''
+ for d in data[0]:
+ data2 = data2 + d + d
+ if audioop.tostereo(data[0], 1, 1, 1) <> data2:
+ return 0
+ return 1
+
+def testfindfactor(data):
+ if audioop.findfactor(data[1], data[1]) <> 1.0:
+ return 0
+ return 1
+
+def testfindfit(data):
+ if audioop.findfit(data[1], data[1]) <> (0, 1.0):
+ return 0
+ return 1
+
+def testfindmax(data):
+ if audioop.findmax(data[1], 1) <> 2:
+ return 0
+ return 1
+
+def testgetsample(data):
+ for i in range(3):
+ if audioop.getsample(data[0], 1, i) <> i or \
+ audioop.getsample(data[1], 2, i) <> i or \
+ audioop.getsample(data[2], 4, i) <> i:
+ return 0
+ return 1
+
+def testone(name, data):
+ try:
+ func = eval('test'+name)
+ except NameError:
+ print 'No test found for audioop.'+name+'()'
+ return
+ try:
+ rv = func(data)
+ except 'xx':
+ print 'Test FAILED for audioop.'+name+'() (with an exception)'
+ return
+ if not rv:
+ print 'Test FAILED for audioop.'+name+'()'
+
+def testall():
+ data = [gendata1(), gendata2(), gendata4()]
+ names = dir(audioop)
+ # We know there is a routine 'add'
+ routines = []
+ for n in names:
+ if type(eval('audioop.'+n)) == type(audioop.add):
+ routines.append(n)
+ for n in routines:
+ testone(n, data)
+testall()
diff --git a/Lib/dos-8x3/test_bui.py b/Lib/dos-8x3/test_bui.py
new file mode 100755
index 0000000..33fef8d
--- /dev/null
+++ b/Lib/dos-8x3/test_bui.py
@@ -0,0 +1,13 @@
+# Python test set -- part 4, built-in functions
+
+from test_support import *
+
+print '4. Built-in functions'
+
+print 'test_b1'
+unload('test_b1')
+import test_b1
+
+print 'test_b2'
+unload('test_b2')
+import test_b2
diff --git a/Lib/dos-8x3/test_exc.py b/Lib/dos-8x3/test_exc.py
new file mode 100755
index 0000000..4fbee3e
--- /dev/null
+++ b/Lib/dos-8x3/test_exc.py
@@ -0,0 +1,92 @@
+# Python test set -- part 5, built-in exceptions
+
+from test_support import *
+
+print '5. Built-in exceptions'
+# XXX This is not really enough, each *operation* should be tested!
+
+def r(name): print name
+
+r(AttributeError)
+import sys
+try: x = sys.undefined_attribute
+except AttributeError: pass
+
+r(EOFError)
+import sys
+fp = open(TESTFN, 'w')
+fp.close()
+fp = open(TESTFN, 'r')
+savestdin = sys.stdin
+try:
+ try:
+ sys.stdin = fp
+ x = raw_input()
+ except EOFError:
+ pass
+finally:
+ sys.stdin = savestdin
+ fp.close()
+
+r(IOError)
+try: open('this file does not exist', 'r')
+except IOError: pass
+
+r(ImportError)
+try: import undefined_module
+except ImportError: pass
+
+r(IndexError)
+x = []
+try: a = x[10]
+except IndexError: pass
+
+r(KeyError)
+x = {}
+try: a = x['key']
+except KeyError: pass
+
+r(KeyboardInterrupt)
+print '(not testable in a script)'
+
+r(MemoryError)
+print '(not safe to test)'
+
+r(NameError)
+try: x = undefined_variable
+except NameError: pass
+
+r(OverflowError)
+x = 1
+try:
+ while 1: x = x+x
+except OverflowError: pass
+
+r(RuntimeError)
+print '(not used any more?)'
+
+r(SyntaxError)
+try: exec '/\n'
+except SyntaxError: pass
+
+r(SystemError)
+print '(hard to reproduce)'
+
+r(SystemExit)
+import sys
+try: sys.exit(0)
+except SystemExit: pass
+
+r(TypeError)
+try: [] + ()
+except TypeError: pass
+
+r(ValueError)
+try: x = chr(10000)
+except ValueError: pass
+
+r(ZeroDivisionError)
+try: x = 1/0
+except ZeroDivisionError: pass
+
+unlink(TESTFN)
diff --git a/Lib/dos-8x3/test_gra.py b/Lib/dos-8x3/test_gra.py
new file mode 100755
index 0000000..b9607ac
--- /dev/null
+++ b/Lib/dos-8x3/test_gra.py
@@ -0,0 +1,513 @@
+# Python test set -- part 1, grammar.
+# This just tests whether the parser accepts them all.
+
+from test_support import *
+
+print '1. Parser'
+
+print '1.1 Tokens'
+
+print '1.1.1 Backslashes'
+
+# Backslash means line continuation:
+x = 1 \
++ 1
+if x <> 2: raise TestFailed, 'backslash for line continuation'
+
+# Backslash does not means continuation in comments :\
+x = 0
+if x <> 0: raise TestFailed, 'backslash ending comment'
+
+print '1.1.2 Numeric literals'
+
+print '1.1.2.1 Plain integers'
+if 0xff <> 255: raise TestFailed, 'hex int'
+if 0377 <> 255: raise TestFailed, 'octal int'
+if 2147483647 != 017777777777: raise TestFailed, 'large positive int'
+try:
+ from sys import maxint
+except ImportError:
+ maxint = 2147483647
+if maxint == 2147483647:
+ if -2147483647-1 != 020000000000: raise TestFailed, 'max negative int'
+ # XXX -2147483648
+ if 037777777777 != -1: raise TestFailed, 'oct -1'
+ if 0xffffffff != -1: raise TestFailed, 'hex -1'
+ for s in '2147483648', '040000000000', '0x100000000':
+ try:
+ x = eval(s)
+ except OverflowError:
+ continue
+## raise TestFailed, \
+ print \
+ 'No OverflowError on huge integer literal ' + `s`
+elif eval('maxint == 9223372036854775807'):
+ if eval('-9223372036854775807-1 != 01000000000000000000000'):
+ raise TestFailed, 'max negative int'
+ if eval('01777777777777777777777') != -1: raise TestFailed, 'oct -1'
+ if eval('0xffffffffffffffff') != -1: raise TestFailed, 'hex -1'
+ for s in '9223372036854775808', '02000000000000000000000', \
+ '0x10000000000000000':
+ try:
+ x = eval(s)
+ except OverflowError:
+ continue
+ raise TestFailed, \
+ 'No OverflowError on huge integer literal ' + `s`
+else:
+ print 'Weird maxint value', maxint
+
+print '1.1.2.2 Long integers'
+x = 0L
+x = 0l
+x = 0xffffffffffffffffL
+x = 0xffffffffffffffffl
+x = 077777777777777777L
+x = 077777777777777777l
+x = 123456789012345678901234567890L
+x = 123456789012345678901234567890l
+
+print '1.1.2.3 Floating point'
+x = 3.14
+x = 314.
+x = 0.314
+# XXX x = 000.314
+x = .314
+x = 3e14
+x = 3E14
+x = 3e-14
+x = 3e+14
+x = 3.e14
+x = .3e14
+x = 3.1e4
+
+print '1.1.3 String literals'
+
+def assert(s):
+ if not s: raise TestFailed, 'see traceback'
+
+x = ''; y = ""; assert(len(x) == 0 and x == y)
+x = '\''; y = "'"; assert(len(x) == 1 and x == y and ord(x) == 39)
+x = '"'; y = "\""; assert(len(x) == 1 and x == y and ord(x) == 34)
+x = "doesn't \"shrink\" does it"
+y = 'doesn\'t "shrink" does it'
+assert(len(x) == 24 and x == y)
+x = "does \"shrink\" doesn't it"
+y = 'does "shrink" doesn\'t it'
+assert(len(x) == 24 and x == y)
+x = """
+The "quick"
+brown fox
+jumps over
+the 'lazy' dog.
+"""
+y = '\nThe "quick"\nbrown fox\njumps over\nthe \'lazy\' dog.\n'
+assert(x == y)
+y = '''
+The "quick"
+brown fox
+jumps over
+the 'lazy' dog.
+'''; assert(x == y)
+y = "\n\
+The \"quick\"\n\
+brown fox\n\
+jumps over\n\
+the 'lazy' dog.\n\
+"; assert(x == y)
+y = '\n\
+The \"quick\"\n\
+brown fox\n\
+jumps over\n\
+the \'lazy\' dog.\n\
+'; assert(x == y)
+
+
+print '1.2 Grammar'
+
+print 'single_input' # NEWLINE | simple_stmt | compound_stmt NEWLINE
+# XXX can't test in a script -- this rule is only used when interactive
+
+print 'file_input' # (NEWLINE | stmt)* ENDMARKER
+# Being tested as this very moment this very module
+
+print 'expr_input' # testlist NEWLINE
+# XXX Hard to test -- used only in calls to input()
+
+print 'eval_input' # testlist ENDMARKER
+x = eval('1, 0 or 1')
+
+print 'funcdef'
+### 'def' NAME parameters ':' suite
+### parameters: '(' [varargslist] ')'
+### varargslist: (fpdef ['=' test] ',')* '*' NAME
+### | fpdef ['=' test] (',' fpdef ['=' test])* [',']
+### fpdef: NAME | '(' fplist ')'
+### fplist: fpdef (',' fpdef)* [',']
+def f1(): pass
+def f2(one_argument): pass
+def f3(two, arguments): pass
+def f4(two, (compound, (argument, list))): pass
+def a1(one_arg,): pass
+def a2(two, args,): pass
+def v0(*rest): pass
+def v1(a, *rest): pass
+def v2(a, b, *rest): pass
+def v3(a, (b, c), *rest): pass
+def d01(a=1): pass
+d01()
+d01(1)
+def d11(a, b=1): pass
+d11(1)
+d11(1, 2)
+def d21(a, b, c=1): pass
+d21(1, 2)
+d21(1, 2, 3)
+def d02(a=1, b=2): pass
+d02()
+d02(1)
+d02(1, 2)
+def d12(a, b=1, c=2): pass
+d12(1)
+d12(1, 2)
+d12(1, 2, 3)
+def d22(a, b, c=1, d=2): pass
+d22(1, 2)
+d22(1, 2, 3)
+d22(1, 2, 3, 4)
+def d01v(a=1, *rest): pass
+d01v()
+d01v(1)
+d01v(1, 2)
+def d11v(a, b=1, *rest): pass
+d11v(1)
+d11v(1, 2)
+d11v(1, 2, 3)
+def d21v(a, b, c=1, *rest): pass
+d21v(1, 2)
+d21v(1, 2, 3)
+d21v(1, 2, 3, 4)
+def d02v(a=1, b=2, *rest): pass
+d02v()
+d02v(1)
+d02v(1, 2)
+d02v(1, 2, 3)
+def d12v(a, b=1, c=2, *rest): pass
+d12v(1)
+d12v(1, 2)
+d12v(1, 2, 3)
+d12v(1, 2, 3, 4)
+def d22v(a, b, c=1, d=2, *rest): pass
+d22v(1, 2)
+d22v(1, 2, 3)
+d22v(1, 2, 3, 4)
+d22v(1, 2, 3, 4, 5)
+
+### stmt: simple_stmt | compound_stmt
+# Tested below
+
+### simple_stmt: small_stmt (';' small_stmt)* [';']
+print 'simple_stmt'
+x = 1; pass; del x
+
+### small_stmt: expr_stmt | print_stmt | pass_stmt | del_stmt | flow_stmt | import_stmt | global_stmt | access_stmt | exec_stmt
+# Tested below
+
+print 'expr_stmt' # (exprlist '=')* exprlist
+1
+1, 2, 3
+x = 1
+x = 1, 2, 3
+x = y = z = 1, 2, 3
+x, y, z = 1, 2, 3
+abc = a, b, c = x, y, z = xyz = 1, 2, (3, 4)
+# NB these variables are deleted below
+
+print 'print_stmt' # 'print' (test ',')* [test]
+print 1, 2, 3
+print 1, 2, 3,
+print
+print 0 or 1, 0 or 1,
+print 0 or 1
+
+print 'del_stmt' # 'del' exprlist
+del abc
+del x, y, (z, xyz)
+
+print 'pass_stmt' # 'pass'
+pass
+
+print 'flow_stmt' # break_stmt | continue_stmt | return_stmt | raise_stmt
+# Tested below
+
+print 'break_stmt' # 'break'
+while 1: break
+
+print 'continue_stmt' # 'continue'
+i = 1
+while i: i = 0; continue
+
+print 'return_stmt' # 'return' [testlist]
+def g1(): return
+def g2(): return 1
+g1()
+x = g2()
+
+print 'raise_stmt' # 'raise' test [',' test]
+try: raise RuntimeError, 'just testing'
+except RuntimeError: pass
+try: raise KeyboardInterrupt
+except KeyboardInterrupt: pass
+
+print 'import_stmt' # 'import' NAME (',' NAME)* | 'from' NAME 'import' ('*' | NAME (',' NAME)*)
+import sys
+import time, sys
+from time import time
+from sys import *
+from sys import path, argv
+
+print 'global_stmt' # 'global' NAME (',' NAME)*
+def f():
+ global a
+ global a, b
+ global one, two, three, four, five, six, seven, eight, nine, ten
+
+print 'exec_stmt' # 'exec' expr ['in' expr [',' expr]]
+def f():
+ z = None
+ del z
+ exec 'z=1+1\n'
+ if z <> 2: raise TestFailed, 'exec \'z=1+1\'\\n'
+ del z
+ exec 'z=1+1'
+ if z <> 2: raise TestFailed, 'exec \'z=1+1\''
+f()
+g = {}
+exec 'z = 1' in g
+if g.has_key('__builtins__'): del g['__builtins__']
+if g <> {'z': 1}: raise TestFailed, 'exec \'z = 1\' in g'
+g = {}
+l = {}
+exec 'global a; a = 1; b = 2' in g, l
+if g.has_key('__builtins__'): del g['__builtins__']
+if l.has_key('__builtins__'): del l['__builtins__']
+if (g, l) <> ({'a':1}, {'b':2}): raise TestFailed, 'exec ... in g, l'
+
+
+### compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef
+# Tested below
+
+print 'if_stmt' # 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
+if 1: pass
+if 1: pass
+else: pass
+if 0: pass
+elif 0: pass
+if 0: pass
+elif 0: pass
+elif 0: pass
+elif 0: pass
+else: pass
+
+print 'while_stmt' # 'while' test ':' suite ['else' ':' suite]
+while 0: pass
+while 0: pass
+else: pass
+
+print 'for_stmt' # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite]
+for i in 1, 2, 3: pass
+for i, j, k in (): pass
+else: pass
+class Squares:
+ def __init__(self, max):
+ self.max = max
+ self.sofar = []
+ def __len__(self): return len(self.sofar)
+ def __getitem__(self, i):
+ if not 0 <= i < self.max: raise IndexError
+ n = len(self.sofar)
+ while n <= i:
+ self.sofar.append(n*n)
+ n = n+1
+ return self.sofar[i]
+n = 0
+for x in Squares(10): n = n+x
+if n != 285: raise TestFailed, 'for over growing sequence'
+
+print 'try_stmt'
+### try_stmt: 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite]
+### | 'try' ':' suite 'finally' ':' suite
+### except_clause: 'except' [expr [',' expr]]
+try:
+ 1/0
+except ZeroDivisionError:
+ pass
+else:
+ pass
+try: 1/0
+except EOFError: pass
+except TypeError, msg: pass
+except RuntimeError, msg: pass
+except: pass
+else: pass
+try: 1/0
+except (EOFError, TypeError, ZeroDivisionError): pass
+try: 1/0
+except (EOFError, TypeError, ZeroDivisionError), msg: pass
+try: pass
+finally: pass
+
+print 'suite' # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT
+if 1: pass
+if 1:
+ pass
+if 1:
+ #
+ #
+ #
+ pass
+ pass
+ #
+ pass
+ #
+
+print 'test'
+### and_test ('or' and_test)*
+### and_test: not_test ('and' not_test)*
+### not_test: 'not' not_test | comparison
+if not 1: pass
+if 1 and 1: pass
+if 1 or 1: pass
+if not not not 1: pass
+if not 1 and 1 and 1: pass
+if 1 and 1 or 1 and 1 and 1 or not 1 and 1: pass
+
+print 'comparison'
+### comparison: expr (comp_op expr)*
+### comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not'
+if 1: pass
+x = (1 == 1)
+if 1 == 1: pass
+if 1 != 1: pass
+if 1 <> 1: pass
+if 1 < 1: pass
+if 1 > 1: pass
+if 1 <= 1: pass
+if 1 >= 1: pass
+if 1 is 1: pass
+if 1 is not 1: pass
+if 1 in (): pass
+if 1 not in (): pass
+if 1 < 1 > 1 == 1 >= 1 <= 1 <> 1 != 1 in 1 not in 1 is 1 is not 1: pass
+
+print 'binary mask ops'
+x = 1 & 1
+x = 1 ^ 1
+x = 1 | 1
+
+print 'shift ops'
+x = 1 << 1
+x = 1 >> 1
+x = 1 << 1 >> 1
+
+print 'additive ops'
+x = 1
+x = 1 + 1
+x = 1 - 1 - 1
+x = 1 - 1 + 1 - 1 + 1
+
+print 'multiplicative ops'
+x = 1 * 1
+x = 1 / 1
+x = 1 % 1
+x = 1 / 1 * 1 % 1
+
+print 'unary ops'
+x = +1
+x = -1
+x = ~1
+x = ~1 ^ 1 & 1 | 1 & 1 ^ -1
+x = -1*1/1 + 1*1 - ---1*1
+
+print 'selectors'
+### trailer: '(' [testlist] ')' | '[' subscript ']' | '.' NAME
+### subscript: expr | [expr] ':' [expr]
+f1()
+f2(1)
+f2(1,)
+f3(1, 2)
+f3(1, 2,)
+f4(1, (2, (3, 4)))
+v0()
+v0(1)
+v0(1,)
+v0(1,2)
+v0(1,2,3,4,5,6,7,8,9,0)
+v1(1)
+v1(1,)
+v1(1,2)
+v1(1,2,3)
+v1(1,2,3,4,5,6,7,8,9,0)
+v2(1,2)
+v2(1,2,3)
+v2(1,2,3,4)
+v2(1,2,3,4,5,6,7,8,9,0)
+v3(1,(2,3))
+v3(1,(2,3),4)
+v3(1,(2,3),4,5,6,7,8,9,0)
+import sys, time
+c = sys.path[0]
+x = time.time()
+x = sys.modules['time'].time()
+a = '01234'
+c = a[0]
+c = a[-1]
+s = a[0:5]
+s = a[:5]
+s = a[0:]
+s = a[:]
+s = a[-5:]
+s = a[:-1]
+s = a[-4:-3]
+
+print 'atoms'
+### atom: '(' [testlist] ')' | '[' [testlist] ']' | '{' [dictmaker] '}' | '`' testlist '`' | NAME | NUMBER | STRING
+### dictmaker: test ':' test (',' test ':' test)* [',']
+
+x = (1)
+x = (1 or 2 or 3)
+x = (1 or 2 or 3, 2, 3)
+
+x = []
+x = [1]
+x = [1 or 2 or 3]
+x = [1 or 2 or 3, 2, 3]
+x = []
+
+x = {}
+x = {'one': 1}
+x = {'one': 1,}
+x = {'one' or 'two': 1 or 2}
+x = {'one': 1, 'two': 2}
+x = {'one': 1, 'two': 2,}
+x = {'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5, 'six': 6}
+
+x = `x`
+x = `1 or 2 or 3`
+x = x
+x = 'x'
+x = 123
+
+### exprlist: expr (',' expr)* [',']
+### testlist: test (',' test)* [',']
+# These have been exercised enough above
+
+print 'classdef' # 'class' NAME ['(' testlist ')'] ':' suite
+class B: pass
+class C1(B): pass
+class C2(B): pass
+class D(C1, C2, B): pass
+class C:
+ def meth1(self): pass
+ def meth2(self, arg): pass
+ def meth3(self, a1, a2): pass
diff --git a/Lib/dos-8x3/test_opc.py b/Lib/dos-8x3/test_opc.py
new file mode 100755
index 0000000..b1e944b
--- /dev/null
+++ b/Lib/dos-8x3/test_opc.py
@@ -0,0 +1,59 @@
+# Python test set -- part 2, opcodes
+
+from test_support import *
+
+
+print '2. Opcodes'
+print 'XXX Not yet fully implemented'
+
+print '2.1 try inside for loop'
+n = 0
+for i in range(10):
+ n = n+i
+ try: 1/0
+ except NameError: pass
+ except ZeroDivisionError: pass
+ except TypeError: pass
+ try: pass
+ except: pass
+ try: pass
+ finally: pass
+ n = n+i
+if n <> 90:
+ raise TestFailed, 'try inside for'
+
+
+print '2.2 raise class exceptions'
+
+class AClass: pass
+class BClass(AClass): pass
+class CClass: pass
+
+try: raise AClass()
+except: pass
+
+try: raise AClass()
+except AClass: pass
+
+try: raise BClass()
+except AClass: pass
+
+try: raise BClass()
+except CClass: raise TestFailed
+except: pass
+
+a = AClass()
+b = BClass()
+
+try: raise AClass, b
+except BClass, v: raise TestFailed
+except AClass, v:
+ if v != b: raise TestFailed
+
+
+try: raise b
+except AClass, v:
+ if v != b: raise TestFailed
+
+try: raise BClass, a
+except TypeError: pass
diff --git a/Lib/dos-8x3/test_ope.py b/Lib/dos-8x3/test_ope.py
new file mode 100755
index 0000000..1a75065
--- /dev/null
+++ b/Lib/dos-8x3/test_ope.py
@@ -0,0 +1,5 @@
+# Python test set -- part 3, built-in operations.
+
+
+print '3. Operations'
+print 'XXX Not yet implemented'
diff --git a/Lib/dos-8x3/test_rgb.py b/Lib/dos-8x3/test_rgb.py
new file mode 100755
index 0000000..cdadc66
--- /dev/null
+++ b/Lib/dos-8x3/test_rgb.py
@@ -0,0 +1,49 @@
+# Testing rgbimg module
+
+import rgbimg, os
+
+error = 'test_rgbimg.error'
+
+print 'RGBimg test suite:'
+
+def findfile(file):
+ if os.path.isabs(file): return file
+ import sys
+ for dn in sys.path:
+ fn = os.path.join(dn, file)
+ if os.path.exists(fn): return fn
+ return file
+
+def testimg(rgb_file, raw_file):
+ rgb_file = findfile(rgb_file)
+ raw_file = findfile(raw_file)
+ width, height = rgbimg.sizeofimage(rgb_file)
+ rgb = rgbimg.longimagedata(rgb_file)
+ if len(rgb) != width * height * 4:
+ raise error, 'bad image length'
+ raw = open(raw_file, 'r').read()
+ if rgb != raw:
+ raise error, 'images don\'t match for '+rgb_file+' and '+raw_file
+ for depth in [1, 3, 4]:
+ rgbimg.longstoimage(rgb, width, height, depth, '@.rgb')
+ os.unlink('@.rgb')
+
+ttob = rgbimg.ttob(0)
+if ttob != 0:
+ raise error, 'ttob should start out as zero'
+
+testimg('test.rgb', 'test.rawimg')
+
+ttob = rgbimg.ttob(1)
+if ttob != 0:
+ raise error, 'ttob should be zero'
+
+testimg('test.rgb', 'test.rawimg.rev')
+
+ttob = rgbimg.ttob(0)
+if ttob != 1:
+ raise error, 'ttob should be one'
+
+ttob = rgbimg.ttob(0)
+if ttob != 0:
+ raise error, 'ttob should be zero'
diff --git a/Lib/dos-8x3/test_sel.py b/Lib/dos-8x3/test_sel.py
new file mode 100755
index 0000000..f185308
--- /dev/null
+++ b/Lib/dos-8x3/test_sel.py
@@ -0,0 +1,23 @@
+# Testing select module
+
+def test():
+ import select
+ import os
+ cmd = 'for i in 0 1 2 3 4 5 6 7 8 9; do date; sleep 3; done'
+ p = os.popen(cmd, 'r')
+ for tout in (0, 1, 2, 4, 8, 16) + (None,)*10:
+ print 'timeout =', tout
+ rfd, wfd, xfd = select.select([p], [], [], tout)
+ print rfd, wfd, xfd
+ if (rfd, wfd, xfd) == ([], [], []):
+ continue
+ if (rfd, wfd, xfd) == ([p], [], []):
+ line = p.readline()
+ print `line`
+ if not line:
+ print 'EOF'
+ break
+ continue
+ print 'Heh?'
+
+test()
diff --git a/Lib/dos-8x3/test_sig.py b/Lib/dos-8x3/test_sig.py
new file mode 100755
index 0000000..bfcf517
--- /dev/null
+++ b/Lib/dos-8x3/test_sig.py
@@ -0,0 +1,50 @@
+# Test the signal module
+
+import signal
+import os
+
+
+pid = os.getpid()
+
+# Shell script that will send us asynchronous signals
+script = """
+(
+ set -x
+ sleep 2
+ kill -5 %(pid)d
+ sleep 2
+ kill -2 %(pid)d
+ sleep 2
+ kill -3 %(pid)d
+) &
+""" % vars()
+
+def handlerA(*args):
+ print "handlerA", args
+
+HandlerBCalled = "HandlerBCalled" # Exception
+
+def handlerB(*args):
+ print "handlerB", args
+ raise HandlerBCalled, args
+
+signal.alarm(20) # Entire test lasts at most 20 sec.
+signal.signal(5, handlerA)
+signal.signal(2, handlerB)
+signal.signal(3, signal.SIG_IGN)
+signal.signal(signal.SIGALRM, signal.default_int_handler)
+
+os.system(script)
+
+print "starting pause() loop..."
+
+try:
+ while 1:
+ print "call pause()..."
+ try:
+ signal.pause()
+ print "pause() returned"
+ except HandlerBCalled:
+ print "HandlerBCalled exception caught"
+except KeyboardInterrupt:
+ print "KeyboardInterrupt (assume the alarm() went off)"
diff --git a/Lib/dos-8x3/test_sup.py b/Lib/dos-8x3/test_sup.py
new file mode 100755
index 0000000..7a76664
--- /dev/null
+++ b/Lib/dos-8x3/test_sup.py
@@ -0,0 +1,41 @@
+# Python test set -- supporting definitions.
+
+TestFailed = 'test_support -- test failed' # Exception
+
+def unload(name):
+ import sys
+ try:
+ del sys.modules[name]
+ except KeyError:
+ pass
+
+def forget(modname):
+ unload(modname)
+ import sys, os
+ for dirname in sys.path:
+ try:
+ os.unlink(os.path.join(dirname, modname + '.pyc'))
+ except os.error:
+ pass
+
+FUZZ = 1e-6
+
+def fcmp(x, y): # fuzzy comparison function
+ if type(x) == type(0.0) or type(y) == type(0.0):
+ try:
+ x, y = coerce(x, y)
+ fuzz = (abs(x) + abs(y)) * FUZZ
+ if abs(x-y) <= fuzz:
+ return 0
+ except:
+ pass
+ elif type(x) == type(y) and type(x) in (type(()), type([])):
+ for i in range(min(len(x), len(y))):
+ outcome = fcmp(x[i], y[i])
+ if outcome <> 0:
+ return outcome
+ return cmp(len(x), len(y))
+ return cmp(x, y)
+
+TESTFN = '@test' # Filename used for testing
+from os import unlink
diff --git a/Lib/dos-8x3/test_thr.py b/Lib/dos-8x3/test_thr.py
new file mode 100755
index 0000000..4e0eb70
--- /dev/null
+++ b/Lib/dos-8x3/test_thr.py
@@ -0,0 +1,106 @@
+# Very rudimentary test of thread module
+
+# Create a bunch of threads, let each do some work, wait until all are done
+
+import whrandom
+import thread
+import time
+
+mutex = thread.allocate_lock()
+whmutex = thread.allocate_lock() # for calls to whrandom
+running = 0
+done = thread.allocate_lock()
+done.acquire()
+
+numtasks = 10
+
+def task(ident):
+ global running
+ whmutex.acquire()
+ delay = whrandom.random() * numtasks
+ whmutex.release()
+ print 'task', ident, 'will run for', delay, 'sec'
+ time.sleep(delay)
+ print 'task', ident, 'done'
+ mutex.acquire()
+ running = running - 1
+ if running == 0:
+ done.release()
+ mutex.release()
+
+next_ident = 0
+def newtask():
+ global next_ident, running
+ mutex.acquire()
+ next_ident = next_ident + 1
+ print 'creating task', next_ident
+ thread.start_new_thread(task, (next_ident,))
+ running = running + 1
+ mutex.release()
+
+for i in range(numtasks):
+ newtask()
+
+print 'waiting for all tasks to complete'
+done.acquire()
+print 'all tasks done'
+
+class barrier:
+ def __init__(self, n):
+ self.n = n
+ self.waiting = 0
+ self.checkin = thread.allocate_lock()
+ self.checkout = thread.allocate_lock()
+ self.checkout.acquire()
+
+ def enter(self):
+ checkin, checkout = self.checkin, self.checkout
+
+ checkin.acquire()
+ self.waiting = self.waiting + 1
+ if self.waiting == self.n:
+ self.waiting = self.n - 1
+ checkout.release()
+ return
+ checkin.release()
+
+ checkout.acquire()
+ self.waiting = self.waiting - 1
+ if self.waiting == 0:
+ checkin.release()
+ return
+ checkout.release()
+
+numtrips = 3
+def task2(ident):
+ global running
+ for i in range(numtrips):
+ if ident == 0:
+ # give it a good chance to enter the next
+ # barrier before the others are all out
+ # of the current one
+ delay = 0.001
+ else:
+ whmutex.acquire()
+ delay = whrandom.random() * numtasks
+ whmutex.release()
+ print 'task', ident, 'will run for', delay, 'sec'
+ time.sleep(delay)
+ print 'task', ident, 'entering barrier', i
+ bar.enter()
+ print 'task', ident, 'leaving barrier', i
+ mutex.acquire()
+ running = running - 1
+ if running == 0:
+ done.release()
+ mutex.release()
+
+print '\n*** Barrier Test ***'
+if done.acquire(0):
+ raise ValueError, "'done' should have remained acquired"
+bar = barrier(numtasks)
+running = numtasks
+for i in range(numtasks):
+ thread.start_new_thread(task2, (i,))
+done.acquire()
+print 'all tasks done'
diff --git a/Lib/dos-8x3/test_typ.py b/Lib/dos-8x3/test_typ.py
new file mode 100755
index 0000000..51c76dc
--- /dev/null
+++ b/Lib/dos-8x3/test_typ.py
@@ -0,0 +1,182 @@
+# Python test set -- part 6, built-in types
+
+from test_support import *
+
+print '6. Built-in types'
+
+print '6.1 Truth value testing'
+if None: raise TestFailed, 'None is true instead of false'
+if 0: raise TestFailed, '0 is true instead of false'
+if 0L: raise TestFailed, '0L is true instead of false'
+if 0.0: raise TestFailed, '0.0 is true instead of false'
+if '': raise TestFailed, '\'\' is true instead of false'
+if (): raise TestFailed, '() is true instead of false'
+if []: raise TestFailed, '[] is true instead of false'
+if {}: raise TestFailed, '{} is true instead of false'
+if not 1: raise TestFailed, '1 is false instead of true'
+if not 1L: raise TestFailed, '1L is false instead of true'
+if not 1.0: raise TestFailed, '1.0 is false instead of true'
+if not 'x': raise TestFailed, '\'x\' is false instead of true'
+if not (1, 1): raise TestFailed, '(1, 1) is false instead of true'
+if not [1]: raise TestFailed, '[1] is false instead of true'
+if not {'x': 1}: raise TestFailed, '{\'x\': 1} is false instead of true'
+def f(): pass
+class C: pass
+import sys
+x = C()
+if not f: raise TestFailed, 'f is false instead of true'
+if not C: raise TestFailed, 'C is false instead of true'
+if not sys: raise TestFailed, 'sys is false instead of true'
+if not x: raise TestFailed, 'x is false instead of true'
+
+print '6.2 Boolean operations'
+if 0 or 0: raise TestFailed, '0 or 0 is true instead of false'
+if 1 and 1: pass
+else: raise TestFailed, '1 and 1 is false instead of false'
+if not 1: raise TestFailed, 'not 1 is true instead of false'
+
+print '6.3 Comparisons'
+if 0 < 1 <= 1 == 1 >= 1 > 0 <> 1: pass
+else: raise TestFailed, 'int comparisons failed'
+if 0L < 1L <= 1L == 1L >= 1L > 0L <> 1L: pass
+else: raise TestFailed, 'long int comparisons failed'
+if 0.0 < 1.0 <= 1.0 == 1.0 >= 1.0 > 0.0 <> 1.0: pass
+else: raise TestFailed, 'float comparisons failed'
+if '' < 'a' <= 'a' == 'a' < 'abc' < 'abd' < 'b': pass
+else: raise TestFailed, 'string comparisons failed'
+if 0 in [0] and 0 not in [1]: pass
+else: raise TestFailed, 'membership test failed'
+if None is None and [] is not []: pass
+else: raise TestFailed, 'identity test failed'
+
+print '6.4 Numeric types (mostly conversions)'
+if 0 <> 0L or 0 <> 0.0 or 0L <> 0.0: raise TestFailed, 'mixed comparisons'
+if 1 <> 1L or 1 <> 1.0 or 1L <> 1.0: raise TestFailed, 'mixed comparisons'
+if -1 <> -1L or -1 <> -1.0 or -1L <> -1.0:
+ raise TestFailed, 'int/long/float value not equal'
+if int(1.9) == 1 == int(1.1) and int(-1.1) == -1 == int(-1.9): pass
+else: raise TestFailed, 'int() does not round properly'
+if long(1.9) == 1L == long(1.1) and long(-1.1) == -1L == long(-1.9): pass
+else: raise TestFailed, 'long() does not round properly'
+if float(1) == 1.0 and float(-1) == -1.0 and float(0) == 0.0: pass
+else: raise TestFailed, 'float() does not work properly'
+print '6.4.1 32-bit integers'
+if 12 + 24 <> 36: raise TestFailed, 'int op'
+if 12 + (-24) <> -12: raise TestFailed, 'int op'
+if (-12) + 24 <> 12: raise TestFailed, 'int op'
+if (-12) + (-24) <> -36: raise TestFailed, 'int op'
+if not 12 < 24: raise TestFailed, 'int op'
+if not -24 < -12: raise TestFailed, 'int op'
+# Test for a particular bug in integer multiply
+xsize, ysize, zsize = 238, 356, 4
+if not (xsize*ysize*zsize == zsize*xsize*ysize == 338912):
+ raise TestFailed, 'int mul commutativity'
+print '6.4.2 Long integers'
+if 12L + 24L <> 36L: raise TestFailed, 'long op'
+if 12L + (-24L) <> -12L: raise TestFailed, 'long op'
+if (-12L) + 24L <> 12L: raise TestFailed, 'long op'
+if (-12L) + (-24L) <> -36L: raise TestFailed, 'long op'
+if not 12L < 24L: raise TestFailed, 'long op'
+if not -24L < -12L: raise TestFailed, 'long op'
+print '6.4.3 Floating point numbers'
+if 12.0 + 24.0 <> 36.0: raise TestFailed, 'float op'
+if 12.0 + (-24.0) <> -12.0: raise TestFailed, 'float op'
+if (-12.0) + 24.0 <> 12.0: raise TestFailed, 'float op'
+if (-12.0) + (-24.0) <> -36.0: raise TestFailed, 'float op'
+if not 12.0 < 24.0: raise TestFailed, 'float op'
+if not -24.0 < -12.0: raise TestFailed, 'float op'
+
+print '6.5 Sequence types'
+
+print '6.5.1 Strings'
+if len('') <> 0: raise TestFailed, 'len(\'\')'
+if len('a') <> 1: raise TestFailed, 'len(\'a\')'
+if len('abcdef') <> 6: raise TestFailed, 'len(\'abcdef\')'
+if 'xyz' + 'abcde' <> 'xyzabcde': raise TestFailed, 'string concatenation'
+if 'xyz'*3 <> 'xyzxyzxyz': raise TestFailed, 'string repetition *3'
+if 0*'abcde' <> '': raise TestFailed, 'string repetition 0*'
+if min('abc') <> 'a' or max('abc') <> 'c': raise TestFailed, 'min/max string'
+if 'a' in 'abc' and 'b' in 'abc' and 'c' in 'abc' and 'd' not in 'abc': pass
+else: raise TestFailed, 'in/not in string'
+x = 'x'*103
+if '%s!'%x != x+'!': raise TestFailed, 'nasty string formatting bug'
+
+print '6.5.2 Tuples'
+if len(()) <> 0: raise TestFailed, 'len(())'
+if len((1,)) <> 1: raise TestFailed, 'len((1,))'
+if len((1,2,3,4,5,6)) <> 6: raise TestFailed, 'len((1,2,3,4,5,6))'
+if (1,2)+(3,4) <> (1,2,3,4): raise TestFailed, 'tuple concatenation'
+if (1,2)*3 <> (1,2,1,2,1,2): raise TestFailed, 'tuple repetition *3'
+if 0*(1,2,3) <> (): raise TestFailed, 'tuple repetition 0*'
+if min((1,2)) <> 1 or max((1,2)) <> 2: raise TestFailed, 'min/max tuple'
+if 0 in (0,1,2) and 1 in (0,1,2) and 2 in (0,1,2) and 3 not in (0,1,2): pass
+else: raise TestFailed, 'in/not in tuple'
+
+print '6.5.3 Lists'
+if len([]) <> 0: raise TestFailed, 'len([])'
+if len([1,]) <> 1: raise TestFailed, 'len([1,])'
+if len([1,2,3,4,5,6]) <> 6: raise TestFailed, 'len([1,2,3,4,5,6])'
+if [1,2]+[3,4] <> [1,2,3,4]: raise TestFailed, 'list concatenation'
+if [1,2]*3 <> [1,2,1,2,1,2]: raise TestFailed, 'list repetition *3'
+if 0*[1,2,3] <> []: raise TestFailed, 'list repetition 0*'
+if min([1,2]) <> 1 or max([1,2]) <> 2: raise TestFailed, 'min/max list'
+if 0 in [0,1,2] and 1 in [0,1,2] and 2 in [0,1,2] and 3 not in [0,1,2]: pass
+else: raise TestFailed, 'in/not in list'
+
+print '6.5.3a Additional list operations'
+a = [0,1,2,3,4]
+a[0] = 5
+a[1] = 6
+a[2] = 7
+if a <> [5,6,7,3,4]: raise TestFailed, 'list item assignment [0], [1], [2]'
+a[-2] = 8
+a[-1] = 9
+if a <> [5,6,7,8,9]: raise TestFailed, 'list item assignment [-2], [-1]'
+a[:2] = [0,4]
+a[-3:] = []
+a[1:1] = [1,2,3]
+if a <> [0,1,2,3,4]: raise TestFailed, 'list slice assignment'
+del a[1:4]
+if a <> [0,4]: raise TestFailed, 'list slice deletion'
+del a[0]
+if a <> [4]: raise TestFailed, 'list item deletion [0]'
+del a[-1]
+if a <> []: raise TestFailed, 'list item deletion [-1]'
+a.append(0)
+a.append(1)
+a.append(2)
+if a <> [0,1,2]: raise TestFailed, 'list append'
+a.insert(0, -2)
+a.insert(1, -1)
+a.insert(2,0)
+if a <> [-2,-1,0,0,1,2]: raise TestFailed, 'list insert'
+if a.count(0) <> 2: raise TestFailed, ' list count'
+if a.index(0) <> 2: raise TestFailed, 'list index'
+a.remove(0)
+if a <> [-2,-1,0,1,2]: raise TestFailed, 'list remove'
+a.reverse()
+if a <> [2,1,0,-1,-2]: raise TestFailed, 'list reverse'
+a.sort()
+if a <> [-2,-1,0,1,2]: raise TestFailed, 'list sort'
+def revcmp(a, b): return cmp(b, a)
+a.sort(revcmp)
+if a <> [2,1,0,-1,-2]: raise TestFailed, 'list sort with cmp func'
+
+print '6.6 Mappings == Dictionaries'
+d = {}
+if d.keys() <> []: raise TestFailed, '{}.keys()'
+if d.has_key('a') <> 0: raise TestFailed, '{}.has_key(\'a\')'
+if len(d) <> 0: raise TestFailed, 'len({})'
+d = {'a': 1, 'b': 2}
+if len(d) <> 2: raise TestFailed, 'len(dict)'
+k = d.keys()
+k.sort()
+if k <> ['a', 'b']: raise TestFailed, 'dict keys()'
+if d.has_key('a') and d.has_key('b') and not d.has_key('c'): pass
+else: raise TestFailed, 'dict keys()'
+if d['a'] <> 1 or d['b'] <> 2: raise TestFailed, 'dict item'
+d['c'] = 3
+d['a'] = 4
+if d['c'] <> 3 or d['a'] <> 4: raise TestFailed, 'dict item assignment'
+del d['b']
+if d <> {'a': 4, 'c': 3}: raise TestFailed, 'dict item deletion'
diff --git a/Lib/dos-8x3/tracebac.py b/Lib/dos-8x3/tracebac.py
new file mode 100755
index 0000000..8d2dfdc
--- /dev/null
+++ b/Lib/dos-8x3/tracebac.py
@@ -0,0 +1,125 @@
+# Format and print Python stack traces
+
+import linecache
+import string
+import sys
+import types
+
+def _print(file, str='', terminator='\n'):
+ file.write(str+terminator)
+
+
+def print_tb(tb, limit=None, file=None):
+ if not file:
+ file = sys.stderr
+ if limit is None:
+ if hasattr(sys, 'tracebacklimit'):
+ limit = sys.tracebacklimit
+ n = 0
+ while tb is not None and (limit is None or n < limit):
+ f = tb.tb_frame
+ lineno = tb.tb_lineno
+ co = f.f_code
+ filename = co.co_filename
+ name = co.co_name
+ _print(file,
+ ' File "%s", line %d, in %s' % (filename,lineno,name))
+ line = linecache.getline(filename, lineno)
+ if line: _print(file, ' ' + string.strip(line))
+ tb = tb.tb_next
+ n = n+1
+
+def format_tb(tb, limit = None):
+ list = []
+ for filename, lineno, name, line in extract_tb(tb, limit):
+ item = ' File "%s", line %d, in %s\n' % (filename,lineno,name)
+ if line:
+ item = item + ' %s\n' % string.strip(line)
+ list.append(item)
+ return list
+
+def extract_tb(tb, limit = None):
+ if limit is None:
+ if hasattr(sys, 'tracebacklimit'):
+ limit = sys.tracebacklimit
+ list = []
+ n = 0
+ while tb is not None and (limit is None or n < limit):
+ f = tb.tb_frame
+ lineno = tb.tb_lineno
+ co = f.f_code
+ filename = co.co_filename
+ name = co.co_name
+ line = linecache.getline(filename, lineno)
+ if line: line = string.strip(line)
+ else: line = None
+ list.append(filename, lineno, name, line)
+ tb = tb.tb_next
+ n = n+1
+ return list
+
+
+def print_exception(etype, value, tb, limit=None, file=None):
+ if not file:
+ file = sys.stderr
+ if tb:
+ _print(file, 'Traceback (innermost last):')
+ print_tb(tb, limit, file)
+ lines = format_exception_only(etype, value)
+ for line in lines[:-1]:
+ _print(file, line, ' ')
+ _print(file, lines[-1], '')
+
+def format_exception(etype, value, tb, limit = None):
+ if tb:
+ list = ['Traceback (innermost last):\n']
+ list = list + format_tb(tb, limit)
+ list = list + format_exception_only(etype, value)
+ return list
+
+def format_exception_only(etype, value):
+ list = []
+ if type(etype) == types.ClassType:
+ stype = etype.__name__
+ else:
+ stype = etype
+ if value is None:
+ list.append(str(stype) + '\n')
+ else:
+ if etype is SyntaxError:
+ try:
+ msg, (filename, lineno, offset, line) = value
+ except:
+ pass
+ else:
+ if not filename: filename = "<string>"
+ list.append(' File "%s", line %d\n' %
+ (filename, lineno))
+ i = 0
+ while i < len(line) and \
+ line[i] in string.whitespace:
+ i = i+1
+ list.append(' %s\n' % string.strip(line))
+ s = ' '
+ for c in line[i:offset-1]:
+ if c in string.whitespace:
+ s = s + c
+ else:
+ s = s + ' '
+ list.append('%s^\n' % s)
+ value = msg
+ list.append('%s: %s\n' % (str(stype), str(value)))
+ return list
+
+
+def print_exc(limit=None, file=None):
+ if not file:
+ file = sys.stderr
+ print_exception(sys.exc_type, sys.exc_value, sys.exc_traceback,
+ limit, file)
+
+def print_last(limit=None, file=None):
+ if not file:
+ file = sys.stderr
+ print_exception(sys.last_type, sys.last_value, sys.last_traceback,
+ limit, file)
diff --git a/Lib/dos-8x3/userdict.py b/Lib/dos-8x3/userdict.py
new file mode 100755
index 0000000..f6b2f82
--- /dev/null
+++ b/Lib/dos-8x3/userdict.py
@@ -0,0 +1,18 @@
+# A more or less complete user-defined wrapper around dictionary objects
+
+class UserDict:
+ def __init__(self): self.data = {}
+ def __repr__(self): return repr(self.data)
+ def __cmp__(self, dict):
+ if type(dict) == type(self.data):
+ return cmp(self.data, dict)
+ else:
+ return cmp(self.data, dict.data)
+ def __len__(self): return len(self.data)
+ def __getitem__(self, key): return self.data[key]
+ def __setitem__(self, key, item): self.data[key] = item
+ def __delitem__(self, key): del self.data[key]
+ def keys(self): return self.data.keys()
+ def items(self): return self.data.items()
+ def values(self): return self.data.values()
+ def has_key(self, key): return self.data.has_key(key)
diff --git a/Lib/dos-8x3/userlist.py b/Lib/dos-8x3/userlist.py
new file mode 100755
index 0000000..1f19ad9
--- /dev/null
+++ b/Lib/dos-8x3/userlist.py
@@ -0,0 +1,50 @@
+# A more or less complete user-defined wrapper around list objects
+
+class UserList:
+ def __init__(self, list = None):
+ self.data = []
+ if list is not None:
+ if type(list) == type(self.data):
+ self.data[:] = list
+ else:
+ self.data[:] = list.data[:]
+ def __repr__(self): return repr(self.data)
+ def __cmp__(self, list):
+ if type(list) == type(self.data):
+ return cmp(self.data, list)
+ else:
+ return cmp(self.data, list.data)
+ def __len__(self): return len(self.data)
+ def __getitem__(self, i): return self.data[i]
+ def __setitem__(self, i, item): self.data[i] = item
+ def __delitem__(self, i): del self.data[i]
+ def __getslice__(self, i, j):
+ userlist = UserList()
+ userlist.data[:] = self.data[i:j]
+ return userlist
+ def __setslice__(self, i, j, list):
+ if type(list) == type(self.data):
+ self.data[i:j] = list
+ else:
+ self.data[i:j] = list.data
+ def __delslice__(self, i, j): del self.data[i:j]
+ def __add__(self, list):
+ if type(list) == type(self.data):
+ return self.__class__(self.data + list)
+ else:
+ return self.__class__(self.data + list.data)
+ def __radd__(self, list):
+ if type(list) == type(self.data):
+ return self.__class__(list + self.data)
+ else:
+ return self.__class__(list.data + self.data)
+ def __mul__(self, n):
+ return self.__class__(self.data*n)
+ __rmul__ = __mul__
+ def append(self, item): self.data.append(item)
+ def insert(self, i, item): self.data.insert(i, item)
+ def remove(self, item): self.data.remove(item)
+ def count(self, item): return self.data.count(item)
+ def index(self, item): return self.data.index(item)
+ def reverse(self): self.data.reverse()
+ def sort(self, *args): apply(self.data.sort, args)
diff --git a/Lib/dos-8x3/whatsoun.py b/Lib/dos-8x3/whatsoun.py
new file mode 100755
index 0000000..b7b349c
--- /dev/null
+++ b/Lib/dos-8x3/whatsoun.py
@@ -0,0 +1,270 @@
+# This module contains several routines that help recognizing sound
+# files.
+#
+# Function whathdr() recognizes various types of sound file headers.
+# It understands almost all headers that SOX can decode.
+#
+# The return tuple contains the following items, in this order:
+# - file type (as SOX understands it)
+# - sampling rate (0 if unknown or hard to decode)
+# - number of channels (0 if unknown or hard to decode)
+# - number of frames in the file (-1 if unknown or hard to decode)
+# - number of bits/sample, or 'U' for U-LAW, or 'A' for A-LAW
+#
+# If the file doesn't have a recognizable type, it returns None.
+# If the file can't be opened, IOError is raised.
+#
+# To compute the total time, divide the number of frames by the
+# sampling rate (a frame contains a sample for each channel).
+#
+# Function whatraw() calls the "whatsound" program and interprets its
+# output. You'll have to guess the sampling rate by listening though!
+#
+# Function what() calls whathdr() and if it doesn't recognize the file
+# then calls whatraw().
+#
+# Finally, the function test() is a simple main program that calls
+# what() for all files mentioned on the argument list. For directory
+# arguments it calls what() for all files in that directory. Default
+# argument is "." (testing all files in the current directory). The
+# option -r tells it to recurse down directories found inside
+# explicitly given directories.
+#
+# The file structure is top-down except that the test program and its
+# subroutine come last.
+
+
+#------------------------------------------------------#
+# Guess the type of any sound file, raw or with header #
+#------------------------------------------------------#
+
+def what(filename):
+ res = whathdr(filename)
+ if not res:
+ res = whatraw(filename)
+ return res
+
+
+#-----------------------------#
+# Guess the type of raw sound #
+#-----------------------------#
+
+def whatraw(filename):
+ # Assume it's always 1 channel, byte-sized samples
+ # Don't assume anything about the rate
+ import os
+ from stat import ST_SIZE
+ # XXX "whatsound" should be part of the distribution somehow...
+ cmd = 'whatsound ' + filename + ' 2>/dev/null'
+ cmd = 'PATH=$PATH:/ufs/guido/bin/sgi\n' + cmd
+ pipe = os.popen(cmd, 'r')
+ data = pipe.read()
+ sts = pipe.close()
+ if sts:
+ return None
+ if data[:13] == '-t raw -b -s ':
+ type = 'sb'
+ sample_size = 8
+ elif data[:13] == '-t raw -b -u ':
+ type = 'ub'
+ sample_size = 8
+ elif data[:13] == '-t raw -b -U ':
+ type = 'ul'
+ sample_size = 'U'
+ else:
+ return None
+ try:
+ frame_count = os.stat(filename)[ST_SIZE]
+ except IOError:
+ frame_count = -1
+ return type, 0, 1, frame_count, sample_size
+
+
+#-------------------------#
+# Recognize sound headers #
+#-------------------------#
+
+def whathdr(filename):
+ f = open(filename, 'r')
+ h = f.read(512)
+ for tf in tests:
+ res = tf(h, f)
+ if res:
+ return res
+ return None
+
+
+#-----------------------------------#
+# Subroutines per sound header type #
+#-----------------------------------#
+
+tests = []
+
+def test_aifc(h, f):
+ import aifc
+ if h[:4] <> 'FORM':
+ return None
+ if h[8:12] == 'AIFC':
+ fmt = 'aifc'
+ elif h[8:12] == 'AIFF':
+ fmt = 'aiff'
+ else:
+ return None
+ f.seek(0)
+ try:
+ a = aifc.openfp(f, 'r')
+ except (EOFError, aifc.Error):
+ return None
+ return (fmt, a.getframerate(), a.getnchannels(), \
+ a.getnframes(), 8*a.getsampwidth())
+
+tests.append(test_aifc)
+
+
+def test_au(h, f):
+ if h[:4] == '.snd':
+ f = get_long_be
+ elif h[:4] in ('\0ds.', 'dns.'):
+ f = get_long_le
+ else:
+ return None
+ type = 'au'
+ hdr_size = f(h[4:8])
+ data_size = f(h[8:12])
+ encoding = f(h[12:16])
+ rate = f(h[16:20])
+ nchannels = f(h[20:24])
+ sample_size = 1 # default
+ if encoding == 1:
+ sample_bits = 'U'
+ elif encoding == 2:
+ sample_bits = 8
+ elif encoding == 3:
+ sample_bits = 16
+ sample_size = 2
+ else:
+ sample_bits = '?'
+ frame_size = sample_size * nchannels
+ return type, rate, nchannels, data_size/frame_size, sample_bits
+
+tests.append(test_au)
+
+
+def test_hcom(h, f):
+ if h[65:69] <> 'FSSD' or h[128:132] <> 'HCOM':
+ return None
+ divisor = get_long_be(h[128+16:128+20])
+ return 'hcom', 22050/divisor, 1, -1, 8
+
+tests.append(test_hcom)
+
+
+def test_voc(h, f):
+ if h[:20] <> 'Creative Voice File\032':
+ return None
+ sbseek = get_short_le(h[20:22])
+ rate = 0
+ if 0 <= sbseek < 500 and h[sbseek] == '\1':
+ ratecode = ord(h[sbseek+4])
+ rate = int(1000000.0 / (256 - ratecode))
+ return 'voc', rate, 1, -1, 8
+
+tests.append(test_voc)
+
+
+def test_wav(h, f):
+ # 'RIFF' <len> 'WAVE' 'fmt ' <len>
+ if h[:4] <> 'RIFF' or h[8:12] <> 'WAVE' or h[12:16] <> 'fmt ':
+ return None
+ style = get_short_le(h[20:22])
+ nchannels = get_short_le(h[22:24])
+ rate = get_long_le(h[24:28])
+ sample_bits = get_short_le(h[34:36])
+ return 'wav', rate, nchannels, -1, sample_bits
+
+tests.append(test_wav)
+
+
+def test_8svx(h, f):
+ if h[:4] <> 'FORM' or h[8:12] <> '8SVX':
+ return None
+ # Should decode it to get #channels -- assume always 1
+ return '8svx', 0, 1, 0, 8
+
+tests.append(test_8svx)
+
+
+def test_sndt(h, f):
+ if h[:5] == 'SOUND':
+ nsamples = get_long_le(h[8:12])
+ rate = get_short_le(h[20:22])
+ return 'sndt', rate, 1, nsamples, 8
+
+tests.append(test_sndt)
+
+
+def test_sndr(h, f):
+ if h[:2] == '\0\0':
+ rate = get_short_le(h[2:4])
+ if 4000 <= rate <= 25000:
+ return 'sndr', rate, 1, -1, 8
+
+tests.append(test_sndr)
+
+
+#---------------------------------------------#
+# Subroutines to extract numbers from strings #
+#---------------------------------------------#
+
+def get_long_be(s):
+ return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3])
+
+def get_long_le(s):
+ return (ord(s[3])<<24) | (ord(s[2])<<16) | (ord(s[1])<<8) | ord(s[0])
+
+def get_short_be(s):
+ return (ord(s[0])<<8) | ord(s[1])
+
+def get_short_le(s):
+ return (ord(s[1])<<8) | ord(s[0])
+
+
+#--------------------#
+# Small test program #
+#--------------------#
+
+def test():
+ import sys
+ recursive = 0
+ if sys.argv[1:] and sys.argv[1] == '-r':
+ del sys.argv[1:2]
+ recursive = 1
+ try:
+ if sys.argv[1:]:
+ testall(sys.argv[1:], recursive, 1)
+ else:
+ testall(['.'], recursive, 1)
+ except KeyboardInterrupt:
+ sys.stderr.write('\n[Interrupted]\n')
+ sys.exit(1)
+
+def testall(list, recursive, toplevel):
+ import sys
+ import os
+ for filename in list:
+ if os.path.isdir(filename):
+ print filename + '/:',
+ if recursive or toplevel:
+ print 'recursing down:'
+ import glob
+ names = glob.glob(os.path.join(filename, '*'))
+ testall(names, recursive, 0)
+ else:
+ print '*** directory (use -r) ***'
+ else:
+ print filename + ':',
+ sys.stdout.flush()
+ try:
+ print what(filename)
+ except IOError:
+ print '*** not found ***'
diff --git a/Lib/dos_8x3/arrayio.py b/Lib/dos_8x3/arrayio.py
new file mode 100755
index 0000000..5b06f92
--- /dev/null
+++ b/Lib/dos_8x3/arrayio.py
@@ -0,0 +1,142 @@
+"""File-like objects that read/write an array buffer.
+
+This implements (nearly) all stdio methods.
+
+f = ArrayIO() # ready for writing
+f = ArrayIO(buf) # ready for reading
+f.close() # explicitly release resources held
+flag = f.isatty() # always false
+pos = f.tell() # get current position
+f.seek(pos) # set current position
+f.seek(pos, mode) # mode 0: absolute; 1: relative; 2: relative to EOF
+buf = f.read() # read until EOF
+buf = f.read(n) # read up to n bytes
+buf = f.readline() # read until end of line ('\n') or EOF
+list = f.readlines()# list of f.readline() results until EOF
+f.write(buf) # write at current position
+f.writelines(list) # for line in list: f.write(line)
+f.getvalue() # return whole file's contents as a string
+
+Notes:
+- This is very similar to StringIO. StringIO is faster for reading,
+ but ArrayIO is faster for writing.
+- ArrayIO uses an array object internally, but all its interfaces
+ accept and return strings.
+- Using a real file is often faster (but less convenient).
+- fileno() is left unimplemented so that code which uses it triggers
+ an exception early.
+- Seeking far beyond EOF and then writing will insert real null
+ bytes that occupy space in the buffer.
+- There's a simple test set (see end of this file).
+"""
+
+import string
+from array import array
+
+class ArrayIO:
+ def __init__(self, buf = ''):
+ self.buf = array('c', buf)
+ self.pos = 0
+ self.closed = 0
+ self.softspace = 0
+ def close(self):
+ if not self.closed:
+ self.closed = 1
+ del self.buf, self.pos
+ def isatty(self):
+ return 0
+ def seek(self, pos, mode = 0):
+ if mode == 1:
+ pos = pos + self.pos
+ elif mode == 2:
+ pos = pos + len(self.buf)
+ self.pos = max(0, pos)
+ def tell(self):
+ return self.pos
+ def read(self, n = -1):
+ if n < 0:
+ newpos = len(self.buf)
+ else:
+ newpos = min(self.pos+n, len(self.buf))
+ r = self.buf[self.pos:newpos].tostring()
+ self.pos = newpos
+ return r
+ def readline(self):
+ i = string.find(self.buf[self.pos:].tostring(), '\n')
+ if i < 0:
+ newpos = len(self.buf)
+ else:
+ newpos = self.pos+i+1
+ r = self.buf[self.pos:newpos].tostring()
+ self.pos = newpos
+ return r
+ def readlines(self):
+ lines = string.splitfields(self.read(), '\n')
+ if not lines:
+ return lines
+ for i in range(len(lines)-1):
+ lines[i] = lines[i] + '\n'
+ if not lines[-1]:
+ del lines[-1]
+ return lines
+ def write(self, s):
+ if not s: return
+ a = array('c', s)
+ n = self.pos - len(self.buf)
+ if n > 0:
+ self.buf[len(self.buf):] = array('c', '\0')*n
+ newpos = self.pos + len(a)
+ self.buf[self.pos:newpos] = a
+ self.pos = newpos
+ def writelines(self, list):
+ self.write(string.joinfields(list, ''))
+ def flush(self):
+ pass
+ def getvalue(self):
+ return self.buf.tostring()
+
+
+# A little test suite
+
+def test():
+ import sys
+ if sys.argv[1:]:
+ file = sys.argv[1]
+ else:
+ file = '/etc/passwd'
+ lines = open(file, 'r').readlines()
+ text = open(file, 'r').read()
+ f = ArrayIO()
+ for line in lines[:-2]:
+ f.write(line)
+ f.writelines(lines[-2:])
+ if f.getvalue() != text:
+ raise RuntimeError, 'write failed'
+ length = f.tell()
+ print 'File length =', length
+ f.seek(len(lines[0]))
+ f.write(lines[1])
+ f.seek(0)
+ print 'First line =', `f.readline()`
+ here = f.tell()
+ line = f.readline()
+ print 'Second line =', `line`
+ f.seek(-len(line), 1)
+ line2 = f.read(len(line))
+ if line != line2:
+ raise RuntimeError, 'bad result after seek back'
+ f.seek(len(line2), 1)
+ list = f.readlines()
+ line = list[-1]
+ f.seek(f.tell() - len(line))
+ line2 = f.read()
+ if line != line2:
+ raise RuntimeError, 'bad result after seek back from EOF'
+ print 'Read', len(list), 'more lines'
+ print 'File length =', f.tell()
+ if f.tell() != length:
+ raise RuntimeError, 'bad length'
+ f.close()
+
+if __name__ == '__main__':
+ test()
diff --git a/Lib/dos_8x3/ast.py b/Lib/dos_8x3/ast.py
new file mode 100755
index 0000000..6f92bee
--- /dev/null
+++ b/Lib/dos_8x3/ast.py
@@ -0,0 +1,224 @@
+"""Object-oriented interface to the parser module.
+
+This module exports three classes which together provide an interface
+to the parser module. Together, the three classes represent two ways
+to create parsed representations of Python source and the two starting
+data types (source text and tuple representations). Each class
+provides interfaces which are identical other than the constructors.
+The constructors are described in detail in the documentation for each
+class and the remaining, shared portion of the interface is documented
+below. Briefly, the three classes provided are:
+
+AST
+ Defines the primary interface to the AST objects and supports creation
+ from the tuple representation of the parse tree.
+
+ExpressionAST
+ Supports creation of expression constructs from source text.
+
+SuiteAST
+ Supports creation of statement suites from source text.
+
+FileSuiteAST
+ Convenience subclass of the `SuiteAST' class; loads source text of the
+ suite from an external file.
+
+Aside from the constructors, several methods are provided to allow
+access to the various interpretations of the parse tree and to check
+conditions of the construct represented by the parse tree.
+
+ast()
+ Returns the corresponding `parser.ASTType' object.
+
+code()
+ Returns the compiled code object.
+
+filename()
+ Returns the name of the associated source file, if known.
+
+isExpression()
+ Returns true value if parse tree represents an expression, or a false
+ value otherwise.
+
+isSuite()
+ Returns true value if parse tree represents a suite of statements, or
+ a false value otherwise.
+
+text()
+ Returns the source text, or None if not available.
+
+tuple()
+ Returns the tuple representing the parse tree.
+"""
+
+__version__ = '$Revision$'
+__copyright__ = """Copyright (c) 1995, 1996 by Fred L. Drake, Jr.
+
+This software may be used and distributed freely for any purpose provided
+that this notice is included unchanged on any and all copies. The author
+does not warrant or guarantee this software in any way.
+"""
+
+class AST:
+ """Base class for Abstract Syntax Tree objects.
+
+ Creates an Abstract Syntax Tree based on the tuple representation
+ of the parse tree. The parse tree can represent either an
+ expression or a suite; which will be recognized automatically.
+ This base class provides all of the query methods for subclass
+ objects defined in this module.
+ """
+ _p = __import__('parser') # import internally to avoid
+ # namespace pollution at the
+ # top level
+ _text = None
+ _code = None
+ _ast = None
+ _type = 'unknown'
+ _tupl = None
+
+ def __init__(self, tuple):
+ """Create an `AST' instance from a tuple-tree representation.
+
+ tuple
+ The tuple tree to convert.
+
+ The tuple-tree may represent either an expression or a suite; the
+ type will be determined automatically.
+ """
+ if type(tuple) is not type(()):
+ raise TypeError, 'Base AST class requires tuple parameter.'
+
+ self._tupl = tuple
+ self._ast = self._p.tuple2ast(tuple)
+ self._type = (self._p.isexpr(self._ast) and 'expression') or 'suite'
+
+ def tuple(self):
+ """Returns the tuple representing the parse tree.
+ """
+ if self._tupl is None:
+ self._tupl = self._p.ast2tuple(self._ast)
+ return self._tupl
+
+ def code(self):
+ """Returns the compiled code object.
+
+ The code object returned by this method may be passed to the
+ exec statement if `AST.isSuite()' is true or to the eval()
+ function if `AST.isExpression()' is true. All the usual rules
+ regarding execution of code objects apply.
+ """
+ if not self._code:
+ self._code = self._p.compileast(self._ast)
+ return self._code
+
+ def ast(self):
+ """Returns the corresponding `parser.ASTType' object.
+ """
+ return self._ast
+
+ def filename(self):
+ """Returns the name of the source file if known, or None.
+ """
+ return None
+
+ def text(self):
+ """Returns the source text, or None if not available.
+
+ If the instance is of class `AST', None is returned since no
+ source text is available. If of class `ExpressionAST' or
+ `SuiteAST', the source text passed to the constructor is
+ returned.
+ """
+ return self._text
+
+ def isSuite(self):
+ """Determine if `AST' instance represents a suite of statements.
+ """
+ return self._type == 'suite'
+
+ def isExpression(self):
+ """Determine if `AST' instance represents an expression.
+ """
+ return self._type == 'expression'
+
+
+
+class SuiteAST(AST):
+ """Statement suite parse tree representation.
+
+ This subclass of the `AST' base class represents statement suites
+ parsed from the source text of a Python suite. If the source text
+ does not represent a parsable suite of statements, the appropriate
+ exception is raised by the parser.
+ """
+ _type = 'suite'
+
+ def __init__(self, text):
+ """Initialize a `SuiteAST' from source text.
+
+ text
+ Source text to parse.
+ """
+ if type(text) is not type(''):
+ raise TypeError, 'SuiteAST requires source text parameter.'
+ self._text = text
+ self._ast = self._p.suite(text)
+
+ def isSuite(self):
+ return 1
+
+ def isExpression(self):
+ return 0
+
+
+class FileSuiteAST(SuiteAST):
+ """Representation of a python source file syntax tree.
+
+ This provides a convenience wrapper around the `SuiteAST' class to
+ load the source text from an external file.
+ """
+ def __init__(self, fileName):
+ """Initialize a `SuiteAST' from a source file.
+
+ fileName
+ Name of the external source file.
+ """
+ self._fileName = fileName
+ SuiteAST.__init__(self, open(fileName).read())
+
+ def filename(self):
+ return self._fileName
+
+
+
+class ExpressionAST(AST):
+ """Expression parse tree representation.
+
+ This subclass of the `AST' base class represents expression
+ constructs parsed from the source text of a Python expression. If
+ the source text does not represent a parsable expression, the
+ appropriate exception is raised by the Python parser.
+ """
+ _type = 'expression'
+
+ def __init__(self, text):
+ """Initialize an expression AST from source text.
+
+ text
+ Source text to parse.
+ """
+ if type(text) is not type(''):
+ raise TypeError, 'ExpressionAST requires source text parameter.'
+ self._text = text
+ self._ast = self._p.expr(text)
+
+ def isSuite(self):
+ return 0
+
+ def isExpression(self):
+ return 1
+
+
+#
+# end of file
diff --git a/Lib/dos_8x3/basehttp.py b/Lib/dos_8x3/basehttp.py
new file mode 100755
index 0000000..281ddf6
--- /dev/null
+++ b/Lib/dos_8x3/basehttp.py
@@ -0,0 +1,482 @@
+"""HTTP server base class.
+
+Note: the class in this module doesn't implement any HTTP request; see
+SimpleHTTPServer for simple implementations of GET, HEAD and POST
+(including CGI scripts).
+
+Contents:
+
+- BaseHTTPRequestHandler: HTTP request handler base class
+- test: test function
+
+XXX To do:
+
+- send server version
+- log requests even later (to capture byte count)
+- log user-agent header and other interesting goodies
+- send error log to separate file
+- are request names really case sensitive?
+
+"""
+
+
+# See also:
+#
+# HTTP Working Group T. Berners-Lee
+# INTERNET-DRAFT R. T. Fielding
+# <draft-ietf-http-v10-spec-00.txt> H. Frystyk Nielsen
+# Expires September 8, 1995 March 8, 1995
+#
+# URL: http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-v10-spec-00.txt
+
+
+# Log files
+# ---------
+#
+# Here's a quote from the NCSA httpd docs about log file format.
+#
+# | The logfile format is as follows. Each line consists of:
+# |
+# | host rfc931 authuser [DD/Mon/YYYY:hh:mm:ss] "request" ddd bbbb
+# |
+# | host: Either the DNS name or the IP number of the remote client
+# | rfc931: Any information returned by identd for this person,
+# | - otherwise.
+# | authuser: If user sent a userid for authentication, the user name,
+# | - otherwise.
+# | DD: Day
+# | Mon: Month (calendar name)
+# | YYYY: Year
+# | hh: hour (24-hour format, the machine's timezone)
+# | mm: minutes
+# | ss: seconds
+# | request: The first line of the HTTP request as sent by the client.
+# | ddd: the status code returned by the server, - if not available.
+# | bbbb: the total number of bytes sent,
+# | *not including the HTTP/1.0 header*, - if not available
+# |
+# | You can determine the name of the file accessed through request.
+#
+# (Actually, the latter is only true if you know the server configuration
+# at the time the request was made!)
+
+
+__version__ = "0.2"
+
+
+import sys
+import time
+import socket # For gethostbyaddr()
+import string
+import rfc822
+import mimetools
+import SocketServer
+
+# Default error message
+DEFAULT_ERROR_MESSAGE = """\
+<head>
+<title>Error response</title>
+</head>
+<body>
+<h1>Error response</h1>
+<p>Error code %(code)d.
+<p>Message: %(message)s.
+<p>Error code explanation: %(code)s = %(explain)s.
+</body>
+"""
+
+
+class HTTPServer(SocketServer.TCPServer):
+
+ def server_bind(self):
+ """Override server_bind to store the server name."""
+ SocketServer.TCPServer.server_bind(self)
+ host, port = self.socket.getsockname()
+ if not host or host == '0.0.0.0':
+ host = socket.gethostname()
+ hostname, hostnames, hostaddrs = socket.gethostbyaddr(host)
+ if '.' not in hostname:
+ for host in hostnames:
+ if '.' in host:
+ hostname = host
+ break
+ self.server_name = hostname
+ self.server_port = port
+
+
+class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler):
+
+ """HTTP request handler base class.
+
+ The following explanation of HTTP serves to guide you through the
+ code as well as to expose any misunderstandings I may have about
+ HTTP (so you don't need to read the code to figure out I'm wrong
+ :-).
+
+ HTTP (HyperText Transfer Protocol) is an extensible protocol on
+ top of a reliable stream transport (e.g. TCP/IP). The protocol
+ recognizes three parts to a request:
+
+ 1. One line identifying the request type and path
+ 2. An optional set of RFC-822-style headers
+ 3. An optional data part
+
+ The headers and data are separated by a blank line.
+
+ The first line of the request has the form
+
+ <command> <path> <version>
+
+ where <command> is a (case-sensitive) keyword such as GET or POST,
+ <path> is a string containing path information for the request,
+ and <version> should be the string "HTTP/1.0". <path> is encoded
+ using the URL encoding scheme (using %xx to signify the ASCII
+ character with hex code xx).
+
+ The protocol is vague about whether lines are separated by LF
+ characters or by CRLF pairs -- for compatibility with the widest
+ range of clients, both should be accepted. Similarly, whitespace
+ in the request line should be treated sensibly (allowing multiple
+ spaces between components and allowing trailing whitespace).
+
+ Similarly, for output, lines ought to be separated by CRLF pairs
+ but most clients grok LF characters just fine.
+
+ If the first line of the request has the form
+
+ <command> <path>
+
+ (i.e. <version> is left out) then this is assumed to be an HTTP
+ 0.9 request; this form has no optional headers and data part and
+ the reply consists of just the data.
+
+ The reply form of the HTTP 1.0 protocol again has three parts:
+
+ 1. One line giving the response code
+ 2. An optional set of RFC-822-style headers
+ 3. The data
+
+ Again, the headers and data are separated by a blank line.
+
+ The response code line has the form
+
+ <version> <responsecode> <responsestring>
+
+ where <version> is the protocol version (always "HTTP/1.0"),
+ <responsecode> is a 3-digit response code indicating success or
+ failure of the request, and <responsestring> is an optional
+ human-readable string explaining what the response code means.
+
+ This server parses the request and the headers, and then calls a
+ function specific to the request type (<command>). Specifically,
+ a request SPAM will be handled by a method handle_SPAM(). If no
+ such method exists the server sends an error response to the
+ client. If it exists, it is called with no arguments:
+
+ do_SPAM()
+
+ Note that the request name is case sensitive (i.e. SPAM and spam
+ are different requests).
+
+ The various request details are stored in instance variables:
+
+ - client_address is the client IP address in the form (host,
+ port);
+
+ - command, path and version are the broken-down request line;
+
+ - headers is an instance of mimetools.Message (or a derived
+ class) containing the header information;
+
+ - rfile is a file object open for reading positioned at the
+ start of the optional input data part;
+
+ - wfile is a file object open for writing.
+
+ IT IS IMPORTANT TO ADHERE TO THE PROTOCOL FOR WRITING!
+
+ The first thing to be written must be the response line. Then
+ follow 0 or more header lines, then a blank line, and then the
+ actual data (if any). The meaning of the header lines depends on
+ the command executed by the server; in most cases, when data is
+ returned, there should be at least one header line of the form
+
+ Content-type: <type>/<subtype>
+
+ where <type> and <subtype> should be registered MIME types,
+ e.g. "text/html" or "text/plain".
+
+ """
+
+ # The Python system version, truncated to its first component.
+ sys_version = "Python/" + string.split(sys.version)[0]
+
+ # The server software version. You may want to override this.
+ # The format is multiple whitespace-separated strings,
+ # where each string is of the form name[/version].
+ server_version = "BaseHTTP/" + __version__
+
+ def handle(self):
+ """Handle a single HTTP request.
+
+ You normally don't need to override this method; see the class
+ __doc__ string for information on how to handle specific HTTP
+ commands such as GET and POST.
+
+ """
+
+ self.raw_requestline = self.rfile.readline()
+ self.request_version = version = "HTTP/0.9" # Default
+ requestline = self.raw_requestline
+ if requestline[-2:] == '\r\n':
+ requestline = requestline[:-2]
+ elif requestline[-1:] == '\n':
+ requestline = requestline[:-1]
+ self.requestline = requestline
+ words = string.split(requestline)
+ if len(words) == 3:
+ [command, path, version] = words
+ if version != self.protocol_version:
+ self.send_error(400, "Bad request version (%s)" % `version`)
+ return
+ elif len(words) == 2:
+ [command, path] = words
+ if command != 'GET':
+ self.send_error(400,
+ "Bad HTTP/0.9 request type (%s)" % `command`)
+ return
+ else:
+ self.send_error(400, "Bad request syntax (%s)" % `requestline`)
+ return
+ self.command, self.path, self.request_version = command, path, version
+ self.headers = self.MessageClass(self.rfile, 0)
+ mname = 'do_' + command
+ if not hasattr(self, mname):
+ self.send_error(501, "Unsupported method (%s)" % `mname`)
+ return
+ method = getattr(self, mname)
+ method()
+
+ def send_error(self, code, message=None):
+ """Send and log an error reply.
+
+ Arguments are the error code, and a detailed message.
+ The detailed message defaults to the short entry matching the
+ response code.
+
+ This sends an error response (so it must be called before any
+ output has been generated), logs the error, and finally sends
+ a piece of HTML explaining the error to the user.
+
+ """
+
+ try:
+ short, long = self.responses[code]
+ except KeyError:
+ short, long = '???', '???'
+ if not message:
+ message = short
+ explain = long
+ self.log_error("code %d, message %s", code, message)
+ self.send_response(code, message)
+ self.end_headers()
+ self.wfile.write(self.error_message_format %
+ {'code': code,
+ 'message': message,
+ 'explain': explain})
+
+ error_message_format = DEFAULT_ERROR_MESSAGE
+
+ def send_response(self, code, message=None):
+ """Send the response header and log the response code.
+
+ Also send two standard headers with the server software
+ version and the current date.
+
+ """
+ self.log_request(code)
+ if message is None:
+ if self.responses.has_key(code):
+ message = self.responses[code][1]
+ else:
+ message = ''
+ if self.request_version != 'HTTP/0.9':
+ self.wfile.write("%s %s %s\r\n" %
+ (self.protocol_version, str(code), message))
+ self.send_header('Server', self.version_string())
+ self.send_header('Date', self.date_time_string())
+
+ def send_header(self, keyword, value):
+ """Send a MIME header."""
+ if self.request_version != 'HTTP/0.9':
+ self.wfile.write("%s: %s\r\n" % (keyword, value))
+
+ def end_headers(self):
+ """Send the blank line ending the MIME headers."""
+ if self.request_version != 'HTTP/0.9':
+ self.wfile.write("\r\n")
+
+ def log_request(self, code='-', size='-'):
+ """Log an accepted request.
+
+ This is called by send_reponse().
+
+ """
+
+ self.log_message('"%s" %s %s',
+ self.requestline, str(code), str(size))
+
+ def log_error(self, *args):
+ """Log an error.
+
+ This is called when a request cannot be fulfilled. By
+ default it passes the message on to log_message().
+
+ Arguments are the same as for log_message().
+
+ XXX This should go to the separate error log.
+
+ """
+
+ apply(self.log_message, args)
+
+ def log_message(self, format, *args):
+ """Log an arbitrary message.
+
+ This is used by all other logging functions. Override
+ it if you have specific logging wishes.
+
+ The first argument, FORMAT, is a format string for the
+ message to be logged. If the format string contains
+ any % escapes requiring parameters, they should be
+ specified as subsequent arguments (it's just like
+ printf!).
+
+ The client host and current date/time are prefixed to
+ every message.
+
+ """
+
+ sys.stderr.write("%s - - [%s] %s\n" %
+ (self.address_string(),
+ self.log_date_time_string(),
+ format%args))
+
+ def version_string(self):
+ """Return the server software version string."""
+ return self.server_version + ' ' + self.sys_version
+
+ def date_time_string(self):
+ """Return the current date and time formatted for a message header."""
+ now = time.time()
+ year, month, day, hh, mm, ss, wd, y, z = time.gmtime(now)
+ s = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
+ self.weekdayname[wd],
+ day, self.monthname[month], year,
+ hh, mm, ss)
+ return s
+
+ def log_date_time_string(self):
+ """Return the current time formatted for logging."""
+ now = time.time()
+ year, month, day, hh, mm, ss, x, y, z = time.localtime(now)
+ s = "%02d/%3s/%04d %02d:%02d:%02d" % (
+ day, self.monthname[month], year, hh, mm, ss)
+ return s
+
+ weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+
+ monthname = [None,
+ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
+ 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
+
+ def address_string(self):
+ """Return the client address formatted for logging.
+
+ This version looks up the full hostname using gethostbyaddr(),
+ and tries to find a name that contains at least one dot.
+
+ """
+
+ (host, port) = self.client_address
+ try:
+ name, names, addresses = socket.gethostbyaddr(host)
+ except socket.error, msg:
+ return host
+ names.insert(0, name)
+ for name in names:
+ if '.' in name: return name
+ return names[0]
+
+
+ # Essentially static class variables
+
+ # The version of the HTTP protocol we support.
+ # Don't override unless you know what you're doing (hint: incoming
+ # requests are required to have exactly this version string).
+ protocol_version = "HTTP/1.0"
+
+ # The Message-like class used to parse headers
+ MessageClass = mimetools.Message
+
+ # Table mapping response codes to messages; entries have the
+ # form {code: (shortmessage, longmessage)}.
+ # See http://www.w3.org/hypertext/WWW/Protocols/HTTP/HTRESP.html
+ responses = {
+ 200: ('OK', 'Request fulfilled, document follows'),
+ 201: ('Created', 'Document created, URL follows'),
+ 202: ('Accepted',
+ 'Request accepted, processing continues off-line'),
+ 203: ('Partial information', 'Request fulfilled from cache'),
+ 204: ('No response', 'Request fulfilled, nothing follows'),
+
+ 301: ('Moved', 'Object moved permanently -- see URI list'),
+ 302: ('Found', 'Object moved temporarily -- see URI list'),
+ 303: ('Method', 'Object moved -- see Method and URL list'),
+ 304: ('Not modified',
+ 'Document has not changed singe given time'),
+
+ 400: ('Bad request',
+ 'Bad request syntax or unsupported method'),
+ 401: ('Unauthorized',
+ 'No permission -- see authorization schemes'),
+ 402: ('Payment required',
+ 'No payment -- see charging schemes'),
+ 403: ('Forbidden',
+ 'Request forbidden -- authorization will not help'),
+ 404: ('Not found', 'Nothing matches the given URI'),
+
+ 500: ('Internal error', 'Server got itself in trouble'),
+ 501: ('Not implemented',
+ 'Server does not support this operation'),
+ 502: ('Service temporarily overloaded',
+ 'The server cannot process the request due to a high load'),
+ 503: ('Gateway timeout',
+ 'The gateway server did not receive a timely response'),
+
+ }
+
+
+def test(HandlerClass = BaseHTTPRequestHandler,
+ ServerClass = HTTPServer):
+ """Test the HTTP request handler class.
+
+ This runs an HTTP server on port 8000 (or the first command line
+ argument).
+
+ """
+
+ if sys.argv[1:]:
+ port = string.atoi(sys.argv[1])
+ else:
+ port = 8000
+ server_address = ('', port)
+
+ httpd = ServerClass(server_address, HandlerClass)
+
+ print "Serving HTTP on port", port, "..."
+ httpd.serve_forever()
+
+
+if __name__ == '__main__':
+ test()
diff --git a/Lib/dos_8x3/bastion.py b/Lib/dos_8x3/bastion.py
new file mode 100755
index 0000000..7ddd93e
--- /dev/null
+++ b/Lib/dos_8x3/bastion.py
@@ -0,0 +1,162 @@
+"""Bastionification utility.
+
+A bastion (for another object -- the 'original') is an object that has
+the same methods as the original but does not give access to its
+instance variables. Bastions have a number of uses, but the most
+obvious one is to provide code executing in restricted mode with a
+safe interface to an object implemented in unrestricted mode.
+
+The bastionification routine has an optional second argument which is
+a filter function. Only those methods for which the filter method
+(called with the method name as argument) returns true are accessible.
+The default filter method returns true unless the method name begins
+with an underscore.
+
+There are a number of possible implementations of bastions. We use a
+'lazy' approach where the bastion's __getattr__() discipline does all
+the work for a particular method the first time it is used. This is
+usually fastest, especially if the user doesn't call all available
+methods. The retrieved methods are stored as instance variables of
+the bastion, so the overhead is only occurred on the first use of each
+method.
+
+Detail: the bastion class has a __repr__() discipline which includes
+the repr() of the original object. This is precomputed when the
+bastion is created.
+
+"""
+
+__version__ = '$Revision$'
+# $Source$
+
+
+from types import MethodType
+
+
+class BastionClass:
+
+ """Helper class used by the Bastion() function.
+
+ You could subclass this and pass the subclass as the bastionclass
+ argument to the Bastion() function, as long as the constructor has
+ the same signature (a get() function and a name for the object).
+
+ """
+
+ def __init__(self, get, name):
+ """Constructor.
+
+ Arguments:
+
+ get - a function that gets the attribute value (by name)
+ name - a human-readable name for the original object
+ (suggestion: use repr(object))
+
+ """
+ self._get_ = get
+ self._name_ = name
+
+ def __repr__(self):
+ """Return a representation string.
+
+ This includes the name passed in to the constructor, so that
+ if you print the bastion during debugging, at least you have
+ some idea of what it is.
+
+ """
+ return "<Bastion for %s>" % self._name_
+
+ def __getattr__(self, name):
+ """Get an as-yet undefined attribute value.
+
+ This calls the get() function that was passed to the
+ constructor. The result is stored as an instance variable so
+ that the next time the same attribute is requested,
+ __getattr__() won't be invoked.
+
+ If the get() function raises an exception, this is simply
+ passed on -- exceptions are not cached.
+
+ """
+ attribute = self._get_(name)
+ self.__dict__[name] = attribute
+ return attribute
+
+
+def Bastion(object, filter = lambda name: name[:1] != '_',
+ name=None, bastionclass=BastionClass):
+ """Create a bastion for an object, using an optional filter.
+
+ See the Bastion module's documentation for background.
+
+ Arguments:
+
+ object - the original object
+ filter - a predicate that decides whether a function name is OK;
+ by default all names are OK that don't start with '_'
+ name - the name of the object; default repr(object)
+ bastionclass - class used to create the bastion; default BastionClass
+
+ """
+
+ # Note: we define *two* ad-hoc functions here, get1 and get2.
+ # Both are intended to be called in the same way: get(name).
+ # It is clear that the real work (getting the attribute
+ # from the object and calling the filter) is done in get1.
+ # Why can't we pass get1 to the bastion? Because the user
+ # would be able to override the filter argument! With get2,
+ # overriding the default argument is no security loophole:
+ # all it does is call it.
+ # Also notice that we can't place the object and filter as
+ # instance variables on the bastion object itself, since
+ # the user has full access to all instance variables!
+
+ def get1(name, object=object, filter=filter):
+ """Internal function for Bastion(). See source comments."""
+ if filter(name):
+ attribute = getattr(object, name)
+ if type(attribute) == MethodType:
+ return attribute
+ raise AttributeError, name
+
+ def get2(name, get1=get1):
+ """Internal function for Bastion(). See source comments."""
+ return get1(name)
+
+ if name is None:
+ name = `object`
+ return bastionclass(get2, name)
+
+
+def _test():
+ """Test the Bastion() function."""
+ class Original:
+ def __init__(self):
+ self.sum = 0
+ def add(self, n):
+ self._add(n)
+ def _add(self, n):
+ self.sum = self.sum + n
+ def total(self):
+ return self.sum
+ o = Original()
+ b = Bastion(o)
+ b.add(81)
+ b.add(18)
+ print "b.total() =", b.total()
+ try:
+ print "b.sum =", b.sum,
+ except:
+ print "inaccessible"
+ else:
+ print "accessible"
+ try:
+ print "b._add =", b._add,
+ except:
+ print "inaccessible"
+ else:
+ print "accessible"
+
+
+if __name__ == '__main__':
+ _test()
diff --git a/Lib/dos_8x3/cgihttps.py b/Lib/dos_8x3/cgihttps.py
new file mode 100755
index 0000000..837f7c2
--- /dev/null
+++ b/Lib/dos_8x3/cgihttps.py
@@ -0,0 +1,203 @@
+"""CGI-savvy HTTP Server.
+
+This module builds on SimpleHTTPServer by implementing GET and POST
+requests to cgi-bin scripts.
+
+"""
+
+
+__version__ = "0.3"
+
+
+import os
+import sys
+import time
+import socket
+import string
+import urllib
+import BaseHTTPServer
+import SimpleHTTPServer
+
+
+class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
+
+ """Complete HTTP server with GET, HEAD and POST commands.
+
+ GET and HEAD also support running CGI scripts.
+
+ The POST command is *only* implemented for CGI scripts.
+
+ """
+
+ def do_POST(self):
+ """Serve a POST request.
+
+ This is only implemented for CGI scripts.
+
+ """
+
+ if self.is_cgi():
+ self.run_cgi()
+ else:
+ self.send_error(501, "Can only POST to CGI scripts")
+
+ def send_head(self):
+ """Version of send_head that support CGI scripts"""
+ if self.is_cgi():
+ return self.run_cgi()
+ else:
+ return SimpleHTTPServer.SimpleHTTPRequestHandler.send_head(self)
+
+ def is_cgi(self):
+ """test whether PATH corresponds to a CGI script.
+
+ Return a tuple (dir, rest) if PATH requires running a
+ CGI script, None if not. Note that rest begins with a
+ slash if it is not empty.
+
+ The default implementation tests whether the path
+ begins with one of the strings in the list
+ self.cgi_directories (and the next character is a '/'
+ or the end of the string).
+
+ """
+
+ path = self.path
+
+ for x in self.cgi_directories:
+ i = len(x)
+ if path[:i] == x and (not path[i:] or path[i] == '/'):
+ self.cgi_info = path[:i], path[i+1:]
+ return 1
+ return 0
+
+ cgi_directories = ['/cgi-bin', '/htbin']
+
+ def run_cgi(self):
+ """Execute a CGI script."""
+ dir, rest = self.cgi_info
+ i = string.rfind(rest, '?')
+ if i >= 0:
+ rest, query = rest[:i], rest[i+1:]
+ else:
+ query = ''
+ i = string.find(rest, '/')
+ if i >= 0:
+ script, rest = rest[:i], rest[i:]
+ else:
+ script, rest = rest, ''
+ scriptname = dir + '/' + script
+ scriptfile = self.translate_path(scriptname)
+ if not os.path.exists(scriptfile):
+ self.send_error(404, "No such CGI script (%s)" % `scriptname`)
+ return
+ if not os.path.isfile(scriptfile):
+ self.send_error(403, "CGI script is not a plain file (%s)" %
+ `scriptname`)
+ return
+ if not executable(scriptfile):
+ self.send_error(403, "CGI script is not executable (%s)" %
+ `scriptname`)
+ return
+ nobody = nobody_uid()
+ self.send_response(200, "Script output follows")
+ self.wfile.flush() # Always flush before forking
+ pid = os.fork()
+ if pid != 0:
+ # Parent
+ pid, sts = os.waitpid(pid, 0)
+ if sts:
+ self.log_error("CGI script exit status x%x" % sts)
+ return
+ # Child
+ try:
+ # Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html
+ # XXX Much of the following could be prepared ahead of time!
+ env = {}
+ env['SERVER_SOFTWARE'] = self.version_string()
+ env['SERVER_NAME'] = self.server.server_name
+ env['GATEWAY_INTERFACE'] = 'CGI/1.1'
+ env['SERVER_PROTOCOL'] = self.protocol_version
+ env['SERVER_PORT'] = str(self.server.server_port)
+ env['REQUEST_METHOD'] = self.command
+ uqrest = urllib.unquote(rest)
+ env['PATH_INFO'] = uqrest
+ env['PATH_TRANSLATED'] = self.translate_path(uqrest)
+ env['SCRIPT_NAME'] = scriptname
+ if query:
+ env['QUERY_STRING'] = query
+ host = self.address_string()
+ if host != self.client_address[0]:
+ env['REMOTE_HOST'] = host
+ env['REMOTE_ADDR'] = self.client_address[0]
+ # AUTH_TYPE
+ # REMOTE_USER
+ # REMOTE_IDENT
+ env['CONTENT_TYPE'] = self.headers.type
+ length = self.headers.getheader('content-length')
+ if length:
+ env['CONTENT_LENGTH'] = length
+ accept = []
+ for line in self.headers.getallmatchingheaders('accept'):
+ if line[:1] in string.whitespace:
+ accept.append(string.strip(line))
+ else:
+ accept = accept + string.split(line[7:])
+ env['HTTP_ACCEPT'] = string.joinfields(accept, ',')
+ ua = self.headers.getheader('user-agent')
+ if ua:
+ env['HTTP_USER_AGENT'] = ua
+ # XXX Other HTTP_* headers
+ import regsub
+ decoded_query = regsub.gsub('+', ' ', query)
+ try:
+ os.setuid(nobody)
+ except os.error:
+ pass
+ os.dup2(self.rfile.fileno(), 0)
+ os.dup2(self.wfile.fileno(), 1)
+ print scriptfile, script, decoded_query
+ os.execve(scriptfile,
+ [script, decoded_query],
+ env)
+ except:
+ self.server.handle_error(self.request, self.client_address)
+ os._exit(127)
+
+
+nobody = None
+
+def nobody_uid():
+ """Internal routine to get nobody's uid"""
+ global nobody
+ if nobody:
+ return nobody
+ import pwd
+ try:
+ nobody = pwd.getpwnam('nobody')[2]
+ except pwd.error:
+ nobody = 1 + max(map(lambda x: x[2], pwd.getpwall()))
+ return nobody
+
+
+def executable(path):
+ """Test for executable file."""
+ try:
+ st = os.stat(path)
+ except os.error:
+ return 0
+ return st[0] & 0111 != 0
+
+
+def test(HandlerClass = CGIHTTPRequestHandler,
+ ServerClass = BaseHTTPServer.HTTPServer):
+ import sys
+ if sys.argv[1:2] == ['-r']:
+ db = MyArchive()
+ db.regenindices()
+ return
+ SimpleHTTPServer.test(HandlerClass, ServerClass)
+
+
+if __name__ == '__main__':
+ test()
diff --git a/Lib/dos_8x3/compilea.py b/Lib/dos_8x3/compilea.py
new file mode 100755
index 0000000..3120284
--- /dev/null
+++ b/Lib/dos_8x3/compilea.py
@@ -0,0 +1,70 @@
+# Routines to force "compilation" of all .py files in a directory
+# tree or on sys.path. By default recursion is pruned at a depth of
+# 10 and the current directory, if it occurs in sys.path, is skipped.
+# When called as a script, compiles argument directories, or sys.path
+# if no arguments.
+# After a similar module by Sjoerd Mullender.
+
+import os
+import sys
+import py_compile
+
+def compile_dir(dir, maxlevels = 10):
+ print 'Listing', dir, '...'
+ try:
+ names = os.listdir(dir)
+ except os.error:
+ print "Can't list", dir
+ names = []
+ names.sort()
+ for name in names:
+ fullname = os.path.join(dir, name)
+ if os.path.isfile(fullname):
+ head, tail = name[:-3], name[-3:]
+ if tail == '.py':
+ print 'Compiling', fullname, '...'
+ try:
+ py_compile.compile(fullname)
+ except KeyboardInterrupt:
+ del names[:]
+ print '\n[interrupt]'
+ break
+ except:
+ if type(sys.exc_type) == type(''):
+ exc_type_name = sys.exc_type
+ else: exc_type_name = sys.exc_type.__name__
+ print 'Sorry:', exc_type_name + ':',
+ print sys.exc_value
+ elif maxlevels > 0 and \
+ name != os.curdir and name != os.pardir and \
+ os.path.isdir(fullname) and \
+ not os.path.islink(fullname):
+ compile_dir(fullname, maxlevels - 1)
+
+def compile_path(skip_curdir = 1):
+ for dir in sys.path:
+ if dir == os.curdir and skip_curdir:
+ print 'Skipping current directory'
+ else:
+ compile_dir(dir, 0)
+
+def main():
+ import getopt
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], 'l')
+ except getopt.error, msg:
+ print msg
+ print "usage: compileall [-l] [directory ...]"
+ print "-l: don't recurse down"
+ print "if no arguments, -l sys.path is assumed"
+ maxlevels = 10
+ for o, a in opts:
+ if o == '-l': maxlevels = 0
+ if args:
+ for dir in sys.argv[1:]:
+ compile_dir(dir, maxlevels)
+ else:
+ compile_path()
+
+if __name__ == '__main__':
+ main()
diff --git a/Lib/dos_8x3/complex.py b/Lib/dos_8x3/complex.py
new file mode 100755
index 0000000..f4892f3
--- /dev/null
+++ b/Lib/dos_8x3/complex.py
@@ -0,0 +1,275 @@
+# Complex numbers
+# ---------------
+
+# This module represents complex numbers as instances of the class Complex.
+# A Complex instance z has two data attribues, z.re (the real part) and z.im
+# (the imaginary part). In fact, z.re and z.im can have any value -- all
+# arithmetic operators work regardless of the type of z.re and z.im (as long
+# as they support numerical operations).
+#
+# The following functions exist (Complex is actually a class):
+# Complex([re [,im]) -> creates a complex number from a real and an imaginary part
+# IsComplex(z) -> true iff z is a complex number (== has .re and .im attributes)
+# Polar([r [,phi [,fullcircle]]]) ->
+# the complex number z for which r == z.radius() and phi == z.angle(fullcircle)
+# (r and phi default to 0)
+#
+# Complex numbers have the following methods:
+# z.abs() -> absolute value of z
+# z.radius() == z.abs()
+# z.angle([fullcircle]) -> angle from positive X axis; fullcircle gives units
+# z.phi([fullcircle]) == z.angle(fullcircle)
+#
+# These standard functions and unary operators accept complex arguments:
+# abs(z)
+# -z
+# +z
+# not z
+# repr(z) == `z`
+# str(z)
+# hash(z) -> a combination of hash(z.re) and hash(z.im) such that if z.im is zero
+# the result equals hash(z.re)
+# Note that hex(z) and oct(z) are not defined.
+#
+# These conversions accept complex arguments only if their imaginary part is zero:
+# int(z)
+# long(z)
+# float(z)
+#
+# The following operators accept two complex numbers, or one complex number
+# and one real number (int, long or float):
+# z1 + z2
+# z1 - z2
+# z1 * z2
+# z1 / z2
+# pow(z1, z2)
+# cmp(z1, z2)
+# Note that z1 % z2 and divmod(z1, z2) are not defined,
+# nor are shift and mask operations.
+#
+# The standard module math does not support complex numbers.
+# (I suppose it would be easy to implement a cmath module.)
+#
+# Idea:
+# add a class Polar(r, phi) and mixed-mode arithmetic which
+# chooses the most appropriate type for the result:
+# Complex for +,-,cmp
+# Polar for *,/,pow
+
+
+import types, math
+
+if not hasattr(math, 'hypot'):
+ def hypot(x, y):
+ # XXX I know there's a way to compute this without possibly causing
+ # overflow, but I can't remember what it is right now...
+ return math.sqrt(x*x + y*y)
+ math.hypot = hypot
+
+twopi = math.pi*2.0
+halfpi = math.pi/2.0
+
+def IsComplex(obj):
+ return hasattr(obj, 're') and hasattr(obj, 'im')
+
+def Polar(r = 0, phi = 0, fullcircle = twopi):
+ phi = phi * (twopi / fullcircle)
+ return Complex(math.cos(phi)*r, math.sin(phi)*r)
+
+class Complex:
+
+ def __init__(self, re=0, im=0):
+ if IsComplex(re):
+ im = im + re.im
+ re = re.re
+ if IsComplex(im):
+ re = re - im.im
+ im = im.re
+ self.re = re
+ self.im = im
+
+ def __setattr__(self, name, value):
+ if hasattr(self, name):
+ raise TypeError, "Complex numbers have set-once attributes"
+ self.__dict__[name] = value
+
+ def __repr__(self):
+ if not self.im:
+ return 'Complex(%s)' % `self.re`
+ else:
+ return 'Complex(%s, %s)' % (`self.re`, `self.im`)
+
+ def __str__(self):
+ if not self.im:
+ return `self.re`
+ else:
+ return 'Complex(%s, %s)' % (`self.re`, `self.im`)
+
+ def __coerce__(self, other):
+ if IsComplex(other):
+ return self, other
+ return self, Complex(other) # May fail
+
+ def __cmp__(self, other):
+ return cmp(self.re, other.re) or cmp(self.im, other.im)
+
+ def __hash__(self):
+ if not self.im: return hash(self.re)
+ mod = sys.maxint + 1L
+ return int((hash(self.re) + 2L*hash(self.im) + mod) % (2L*mod) - mod)
+
+ def __neg__(self):
+ return Complex(-self.re, -self.im)
+
+ def __pos__(self):
+ return self
+
+ def __abs__(self):
+ return math.hypot(self.re, self.im)
+ ##return math.sqrt(self.re*self.re + self.im*self.im)
+
+
+ def __int__(self):
+ if self.im:
+ raise ValueError, "can't convert Complex with nonzero im to int"
+ return int(self.re)
+
+ def __long__(self):
+ if self.im:
+ raise ValueError, "can't convert Complex with nonzero im to long"
+ return long(self.re)
+
+ def __float__(self):
+ if self.im:
+ raise ValueError, "can't convert Complex with nonzero im to float"
+ return float(self.re)
+
+ def __nonzero__(self):
+ return not (self.re == self.im == 0)
+
+ abs = radius = __abs__
+
+ def angle(self, fullcircle = twopi):
+ return (fullcircle/twopi) * ((halfpi - math.atan2(self.re, self.im)) % twopi)
+
+ phi = angle
+
+ def __add__(self, other):
+ return Complex(self.re + other.re, self.im + other.im)
+
+ __radd__ = __add__
+
+ def __sub__(self, other):
+ return Complex(self.re - other.re, self.im - other.im)
+
+ def __rsub__(self, other):
+ return Complex(other.re - self.re, other.im - self.im)
+
+ def __mul__(self, other):
+ return Complex(self.re*other.re - self.im*other.im,
+ self.re*other.im + self.im*other.re)
+
+ __rmul__ = __mul__
+
+ def __div__(self, other):
+ # Deviating from the general principle of not forcing re or im
+ # to be floats, we cast to float here, otherwise division
+ # of Complex numbers with integer re and im parts would use
+ # the (truncating) integer division
+ d = float(other.re*other.re + other.im*other.im)
+ if not d: raise ZeroDivisionError, 'Complex division'
+ return Complex((self.re*other.re + self.im*other.im) / d,
+ (self.im*other.re - self.re*other.im) / d)
+
+ def __rdiv__(self, other):
+ return other / self
+
+ def __pow__(self, n, z=None):
+ if z is not None:
+ raise TypeError, 'Complex does not support ternary pow()'
+ if IsComplex(n):
+ if n.im: raise TypeError, 'Complex to the Complex power'
+ n = n.re
+ r = pow(self.abs(), n)
+ phi = n*self.angle()
+ return Complex(math.cos(phi)*r, math.sin(phi)*r)
+
+ def __rpow__(self, base):
+ return pow(base, self)
+
+
+# Everything below this point is part of the test suite
+
+def checkop(expr, a, b, value, fuzz = 1e-6):
+ import sys
+ print ' ', a, 'and', b,
+ try:
+ result = eval(expr)
+ except:
+ result = sys.exc_type
+ print '->', result
+ if (type(result) == type('') or type(value) == type('')):
+ ok = result == value
+ else:
+ ok = abs(result - value) <= fuzz
+ if not ok:
+ print '!!\t!!\t!! should be', value, 'diff', abs(result - value)
+
+
+def test():
+ testsuite = {
+ 'a+b': [
+ (1, 10, 11),
+ (1, Complex(0,10), Complex(1,10)),
+ (Complex(0,10), 1, Complex(1,10)),
+ (Complex(0,10), Complex(1), Complex(1,10)),
+ (Complex(1), Complex(0,10), Complex(1,10)),
+ ],
+ 'a-b': [
+ (1, 10, -9),
+ (1, Complex(0,10), Complex(1,-10)),
+ (Complex(0,10), 1, Complex(-1,10)),
+ (Complex(0,10), Complex(1), Complex(-1,10)),
+ (Complex(1), Complex(0,10), Complex(1,-10)),
+ ],
+ 'a*b': [
+ (1, 10, 10),
+ (1, Complex(0,10), Complex(0, 10)),
+ (Complex(0,10), 1, Complex(0,10)),
+ (Complex(0,10), Complex(1), Complex(0,10)),
+ (Complex(1), Complex(0,10), Complex(0,10)),
+ ],
+ 'a/b': [
+ (1., 10, 0.1),
+ (1, Complex(0,10), Complex(0, -0.1)),
+ (Complex(0, 10), 1, Complex(0, 10)),
+ (Complex(0, 10), Complex(1), Complex(0, 10)),
+ (Complex(1), Complex(0,10), Complex(0, -0.1)),
+ ],
+ 'pow(a,b)': [
+ (1, 10, 1),
+ (1, Complex(0,10), 'TypeError'),
+ (Complex(0,10), 1, Complex(0,10)),
+ (Complex(0,10), Complex(1), Complex(0,10)),
+ (Complex(1), Complex(0,10), 'TypeError'),
+ (2, Complex(4,0), 16),
+ ],
+ 'cmp(a,b)': [
+ (1, 10, -1),
+ (1, Complex(0,10), 1),
+ (Complex(0,10), 1, -1),
+ (Complex(0,10), Complex(1), -1),
+ (Complex(1), Complex(0,10), 1),
+ ],
+ }
+ exprs = testsuite.keys()
+ exprs.sort()
+ for expr in exprs:
+ print expr + ':'
+ t = (expr,)
+ for item in testsuite[expr]:
+ apply(checkop, t+item)
+
+
+if __name__ == '__main__':
+ test()
diff --git a/Lib/dos_8x3/formatte.py b/Lib/dos_8x3/formatte.py
new file mode 100755
index 0000000..0266379
--- /dev/null
+++ b/Lib/dos_8x3/formatte.py
@@ -0,0 +1,399 @@
+import regex
+import regsub
+import string
+import sys
+from types import StringType
+
+
+AS_IS = None
+
+
+class NullFormatter:
+
+ def __init__(self): pass
+ def end_paragraph(self, blankline): pass
+ def add_line_break(self): pass
+ def add_hor_rule(self, abswidth=None, percentwidth=1.0,
+ height=None, align=None): pass
+ def add_label_data(self, format, counter): pass
+ def add_flowing_data(self, data): pass
+ def add_literal_data(self, data): pass
+ def flush_softspace(self): pass
+ def push_alignment(self, align): pass
+ def pop_alignment(self): pass
+ def push_font(self, x): pass
+ def pop_font(self): pass
+ def push_margin(self, margin): pass
+ def pop_margin(self): pass
+ def set_spacing(self, spacing): pass
+ def push_style(self, *styles): pass
+ def pop_style(self, n=1): pass
+ def assert_line_data(self, flag=1): pass
+
+
+class AbstractFormatter:
+
+ def __init__(self, writer):
+ self.writer = writer # Output device
+ self.align = None # Current alignment
+ self.align_stack = [] # Alignment stack
+ self.font_stack = [] # Font state
+ self.margin_stack = [] # Margin state
+ self.spacing = None # Vertical spacing state
+ self.style_stack = [] # Other state, e.g. color
+ self.nospace = 1 # Should leading space be suppressed
+ self.softspace = 0 # Should a space be inserted
+ self.para_end = 1 # Just ended a paragraph
+ self.parskip = 0 # Skipped space between paragraphs?
+ self.hard_break = 1 # Have a hard break
+ self.have_label = 0
+
+ def end_paragraph(self, blankline):
+ if not self.hard_break:
+ self.writer.send_line_break()
+ self.have_label = 0
+ if self.parskip < blankline and not self.have_label:
+ self.writer.send_paragraph(blankline - self.parskip)
+ self.parskip = blankline
+ self.have_label = 0
+ self.hard_break = self.nospace = self.para_end = 1
+ self.softspace = 0
+
+ def add_line_break(self):
+ if not (self.hard_break or self.para_end):
+ self.writer.send_line_break()
+ self.have_label = self.parskip = 0
+ self.hard_break = self.nospace = 1
+ self.softspace = 0
+
+ def add_hor_rule(self, *args, **kw):
+ if not self.hard_break:
+ self.writer.send_line_break()
+ apply(self.writer.send_hor_rule, args, kw)
+ self.hard_break = self.nospace = 1
+ self.have_label = self.para_end = self.softspace = self.parskip = 0
+
+ def add_label_data(self, format, counter, blankline = None):
+ if self.have_label or not self.hard_break:
+ self.writer.send_line_break()
+ if not self.para_end:
+ self.writer.send_paragraph((blankline and 1) or 0)
+ if type(format) is StringType:
+ self.writer.send_label_data(self.format_counter(format, counter))
+ else:
+ self.writer.send_label_data(format)
+ self.nospace = self.have_label = self.hard_break = self.para_end = 1
+ self.softspace = self.parskip = 0
+
+ def format_counter(self, format, counter):
+ label = ''
+ for c in format:
+ try:
+ if c == '1':
+ label = label + ('%d' % counter)
+ elif c in 'aA':
+ if counter > 0:
+ label = label + self.format_letter(c, counter)
+ elif c in 'iI':
+ if counter > 0:
+ label = label + self.format_roman(c, counter)
+ else:
+ label = label + c
+ except:
+ label = label + c
+ return label
+
+ def format_letter(self, case, counter):
+ label = ''
+ while counter > 0:
+ counter, x = divmod(counter-1, 26)
+ s = chr(ord(case) + x)
+ label = s + label
+ return label
+
+ def format_roman(self, case, counter):
+ ones = ['i', 'x', 'c', 'm']
+ fives = ['v', 'l', 'd']
+ label, index = '', 0
+ # This will die of IndexError when counter is too big
+ while counter > 0:
+ counter, x = divmod(counter, 10)
+ if x == 9:
+ label = ones[index] + ones[index+1] + label
+ elif x == 4:
+ label = ones[index] + fives[index] + label
+ else:
+ if x >= 5:
+ s = fives[index]
+ x = x-5
+ else:
+ s = ''
+ s = s + ones[index]*x
+ label = s + label
+ index = index + 1
+ if case == 'I':
+ return string.upper(label)
+ return label
+
+ def add_flowing_data(self, data,
+ # These are only here to load them into locals:
+ whitespace = string.whitespace,
+ join = string.join, split = string.split):
+ if not data: return
+ # The following looks a bit convoluted but is a great improvement over
+ # data = regsub.gsub('[' + string.whitespace + ']+', ' ', data)
+ prespace = data[:1] in whitespace
+ postspace = data[-1:] in whitespace
+ data = join(split(data))
+ if self.nospace and not data:
+ return
+ elif prespace or self.softspace:
+ if not data:
+ if not self.nospace:
+ self.softspace = 1
+ self.parskip = 0
+ return
+ if not self.nospace:
+ data = ' ' + data
+ self.hard_break = self.nospace = self.para_end = \
+ self.parskip = self.have_label = 0
+ self.softspace = postspace
+ self.writer.send_flowing_data(data)
+
+ def add_literal_data(self, data):
+ if not data: return
+ # Caller is expected to cause flush_softspace() if needed.
+ self.hard_break = data[-1:] == '\n'
+ self.nospace = self.para_end = self.softspace = \
+ self.parskip = self.have_label = 0
+ self.writer.send_literal_data(data)
+
+ def flush_softspace(self):
+ if self.softspace:
+ self.hard_break = self.nospace = self.para_end = self.parskip = \
+ self.have_label = self.softspace = 0
+ self.writer.send_flowing_data(' ')
+
+ def push_alignment(self, align):
+ if align and align != self.align:
+ self.writer.new_alignment(align)
+ self.align = align
+ self.align_stack.append(align)
+ else:
+ self.align_stack.append(self.align)
+
+ def pop_alignment(self):
+ if self.align_stack:
+ del self.align_stack[-1]
+ if self.align_stack:
+ self.align = align = self.align_stack[-1]
+ self.writer.new_alignment(align)
+ else:
+ self.align = None
+ self.writer.new_alignment(None)
+
+ def push_font(self, (size, i, b, tt)):
+ if self.softspace:
+ self.hard_break = self.nospace = self.para_end = self.softspace = 0
+ self.writer.send_flowing_data(' ')
+ if self.font_stack:
+ csize, ci, cb, ctt = self.font_stack[-1]
+ if size is AS_IS: size = csize
+ if i is AS_IS: i = ci
+ if b is AS_IS: b = cb
+ if tt is AS_IS: tt = ctt
+ font = (size, i, b, tt)
+ self.font_stack.append(font)
+ self.writer.new_font(font)
+
+ def pop_font(self):
+ if self.softspace:
+ self.hard_break = self.nospace = self.para_end = self.softspace = 0
+ self.writer.send_flowing_data(' ')
+ if self.font_stack:
+ del self.font_stack[-1]
+ if self.font_stack:
+ font = self.font_stack[-1]
+ else:
+ font = None
+ self.writer.new_font(font)
+
+ def push_margin(self, margin):
+ self.margin_stack.append(margin)
+ fstack = filter(None, self.margin_stack)
+ if not margin and fstack:
+ margin = fstack[-1]
+ self.writer.new_margin(margin, len(fstack))
+
+ def pop_margin(self):
+ if self.margin_stack:
+ del self.margin_stack[-1]
+ fstack = filter(None, self.margin_stack)
+ if fstack:
+ margin = fstack[-1]
+ else:
+ margin = None
+ self.writer.new_margin(margin, len(fstack))
+
+ def set_spacing(self, spacing):
+ self.spacing = spacing
+ self.writer.new_spacing(spacing)
+
+ def push_style(self, *styles):
+ if self.softspace:
+ self.hard_break = self.nospace = self.para_end = self.softspace = 0
+ self.writer.send_flowing_data(' ')
+ for style in styles:
+ self.style_stack.append(style)
+ self.writer.new_styles(tuple(self.style_stack))
+
+ def pop_style(self, n=1):
+ if self.softspace:
+ self.hard_break = self.nospace = self.para_end = self.softspace = 0
+ self.writer.send_flowing_data(' ')
+ del self.style_stack[-n:]
+ self.writer.new_styles(tuple(self.style_stack))
+
+ def assert_line_data(self, flag=1):
+ self.nospace = self.hard_break = not flag
+ self.para_end = self.have_label = 0
+
+
+class NullWriter:
+ """Minimal writer interface to use in testing.
+ """
+ def __init__(self): pass
+ def new_alignment(self, align): pass
+ def new_font(self, font): pass
+ def new_margin(self, margin, level): pass
+ def new_spacing(self, spacing): pass
+ def new_styles(self, styles): pass
+ def send_paragraph(self, blankline): pass
+ def send_line_break(self): pass
+ def send_hor_rule(self, *args, **kw): pass
+ def send_label_data(self, data): pass
+ def send_flowing_data(self, data): pass
+ def send_literal_data(self, data): pass
+
+
+class AbstractWriter(NullWriter):
+
+ def __init__(self):
+ pass
+
+ def new_alignment(self, align):
+ print "new_alignment(%s)" % `align`
+
+ def new_font(self, font):
+ print "new_font(%s)" % `font`
+
+ def new_margin(self, margin, level):
+ print "new_margin(%s, %d)" % (`margin`, level)
+
+ def new_spacing(self, spacing):
+ print "new_spacing(%s)" % `spacing`
+
+ def new_styles(self, styles):
+ print "new_styles(%s)" % `styles`
+
+ def send_paragraph(self, blankline):
+ print "send_paragraph(%s)" % `blankline`
+
+ def send_line_break(self):
+ print "send_line_break()"
+
+ def send_hor_rule(self, *args, **kw):
+ print "send_hor_rule()"
+
+ def send_label_data(self, data):
+ print "send_label_data(%s)" % `data`
+
+ def send_flowing_data(self, data):
+ print "send_flowing_data(%s)" % `data`
+
+ def send_literal_data(self, data):
+ print "send_literal_data(%s)" % `data`
+
+
+class DumbWriter(NullWriter):
+
+ def __init__(self, file=None, maxcol=72):
+ self.file = file or sys.stdout
+ self.maxcol = maxcol
+ NullWriter.__init__(self)
+ self.reset()
+
+ def reset(self):
+ self.col = 0
+ self.atbreak = 0
+
+ def send_paragraph(self, blankline):
+ self.file.write('\n' + '\n'*blankline)
+ self.col = 0
+ self.atbreak = 0
+
+ def send_line_break(self):
+ self.file.write('\n')
+ self.col = 0
+ self.atbreak = 0
+
+ def send_hor_rule(self, *args, **kw):
+ self.file.write('\n')
+ self.file.write('-'*self.maxcol)
+ self.file.write('\n')
+ self.col = 0
+ self.atbreak = 0
+
+ def send_literal_data(self, data):
+ self.file.write(data)
+ i = string.rfind(data, '\n')
+ if i >= 0:
+ self.col = 0
+ data = data[i+1:]
+ data = string.expandtabs(data)
+ self.col = self.col + len(data)
+ self.atbreak = 0
+
+ def send_flowing_data(self, data):
+ if not data: return
+ atbreak = self.atbreak or data[0] in string.whitespace
+ col = self.col
+ maxcol = self.maxcol
+ write = self.file.write
+ for word in string.split(data):
+ if atbreak:
+ if col + len(word) >= maxcol:
+ write('\n')
+ col = 0
+ else:
+ write(' ')
+ col = col + 1
+ write(word)
+ col = col + len(word)
+ atbreak = 1
+ self.col = col
+ self.atbreak = data[-1] in string.whitespace
+
+
+def test(file = None):
+ w = DumbWriter()
+ f = AbstractFormatter(w)
+ if file:
+ fp = open(file)
+ elif sys.argv[1:]:
+ fp = open(sys.argv[1])
+ else:
+ fp = sys.stdin
+ while 1:
+ line = fp.readline()
+ if not line:
+ break
+ if line == '\n':
+ f.end_paragraph(1)
+ else:
+ f.add_flowing_data(line)
+ f.end_paragraph(0)
+
+
+if __name__ == '__main__':
+ test()
diff --git a/Lib/dos_8x3/gopherli.py b/Lib/dos_8x3/gopherli.py
new file mode 100755
index 0000000..cf06e95
--- /dev/null
+++ b/Lib/dos_8x3/gopherli.py
@@ -0,0 +1,191 @@
+# Gopher protocol client interface
+
+import string
+
+# Default selector, host and port
+DEF_SELECTOR = '1/'
+DEF_HOST = 'gopher.micro.umn.edu'
+DEF_PORT = 70
+
+# Recognized file types
+A_TEXT = '0'
+A_MENU = '1'
+A_CSO = '2'
+A_ERROR = '3'
+A_MACBINHEX = '4'
+A_PCBINHEX = '5'
+A_UUENCODED = '6'
+A_INDEX = '7'
+A_TELNET = '8'
+A_BINARY = '9'
+A_DUPLICATE = '+'
+A_SOUND = 's'
+A_EVENT = 'e'
+A_CALENDAR = 'c'
+A_HTML = 'h'
+A_TN3270 = 'T'
+A_MIME = 'M'
+A_IMAGE = 'I'
+A_WHOIS = 'w'
+A_QUERY = 'q'
+A_GIF = 'g'
+A_HTML = 'h' # HTML file
+A_WWW = 'w' # WWW address
+A_PLUS_IMAGE = ':'
+A_PLUS_MOVIE = ';'
+A_PLUS_SOUND = '<'
+
+
+# Function mapping all file types to strings; unknown types become TYPE='x'
+_names = dir()
+_type_to_name_map = None
+def type_to_name(gtype):
+ global _type_to_name_map
+ if not _type_to_name_map:
+ for name in _names:
+ if name[:2] == 'A_':
+ _type_to_name_map[eval(name)] = name[2:]
+ if _type_to_name_map.has_key(gtype):
+ return _type_to_name_map[gtype]
+ return 'TYPE=' + `gtype`
+
+# Names for characters and strings
+CRLF = '\r\n'
+TAB = '\t'
+
+# Send a selector to a given host and port, return a file with the reply
+def send_selector(selector, host, port = 0):
+ import socket
+ import string
+ if not port:
+ i = string.find(host, ':')
+ if i >= 0:
+ host, port = host[:i], string.atoi(host[i+1:])
+ if not port:
+ port = DEF_PORT
+ elif type(port) == type(''):
+ port = string.atoi(port)
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ s.connect(host, port)
+ s.send(selector + CRLF)
+ s.shutdown(1)
+ return s.makefile('rb')
+
+# Send a selector and a query string
+def send_query(selector, query, host, port = 0):
+ return send_selector(selector + '\t' + query, host, port)
+
+# The following functions interpret the data returned by the gopher
+# server according to the expected type, e.g. textfile or directory
+
+# Get a directory in the form of a list of entries
+def get_directory(f):
+ import string
+ list = []
+ while 1:
+ line = f.readline()
+ if not line:
+ print '(Unexpected EOF from server)'
+ break
+ if line[-2:] == CRLF:
+ line = line[:-2]
+ elif line[-1:] in CRLF:
+ line = line[:-1]
+ if line == '.':
+ break
+ if not line:
+ print '(Empty line from server)'
+ continue
+ gtype = line[0]
+ parts = string.splitfields(line[1:], TAB)
+ if len(parts) < 4:
+ print '(Bad line from server:', `line`, ')'
+ continue
+ if len(parts) > 4:
+ if parts[4:] != ['+']:
+ print '(Extra info from server:', parts[4:], ')'
+ else:
+ parts.append('')
+ parts.insert(0, gtype)
+ list.append(parts)
+ return list
+
+# Get a text file as a list of lines, with trailing CRLF stripped
+def get_textfile(f):
+ list = []
+ get_alt_textfile(f, list.append)
+ return list
+
+# Get a text file and pass each line to a function, with trailing CRLF stripped
+def get_alt_textfile(f, func):
+ while 1:
+ line = f.readline()
+ if not line:
+ print '(Unexpected EOF from server)'
+ break
+ if line[-2:] == CRLF:
+ line = line[:-2]
+ elif line[-1:] in CRLF:
+ line = line[:-1]
+ if line == '.':
+ break
+ if line[:2] == '..':
+ line = line[1:]
+ func(line)
+
+# Get a binary file as one solid data block
+def get_binary(f):
+ data = f.read()
+ return data
+
+# Get a binary file and pass each block to a function
+def get_alt_binary(f, func, blocksize):
+ while 1:
+ data = f.read(blocksize)
+ if not data:
+ break
+ func(data)
+
+# Trivial test program
+def test():
+ import sys
+ import getopt
+ opts, args = getopt.getopt(sys.argv[1:], '')
+ selector = DEF_SELECTOR
+ type = selector[0]
+ host = DEF_HOST
+ port = DEF_PORT
+ if args:
+ host = args[0]
+ args = args[1:]
+ if args:
+ type = args[0]
+ args = args[1:]
+ if len(type) > 1:
+ type, selector = type[0], type
+ else:
+ selector = ''
+ if args:
+ selector = args[0]
+ args = args[1:]
+ query = ''
+ if args:
+ query = args[0]
+ args = args[1:]
+ if type == A_INDEX:
+ f = send_query(selector, query, host)
+ else:
+ f = send_selector(selector, host)
+ if type == A_TEXT:
+ list = get_textfile(f)
+ for item in list: print item
+ elif type in (A_MENU, A_INDEX):
+ list = get_directory(f)
+ for item in list: print item
+ else:
+ data = get_binary(f)
+ print 'binary data:', len(data), 'bytes:', `data[:100]`[:40]
+
+# Run the test when run as script
+if __name__ == '__main__':
+ test()
diff --git a/Lib/dos_8x3/htmlenti.py b/Lib/dos_8x3/htmlenti.py
new file mode 100755
index 0000000..55aefaa
--- /dev/null
+++ b/Lib/dos_8x3/htmlenti.py
@@ -0,0 +1,105 @@
+# Proposed entity definitions for HTML, taken from
+# http://www.w3.org/hypertext/WWW/MarkUp/html-spec/html-spec_14.html
+
+entitydefs = {
+ 'lt': '<',
+ 'gt': '>',
+ 'amp': '&',
+ 'quot': '"',
+ 'nbsp': chr(160), # no-break space
+ 'iexcl': chr(161), # inverted exclamation mark
+ 'cent': chr(162), # cent sign
+ 'pound': chr(163), # pound sterling sign
+ 'curren': chr(164), # general currency sign
+ 'yen': chr(165), # yen sign
+ 'brvbar': chr(166), # broken (vertical) bar
+ 'sect': chr(167), # section sign
+ 'uml': chr(168), # umlaut (dieresis)
+ 'copy': chr(169), # copyright sign
+ 'ordf': chr(170), # ordinal indicator, feminine
+ 'laquo': chr(171), # angle quotation mark, left
+ 'not': chr(172), # not sign
+ 'shy': chr(173), # soft hyphen
+ 'reg': chr(174), # registered sign
+ 'macr': chr(175), # macron
+ 'deg': chr(176), # degree sign
+ 'plusmn': chr(177), # plus-or-minus sign
+ 'sup2': chr(178), # superscript two
+ 'sup3': chr(179), # superscript three
+ 'acute': chr(180), # acute accent
+ 'micro': chr(181), # micro sign
+ 'para': chr(182), # pilcrow (paragraph sign)
+ 'middot': chr(183), # middle dot
+ 'cedil': chr(184), # cedilla
+ 'sup1': chr(185), # superscript one
+ 'ordm': chr(186), # ordinal indicator, masculine
+ 'raquo': chr(187), # angle quotation mark, right
+ 'frac14': chr(188), # fraction one-quarter
+ 'frac12': chr(189), # fraction one-half
+ 'frac34': chr(190), # fraction three-quarters
+ 'iquest': chr(191), # inverted question mark
+ 'Agrave': chr(192), # capital A, grave accent
+ 'Aacute': chr(193), # capital A, acute accent
+ 'Acirc': chr(194), # capital A, circumflex accent
+ 'Atilde': chr(195), # capital A, tilde
+ 'Auml': chr(196), # capital A, dieresis or umlaut mark
+ 'Aring': chr(197), # capital A, ring
+ 'AElig': chr(198), # capital AE diphthong (ligature)
+ 'Ccedil': chr(199), # capital C, cedilla
+ 'Egrave': chr(200), # capital E, grave accent
+ 'Eacute': chr(201), # capital E, acute accent
+ 'Ecirc': chr(202), # capital E, circumflex accent
+ 'Euml': chr(203), # capital E, dieresis or umlaut mark
+ 'Igrave': chr(204), # capital I, grave accent
+ 'Iacute': chr(205), # capital I, acute accent
+ 'Icirc': chr(206), # capital I, circumflex accent
+ 'Iuml': chr(207), # capital I, dieresis or umlaut mark
+ 'ETH': chr(208), # capital Eth, Icelandic
+ 'Ntilde': chr(209), # capital N, tilde
+ 'Ograve': chr(210), # capital O, grave accent
+ 'Oacute': chr(211), # capital O, acute accent
+ 'Ocirc': chr(212), # capital O, circumflex accent
+ 'Otilde': chr(213), # capital O, tilde
+ 'Ouml': chr(214), # capital O, dieresis or umlaut mark
+ 'times': chr(215), # multiply sign
+ 'Oslash': chr(216), # capital O, slash
+ 'Ugrave': chr(217), # capital U, grave accent
+ 'Uacute': chr(218), # capital U, acute accent
+ 'Ucirc': chr(219), # capital U, circumflex accent
+ 'Uuml': chr(220), # capital U, dieresis or umlaut mark
+ 'Yacute': chr(221), # capital Y, acute accent
+ 'THORN': chr(222), # capital THORN, Icelandic
+ 'szlig': chr(223), # small sharp s, German (sz ligature)
+ 'agrave': chr(224), # small a, grave accent
+ 'aacute': chr(225), # small a, acute accent
+ 'acirc': chr(226), # small a, circumflex accent
+ 'atilde': chr(227), # small a, tilde
+ 'auml': chr(228), # small a, dieresis or umlaut mark
+ 'aring': chr(229), # small a, ring
+ 'aelig': chr(230), # small ae diphthong (ligature)
+ 'ccedil': chr(231), # small c, cedilla
+ 'egrave': chr(232), # small e, grave accent
+ 'eacute': chr(233), # small e, acute accent
+ 'ecirc': chr(234), # small e, circumflex accent
+ 'euml': chr(235), # small e, dieresis or umlaut mark
+ 'igrave': chr(236), # small i, grave accent
+ 'iacute': chr(237), # small i, acute accent
+ 'icirc': chr(238), # small i, circumflex accent
+ 'iuml': chr(239), # small i, dieresis or umlaut mark
+ 'eth': chr(240), # small eth, Icelandic
+ 'ntilde': chr(241), # small n, tilde
+ 'ograve': chr(242), # small o, grave accent
+ 'oacute': chr(243), # small o, acute accent
+ 'ocirc': chr(244), # small o, circumflex accent
+ 'otilde': chr(245), # small o, tilde
+ 'ouml': chr(246), # small o, dieresis or umlaut mark
+ 'divide': chr(247), # divide sign
+ 'oslash': chr(248), # small o, slash
+ 'ugrave': chr(249), # small u, grave accent
+ 'uacute': chr(250), # small u, acute accent
+ 'ucirc': chr(251), # small u, circumflex accent
+ 'uuml': chr(252), # small u, dieresis or umlaut mark
+ 'yacute': chr(253), # small y, acute accent
+ 'thorn': chr(254), # small thorn, Icelandic
+ 'yuml': chr(255), # small y, dieresis or umlaut mark
+}
diff --git a/Lib/dos_8x3/importal.py b/Lib/dos_8x3/importal.py
new file mode 100755
index 0000000..780862c
--- /dev/null
+++ b/Lib/dos_8x3/importal.py
@@ -0,0 +1,36 @@
+# THIS IS OBSOLETE -- USE MODULE 'compileall' INSTEAD!
+
+# Utility module to import all modules in the path, in the hope
+# that this will update their ".pyc" files.
+
+import os
+import sys
+
+# Sabotage 'gl' and 'stdwin' to prevent windows popping up...
+for m in 'gl', 'stdwin', 'fl', 'fm':
+ sys.modules[m] = sys
+
+exceptions = ['importall']
+
+for dir in sys.path:
+ print 'Listing', dir
+ try:
+ names = os.listdir(dir)
+ except os.error:
+ print 'Can\'t list', dir
+ names = []
+ names.sort()
+ for name in names:
+ head, tail = name[:-3], name[-3:]
+ if tail == '.py' and head not in exceptions:
+ s = 'import ' + head
+ print s
+ try:
+ exec s + '\n'
+ except KeyboardInterrupt:
+ del names[:]
+ print '\n[interrupt]'
+ break
+ except:
+ print 'Sorry:', sys.exc_type + ':',
+ print sys.exc_value
diff --git a/Lib/dos_8x3/linecach.py b/Lib/dos_8x3/linecach.py
new file mode 100755
index 0000000..7de373f
--- /dev/null
+++ b/Lib/dos_8x3/linecach.py
@@ -0,0 +1,90 @@
+# Cache lines from files.
+# This is intended to read lines from modules imported -- hence if a filename
+# is not found, it will look down the module search path for a file by
+# that name.
+
+import sys
+import os
+from stat import *
+
+def getline(filename, lineno):
+ lines = getlines(filename)
+ if 1 <= lineno <= len(lines):
+ return lines[lineno-1]
+ else:
+ return ''
+
+
+# The cache
+
+cache = {} # The cache
+
+
+# Clear the cache entirely
+
+def clearcache():
+ global cache
+ cache = {}
+
+
+# Get the lines for a file from the cache.
+# Update the cache if it doesn't contain an entry for this file already.
+
+def getlines(filename):
+ if cache.has_key(filename):
+ return cache[filename][2]
+ else:
+ return updatecache(filename)
+
+
+# Discard cache entries that are out of date.
+# (This is not checked upon each call!)
+
+def checkcache():
+ for filename in cache.keys():
+ size, mtime, lines, fullname = cache[filename]
+ try:
+ stat = os.stat(fullname)
+ except os.error:
+ del cache[filename]
+ continue
+ if size <> stat[ST_SIZE] or mtime <> stat[ST_MTIME]:
+ del cache[filename]
+
+
+# Update a cache entry and return its list of lines.
+# If something's wrong, print a message, discard the cache entry,
+# and return an empty list.
+
+def updatecache(filename):
+ if cache.has_key(filename):
+ del cache[filename]
+ if not filename or filename[0] + filename[-1] == '<>':
+ return []
+ fullname = filename
+ try:
+ stat = os.stat(fullname)
+ except os.error, msg:
+ # Try looking through the module search path
+ basename = os.path.split(filename)[1]
+ for dirname in sys.path:
+ fullname = os.path.join(dirname, basename)
+ try:
+ stat = os.stat(fullname)
+ break
+ except os.error:
+ pass
+ else:
+ # No luck
+## print '*** Cannot stat', filename, ':', msg
+ return []
+ try:
+ fp = open(fullname, 'r')
+ lines = fp.readlines()
+ fp.close()
+ except IOError, msg:
+## print '*** Cannot open', fullname, ':', msg
+ return []
+ size, mtime = stat[ST_SIZE], stat[ST_MTIME]
+ cache[filename] = size, mtime, lines, fullname
+ return lines
diff --git a/Lib/dos_8x3/macurl2p.py b/Lib/dos_8x3/macurl2p.py
new file mode 100755
index 0000000..65afe69
--- /dev/null
+++ b/Lib/dos_8x3/macurl2p.py
@@ -0,0 +1,76 @@
+"""Mac specific module for conversion between pathnames and URLs."""
+
+import string
+import urllib
+import os
+
+def url2pathname(pathname):
+ "Convert /-delimited pathname to mac pathname"
+ #
+ # XXXX The .. handling should be fixed...
+ #
+ tp = urllib.splittype(pathname)[0]
+ if tp and tp <> 'file':
+ raise RuntimeError, 'Cannot convert non-local URL to pathname'
+ components = string.split(pathname, '/')
+ # Remove . and embedded ..
+ i = 0
+ while i < len(components):
+ if components[i] == '.':
+ del components[i]
+ elif components[i] == '..' and i > 0 and \
+ components[i-1] not in ('', '..'):
+ del components[i-1:i+1]
+ i = i-1
+ elif components[i] == '' and i > 0 and components[i-1] <> '':
+ del components[i]
+ else:
+ i = i+1
+ if not components[0]:
+ # Absolute unix path, don't start with colon
+ return string.join(components[1:], ':')
+ else:
+ # relative unix path, start with colon. First replace
+ # leading .. by empty strings (giving ::file)
+ i = 0
+ while i < len(components) and components[i] == '..':
+ components[i] = ''
+ i = i + 1
+ return ':' + string.join(components, ':')
+
+def pathname2url(pathname):
+ "convert mac pathname to /-delimited pathname"
+ if '/' in pathname:
+ raise RuntimeError, "Cannot convert pathname containing slashes"
+ components = string.split(pathname, ':')
+ # Replace empty string ('::') by .. (will result in '/../' later)
+ for i in range(1, len(components)):
+ if components[i] == '':
+ components[i] = '..'
+ # Truncate names longer than 31 bytes
+ components = map(lambda x: x[:31], components)
+
+ if os.path.isabs(pathname):
+ return '/' + string.join(components, '/')
+ else:
+ return string.join(components, '/')
+
+def test():
+ for url in ["index.html",
+ "bar/index.html",
+ "/foo/bar/index.html",
+ "/foo/bar/",
+ "/"]:
+ print `url`, '->', `url2pathname(url)`
+ for path in ["drive:",
+ "drive:dir:",
+ "drive:dir:file",
+ "drive:file",
+ "file",
+ ":file",
+ ":dir:",
+ ":dir:file"]:
+ print `path`, '->', `pathname2url(path)`
+
+if __name__ == '__main__':
+ test()
diff --git a/Lib/dos_8x3/mimetool.py b/Lib/dos_8x3/mimetool.py
new file mode 100755
index 0000000..da33a77
--- /dev/null
+++ b/Lib/dos_8x3/mimetool.py
@@ -0,0 +1,187 @@
+# Various tools used by MIME-reading or MIME-writing programs.
+
+
+import os
+import rfc822
+import string
+import tempfile
+
+
+# A derived class of rfc822.Message that knows about MIME headers and
+# contains some hooks for decoding encoded and multipart messages.
+
+class Message(rfc822.Message):
+
+ def __init__(self, fp, seekable = 1):
+ rfc822.Message.__init__(self, fp, seekable)
+ self.encodingheader = \
+ self.getheader('content-transfer-encoding')
+ self.typeheader = \
+ self.getheader('content-type')
+ self.parsetype()
+ self.parseplist()
+
+ def parsetype(self):
+ str = self.typeheader
+ if str == None:
+ str = 'text/plain'
+ if ';' in str:
+ i = string.index(str, ';')
+ self.plisttext = str[i:]
+ str = str[:i]
+ else:
+ self.plisttext = ''
+ fields = string.splitfields(str, '/')
+ for i in range(len(fields)):
+ fields[i] = string.lower(string.strip(fields[i]))
+ self.type = string.joinfields(fields, '/')
+ self.maintype = fields[0]
+ self.subtype = string.joinfields(fields[1:], '/')
+
+ def parseplist(self):
+ str = self.plisttext
+ self.plist = []
+ while str[:1] == ';':
+ str = str[1:]
+ if ';' in str:
+ # XXX Should parse quotes!
+ end = string.index(str, ';')
+ else:
+ end = len(str)
+ f = str[:end]
+ if '=' in f:
+ i = string.index(f, '=')
+ f = string.lower(string.strip(f[:i])) + \
+ '=' + string.strip(f[i+1:])
+ self.plist.append(string.strip(f))
+ str = str[end:]
+
+ def getplist(self):
+ return self.plist
+
+ def getparam(self, name):
+ name = string.lower(name) + '='
+ n = len(name)
+ for p in self.plist:
+ if p[:n] == name:
+ return rfc822.unquote(p[n:])
+ return None
+
+ def getencoding(self):
+ if self.encodingheader == None:
+ return '7bit'
+ return string.lower(self.encodingheader)
+
+ def gettype(self):
+ return self.type
+
+ def getmaintype(self):
+ return self.maintype
+
+ def getsubtype(self):
+ return self.subtype
+
+
+
+
+# Utility functions
+# -----------------
+
+
+# Return a random string usable as a multipart boundary.
+# The method used is so that it is *very* unlikely that the same
+# string of characters will every occur again in the Universe,
+# so the caller needn't check the data it is packing for the
+# occurrence of the boundary.
+#
+# The boundary contains dots so you have to quote it in the header.
+
+_prefix = None
+
+def choose_boundary():
+ global _prefix
+ import time
+ import rand
+ if _prefix == None:
+ import socket
+ import os
+ hostid = socket.gethostbyname(socket.gethostname())
+ uid = `os.getuid()`
+ pid = `os.getpid()`
+ seed = `rand.rand()`
+ _prefix = hostid + '.' + uid + '.' + pid
+ timestamp = `int(time.time())`
+ seed = `rand.rand()`
+ return _prefix + '.' + timestamp + '.' + seed
+
+
+# Subroutines for decoding some common content-transfer-types
+
+# XXX This requires that uudecode and mmencode are in $PATH
+
+def decode(input, output, encoding):
+ if decodetab.has_key(encoding):
+ pipethrough(input, decodetab[encoding], output)
+ else:
+ raise ValueError, \
+ 'unknown Content-Transfer-Encoding: %s' % encoding
+
+def encode(input, output, encoding):
+ if encodetab.has_key(encoding):
+ pipethrough(input, encodetab[encoding], output)
+ else:
+ raise ValueError, \
+ 'unknown Content-Transfer-Encoding: %s' % encoding
+
+uudecode_pipe = '''(
+TEMP=/tmp/@uu.$$
+sed "s%^begin [0-7][0-7]* .*%begin 600 $TEMP%" | uudecode
+cat $TEMP
+rm $TEMP
+)'''
+
+decodetab = {
+ 'uuencode': uudecode_pipe,
+ 'x-uuencode': uudecode_pipe,
+ 'quoted-printable': 'mmencode -u -q',
+ 'base64': 'mmencode -u -b',
+}
+
+encodetab = {
+ 'x-uuencode': 'uuencode tempfile',
+ 'uuencode': 'uuencode tempfile',
+ 'quoted-printable': 'mmencode -q',
+ 'base64': 'mmencode -b',
+}
+
+def pipeto(input, command):
+ pipe = os.popen(command, 'w')
+ copyliteral(input, pipe)
+ pipe.close()
+
+def pipethrough(input, command, output):
+ tempname = tempfile.mktemp()
+ try:
+ temp = open(tempname, 'w')
+ except IOError:
+ print '*** Cannot create temp file', `tempname`
+ return
+ copyliteral(input, temp)
+ temp.close()
+ pipe = os.popen(command + ' <' + tempname, 'r')
+ copybinary(pipe, output)
+ pipe.close()
+ os.unlink(tempname)
+
+def copyliteral(input, output):
+ while 1:
+ line = input.readline()
+ if not line: break
+ output.write(line)
+
+def copybinary(input, output):
+ BUFSIZE = 8192
+ while 1:
+ line = input.read(BUFSIZE)
+ if not line: break
+ output.write(line)
diff --git a/Lib/dos_8x3/multifil.py b/Lib/dos_8x3/multifil.py
new file mode 100755
index 0000000..71e0dd0
--- /dev/null
+++ b/Lib/dos_8x3/multifil.py
@@ -0,0 +1,128 @@
+# A class that makes each part of a multipart message "feel" like an
+# ordinary file, as long as you use fp.readline(). Allows recursive
+# use, for nested multipart messages. Probably best used together
+# with module mimetools.
+#
+# Suggested use:
+#
+# real_fp = open(...)
+# fp = MultiFile(real_fp)
+#
+# "read some lines from fp"
+# fp.push(separator)
+# while 1:
+# "read lines from fp until it returns an empty string" (A)
+# if not fp.next(): break
+# fp.pop()
+# "read remaining lines from fp until it returns an empty string"
+#
+# The latter sequence may be used recursively at (A).
+# It is also allowed to use multiple push()...pop() sequences.
+# Note that if a nested multipart message is terminated by a separator
+# for an outer message, this is not reported, even though it is really
+# illegal input.
+
+import sys
+import string
+
+err = sys.stderr.write
+
+Error = 'multifile.Error'
+
+class MultiFile:
+ #
+ def __init__(self, fp):
+ self.fp = fp
+ self.stack = [] # Grows down
+ self.level = 0
+ self.last = 0
+ self.start = self.fp.tell()
+ self.posstack = [] # Grows down
+ #
+ def tell(self):
+ if self.level > 0:
+ return self.lastpos
+ return self.fp.tell() - self.start
+ #
+ def seek(self, pos):
+ if not 0 <= pos <= self.tell() or \
+ self.level > 0 and pos > self.lastpos:
+ raise Error, 'bad MultiFile.seek() call'
+ self.fp.seek(pos + self.start)
+ self.level = 0
+ self.last = 0
+ #
+ def readline(self):
+ if self.level > 0: return ''
+ line = self.fp.readline()
+ if not line:
+ self.level = len(self.stack)
+ self.last = (self.level > 0)
+ if self.last:
+ err('*** Sudden EOF in MultiFile.readline()\n')
+ return ''
+ if line[:2] <> '--': return line
+ n = len(line)
+ k = n
+ while k > 0 and line[k-1] in string.whitespace: k = k-1
+ mark = line[2:k]
+ if mark[-2:] == '--': mark1 = mark[:-2]
+ else: mark1 = None
+ for i in range(len(self.stack)):
+ sep = self.stack[i]
+ if sep == mark:
+ self.last = 0
+ break
+ elif mark1 <> None and sep == mark1:
+ self.last = 1
+ break
+ else:
+ return line
+ # Get here after break out of loop
+ self.lastpos = self.tell() - len(line)
+ self.level = i+1
+ if self.level > 1:
+ err('*** Missing endmarker in MultiFile.readline()\n')
+ return ''
+ #
+ def readlines(self):
+ list = []
+ while 1:
+ line = self.readline()
+ if not line: break
+ list.append(line)
+ return list
+ #
+ def read(self): # Note: no size argument -- read until EOF only!
+ return string.joinfields(self.readlines(), '')
+ #
+ def next(self):
+ while self.readline(): pass
+ if self.level > 1 or self.last:
+ return 0
+ self.level = 0
+ self.last = 0
+ self.start = self.fp.tell()
+ return 1
+ #
+ def push(self, sep):
+ if self.level > 0:
+ raise Error, 'bad MultiFile.push() call'
+ self.stack.insert(0, sep)
+ self.posstack.insert(0, self.start)
+ self.start = self.fp.tell()
+ #
+ def pop(self):
+ if self.stack == []:
+ raise Error, 'bad MultiFile.pop() call'
+ if self.level <= 1:
+ self.last = 0
+ else:
+ abslastpos = self.lastpos + self.start
+ self.level = max(0, self.level - 1)
+ del self.stack[0]
+ self.start = self.posstack[0]
+ del self.posstack[0]
+ if self.level > 0:
+ self.lastpos = abslastpos - self.start
+ #
diff --git a/Lib/dos_8x3/nturl2pa.py b/Lib/dos_8x3/nturl2pa.py
new file mode 100755
index 0000000..17f01f5
--- /dev/null
+++ b/Lib/dos_8x3/nturl2pa.py
@@ -0,0 +1,52 @@
+#
+# nturl2path convert a NT pathname to a file URL and
+# vice versa
+
+def url2pathname(url):
+ """ Convert a URL to a DOS path...
+ Currently only works for absolute paths
+
+ ///C|/foo/bar/spam.foo
+
+ becomes
+
+ C:\foo\bar\spam.foo
+ """
+ import string
+ comp = string.splitfields(url, '|')
+ if len(comp) != 2 or comp[0][-1] not in string.letters:
+ error = 'Bad URL: ' + url
+ raise IOError, error
+ drive = string.upper(comp[0][-1])
+ components = string.splitfields(comp[1], '/')
+ path = drive + ':'
+ for comp in components:
+ if comp:
+ path = path + '\\' + comp
+ return path
+
+def pathname2url(p):
+
+ """ Convert a DOS path name to a file url...
+ Currently only works for absolute paths
+
+ C:\foo\bar\spam.foo
+
+ becomes
+
+ ///C|/foo/bar/spam.foo
+ """
+
+ import string
+ comp = string.splitfields(p, ':')
+ if len(comp) != 2 or len(comp[0]) > 1:
+ error = 'Bad path: ' + p
+ raise IOError, error
+
+ drive = string.upper(comp[0])
+ components = string.splitfields(comp[1], '\\')
+ path = '///' + drive + '|'
+ for comp in components:
+ if comp:
+ path = path + '/' + comp
+ return path
diff --git a/Lib/dos_8x3/para.py b/Lib/dos_8x3/para.py
new file mode 100755
index 0000000..c9b3bdd
--- /dev/null
+++ b/Lib/dos_8x3/para.py
@@ -0,0 +1,409 @@
+# Text formatting abstractions
+# Note -- this module is obsolete, it's too slow anyway
+
+
+# Oft-used type object
+Int = type(0)
+
+
+# Represent a paragraph. This is a list of words with associated
+# font and size information, plus indents and justification for the
+# entire paragraph.
+# Once the words have been added to a paragraph, it can be laid out
+# for different line widths. Once laid out, it can be rendered at
+# different screen locations. Once rendered, it can be queried
+# for mouse hits, and parts of the text can be highlighted
+class Para:
+ #
+ def __init__(self):
+ self.words = [] # The words
+ self.just = 'l' # Justification: 'l', 'r', 'lr' or 'c'
+ self.indent_left = self.indent_right = self.indent_hang = 0
+ # Final lay-out parameters, may change
+ self.left = self.top = self.right = self.bottom = \
+ self.width = self.height = self.lines = None
+ #
+ # Add a word, computing size information for it.
+ # Words may also be added manually by appending to self.words
+ # Each word should be a 7-tuple:
+ # (font, text, width, space, stretch, ascent, descent)
+ def addword(self, d, font, text, space, stretch):
+ if font <> None:
+ d.setfont(font)
+ width = d.textwidth(text)
+ ascent = d.baseline()
+ descent = d.lineheight() - ascent
+ spw = d.textwidth(' ')
+ space = space * spw
+ stretch = stretch * spw
+ tuple = (font, text, width, space, stretch, ascent, descent)
+ self.words.append(tuple)
+ #
+ # Hooks to begin and end anchors -- insert numbers in the word list!
+ def bgn_anchor(self, id):
+ self.words.append(id)
+ #
+ def end_anchor(self, id):
+ self.words.append(0)
+ #
+ # Return the total length (width) of the text added so far, in pixels
+ def getlength(self):
+ total = 0
+ for word in self.words:
+ if type(word) <> Int:
+ total = total + word[2] + word[3]
+ return total
+ #
+ # Tab to a given position (relative to the current left indent):
+ # remove all stretch, add fixed space up to the new indent.
+ # If the current position is already beying the tab stop,
+ # don't add any new space (but still remove the stretch)
+ def tabto(self, tab):
+ total = 0
+ as, de = 1, 0
+ for i in range(len(self.words)):
+ word = self.words[i]
+ if type(word) == Int: continue
+ fo, te, wi, sp, st, as, de = word
+ self.words[i] = fo, te, wi, sp, 0, as, de
+ total = total + wi + sp
+ if total < tab:
+ self.words.append(None, '', 0, tab-total, 0, as, de)
+ #
+ # Make a hanging tag: tab to hang, increment indent_left by hang,
+ # and reset indent_hang to -hang
+ def makehangingtag(self, hang):
+ self.tabto(hang)
+ self.indent_left = self.indent_left + hang
+ self.indent_hang = -hang
+ #
+ # Decide where the line breaks will be given some screen width
+ def layout(self, linewidth):
+ self.width = linewidth
+ height = 0
+ self.lines = lines = []
+ avail1 = self.width - self.indent_left - self.indent_right
+ avail = avail1 - self.indent_hang
+ words = self.words
+ i = 0
+ n = len(words)
+ lastfont = None
+ while i < n:
+ firstfont = lastfont
+ charcount = 0
+ width = 0
+ stretch = 0
+ ascent = 0
+ descent = 0
+ lsp = 0
+ j = i
+ while i < n:
+ word = words[i]
+ if type(word) == Int:
+ if word > 0 and width >= avail:
+ break
+ i = i+1
+ continue
+ fo, te, wi, sp, st, as, de = word
+ if width + wi > avail and width > 0 and wi > 0:
+ break
+ if fo <> None:
+ lastfont = fo
+ if width == 0:
+ firstfont = fo
+ charcount = charcount + len(te) + (sp > 0)
+ width = width + wi + sp
+ lsp = sp
+ stretch = stretch + st
+ lst = st
+ ascent = max(ascent, as)
+ descent = max(descent, de)
+ i = i+1
+ while i > j and type(words[i-1]) == Int and \
+ words[i-1] > 0: i = i-1
+ width = width - lsp
+ if i < n:
+ stretch = stretch - lst
+ else:
+ stretch = 0
+ tuple = i-j, firstfont, charcount, width, stretch, \
+ ascent, descent
+ lines.append(tuple)
+ height = height + ascent + descent
+ avail = avail1
+ self.height = height
+ #
+ # Call a function for all words in a line
+ def visit(self, wordfunc, anchorfunc):
+ avail1 = self.width - self.indent_left - self.indent_right
+ avail = avail1 - self.indent_hang
+ v = self.top
+ i = 0
+ for tuple in self.lines:
+ wordcount, firstfont, charcount, width, stretch, \
+ ascent, descent = tuple
+ h = self.left + self.indent_left
+ if i == 0: h = h + self.indent_hang
+ extra = 0
+ if self.just == 'r': h = h + avail - width
+ elif self.just == 'c': h = h + (avail - width) / 2
+ elif self.just == 'lr' and stretch > 0:
+ extra = avail - width
+ v2 = v + ascent + descent
+ for j in range(i, i+wordcount):
+ word = self.words[j]
+ if type(word) == Int:
+ ok = anchorfunc(self, tuple, word, \
+ h, v)
+ if ok <> None: return ok
+ continue
+ fo, te, wi, sp, st, as, de = word
+ if extra > 0 and stretch > 0:
+ ex = extra * st / stretch
+ extra = extra - ex
+ stretch = stretch - st
+ else:
+ ex = 0
+ h2 = h + wi + sp + ex
+ ok = wordfunc(self, tuple, word, h, v, \
+ h2, v2, (j==i), (j==i+wordcount-1))
+ if ok <> None: return ok
+ h = h2
+ v = v2
+ i = i + wordcount
+ avail = avail1
+ #
+ # Render a paragraph in "drawing object" d, using the rectangle
+ # given by (left, top, right) with an unspecified bottom.
+ # Return the computed bottom of the text.
+ def render(self, d, left, top, right):
+ if self.width <> right-left:
+ self.layout(right-left)
+ self.left = left
+ self.top = top
+ self.right = right
+ self.bottom = self.top + self.height
+ self.anchorid = 0
+ try:
+ self.d = d
+ self.visit(self.__class__._renderword, \
+ self.__class__._renderanchor)
+ finally:
+ self.d = None
+ return self.bottom
+ #
+ def _renderword(self, tuple, word, h, v, h2, v2, isfirst, islast):
+ if word[0] <> None: self.d.setfont(word[0])
+ baseline = v + tuple[5]
+ self.d.text((h, baseline - word[5]), word[1])
+ if self.anchorid > 0:
+ self.d.line((h, baseline+2), (h2, baseline+2))
+ #
+ def _renderanchor(self, tuple, word, h, v):
+ self.anchorid = word
+ #
+ # Return which anchor(s) was hit by the mouse
+ def hitcheck(self, mouseh, mousev):
+ self.mouseh = mouseh
+ self.mousev = mousev
+ self.anchorid = 0
+ self.hits = []
+ self.visit(self.__class__._hitcheckword, \
+ self.__class__._hitcheckanchor)
+ return self.hits
+ #
+ def _hitcheckword(self, tuple, word, h, v, h2, v2, isfirst, islast):
+ if self.anchorid > 0 and h <= self.mouseh <= h2 and \
+ v <= self.mousev <= v2:
+ self.hits.append(self.anchorid)
+ #
+ def _hitcheckanchor(self, tuple, word, h, v):
+ self.anchorid = word
+ #
+ # Return whether the given anchor id is present
+ def hasanchor(self, id):
+ return id in self.words or -id in self.words
+ #
+ # Extract the raw text from the word list, substituting one space
+ # for non-empty inter-word space, and terminating with '\n'
+ def extract(self):
+ text = ''
+ for w in self.words:
+ if type(w) <> Int:
+ word = w[1]
+ if w[3]: word = word + ' '
+ text = text + word
+ return text + '\n'
+ #
+ # Return which character position was hit by the mouse, as
+ # an offset in the entire text as returned by extract().
+ # Return None if the mouse was not in this paragraph
+ def whereis(self, d, mouseh, mousev):
+ if mousev < self.top or mousev > self.bottom:
+ return None
+ self.mouseh = mouseh
+ self.mousev = mousev
+ self.lastfont = None
+ self.charcount = 0
+ try:
+ self.d = d
+ return self.visit(self.__class__._whereisword, \
+ self.__class__._whereisanchor)
+ finally:
+ self.d = None
+ #
+ def _whereisword(self, tuple, word, h1, v1, h2, v2, isfirst, islast):
+ fo, te, wi, sp, st, as, de = word
+ if fo <> None: self.lastfont = fo
+ h = h1
+ if isfirst: h1 = 0
+ if islast: h2 = 999999
+ if not (v1 <= self.mousev <= v2 and h1 <= self.mouseh <= h2):
+ self.charcount = self.charcount + len(te) + (sp > 0)
+ return
+ if self.lastfont <> None:
+ self.d.setfont(self.lastfont)
+ cc = 0
+ for c in te:
+ cw = self.d.textwidth(c)
+ if self.mouseh <= h + cw/2:
+ return self.charcount + cc
+ cc = cc+1
+ h = h+cw
+ self.charcount = self.charcount + cc
+ if self.mouseh <= (h+h2) / 2:
+ return self.charcount
+ else:
+ return self.charcount + 1
+ #
+ def _whereisanchor(self, tuple, word, h, v):
+ pass
+ #
+ # Return screen position corresponding to position in paragraph.
+ # Return tuple (h, vtop, vbaseline, vbottom).
+ # This is more or less the inverse of whereis()
+ def screenpos(self, d, pos):
+ if pos < 0:
+ ascent, descent = self.lines[0][5:7]
+ return self.left, self.top, self.top + ascent, \
+ self.top + ascent + descent
+ self.pos = pos
+ self.lastfont = None
+ try:
+ self.d = d
+ ok = self.visit(self.__class__._screenposword, \
+ self.__class__._screenposanchor)
+ finally:
+ self.d = None
+ if ok == None:
+ ascent, descent = self.lines[-1][5:7]
+ ok = self.right, self.bottom - ascent - descent, \
+ self.bottom - descent, self.bottom
+ return ok
+ #
+ def _screenposword(self, tuple, word, h1, v1, h2, v2, isfirst, islast):
+ fo, te, wi, sp, st, as, de = word
+ if fo <> None: self.lastfont = fo
+ cc = len(te) + (sp > 0)
+ if self.pos > cc:
+ self.pos = self.pos - cc
+ return
+ if self.pos < cc:
+ self.d.setfont(self.lastfont)
+ h = h1 + self.d.textwidth(te[:self.pos])
+ else:
+ h = h2
+ ascent, descent = tuple[5:7]
+ return h, v1, v1+ascent, v2
+ #
+ def _screenposanchor(self, tuple, word, h, v):
+ pass
+ #
+ # Invert the stretch of text between pos1 and pos2.
+ # If pos1 is None, the beginning is implied;
+ # if pos2 is None, the end is implied.
+ # Undoes its own effect when called again with the same arguments
+ def invert(self, d, pos1, pos2):
+ if pos1 == None:
+ pos1 = self.left, self.top, self.top, self.top
+ else:
+ pos1 = self.screenpos(d, pos1)
+ if pos2 == None:
+ pos2 = self.right, self.bottom,self.bottom,self.bottom
+ else:
+ pos2 = self.screenpos(d, pos2)
+ h1, top1, baseline1, bottom1 = pos1
+ h2, top2, baseline2, bottom2 = pos2
+ if bottom1 <= top2:
+ d.invert((h1, top1), (self.right, bottom1))
+ h1 = self.left
+ if bottom1 < top2:
+ d.invert((h1, bottom1), (self.right, top2))
+ top1, bottom1 = top2, bottom2
+ d.invert((h1, top1), (h2, bottom2))
+
+
+# Test class Para
+# XXX This was last used on the Mac, hence the weird fonts...
+def test():
+ import stdwin
+ from stdwinevents import *
+ words = 'The', 'quick', 'brown', 'fox', 'jumps', 'over', \
+ 'the', 'lazy', 'dog.'
+ paralist = []
+ for just in 'l', 'r', 'lr', 'c':
+ p = Para()
+ p.just = just
+ p.addword(stdwin, ('New York', 'p', 12), words[0], 1, 1)
+ for word in words[1:-1]:
+ p.addword(stdwin, None, word, 1, 1)
+ p.addword(stdwin, None, words[-1], 2, 4)
+ p.addword(stdwin, ('New York', 'b', 18), 'Bye!', 0, 0)
+ p.addword(stdwin, ('New York', 'p', 10), 'Bye!', 0, 0)
+ paralist.append(p)
+ window = stdwin.open('Para.test()')
+ start = stop = selpara = None
+ while 1:
+ etype, win, detail = stdwin.getevent()
+ if etype == WE_CLOSE:
+ break
+ if etype == WE_SIZE:
+ window.change((0, 0), (1000, 1000))
+ if etype == WE_DRAW:
+ width, height = window.getwinsize()
+ d = None
+ try:
+ d = window.begindrawing()
+ d.cliprect(detail)
+ d.erase(detail)
+ v = 0
+ for p in paralist:
+ v = p.render(d, 0, v, width)
+ if p == selpara and \
+ start <> None and stop <> None:
+ p.invert(d, start, stop)
+ finally:
+ if d: d.close()
+ if etype == WE_MOUSE_DOWN:
+ if selpara and start <> None and stop <> None:
+ d = window.begindrawing()
+ selpara.invert(d, start, stop)
+ d.close()
+ start = stop = selpara = None
+ mouseh, mousev = detail[0]
+ for p in paralist:
+ start = p.whereis(stdwin, mouseh, mousev)
+ if start <> None:
+ selpara = p
+ break
+ if etype == WE_MOUSE_UP and start <> None and selpara:
+ mouseh, mousev = detail[0]
+ stop = selpara.whereis(stdwin, mouseh, mousev)
+ if stop == None: start = selpara = None
+ else:
+ if start > stop:
+ start, stop = stop, start
+ d = window.begindrawing()
+ selpara.invert(d, start, stop)
+ d.close()
+ window.close()
diff --git a/Lib/dos_8x3/posixfil.py b/Lib/dos_8x3/posixfil.py
new file mode 100755
index 0000000..459cd52
--- /dev/null
+++ b/Lib/dos_8x3/posixfil.py
@@ -0,0 +1,207 @@
+#
+# Start of posixfile.py
+#
+
+#
+# Extended file operations
+#
+# f = posixfile.open(filename, [mode, [bufsize]])
+# will create a new posixfile object
+#
+# f = posixfile.fileopen(fileobject)
+# will create a posixfile object from a builtin file object
+#
+# f.file()
+# will return the original builtin file object
+#
+# f.dup()
+# will return a new file object based on a new filedescriptor
+#
+# f.dup2(fd)
+# will return a new file object based on the given filedescriptor
+#
+# f.flags(mode)
+# will turn on the associated flag (merge)
+# mode can contain the following characters:
+#
+# (character representing a flag)
+# a append only flag
+# c close on exec flag
+# n no delay flag
+# s synchronization flag
+# (modifiers)
+# ! turn flags 'off' instead of default 'on'
+# = copy flags 'as is' instead of default 'merge'
+# ? return a string in which the characters represent the flags
+# that are set
+#
+# note: - the '!' and '=' modifiers are mutually exclusive.
+# - the '?' modifier will return the status of the flags after they
+# have been changed by other characters in the mode string
+#
+# f.lock(mode [, len [, start [, whence]]])
+# will (un)lock a region
+# mode can contain the following characters:
+#
+# (character representing type of lock)
+# u unlock
+# r read lock
+# w write lock
+# (modifiers)
+# | wait until the lock can be granted
+# ? return the first lock conflicting with the requested lock
+# or 'None' if there is no conflict. The lock returned is in the
+# format (mode, len, start, whence, pid) where mode is a
+# character representing the type of lock ('r' or 'w')
+#
+# note: - the '?' modifier prevents a region from being locked; it is
+# query only
+#
+
+class _posixfile_:
+ states = ['open', 'closed']
+
+ #
+ # Internal routines
+ #
+ def __repr__(self):
+ file = self._file_
+ return "<%s posixfile '%s', mode '%s' at %s>" % \
+ (self.states[file.closed], file.name, file.mode, \
+ hex(id(self))[2:])
+
+ def __del__(self):
+ self._file_.close()
+
+ #
+ # Initialization routines
+ #
+ def open(self, name, mode='r', bufsize=-1):
+ import __builtin__
+ return self.fileopen(__builtin__.open(name, mode, bufsize))
+
+ def fileopen(self, file):
+ if `type(file)` != "<type 'file'>":
+ raise TypeError, 'posixfile.fileopen() arg must be file object'
+ self._file_ = file
+ # Copy basic file methods
+ for method in file.__methods__:
+ setattr(self, method, getattr(file, method))
+ return self
+
+ #
+ # New methods
+ #
+ def file(self):
+ return self._file_
+
+ def dup(self):
+ import posix
+
+ try: ignore = posix.fdopen
+ except: raise AttributeError, 'dup() method unavailable'
+
+ return posix.fdopen(posix.dup(self._file_.fileno()), self._file_.mode)
+
+ def dup2(self, fd):
+ import posix
+
+ try: ignore = posix.fdopen
+ except: raise AttributeError, 'dup() method unavailable'
+
+ posix.dup2(self._file_.fileno(), fd)
+ return posix.fdopen(fd, self._file_.mode)
+
+ def flags(self, *which):
+ import fcntl, FCNTL
+
+ if which:
+ if len(which) > 1:
+ raise TypeError, 'Too many arguments'
+ which = which[0]
+ else: which = '?'
+
+ l_flags = 0
+ if 'n' in which: l_flags = l_flags | FCNTL.O_NDELAY
+ if 'a' in which: l_flags = l_flags | FCNTL.O_APPEND
+ if 's' in which: l_flags = l_flags | FCNTL.O_SYNC
+
+ file = self._file_
+
+ if '=' not in which:
+ cur_fl = fcntl.fcntl(file.fileno(), FCNTL.F_GETFL, 0)
+ if '!' in which: l_flags = cur_fl & ~ l_flags
+ else: l_flags = cur_fl | l_flags
+
+ l_flags = fcntl.fcntl(file.fileno(), FCNTL.F_SETFL, l_flags)
+
+ if 'c' in which:
+ arg = ('!' not in which) # 0 is don't, 1 is do close on exec
+ l_flags = fcntl.fcntl(file.fileno(), FCNTL.F_SETFD, arg)
+
+ if '?' in which:
+ which = '' # Return current flags
+ l_flags = fcntl.fcntl(file.fileno(), FCNTL.F_GETFL, 0)
+ if FCNTL.O_APPEND & l_flags: which = which + 'a'
+ if fcntl.fcntl(file.fileno(), FCNTL.F_GETFD, 0) & 1:
+ which = which + 'c'
+ if FCNTL.O_NDELAY & l_flags: which = which + 'n'
+ if FCNTL.O_SYNC & l_flags: which = which + 's'
+ return which
+
+ def lock(self, how, *args):
+ import struct, fcntl, FCNTL
+
+ if 'w' in how: l_type = FCNTL.F_WRLCK
+ elif 'r' in how: l_type = FCNTL.F_RDLCK
+ elif 'u' in how: l_type = FCNTL.F_UNLCK
+ else: raise TypeError, 'no type of lock specified'
+
+ if '|' in how: cmd = FCNTL.F_SETLKW
+ elif '?' in how: cmd = FCNTL.F_GETLK
+ else: cmd = FCNTL.F_SETLK
+
+ l_whence = 0
+ l_start = 0
+ l_len = 0
+
+ if len(args) == 1:
+ l_len = args[0]
+ elif len(args) == 2:
+ l_len, l_start = args
+ elif len(args) == 3:
+ l_len, l_start, l_whence = args
+ elif len(args) > 3:
+ raise TypeError, 'too many arguments'
+
+ flock = struct.pack('hhllhh', l_type, l_whence, l_start, l_len, 0, 0)
+ flock = fcntl.fcntl(self._file_.fileno(), cmd, flock)
+
+ if '?' in how:
+ l_type, l_whence, l_start, l_len, l_sysid, l_pid = \
+ struct.unpack('hhllhh', flock)
+ if l_type != FCNTL.F_UNLCK:
+ if l_type == FCNTL.F_RDLCK:
+ return 'r', l_len, l_start, l_whence, l_pid
+ else:
+ return 'w', l_len, l_start, l_whence, l_pid
+
+#
+# Public routine to obtain a posixfile object
+#
+def open(name, mode='r', bufsize=-1):
+ return _posixfile_().open(name, mode, bufsize)
+
+def fileopen(file):
+ return _posixfile_().fileopen(file)
+
+#
+# Constants
+#
+SEEK_SET = 0
+SEEK_CUR = 1
+SEEK_END = 2
+
+#
+# End of posixfile.py
+#
diff --git a/Lib/dos_8x3/posixpat.py b/Lib/dos_8x3/posixpat.py
new file mode 100755
index 0000000..d284834
--- /dev/null
+++ b/Lib/dos_8x3/posixpat.py
@@ -0,0 +1,307 @@
+# Module 'posixpath' -- common operations on POSIX pathnames
+
+import posix
+import stat
+
+
+# Normalize the case of a pathname. Trivial in Posix, string.lower on Mac.
+# On MS-DOS this may also turn slashes into backslashes; however, other
+# normalizations (such as optimizing '../' away) are not allowed
+# (another function should be defined to do that).
+
+def normcase(s):
+ return s
+
+
+# Return wheter a path is absolute.
+# Trivial in Posix, harder on the Mac or MS-DOS.
+
+def isabs(s):
+ return s[:1] == '/'
+
+
+# Join two pathnames.
+# Ignore the first part if the second part is absolute.
+# Insert a '/' unless the first part is empty or already ends in '/'.
+
+def join(a, b):
+ if b[:1] == '/': return b
+ if a == '' or a[-1:] == '/': return a + b
+ # Note: join('x', '') returns 'x/'; is this what we want?
+ return a + '/' + b
+
+
+# Split a path in head (everything up to the last '/') and tail (the
+# rest). If the path ends in '/', tail will be empty. If there is no
+# '/' in the path, head will be empty.
+# Trailing '/'es are stripped from head unless it is the root.
+
+def split(p):
+ import string
+ i = string.rfind(p, '/') + 1
+ head, tail = p[:i], p[i:]
+ if head and head <> '/'*len(head):
+ while head[-1] == '/':
+ head = head[:-1]
+ return head, tail
+
+
+# Split a path in root and extension.
+# The extension is everything starting at the first dot in the last
+# pathname component; the root is everything before that.
+# It is always true that root + ext == p.
+
+def splitext(p):
+ root, ext = '', ''
+ for c in p:
+ if c == '/':
+ root, ext = root + ext + c, ''
+ elif c == '.':
+ if ext:
+ root, ext = root + ext, c
+ else:
+ ext = c
+ elif ext:
+ ext = ext + c
+ else:
+ root = root + c
+ return root, ext
+
+
+# Split a pathname into a drive specification and the rest of the
+# path. Useful on DOS/Windows/NT; on Unix, the drive is always empty.
+
+def splitdrive(p):
+ return '', p
+
+
+# Return the tail (basename) part of a path.
+
+def basename(p):
+ return split(p)[1]
+
+
+# Return the head (dirname) part of a path.
+
+def dirname(p):
+ return split(p)[0]
+
+
+# Return the longest prefix of all list elements.
+
+def commonprefix(m):
+ if not m: return ''
+ prefix = m[0]
+ for item in m:
+ for i in range(len(prefix)):
+ if prefix[:i+1] <> item[:i+1]:
+ prefix = prefix[:i]
+ if i == 0: return ''
+ break
+ return prefix
+
+
+# Is a path a symbolic link?
+# This will always return false on systems where posix.lstat doesn't exist.
+
+def islink(path):
+ try:
+ st = posix.lstat(path)
+ except (posix.error, AttributeError):
+ return 0
+ return stat.S_ISLNK(st[stat.ST_MODE])
+
+
+# Does a path exist?
+# This is false for dangling symbolic links.
+
+def exists(path):
+ try:
+ st = posix.stat(path)
+ except posix.error:
+ return 0
+ return 1
+
+
+# Is a path a posix directory?
+# This follows symbolic links, so both islink() and isdir() can be true
+# for the same path.
+
+def isdir(path):
+ try:
+ st = posix.stat(path)
+ except posix.error:
+ return 0
+ return stat.S_ISDIR(st[stat.ST_MODE])
+
+
+# Is a path a regular file?
+# This follows symbolic links, so both islink() and isfile() can be true
+# for the same path.
+
+def isfile(path):
+ try:
+ st = posix.stat(path)
+ except posix.error:
+ return 0
+ return stat.S_ISREG(st[stat.ST_MODE])
+
+
+# Are two filenames really pointing to the same file?
+
+def samefile(f1, f2):
+ s1 = posix.stat(f1)
+ s2 = posix.stat(f2)
+ return samestat(s1, s2)
+
+
+# Are two open files really referencing the same file?
+# (Not necessarily the same file descriptor!)
+# XXX Oops, posix.fstat() doesn't exist yet!
+
+def sameopenfile(fp1, fp2):
+ s1 = posix.fstat(fp1)
+ s2 = posix.fstat(fp2)
+ return samestat(s1, s2)
+
+
+# Are two stat buffers (obtained from stat, fstat or lstat)
+# describing the same file?
+
+def samestat(s1, s2):
+ return s1[stat.ST_INO] == s2[stat.ST_INO] and \
+ s1[stat.ST_DEV] == s2[stat.ST_DEV]
+
+
+# Is a path a mount point?
+# (Does this work for all UNIXes? Is it even guaranteed to work by POSIX?)
+
+def ismount(path):
+ try:
+ s1 = posix.stat(path)
+ s2 = posix.stat(join(path, '..'))
+ except posix.error:
+ return 0 # It doesn't exist -- so not a mount point :-)
+ dev1 = s1[stat.ST_DEV]
+ dev2 = s2[stat.ST_DEV]
+ if dev1 != dev2:
+ return 1 # path/.. on a different device as path
+ ino1 = s1[stat.ST_INO]
+ ino2 = s2[stat.ST_INO]
+ if ino1 == ino2:
+ return 1 # path/.. is the same i-node as path
+ return 0
+
+
+# Directory tree walk.
+# For each directory under top (including top itself, but excluding
+# '.' and '..'), func(arg, dirname, filenames) is called, where
+# dirname is the name of the directory and filenames is the list
+# files files (and subdirectories etc.) in the directory.
+# The func may modify the filenames list, to implement a filter,
+# or to impose a different order of visiting.
+
+def walk(top, func, arg):
+ try:
+ names = posix.listdir(top)
+ except posix.error:
+ return
+ func(arg, top, names)
+ exceptions = ('.', '..')
+ for name in names:
+ if name not in exceptions:
+ name = join(top, name)
+ if isdir(name) and not islink(name):
+ walk(name, func, arg)
+
+
+# Expand paths beginning with '~' or '~user'.
+# '~' means $HOME; '~user' means that user's home directory.
+# If the path doesn't begin with '~', or if the user or $HOME is unknown,
+# the path is returned unchanged (leaving error reporting to whatever
+# function is called with the expanded path as argument).
+# See also module 'glob' for expansion of *, ? and [...] in pathnames.
+# (A function should also be defined to do full *sh-style environment
+# variable expansion.)
+
+def expanduser(path):
+ if path[:1] <> '~':
+ return path
+ i, n = 1, len(path)
+ while i < n and path[i] <> '/':
+ i = i+1
+ if i == 1:
+ if not posix.environ.has_key('HOME'):
+ return path
+ userhome = posix.environ['HOME']
+ else:
+ import pwd
+ try:
+ pwent = pwd.getpwnam(path[1:i])
+ except KeyError:
+ return path
+ userhome = pwent[5]
+ if userhome[-1:] == '/': i = i+1
+ return userhome + path[i:]
+
+
+# Expand paths containing shell variable substitutions.
+# This expands the forms $variable and ${variable} only.
+# Non-existant variables are left unchanged.
+
+_varprog = None
+
+def expandvars(path):
+ global _varprog
+ if '$' not in path:
+ return path
+ if not _varprog:
+ import regex
+ _varprog = regex.compile('$\([a-zA-Z0-9_]+\|{[^}]*}\)')
+ i = 0
+ while 1:
+ i = _varprog.search(path, i)
+ if i < 0:
+ break
+ name = _varprog.group(1)
+ j = i + len(_varprog.group(0))
+ if name[:1] == '{' and name[-1:] == '}':
+ name = name[1:-1]
+ if posix.environ.has_key(name):
+ tail = path[j:]
+ path = path[:i] + posix.environ[name]
+ i = len(path)
+ path = path + tail
+ else:
+ i = j
+ return path
+
+
+# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
+# It should be understood that this may change the meaning of the path
+# if it contains symbolic links!
+
+def normpath(path):
+ import string
+ # Treat initial slashes specially
+ slashes = ''
+ while path[:1] == '/':
+ slashes = slashes + '/'
+ path = path[1:]
+ comps = string.splitfields(path, '/')
+ i = 0
+ while i < len(comps):
+ if comps[i] == '.':
+ del comps[i]
+ elif comps[i] == '..' and i > 0 and \
+ comps[i-1] not in ('', '..'):
+ del comps[i-1:i+1]
+ i = i-1
+ elif comps[i] == '' and i > 0 and comps[i-1] <> '':
+ del comps[i]
+ else:
+ i = i+1
+ # If the path is now empty, substitute '.'
+ if not comps and not slashes:
+ comps.append('.')
+ return slashes + string.joinfields(comps, '/')
diff --git a/Lib/dos_8x3/py_compi.py b/Lib/dos_8x3/py_compi.py
new file mode 100755
index 0000000..2e68ba8
--- /dev/null
+++ b/Lib/dos_8x3/py_compi.py
@@ -0,0 +1,31 @@
+# Routine to "compile" a .py file to a .pyc file.
+# This has intimate knowledge of how Python/import.c does it.
+# By Sjoerd Mullender (I forced him to write it :-).
+
+import imp
+MAGIC = imp.get_magic()
+
+def wr_long(f, x):
+ f.write(chr( x & 0xff))
+ f.write(chr((x >> 8) & 0xff))
+ f.write(chr((x >> 16) & 0xff))
+ f.write(chr((x >> 24) & 0xff))
+
+def compile(file, cfile = None):
+ import os, marshal, __builtin__
+ f = open(file)
+ codestring = f.read()
+ f.close()
+ timestamp = os.stat(file)[8]
+ codeobject = __builtin__.compile(codestring, file, 'exec')
+ if not cfile:
+ cfile = file + 'c'
+ fc = open(cfile, 'wb')
+ fc.write(MAGIC)
+ wr_long(fc, timestamp)
+ marshal.dump(codeobject, fc)
+ fc.close()
+ if os.name == 'mac':
+ import macfs
+ macfs.FSSpec(cfile).SetCreatorType('Pyth', 'PYC ')
+ macfs.FSSpec(file).SetCreatorType('Pyth', 'TEXT')
diff --git a/Lib/dos_8x3/queue.py b/Lib/dos_8x3/queue.py
new file mode 100755
index 0000000..5125fd5
--- /dev/null
+++ b/Lib/dos_8x3/queue.py
@@ -0,0 +1,121 @@
+# A multi-producer, multi-consumer queue.
+
+Empty = 'Queue.Empty' # Exception raised by get_nowait()
+
+class Queue:
+
+ # Initialize a queue object with a given maximum size
+ # (If maxsize is <= 0, the maximum size is infinite)
+ def __init__(self, maxsize):
+ import thread
+ self._init(maxsize)
+ self.mutex = thread.allocate_lock()
+ self.esema = thread.allocate_lock()
+ self.esema.acquire_lock()
+ self.fsema = thread.allocate_lock()
+
+ # Get an approximation of the queue size (not reliable!)
+ def qsize(self):
+ self.mutex.acquire_lock()
+ n = self._qsize()
+ self.mutex.release_lock()
+ return n
+
+ # Check if the queue is empty (not reliable!)
+ def empty(self):
+ self.mutex.acquire_lock()
+ n = self._empty()
+ self.mutex.release_lock()
+ return n
+
+ # Check if the queue is full (not reliable!)
+ def full(self):
+ self.mutex.acquire_lock()
+ n = self._full()
+ self.mutex.release_lock()
+ return n
+
+ # Put a new item into the queue
+ def put(self, item):
+ self.fsema.acquire_lock()
+ self.mutex.acquire_lock()
+ was_empty = self._empty()
+ self._put(item)
+ if was_empty:
+ self.esema.release_lock()
+ if not self._full():
+ self.fsema.release_lock()
+ self.mutex.release_lock()
+
+ # Get an item from the queue,
+ # blocking if necessary until one is available
+ def get(self):
+ self.esema.acquire_lock()
+ self.mutex.acquire_lock()
+ was_full = self._full()
+ item = self._get()
+ if was_full:
+ self.fsema.release_lock()
+ if not self._empty():
+ self.esema.release_lock()
+ self.mutex.release_lock()
+ return item
+
+ # Get an item from the queue if one is immediately available,
+ # raise Empty if the queue is empty or temporarily unavailable
+ def get_nowait(self):
+ locked = self.esema.acquire_lock(0)
+ self.mutex.acquire_lock()
+ if self._empty():
+ # The queue is empyt -- we can't have esema
+ self.mutex.release_lock()
+ raise Empty
+ if not locked:
+ locked = self.esema.acquire_lock(0)
+ if not locked:
+ # Somebody else has esema
+ # but we have mutex --
+ # go out of their way
+ self.mutex.release_lock()
+ raise Empty
+ was_full = self._full()
+ item = self._get()
+ if was_full:
+ self.fsema.release_lock()
+ if not self._empty():
+ self.esema.release_lock()
+ self.mutex.release_lock()
+ return item
+
+ # XXX Need to define put_nowait() as well.
+
+
+ # Override these methods to implement other queue organizations
+ # (e.g. stack or priority queue).
+ # These will only be called with appropriate locks held
+
+ # Initialize the queue representation
+ def _init(self, maxsize):
+ self.maxsize = maxsize
+ self.queue = []
+
+ def _qsize(self):
+ return len(self.queue)
+
+ # Check wheter the queue is empty
+ def _empty(self):
+ return not self.queue
+
+ # Check whether the queue is full
+ def _full(self):
+ return self.maxsize > 0 and len(self.queue) == self.maxsize
+
+ # Put a new item in the queue
+ def _put(self, item):
+ self.queue.append(item)
+
+ # Get an item from the queue
+ def _get(self):
+ item = self.queue[0]
+ del self.queue[0]
+ return item
diff --git a/Lib/dos_8x3/regex_sy.py b/Lib/dos_8x3/regex_sy.py
new file mode 100755
index 0000000..bb80f4e
--- /dev/null
+++ b/Lib/dos_8x3/regex_sy.py
@@ -0,0 +1,41 @@
+# These bits are passed to regex.set_syntax() to choose among
+# alternative regexp syntaxes.
+
+# 1 means plain parentheses serve as grouping, and backslash
+# parentheses are needed for literal searching.
+# 0 means backslash-parentheses are grouping, and plain parentheses
+# are for literal searching.
+RE_NO_BK_PARENS = 1
+
+# 1 means plain | serves as the "or"-operator, and \| is a literal.
+# 0 means \| serves as the "or"-operator, and | is a literal.
+RE_NO_BK_VBAR = 2
+
+# 0 means plain + or ? serves as an operator, and \+, \? are literals.
+# 1 means \+, \? are operators and plain +, ? are literals.
+RE_BK_PLUS_QM = 4
+
+# 1 means | binds tighter than ^ or $.
+# 0 means the contrary.
+RE_TIGHT_VBAR = 8
+
+# 1 means treat \n as an _OR operator
+# 0 means treat it as a normal character
+RE_NEWLINE_OR = 16
+
+# 0 means that a special characters (such as *, ^, and $) always have
+# their special meaning regardless of the surrounding context.
+# 1 means that special characters may act as normal characters in some
+# contexts. Specifically, this applies to:
+# ^ - only special at the beginning, or after ( or |
+# $ - only special at the end, or before ) or |
+# *, +, ? - only special when not after the beginning, (, or |
+RE_CONTEXT_INDEP_OPS = 32
+
+# Now define combinations of bits for the standard possibilities.
+RE_SYNTAX_AWK = (RE_NO_BK_PARENS | RE_NO_BK_VBAR | RE_CONTEXT_INDEP_OPS)
+RE_SYNTAX_EGREP = (RE_SYNTAX_AWK | RE_NEWLINE_OR)
+RE_SYNTAX_GREP = (RE_BK_PLUS_QM | RE_NEWLINE_OR)
+RE_SYNTAX_EMACS = 0
+
+# (Python's obsolete "regexp" module used a syntax similar to awk.)
diff --git a/Lib/dos_8x3/simpleht.py b/Lib/dos_8x3/simpleht.py
new file mode 100755
index 0000000..dd3107a
--- /dev/null
+++ b/Lib/dos_8x3/simpleht.py
@@ -0,0 +1,168 @@
+"""Simple HTTP Server.
+
+This module builds on BaseHTTPServer by implementing the standard GET
+and HEAD requests in a fairly straightforward manner.
+
+"""
+
+
+__version__ = "0.3"
+
+
+import os
+import pwd
+import sys
+import time
+import socket
+import string
+import posixpath
+import SocketServer
+import BaseHTTPServer
+
+
+def nobody_uid():
+ """Internal routine to get nobody's uid"""
+ try:
+ nobody = pwd.getpwnam('nobody')[2]
+ except pwd.error:
+ nobody = 1 + max(map(lambda x: x[2], pwd.getpwall()))
+ return nobody
+
+nobody = nobody_uid()
+
+
+class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+
+ """Simple HTTP request handler with GET and HEAD commands.
+
+ This serves files from the current directory and any of its
+ subdirectories. It assumes that all files are plain text files
+ unless they have the extension ".html" in which case it assumes
+ they are HTML files.
+
+ The GET and HEAD requests are identical except that the HEAD
+ request omits the actual contents of the file.
+
+ """
+
+ server_version = "SimpleHTTP/" + __version__
+
+ def do_GET(self):
+ """Serve a GET request."""
+ f = self.send_head()
+ if f:
+ self.copyfile(f, self.wfile)
+ f.close()
+
+ def do_HEAD(self):
+ """Serve a HEAD request."""
+ f = self.send_head()
+ if f:
+ f.close()
+
+ def send_head(self):
+ """Common code for GET and HEAD commands.
+
+ This sends the response code and MIME headers.
+
+ Return value is either a file object (which has to be copied
+ to the outputfile by the caller unless the command was HEAD,
+ and must be closed by the caller under all circumstances), or
+ None, in which case the caller has nothing further to do.
+
+ """
+ path = self.translate_path(self.path)
+ if os.path.isdir(path):
+ self.send_error(403, "Directory listing not supported")
+ return None
+ try:
+ f = open(path)
+ except IOError:
+ self.send_error(404, "File not found")
+ return None
+ self.send_response(200)
+ self.send_header("Content-type", self.guess_type(path))
+ self.end_headers()
+ return f
+
+ def translate_path(self, path):
+ """Translate a /-separated PATH to the local filename syntax.
+
+ Components that mean special things to the local file system
+ (e.g. drive or directory names) are ignored. (XXX They should
+ probably be diagnosed.)
+
+ """
+ path = posixpath.normpath(path)
+ words = string.splitfields(path, '/')
+ words = filter(None, words)
+ path = os.getcwd()
+ for word in words:
+ drive, word = os.path.splitdrive(word)
+ head, word = os.path.split(word)
+ if word in (os.curdir, os.pardir): continue
+ path = os.path.join(path, word)
+ return path
+
+ def copyfile(self, source, outputfile):
+ """Copy all data between two file objects.
+
+ The SOURCE argument is a file object open for reading
+ (or anything with a read() method) and the DESTINATION
+ argument is a file object open for writing (or
+ anything with a write() method).
+
+ The only reason for overriding this would be to change
+ the block size or perhaps to replace newlines by CRLF
+ -- note however that this the default server uses this
+ to copy binary data as well.
+
+ """
+
+ BLOCKSIZE = 8192
+ while 1:
+ data = source.read(BLOCKSIZE)
+ if not data: break
+ outputfile.write(data)
+
+ def guess_type(self, path):
+ """Guess the type of a file.
+
+ Argument is a PATH (a filename).
+
+ Return value is a string of the form type/subtype,
+ usable for a MIME Content-type header.
+
+ The default implementation looks the file's extension
+ up in the table self.extensions_map, using text/plain
+ as a default; however it would be permissible (if
+ slow) to look inside the data to make a better guess.
+
+ """
+
+ base, ext = posixpath.splitext(path)
+ if self.extensions_map.has_key(ext):
+ return self.extensions_map[ext]
+ ext = string.lower(ext)
+ if self.extensions_map.has_key(ext):
+ return self.extensions_map[ext]
+ else:
+ return self.extensions_map['']
+
+ extensions_map = {
+ '': 'text/plain', # Default, *must* be present
+ '.html': 'text/html',
+ '.htm': 'text/html',
+ '.gif': 'image/gif',
+ '.jpg': 'image/jpeg',
+ '.jpeg': 'image/jpeg',
+ }
+
+
+def test(HandlerClass = SimpleHTTPRequestHandler,
+ ServerClass = SocketServer.TCPServer):
+ BaseHTTPServer.test(HandlerClass, ServerClass)
+
+
+if __name__ == '__main__':
+ test()
diff --git a/Lib/dos_8x3/socketse.py b/Lib/dos_8x3/socketse.py
new file mode 100755
index 0000000..9a646ab
--- /dev/null
+++ b/Lib/dos_8x3/socketse.py
@@ -0,0 +1,413 @@
+"""Generic socket server classes.
+
+This module tries to capture the various aspects of defining a server:
+
+- address family:
+ - AF_INET: IP (Internet Protocol) sockets (default)
+ - AF_UNIX: Unix domain sockets
+ - others, e.g. AF_DECNET are conceivable (see <socket.h>
+- socket type:
+ - SOCK_STREAM (reliable stream, e.g. TCP)
+ - SOCK_DGRAM (datagrams, e.g. UDP)
+- client address verification before further looking at the request
+ (This is actually a hook for any processing that needs to look
+ at the request before anything else, e.g. logging)
+- how to handle multiple requests:
+ - synchronous (one request is handled at a time)
+ - forking (each request is handled by a new process)
+ - threading (each request is handled by a new thread)
+
+The classes in this module favor the server type that is simplest to
+write: a synchronous TCP/IP server. This is bad class design, but
+save some typing. (There's also the issue that a deep class hierarchy
+slows down method lookups.)
+
+There are four classes in an inheritance diagram that represent
+synchronous servers of four types:
+
+ +-----------+ +------------------+
+ | TCPServer |------->| UnixStreamServer |
+ +-----------+ +------------------+
+ |
+ v
+ +-----------+ +--------------------+
+ | UDPServer |------->| UnixDatagramServer |
+ +-----------+ +--------------------+
+
+(Note that UnixDatagramServer derives from UDPServer, not from
+UnixStreamServer -- the only difference between an IP and a Unix
+stream server is the address family, which is simply repeated in both
+unix server classes.)
+
+Forking and threading versions of each type of server can be created
+using the ForkingServer and ThreadingServer mix-in classes. For
+instance, a threading UDP server class is created as follows:
+
+ class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
+
+(The Mix-in class must come first, since it overrides a method defined
+in UDPServer!)
+
+To implement a service, you must derive a class from
+BaseRequestHandler and redefine its handle() method. You can then run
+various versions of the service by combining one of the server classes
+with your request handler class.
+
+The request handler class must be different for datagram or stream
+services. This can be hidden by using the mix-in request handler
+classes StreamRequestHandler or DatagramRequestHandler.
+
+Of course, you still have to use your head!
+
+For instance, it makes no sense to use a forking server if the service
+contains state in memory that can be modified by requests (since the
+modifications in the child process would never reach the initial state
+kept in the parent process and passed to each child). In this case,
+you can use a threading server, but you will probably have to use
+locks to avoid two requests that come in nearly simultaneous to apply
+conflicting changes to the server state.
+
+On the other hand, if you are building e.g. an HTTP server, where all
+data is stored externally (e.g. in the file system), a synchronous
+class will essentially render the service "deaf" while one request is
+being handled -- which may be for a very long time if a client is slow
+to reqd all the data it has requested. Here a threading or forking
+server is appropriate.
+
+In some cases, it may be appropriate to process part of a request
+synchronously, but to finish processing in a forked child depending on
+the request data. This can be implemented by using a synchronous
+server and doing an explicit fork in the request handler class's
+handle() method.
+
+Another approach to handling multiple simultaneous requests in an
+environment that supports neither threads nor fork (or where these are
+too expensive or inappropriate for the service) is to maintain an
+explicit table of partially finished requests and to use select() to
+decide which request to work on next (or whether to handle a new
+incoming request). This is particularly important for stream services
+where each client can potentially be connected for a long time (if
+threads or subprocesses can't be used).
+
+Future work:
+- Standard classes for Sun RPC (which uses either UDP or TCP)
+- Standard mix-in classes to implement various authentication
+ and encryption schemes
+- Standard framework for select-based multiplexing
+
+XXX Open problems:
+- What to do with out-of-band data?
+
+"""
+
+
+__version__ = "0.2"
+
+
+import socket
+import sys
+import os
+
+
+class TCPServer:
+
+ """Base class for various socket-based server classes.
+
+ Defaults to synchronous IP stream (i.e., TCP).
+
+ Methods for the caller:
+
+ - __init__(server_address, RequestHandlerClass)
+ - serve_forever()
+ - handle_request() # if you don't use serve_forever()
+ - fileno() -> int # for select()
+
+ Methods that may be overridden:
+
+ - server_bind()
+ - server_activate()
+ - get_request() -> request, client_address
+ - verify_request(request, client_address)
+ - process_request(request, client_address)
+ - handle_error()
+
+ Methods for derived classes:
+
+ - finish_request(request, client_address)
+
+ Class variables that may be overridden by derived classes or
+ instances:
+
+ - address_family
+ - socket_type
+ - request_queue_size (only for stream sockets)
+
+ Instance variables:
+
+ - server_address
+ - RequestHandlerClass
+ - socket
+
+ """
+
+ address_family = socket.AF_INET
+
+ socket_type = socket.SOCK_STREAM
+
+ request_queue_size = 5
+
+ def __init__(self, server_address, RequestHandlerClass):
+ """Constructor. May be extended, do not override."""
+ self.server_address = server_address
+ self.RequestHandlerClass = RequestHandlerClass
+ self.socket = socket.socket(self.address_family,
+ self.socket_type)
+ self.server_bind()
+ self.server_activate()
+
+ def server_bind(self):
+ """Called by constructor to bind the socket.
+
+ May be overridden.
+
+ """
+ self.socket.bind(self.server_address)
+
+ def server_activate(self):
+ """Called by constructor to activate the server.
+
+ May be overridden.
+
+ """
+ self.socket.listen(self.request_queue_size)
+
+ def fileno(self):
+ """Return socket file number.
+
+ Interface required by select().
+
+ """
+ return self.socket.fileno()
+
+ def serve_forever(self):
+ """Handle one request at a time until doomsday."""
+ while 1:
+ self.handle_request()
+
+ # The distinction between handling, getting, processing and
+ # finishing a request is fairly arbitrary. Remember:
+ #
+ # - handle_request() is the top-level call. It calls
+ # get_request(), verify_request() and process_request()
+ # - get_request() is different for stream or datagram sockets
+ # - process_request() is the place that may fork a new process
+ # or create a new thread to finish the request
+ # - finish_request() instantiates the request handler class;
+ # this constructor will handle the request all by itself
+
+ def handle_request(self):
+ """Handle one request, possibly blocking."""
+ request, client_address = self.get_request()
+ if self.verify_request(request, client_address):
+ try:
+ self.process_request(request, client_address)
+ except:
+ self.handle_error(request, client_address)
+
+ def get_request(self):
+ """Get the request and client address from the socket.
+
+ May be overridden.
+
+ """
+ return self.socket.accept()
+
+ def verify_request(self, request, client_address):
+ """Verify the request. May be overridden.
+
+ Return true if we should proceed with this request.
+
+ """
+ return 1
+
+ def process_request(self, request, client_address):
+ """Call finish_request.
+
+ Overridden by ForkingMixIn and ThreadingMixIn.
+
+ """
+ self.finish_request(request, client_address)
+
+ def finish_request(self, request, client_address):
+ """Finish one request by instantiating RequestHandlerClass."""
+ self.RequestHandlerClass(request, client_address, self)
+
+ def handle_error(self, request, client_address):
+ """Handle an error gracefully. May be overridden.
+
+ The default is to print a traceback and continue.
+
+ """
+ exc, value, tb = sys.exc_type, sys.exc_value, sys.exc_traceback
+ print '-'*40
+ print 'Exception happened during processing of request from',
+ print client_address
+ import traceback
+ traceback.print_exception(exc, value, tb)
+ print '-'*40
+
+
+class UDPServer(TCPServer):
+
+ """UDP server class."""
+
+ socket_type = socket.SOCK_DGRAM
+
+ max_packet_size = 8192
+
+ def get_request(self):
+ return self.socket.recvfrom(max_packet_size)
+
+
+if hasattr(socket, 'AF_UNIX'):
+
+ class UnixStreamServer(TCPServer):
+
+ address_family = socket.AF_UNIX
+
+
+ class UnixDatagramServer(UDPServer):
+
+ address_family = socket.AF_UNIX
+
+
+class ForkingMixIn:
+
+ """Mix-in class to handle each request in a new process."""
+
+ active_children = None
+
+ def collect_children(self):
+ """Internal routine to wait for died children."""
+ while self.active_children:
+ pid, status = os.waitpid(0, os.WNOHANG)
+ if not pid: break
+ self.active_children.remove(pid)
+
+ def process_request(self, request, client_address):
+ """Fork a new subprocess to process the request."""
+ self.collect_children()
+ pid = os.fork()
+ if pid:
+ # Parent process
+ if self.active_children is None:
+ self.active_children = []
+ self.active_children.append(pid)
+ return
+ else:
+ # Child process.
+ # This must never return, hence os._exit()!
+ try:
+ self.finish_request(request, client_address)
+ os._exit(0)
+ except:
+ try:
+ self.handle_error(request,
+ client_address)
+ finally:
+ os._exit(1)
+
+
+class ThreadingMixIn:
+
+ """Mix-in class to handle each request in a new thread."""
+
+ def process_request(self, request, client_address):
+ """Start a new thread to process the request."""
+ import thread
+ thread.start_new_thread(self.finish_request,
+ (request, client_address))
+
+
+class ForkingUDPServer(ForkingMixIn, UDPServer): pass
+class ForkingTCPServer(ForkingMixIn, TCPServer): pass
+
+class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
+class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
+
+
+class BaseRequestHandler:
+
+ """Base class for request handler classes.
+
+ This class is instantiated for each request to be handled. The
+ constructor sets the instance variables request, client_address
+ and server, and then calls the handle() method. To implement a
+ specific service, all you need to do is to derive a class which
+ defines a handle() method.
+
+ The handle() method can find the request as self.request, the
+ client address as self.client_request, and the server (in case it
+ needs access to per-server information) as self.server. Since a
+ separate instance is created for each request, the handle() method
+ can define arbitrary other instance variariables.
+
+ """
+
+ def __init__(self, request, client_address, server):
+ self.request = request
+ self.client_address = client_address
+ self.server = server
+ try:
+ self.setup()
+ self.handle()
+ self.finish()
+ finally:
+ sys.exc_traceback = None # Help garbage collection
+
+ def setup(self):
+ pass
+
+ def __del__(self):
+ pass
+
+ def handle(self):
+ pass
+
+ def finish(self):
+ pass
+
+
+# The following two classes make it possible to use the same service
+# class for stream or datagram servers.
+# Each class sets up these instance variables:
+# - rfile: a file object from which receives the request is read
+# - wfile: a file object to which the reply is written
+# When the handle() method returns, wfile is flushed properly
+
+
+class StreamRequestHandler(BaseRequestHandler):
+
+ """Define self.rfile and self.wfile for stream sockets."""
+
+ def setup(self):
+ self.connection = self.request
+ self.rfile = self.connection.makefile('rb')
+ self.wfile = self.connection.makefile('wb', 0)
+
+ def finish(self):
+ self.wfile.flush()
+
+
+class DatagramRequestHandler(BaseRequestHandler):
+
+ """Define self.rfile and self.wfile for datagram sockets."""
+
+ def setup(self):
+ import StringIO
+ self.packet, self.socket = self.request
+ self.rfile = StringIO.StringIO(self.packet)
+ self.wfile = StringIO.StringIO(self.packet)
+
+ def finish(self):
+ self.socket.send(self.wfile.getvalue())
diff --git a/Lib/dos_8x3/statcach.py b/Lib/dos_8x3/statcach.py
new file mode 100755
index 0000000..770aef0
--- /dev/null
+++ b/Lib/dos_8x3/statcach.py
@@ -0,0 +1,82 @@
+# Module 'statcache'
+#
+# Maintain a cache of file stats.
+# There are functions to reset the cache or to selectively remove items.
+
+import os
+from stat import *
+
+# The cache.
+# Keys are pathnames, values are `os.stat' outcomes.
+#
+cache = {}
+
+
+# Stat a file, possibly out of the cache.
+#
+def stat(path):
+ if cache.has_key(path):
+ return cache[path]
+ cache[path] = ret = os.stat(path)
+ return ret
+
+
+# Reset the cache completely.
+#
+def reset():
+ global cache
+ cache = {}
+
+
+# Remove a given item from the cache, if it exists.
+#
+def forget(path):
+ if cache.has_key(path):
+ del cache[path]
+
+
+# Remove all pathnames with a given prefix.
+#
+def forget_prefix(prefix):
+ n = len(prefix)
+ for path in cache.keys():
+ if path[:n] == prefix:
+ del cache[path]
+
+
+# Forget about a directory and all entries in it, but not about
+# entries in subdirectories.
+#
+def forget_dir(prefix):
+ if prefix[-1:] == '/' and prefix <> '/':
+ prefix = prefix[:-1]
+ forget(prefix)
+ if prefix[-1:] <> '/':
+ prefix = prefix + '/'
+ n = len(prefix)
+ for path in cache.keys():
+ if path[:n] == prefix:
+ rest = path[n:]
+ if rest[-1:] == '/': rest = rest[:-1]
+ if '/' not in rest:
+ del cache[path]
+
+
+# Remove all pathnames except with a given prefix.
+# Normally used with prefix = '/' after a chdir().
+#
+def forget_except_prefix(prefix):
+ n = len(prefix)
+ for path in cache.keys():
+ if path[:n] <> prefix:
+ del cache[path]
+
+
+# Check for directory.
+#
+def isdir(path):
+ try:
+ st = stat(path)
+ except os.error:
+ return 0
+ return S_ISDIR(st[ST_MODE])
diff --git a/Lib/dos_8x3/stringio.py b/Lib/dos_8x3/stringio.py
new file mode 100755
index 0000000..bbd9428
--- /dev/null
+++ b/Lib/dos_8x3/stringio.py
@@ -0,0 +1,156 @@
+# class StringIO implements file-like objects that read/write a
+# string buffer (a.k.a. "memory files").
+#
+# This implements (nearly) all stdio methods.
+#
+# f = StringIO() # ready for writing
+# f = StringIO(buf) # ready for reading
+# f.close() # explicitly release resources held
+# flag = f.isatty() # always false
+# pos = f.tell() # get current position
+# f.seek(pos) # set current position
+# f.seek(pos, mode) # mode 0: absolute; 1: relative; 2: relative to EOF
+# buf = f.read() # read until EOF
+# buf = f.read(n) # read up to n bytes
+# buf = f.readline() # read until end of line ('\n') or EOF
+# list = f.readlines()# list of f.readline() results until EOF
+# f.write(buf) # write at current position
+# f.writelines(list) # for line in list: f.write(line)
+# f.getvalue() # return whole file's contents as a string
+#
+# Notes:
+# - Using a real file is often faster (but less convenient).
+# - fileno() is left unimplemented so that code which uses it triggers
+# an exception early.
+# - Seeking far beyond EOF and then writing will insert real null
+# bytes that occupy space in the buffer.
+# - There's a simple test set (see end of this file).
+
+import string
+
+class StringIO:
+ def __init__(self, buf = ''):
+ self.buf = buf
+ self.len = len(buf)
+ self.buflist = []
+ self.pos = 0
+ self.closed = 0
+ self.softspace = 0
+ def close(self):
+ if not self.closed:
+ self.closed = 1
+ del self.buf, self.pos
+ def isatty(self):
+ return 0
+ def seek(self, pos, mode = 0):
+ if self.buflist:
+ self.buf = self.buf + string.joinfields(self.buflist, '')
+ self.buflist = []
+ if mode == 1:
+ pos = pos + self.pos
+ elif mode == 2:
+ pos = pos + self.len
+ self.pos = max(0, pos)
+ def tell(self):
+ return self.pos
+ def read(self, n = -1):
+ if self.buflist:
+ self.buf = self.buf + string.joinfields(self.buflist, '')
+ self.buflist = []
+ if n < 0:
+ newpos = self.len
+ else:
+ newpos = min(self.pos+n, self.len)
+ r = self.buf[self.pos:newpos]
+ self.pos = newpos
+ return r
+ def readline(self):
+ if self.buflist:
+ self.buf = self.buf + string.joinfields(self.buflist, '')
+ self.buflist = []
+ i = string.find(self.buf, '\n', self.pos)
+ if i < 0:
+ newpos = self.len
+ else:
+ newpos = i+1
+ r = self.buf[self.pos:newpos]
+ self.pos = newpos
+ return r
+ def readlines(self):
+ lines = []
+ line = self.readline()
+ while line:
+ lines.append(line)
+ line = self.readline()
+ return lines
+ def write(self, s):
+ if not s: return
+ if self.pos > self.len:
+ self.buflist.append('\0'*(self.pos - self.len))
+ self.len = self.pos
+ newpos = self.pos + len(s)
+ if self.pos < self.len:
+ if self.buflist:
+ self.buf = self.buf + string.joinfields(self.buflist, '')
+ self.buflist = []
+ self.buflist = [self.buf[:self.pos], s, self.buf[newpos:]]
+ self.buf = ''
+ else:
+ self.buflist.append(s)
+ self.len = newpos
+ self.pos = newpos
+ def writelines(self, list):
+ self.write(string.joinfields(list, ''))
+ def flush(self):
+ pass
+ def getvalue(self):
+ if self.buflist:
+ self.buf = self.buf + string.joinfields(self.buflist, '')
+ self.buflist = []
+ return self.buf
+
+
+# A little test suite
+
+def test():
+ import sys
+ if sys.argv[1:]:
+ file = sys.argv[1]
+ else:
+ file = '/etc/passwd'
+ lines = open(file, 'r').readlines()
+ text = open(file, 'r').read()
+ f = StringIO()
+ for line in lines[:-2]:
+ f.write(line)
+ f.writelines(lines[-2:])
+ if f.getvalue() != text:
+ raise RuntimeError, 'write failed'
+ length = f.tell()
+ print 'File length =', length
+ f.seek(len(lines[0]))
+ f.write(lines[1])
+ f.seek(0)
+ print 'First line =', `f.readline()`
+ here = f.tell()
+ line = f.readline()
+ print 'Second line =', `line`
+ f.seek(-len(line), 1)
+ line2 = f.read(len(line))
+ if line != line2:
+ raise RuntimeError, 'bad result after seek back'
+ f.seek(len(line2), 1)
+ list = f.readlines()
+ line = list[-1]
+ f.seek(f.tell() - len(line))
+ line2 = f.read()
+ if line != line2:
+ raise RuntimeError, 'bad result after seek back from EOF'
+ print 'Read', len(list), 'more lines'
+ print 'File length =', f.tell()
+ if f.tell() != length:
+ raise RuntimeError, 'bad length'
+ f.close()
+
+if __name__ == '__main__':
+ test()
diff --git a/Lib/dos_8x3/test_aud.py b/Lib/dos_8x3/test_aud.py
new file mode 100755
index 0000000..3acf1bf
--- /dev/null
+++ b/Lib/dos_8x3/test_aud.py
@@ -0,0 +1,202 @@
+# Test audioop.
+import audioop
+
+def gendata1():
+ return '\0\1\2'
+
+def gendata2():
+ if audioop.getsample('\0\1', 2, 0) == 1:
+ return '\0\0\0\1\0\2'
+ else:
+ return '\0\0\1\0\2\0'
+
+def gendata4():
+ if audioop.getsample('\0\0\0\1', 4, 0) == 1:
+ return '\0\0\0\0\0\0\0\1\0\0\0\2'
+ else:
+ return '\0\0\0\0\1\0\0\0\2\0\0\0'
+
+def testmax(data):
+ if audioop.max(data[0], 1) <> 2 or \
+ audioop.max(data[1], 2) <> 2 or \
+ audioop.max(data[2], 4) <> 2:
+ return 0
+ return 1
+
+def testmaxpp(data):
+ if audioop.maxpp(data[0], 1) <> 0 or \
+ audioop.maxpp(data[1], 2) <> 0 or \
+ audioop.maxpp(data[2], 4) <> 0:
+ return 0
+ return 1
+
+def testavg(data):
+ if audioop.avg(data[0], 1) <> 1 or \
+ audioop.avg(data[1], 2) <> 1 or \
+ audioop.avg(data[2], 4) <> 1:
+ return 0
+ return 1
+
+def testavgpp(data):
+ if audioop.avgpp(data[0], 1) <> 0 or \
+ audioop.avgpp(data[1], 2) <> 0 or \
+ audioop.avgpp(data[2], 4) <> 0:
+ return 0
+ return 1
+
+def testrms(data):
+ if audioop.rms(data[0], 1) <> 1 or \
+ audioop.rms(data[1], 2) <> 1 or \
+ audioop.rms(data[2], 4) <> 1:
+ return 0
+ return 1
+
+def testcross(data):
+ if audioop.cross(data[0], 1) <> 0 or \
+ audioop.cross(data[1], 2) <> 0 or \
+ audioop.cross(data[2], 4) <> 0:
+ return 0
+ return 1
+
+def testadd(data):
+ data2 = []
+ for d in data:
+ str = ''
+ for s in d:
+ str = str + chr(ord(s)*2)
+ data2.append(str)
+ if audioop.add(data[0], data[0], 1) <> data2[0] or \
+ audioop.add(data[1], data[1], 2) <> data2[1] or \
+ audioop.add(data[2], data[2], 4) <> data2[2]:
+ return 0
+ return 1
+
+def testbias(data):
+ # Note: this test assumes that avg() works
+ d1 = audioop.bias(data[0], 1, 100)
+ d2 = audioop.bias(data[1], 2, 100)
+ d4 = audioop.bias(data[2], 4, 100)
+ if audioop.avg(d1, 1) <> 101 or \
+ audioop.avg(d2, 2) <> 101 or \
+ audioop.avg(d4, 4) <> 101:
+ return 0
+ return 1
+
+def testlin2lin(data):
+ # too simple: we test only the size
+ for d1 in data:
+ for d2 in data:
+ got = len(d1)/3
+ wtd = len(d2)/3
+ if len(audioop.lin2lin(d1, got, wtd)) <> len(d2):
+ return 0
+ return 1
+
+def testadpcm2lin(data):
+ # Very cursory test
+ if audioop.adpcm2lin('\0\0', 1, None) <> ('\0\0\0\0', (0,0)):
+ return 0
+ return 1
+
+def testlin2adpcm(data):
+ # Very cursory test
+ if audioop.lin2adpcm('\0\0\0\0', 1, None) <> ('\0\0', (0,0)):
+ return 0
+ return 1
+
+def testlin2ulaw(data):
+ if audioop.lin2ulaw(data[0], 1) <> '\377\347\333' or \
+ audioop.lin2ulaw(data[1], 2) <> '\377\377\377' or \
+ audioop.lin2ulaw(data[2], 4) <> '\377\377\377':
+ return 0
+ return 1
+
+def testulaw2lin(data):
+ # Cursory
+ d = audioop.lin2ulaw(data[0], 1)
+ if audioop.ulaw2lin(d, 1) <> data[0]:
+ return 0
+ return 1
+
+def testmul(data):
+ data2 = []
+ for d in data:
+ str = ''
+ for s in d:
+ str = str + chr(ord(s)*2)
+ data2.append(str)
+ if audioop.mul(data[0], 1, 2) <> data2[0] or \
+ audioop.mul(data[1],2, 2) <> data2[1] or \
+ audioop.mul(data[2], 4, 2) <> data2[2]:
+ return 0
+ return 1
+
+def testreverse(data):
+ if audioop.reverse(data[0], 1) <> '\2\1\0':
+ return 0
+ return 1
+
+def testtomono(data):
+ data2 = ''
+ for d in data[0]:
+ data2 = data2 + d + d
+ if audioop.tomono(data2, 1, 0.5, 0.5) <> data[0]:
+ return 0
+ return 1
+
+def testtostereo(data):
+ data2 = ''
+ for d in data[0]:
+ data2 = data2 + d + d
+ if audioop.tostereo(data[0], 1, 1, 1) <> data2:
+ return 0
+ return 1
+
+def testfindfactor(data):
+ if audioop.findfactor(data[1], data[1]) <> 1.0:
+ return 0
+ return 1
+
+def testfindfit(data):
+ if audioop.findfit(data[1], data[1]) <> (0, 1.0):
+ return 0
+ return 1
+
+def testfindmax(data):
+ if audioop.findmax(data[1], 1) <> 2:
+ return 0
+ return 1
+
+def testgetsample(data):
+ for i in range(3):
+ if audioop.getsample(data[0], 1, i) <> i or \
+ audioop.getsample(data[1], 2, i) <> i or \
+ audioop.getsample(data[2], 4, i) <> i:
+ return 0
+ return 1
+
+def testone(name, data):
+ try:
+ func = eval('test'+name)
+ except NameError:
+ print 'No test found for audioop.'+name+'()'
+ return
+ try:
+ rv = func(data)
+ except 'xx':
+ print 'Test FAILED for audioop.'+name+'() (with an exception)'
+ return
+ if not rv:
+ print 'Test FAILED for audioop.'+name+'()'
+
+def testall():
+ data = [gendata1(), gendata2(), gendata4()]
+ names = dir(audioop)
+ # We know there is a routine 'add'
+ routines = []
+ for n in names:
+ if type(eval('audioop.'+n)) == type(audioop.add):
+ routines.append(n)
+ for n in routines:
+ testone(n, data)
+testall()
diff --git a/Lib/dos_8x3/test_bui.py b/Lib/dos_8x3/test_bui.py
new file mode 100755
index 0000000..33fef8d
--- /dev/null
+++ b/Lib/dos_8x3/test_bui.py
@@ -0,0 +1,13 @@
+# Python test set -- part 4, built-in functions
+
+from test_support import *
+
+print '4. Built-in functions'
+
+print 'test_b1'
+unload('test_b1')
+import test_b1
+
+print 'test_b2'
+unload('test_b2')
+import test_b2
diff --git a/Lib/dos_8x3/test_exc.py b/Lib/dos_8x3/test_exc.py
new file mode 100755
index 0000000..4fbee3e
--- /dev/null
+++ b/Lib/dos_8x3/test_exc.py
@@ -0,0 +1,92 @@
+# Python test set -- part 5, built-in exceptions
+
+from test_support import *
+
+print '5. Built-in exceptions'
+# XXX This is not really enough, each *operation* should be tested!
+
+def r(name): print name
+
+r(AttributeError)
+import sys
+try: x = sys.undefined_attribute
+except AttributeError: pass
+
+r(EOFError)
+import sys
+fp = open(TESTFN, 'w')
+fp.close()
+fp = open(TESTFN, 'r')
+savestdin = sys.stdin
+try:
+ try:
+ sys.stdin = fp
+ x = raw_input()
+ except EOFError:
+ pass
+finally:
+ sys.stdin = savestdin
+ fp.close()
+
+r(IOError)
+try: open('this file does not exist', 'r')
+except IOError: pass
+
+r(ImportError)
+try: import undefined_module
+except ImportError: pass
+
+r(IndexError)
+x = []
+try: a = x[10]
+except IndexError: pass
+
+r(KeyError)
+x = {}
+try: a = x['key']
+except KeyError: pass
+
+r(KeyboardInterrupt)
+print '(not testable in a script)'
+
+r(MemoryError)
+print '(not safe to test)'
+
+r(NameError)
+try: x = undefined_variable
+except NameError: pass
+
+r(OverflowError)
+x = 1
+try:
+ while 1: x = x+x
+except OverflowError: pass
+
+r(RuntimeError)
+print '(not used any more?)'
+
+r(SyntaxError)
+try: exec '/\n'
+except SyntaxError: pass
+
+r(SystemError)
+print '(hard to reproduce)'
+
+r(SystemExit)
+import sys
+try: sys.exit(0)
+except SystemExit: pass
+
+r(TypeError)
+try: [] + ()
+except TypeError: pass
+
+r(ValueError)
+try: x = chr(10000)
+except ValueError: pass
+
+r(ZeroDivisionError)
+try: x = 1/0
+except ZeroDivisionError: pass
+
+unlink(TESTFN)
diff --git a/Lib/dos_8x3/test_gra.py b/Lib/dos_8x3/test_gra.py
new file mode 100755
index 0000000..b9607ac
--- /dev/null
+++ b/Lib/dos_8x3/test_gra.py
@@ -0,0 +1,513 @@
+# Python test set -- part 1, grammar.
+# This just tests whether the parser accepts them all.
+
+from test_support import *
+
+print '1. Parser'
+
+print '1.1 Tokens'
+
+print '1.1.1 Backslashes'
+
+# Backslash means line continuation:
+x = 1 \
++ 1
+if x <> 2: raise TestFailed, 'backslash for line continuation'
+
+# Backslash does not means continuation in comments :\
+x = 0
+if x <> 0: raise TestFailed, 'backslash ending comment'
+
+print '1.1.2 Numeric literals'
+
+print '1.1.2.1 Plain integers'
+if 0xff <> 255: raise TestFailed, 'hex int'
+if 0377 <> 255: raise TestFailed, 'octal int'
+if 2147483647 != 017777777777: raise TestFailed, 'large positive int'
+try:
+ from sys import maxint
+except ImportError:
+ maxint = 2147483647
+if maxint == 2147483647:
+ if -2147483647-1 != 020000000000: raise TestFailed, 'max negative int'
+ # XXX -2147483648
+ if 037777777777 != -1: raise TestFailed, 'oct -1'
+ if 0xffffffff != -1: raise TestFailed, 'hex -1'
+ for s in '2147483648', '040000000000', '0x100000000':
+ try:
+ x = eval(s)
+ except OverflowError:
+ continue
+## raise TestFailed, \
+ print \
+ 'No OverflowError on huge integer literal ' + `s`
+elif eval('maxint == 9223372036854775807'):
+ if eval('-9223372036854775807-1 != 01000000000000000000000'):
+ raise TestFailed, 'max negative int'
+ if eval('01777777777777777777777') != -1: raise TestFailed, 'oct -1'
+ if eval('0xffffffffffffffff') != -1: raise TestFailed, 'hex -1'
+ for s in '9223372036854775808', '02000000000000000000000', \
+ '0x10000000000000000':
+ try:
+ x = eval(s)
+ except OverflowError:
+ continue
+ raise TestFailed, \
+ 'No OverflowError on huge integer literal ' + `s`
+else:
+ print 'Weird maxint value', maxint
+
+print '1.1.2.2 Long integers'
+x = 0L
+x = 0l
+x = 0xffffffffffffffffL
+x = 0xffffffffffffffffl
+x = 077777777777777777L
+x = 077777777777777777l
+x = 123456789012345678901234567890L
+x = 123456789012345678901234567890l
+
+print '1.1.2.3 Floating point'
+x = 3.14
+x = 314.
+x = 0.314
+# XXX x = 000.314
+x = .314
+x = 3e14
+x = 3E14
+x = 3e-14
+x = 3e+14
+x = 3.e14
+x = .3e14
+x = 3.1e4
+
+print '1.1.3 String literals'
+
+def assert(s):
+ if not s: raise TestFailed, 'see traceback'
+
+x = ''; y = ""; assert(len(x) == 0 and x == y)
+x = '\''; y = "'"; assert(len(x) == 1 and x == y and ord(x) == 39)
+x = '"'; y = "\""; assert(len(x) == 1 and x == y and ord(x) == 34)
+x = "doesn't \"shrink\" does it"
+y = 'doesn\'t "shrink" does it'
+assert(len(x) == 24 and x == y)
+x = "does \"shrink\" doesn't it"
+y = 'does "shrink" doesn\'t it'
+assert(len(x) == 24 and x == y)
+x = """
+The "quick"
+brown fox
+jumps over
+the 'lazy' dog.
+"""
+y = '\nThe "quick"\nbrown fox\njumps over\nthe \'lazy\' dog.\n'
+assert(x == y)
+y = '''
+The "quick"
+brown fox
+jumps over
+the 'lazy' dog.
+'''; assert(x == y)
+y = "\n\
+The \"quick\"\n\
+brown fox\n\
+jumps over\n\
+the 'lazy' dog.\n\
+"; assert(x == y)
+y = '\n\
+The \"quick\"\n\
+brown fox\n\
+jumps over\n\
+the \'lazy\' dog.\n\
+'; assert(x == y)
+
+
+print '1.2 Grammar'
+
+print 'single_input' # NEWLINE | simple_stmt | compound_stmt NEWLINE
+# XXX can't test in a script -- this rule is only used when interactive
+
+print 'file_input' # (NEWLINE | stmt)* ENDMARKER
+# Being tested as this very moment this very module
+
+print 'expr_input' # testlist NEWLINE
+# XXX Hard to test -- used only in calls to input()
+
+print 'eval_input' # testlist ENDMARKER
+x = eval('1, 0 or 1')
+
+print 'funcdef'
+### 'def' NAME parameters ':' suite
+### parameters: '(' [varargslist] ')'
+### varargslist: (fpdef ['=' test] ',')* '*' NAME
+### | fpdef ['=' test] (',' fpdef ['=' test])* [',']
+### fpdef: NAME | '(' fplist ')'
+### fplist: fpdef (',' fpdef)* [',']
+def f1(): pass
+def f2(one_argument): pass
+def f3(two, arguments): pass
+def f4(two, (compound, (argument, list))): pass
+def a1(one_arg,): pass
+def a2(two, args,): pass
+def v0(*rest): pass
+def v1(a, *rest): pass
+def v2(a, b, *rest): pass
+def v3(a, (b, c), *rest): pass
+def d01(a=1): pass
+d01()
+d01(1)
+def d11(a, b=1): pass
+d11(1)
+d11(1, 2)
+def d21(a, b, c=1): pass
+d21(1, 2)
+d21(1, 2, 3)
+def d02(a=1, b=2): pass
+d02()
+d02(1)
+d02(1, 2)
+def d12(a, b=1, c=2): pass
+d12(1)
+d12(1, 2)
+d12(1, 2, 3)
+def d22(a, b, c=1, d=2): pass
+d22(1, 2)
+d22(1, 2, 3)
+d22(1, 2, 3, 4)
+def d01v(a=1, *rest): pass
+d01v()
+d01v(1)
+d01v(1, 2)
+def d11v(a, b=1, *rest): pass
+d11v(1)
+d11v(1, 2)
+d11v(1, 2, 3)
+def d21v(a, b, c=1, *rest): pass
+d21v(1, 2)
+d21v(1, 2, 3)
+d21v(1, 2, 3, 4)
+def d02v(a=1, b=2, *rest): pass
+d02v()
+d02v(1)
+d02v(1, 2)
+d02v(1, 2, 3)
+def d12v(a, b=1, c=2, *rest): pass
+d12v(1)
+d12v(1, 2)
+d12v(1, 2, 3)
+d12v(1, 2, 3, 4)
+def d22v(a, b, c=1, d=2, *rest): pass
+d22v(1, 2)
+d22v(1, 2, 3)
+d22v(1, 2, 3, 4)
+d22v(1, 2, 3, 4, 5)
+
+### stmt: simple_stmt | compound_stmt
+# Tested below
+
+### simple_stmt: small_stmt (';' small_stmt)* [';']
+print 'simple_stmt'
+x = 1; pass; del x
+
+### small_stmt: expr_stmt | print_stmt | pass_stmt | del_stmt | flow_stmt | import_stmt | global_stmt | access_stmt | exec_stmt
+# Tested below
+
+print 'expr_stmt' # (exprlist '=')* exprlist
+1
+1, 2, 3
+x = 1
+x = 1, 2, 3
+x = y = z = 1, 2, 3
+x, y, z = 1, 2, 3
+abc = a, b, c = x, y, z = xyz = 1, 2, (3, 4)
+# NB these variables are deleted below
+
+print 'print_stmt' # 'print' (test ',')* [test]
+print 1, 2, 3
+print 1, 2, 3,
+print
+print 0 or 1, 0 or 1,
+print 0 or 1
+
+print 'del_stmt' # 'del' exprlist
+del abc
+del x, y, (z, xyz)
+
+print 'pass_stmt' # 'pass'
+pass
+
+print 'flow_stmt' # break_stmt | continue_stmt | return_stmt | raise_stmt
+# Tested below
+
+print 'break_stmt' # 'break'
+while 1: break
+
+print 'continue_stmt' # 'continue'
+i = 1
+while i: i = 0; continue
+
+print 'return_stmt' # 'return' [testlist]
+def g1(): return
+def g2(): return 1
+g1()
+x = g2()
+
+print 'raise_stmt' # 'raise' test [',' test]
+try: raise RuntimeError, 'just testing'
+except RuntimeError: pass
+try: raise KeyboardInterrupt
+except KeyboardInterrupt: pass
+
+print 'import_stmt' # 'import' NAME (',' NAME)* | 'from' NAME 'import' ('*' | NAME (',' NAME)*)
+import sys
+import time, sys
+from time import time
+from sys import *
+from sys import path, argv
+
+print 'global_stmt' # 'global' NAME (',' NAME)*
+def f():
+ global a
+ global a, b
+ global one, two, three, four, five, six, seven, eight, nine, ten
+
+print 'exec_stmt' # 'exec' expr ['in' expr [',' expr]]
+def f():
+ z = None
+ del z
+ exec 'z=1+1\n'
+ if z <> 2: raise TestFailed, 'exec \'z=1+1\'\\n'
+ del z
+ exec 'z=1+1'
+ if z <> 2: raise TestFailed, 'exec \'z=1+1\''
+f()
+g = {}
+exec 'z = 1' in g
+if g.has_key('__builtins__'): del g['__builtins__']
+if g <> {'z': 1}: raise TestFailed, 'exec \'z = 1\' in g'
+g = {}
+l = {}
+exec 'global a; a = 1; b = 2' in g, l
+if g.has_key('__builtins__'): del g['__builtins__']
+if l.has_key('__builtins__'): del l['__builtins__']
+if (g, l) <> ({'a':1}, {'b':2}): raise TestFailed, 'exec ... in g, l'
+
+
+### compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef
+# Tested below
+
+print 'if_stmt' # 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
+if 1: pass
+if 1: pass
+else: pass
+if 0: pass
+elif 0: pass
+if 0: pass
+elif 0: pass
+elif 0: pass
+elif 0: pass
+else: pass
+
+print 'while_stmt' # 'while' test ':' suite ['else' ':' suite]
+while 0: pass
+while 0: pass
+else: pass
+
+print 'for_stmt' # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite]
+for i in 1, 2, 3: pass
+for i, j, k in (): pass
+else: pass
+class Squares:
+ def __init__(self, max):
+ self.max = max
+ self.sofar = []
+ def __len__(self): return len(self.sofar)
+ def __getitem__(self, i):
+ if not 0 <= i < self.max: raise IndexError
+ n = len(self.sofar)
+ while n <= i:
+ self.sofar.append(n*n)
+ n = n+1
+ return self.sofar[i]
+n = 0
+for x in Squares(10): n = n+x
+if n != 285: raise TestFailed, 'for over growing sequence'
+
+print 'try_stmt'
+### try_stmt: 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite]
+### | 'try' ':' suite 'finally' ':' suite
+### except_clause: 'except' [expr [',' expr]]
+try:
+ 1/0
+except ZeroDivisionError:
+ pass
+else:
+ pass
+try: 1/0
+except EOFError: pass
+except TypeError, msg: pass
+except RuntimeError, msg: pass
+except: pass
+else: pass
+try: 1/0
+except (EOFError, TypeError, ZeroDivisionError): pass
+try: 1/0
+except (EOFError, TypeError, ZeroDivisionError), msg: pass
+try: pass
+finally: pass
+
+print 'suite' # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT
+if 1: pass
+if 1:
+ pass
+if 1:
+ #
+ #
+ #
+ pass
+ pass
+ #
+ pass
+ #
+
+print 'test'
+### and_test ('or' and_test)*
+### and_test: not_test ('and' not_test)*
+### not_test: 'not' not_test | comparison
+if not 1: pass
+if 1 and 1: pass
+if 1 or 1: pass
+if not not not 1: pass
+if not 1 and 1 and 1: pass
+if 1 and 1 or 1 and 1 and 1 or not 1 and 1: pass
+
+print 'comparison'
+### comparison: expr (comp_op expr)*
+### comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not'
+if 1: pass
+x = (1 == 1)
+if 1 == 1: pass
+if 1 != 1: pass
+if 1 <> 1: pass
+if 1 < 1: pass
+if 1 > 1: pass
+if 1 <= 1: pass
+if 1 >= 1: pass
+if 1 is 1: pass
+if 1 is not 1: pass
+if 1 in (): pass
+if 1 not in (): pass
+if 1 < 1 > 1 == 1 >= 1 <= 1 <> 1 != 1 in 1 not in 1 is 1 is not 1: pass
+
+print 'binary mask ops'
+x = 1 & 1
+x = 1 ^ 1
+x = 1 | 1
+
+print 'shift ops'
+x = 1 << 1
+x = 1 >> 1
+x = 1 << 1 >> 1
+
+print 'additive ops'
+x = 1
+x = 1 + 1
+x = 1 - 1 - 1
+x = 1 - 1 + 1 - 1 + 1
+
+print 'multiplicative ops'
+x = 1 * 1
+x = 1 / 1
+x = 1 % 1
+x = 1 / 1 * 1 % 1
+
+print 'unary ops'
+x = +1
+x = -1
+x = ~1
+x = ~1 ^ 1 & 1 | 1 & 1 ^ -1
+x = -1*1/1 + 1*1 - ---1*1
+
+print 'selectors'
+### trailer: '(' [testlist] ')' | '[' subscript ']' | '.' NAME
+### subscript: expr | [expr] ':' [expr]
+f1()
+f2(1)
+f2(1,)
+f3(1, 2)
+f3(1, 2,)
+f4(1, (2, (3, 4)))
+v0()
+v0(1)
+v0(1,)
+v0(1,2)
+v0(1,2,3,4,5,6,7,8,9,0)
+v1(1)
+v1(1,)
+v1(1,2)
+v1(1,2,3)
+v1(1,2,3,4,5,6,7,8,9,0)
+v2(1,2)
+v2(1,2,3)
+v2(1,2,3,4)
+v2(1,2,3,4,5,6,7,8,9,0)
+v3(1,(2,3))
+v3(1,(2,3),4)
+v3(1,(2,3),4,5,6,7,8,9,0)
+import sys, time
+c = sys.path[0]
+x = time.time()
+x = sys.modules['time'].time()
+a = '01234'
+c = a[0]
+c = a[-1]
+s = a[0:5]
+s = a[:5]
+s = a[0:]
+s = a[:]
+s = a[-5:]
+s = a[:-1]
+s = a[-4:-3]
+
+print 'atoms'
+### atom: '(' [testlist] ')' | '[' [testlist] ']' | '{' [dictmaker] '}' | '`' testlist '`' | NAME | NUMBER | STRING
+### dictmaker: test ':' test (',' test ':' test)* [',']
+
+x = (1)
+x = (1 or 2 or 3)
+x = (1 or 2 or 3, 2, 3)
+
+x = []
+x = [1]
+x = [1 or 2 or 3]
+x = [1 or 2 or 3, 2, 3]
+x = []
+
+x = {}
+x = {'one': 1}
+x = {'one': 1,}
+x = {'one' or 'two': 1 or 2}
+x = {'one': 1, 'two': 2}
+x = {'one': 1, 'two': 2,}
+x = {'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5, 'six': 6}
+
+x = `x`
+x = `1 or 2 or 3`
+x = x
+x = 'x'
+x = 123
+
+### exprlist: expr (',' expr)* [',']
+### testlist: test (',' test)* [',']
+# These have been exercised enough above
+
+print 'classdef' # 'class' NAME ['(' testlist ')'] ':' suite
+class B: pass
+class C1(B): pass
+class C2(B): pass
+class D(C1, C2, B): pass
+class C:
+ def meth1(self): pass
+ def meth2(self, arg): pass
+ def meth3(self, a1, a2): pass
diff --git a/Lib/dos_8x3/test_opc.py b/Lib/dos_8x3/test_opc.py
new file mode 100755
index 0000000..b1e944b
--- /dev/null
+++ b/Lib/dos_8x3/test_opc.py
@@ -0,0 +1,59 @@
+# Python test set -- part 2, opcodes
+
+from test_support import *
+
+
+print '2. Opcodes'
+print 'XXX Not yet fully implemented'
+
+print '2.1 try inside for loop'
+n = 0
+for i in range(10):
+ n = n+i
+ try: 1/0
+ except NameError: pass
+ except ZeroDivisionError: pass
+ except TypeError: pass
+ try: pass
+ except: pass
+ try: pass
+ finally: pass
+ n = n+i
+if n <> 90:
+ raise TestFailed, 'try inside for'
+
+
+print '2.2 raise class exceptions'
+
+class AClass: pass
+class BClass(AClass): pass
+class CClass: pass
+
+try: raise AClass()
+except: pass
+
+try: raise AClass()
+except AClass: pass
+
+try: raise BClass()
+except AClass: pass
+
+try: raise BClass()
+except CClass: raise TestFailed
+except: pass
+
+a = AClass()
+b = BClass()
+
+try: raise AClass, b
+except BClass, v: raise TestFailed
+except AClass, v:
+ if v != b: raise TestFailed
+
+
+try: raise b
+except AClass, v:
+ if v != b: raise TestFailed
+
+try: raise BClass, a
+except TypeError: pass
diff --git a/Lib/dos_8x3/test_ope.py b/Lib/dos_8x3/test_ope.py
new file mode 100755
index 0000000..1a75065
--- /dev/null
+++ b/Lib/dos_8x3/test_ope.py
@@ -0,0 +1,5 @@
+# Python test set -- part 3, built-in operations.
+
+
+print '3. Operations'
+print 'XXX Not yet implemented'
diff --git a/Lib/dos_8x3/test_rgb.py b/Lib/dos_8x3/test_rgb.py
new file mode 100755
index 0000000..cdadc66
--- /dev/null
+++ b/Lib/dos_8x3/test_rgb.py
@@ -0,0 +1,49 @@
+# Testing rgbimg module
+
+import rgbimg, os
+
+error = 'test_rgbimg.error'
+
+print 'RGBimg test suite:'
+
+def findfile(file):
+ if os.path.isabs(file): return file
+ import sys
+ for dn in sys.path:
+ fn = os.path.join(dn, file)
+ if os.path.exists(fn): return fn
+ return file
+
+def testimg(rgb_file, raw_file):
+ rgb_file = findfile(rgb_file)
+ raw_file = findfile(raw_file)
+ width, height = rgbimg.sizeofimage(rgb_file)
+ rgb = rgbimg.longimagedata(rgb_file)
+ if len(rgb) != width * height * 4:
+ raise error, 'bad image length'
+ raw = open(raw_file, 'r').read()
+ if rgb != raw:
+ raise error, 'images don\'t match for '+rgb_file+' and '+raw_file
+ for depth in [1, 3, 4]:
+ rgbimg.longstoimage(rgb, width, height, depth, '@.rgb')
+ os.unlink('@.rgb')
+
+ttob = rgbimg.ttob(0)
+if ttob != 0:
+ raise error, 'ttob should start out as zero'
+
+testimg('test.rgb', 'test.rawimg')
+
+ttob = rgbimg.ttob(1)
+if ttob != 0:
+ raise error, 'ttob should be zero'
+
+testimg('test.rgb', 'test.rawimg.rev')
+
+ttob = rgbimg.ttob(0)
+if ttob != 1:
+ raise error, 'ttob should be one'
+
+ttob = rgbimg.ttob(0)
+if ttob != 0:
+ raise error, 'ttob should be zero'
diff --git a/Lib/dos_8x3/test_sel.py b/Lib/dos_8x3/test_sel.py
new file mode 100755
index 0000000..f185308
--- /dev/null
+++ b/Lib/dos_8x3/test_sel.py
@@ -0,0 +1,23 @@
+# Testing select module
+
+def test():
+ import select
+ import os
+ cmd = 'for i in 0 1 2 3 4 5 6 7 8 9; do date; sleep 3; done'
+ p = os.popen(cmd, 'r')
+ for tout in (0, 1, 2, 4, 8, 16) + (None,)*10:
+ print 'timeout =', tout
+ rfd, wfd, xfd = select.select([p], [], [], tout)
+ print rfd, wfd, xfd
+ if (rfd, wfd, xfd) == ([], [], []):
+ continue
+ if (rfd, wfd, xfd) == ([p], [], []):
+ line = p.readline()
+ print `line`
+ if not line:
+ print 'EOF'
+ break
+ continue
+ print 'Heh?'
+
+test()
diff --git a/Lib/dos_8x3/test_sig.py b/Lib/dos_8x3/test_sig.py
new file mode 100755
index 0000000..bfcf517
--- /dev/null
+++ b/Lib/dos_8x3/test_sig.py
@@ -0,0 +1,50 @@
+# Test the signal module
+
+import signal
+import os
+
+
+pid = os.getpid()
+
+# Shell script that will send us asynchronous signals
+script = """
+(
+ set -x
+ sleep 2
+ kill -5 %(pid)d
+ sleep 2
+ kill -2 %(pid)d
+ sleep 2
+ kill -3 %(pid)d
+) &
+""" % vars()
+
+def handlerA(*args):
+ print "handlerA", args
+
+HandlerBCalled = "HandlerBCalled" # Exception
+
+def handlerB(*args):
+ print "handlerB", args
+ raise HandlerBCalled, args
+
+signal.alarm(20) # Entire test lasts at most 20 sec.
+signal.signal(5, handlerA)
+signal.signal(2, handlerB)
+signal.signal(3, signal.SIG_IGN)
+signal.signal(signal.SIGALRM, signal.default_int_handler)
+
+os.system(script)
+
+print "starting pause() loop..."
+
+try:
+ while 1:
+ print "call pause()..."
+ try:
+ signal.pause()
+ print "pause() returned"
+ except HandlerBCalled:
+ print "HandlerBCalled exception caught"
+except KeyboardInterrupt:
+ print "KeyboardInterrupt (assume the alarm() went off)"
diff --git a/Lib/dos_8x3/test_sup.py b/Lib/dos_8x3/test_sup.py
new file mode 100755
index 0000000..7a76664
--- /dev/null
+++ b/Lib/dos_8x3/test_sup.py
@@ -0,0 +1,41 @@
+# Python test set -- supporting definitions.
+
+TestFailed = 'test_support -- test failed' # Exception
+
+def unload(name):
+ import sys
+ try:
+ del sys.modules[name]
+ except KeyError:
+ pass
+
+def forget(modname):
+ unload(modname)
+ import sys, os
+ for dirname in sys.path:
+ try:
+ os.unlink(os.path.join(dirname, modname + '.pyc'))
+ except os.error:
+ pass
+
+FUZZ = 1e-6
+
+def fcmp(x, y): # fuzzy comparison function
+ if type(x) == type(0.0) or type(y) == type(0.0):
+ try:
+ x, y = coerce(x, y)
+ fuzz = (abs(x) + abs(y)) * FUZZ
+ if abs(x-y) <= fuzz:
+ return 0
+ except:
+ pass
+ elif type(x) == type(y) and type(x) in (type(()), type([])):
+ for i in range(min(len(x), len(y))):
+ outcome = fcmp(x[i], y[i])
+ if outcome <> 0:
+ return outcome
+ return cmp(len(x), len(y))
+ return cmp(x, y)
+
+TESTFN = '@test' # Filename used for testing
+from os import unlink
diff --git a/Lib/dos_8x3/test_thr.py b/Lib/dos_8x3/test_thr.py
new file mode 100755
index 0000000..4e0eb70
--- /dev/null
+++ b/Lib/dos_8x3/test_thr.py
@@ -0,0 +1,106 @@
+# Very rudimentary test of thread module
+
+# Create a bunch of threads, let each do some work, wait until all are done
+
+import whrandom
+import thread
+import time
+
+mutex = thread.allocate_lock()
+whmutex = thread.allocate_lock() # for calls to whrandom
+running = 0
+done = thread.allocate_lock()
+done.acquire()
+
+numtasks = 10
+
+def task(ident):
+ global running
+ whmutex.acquire()
+ delay = whrandom.random() * numtasks
+ whmutex.release()
+ print 'task', ident, 'will run for', delay, 'sec'
+ time.sleep(delay)
+ print 'task', ident, 'done'
+ mutex.acquire()
+ running = running - 1
+ if running == 0:
+ done.release()
+ mutex.release()
+
+next_ident = 0
+def newtask():
+ global next_ident, running
+ mutex.acquire()
+ next_ident = next_ident + 1
+ print 'creating task', next_ident
+ thread.start_new_thread(task, (next_ident,))
+ running = running + 1
+ mutex.release()
+
+for i in range(numtasks):
+ newtask()
+
+print 'waiting for all tasks to complete'
+done.acquire()
+print 'all tasks done'
+
+class barrier:
+ def __init__(self, n):
+ self.n = n
+ self.waiting = 0
+ self.checkin = thread.allocate_lock()
+ self.checkout = thread.allocate_lock()
+ self.checkout.acquire()
+
+ def enter(self):
+ checkin, checkout = self.checkin, self.checkout
+
+ checkin.acquire()
+ self.waiting = self.waiting + 1
+ if self.waiting == self.n:
+ self.waiting = self.n - 1
+ checkout.release()
+ return
+ checkin.release()
+
+ checkout.acquire()
+ self.waiting = self.waiting - 1
+ if self.waiting == 0:
+ checkin.release()
+ return
+ checkout.release()
+
+numtrips = 3
+def task2(ident):
+ global running
+ for i in range(numtrips):
+ if ident == 0:
+ # give it a good chance to enter the next
+ # barrier before the others are all out
+ # of the current one
+ delay = 0.001
+ else:
+ whmutex.acquire()
+ delay = whrandom.random() * numtasks
+ whmutex.release()
+ print 'task', ident, 'will run for', delay, 'sec'
+ time.sleep(delay)
+ print 'task', ident, 'entering barrier', i
+ bar.enter()
+ print 'task', ident, 'leaving barrier', i
+ mutex.acquire()
+ running = running - 1
+ if running == 0:
+ done.release()
+ mutex.release()
+
+print '\n*** Barrier Test ***'
+if done.acquire(0):
+ raise ValueError, "'done' should have remained acquired"
+bar = barrier(numtasks)
+running = numtasks
+for i in range(numtasks):
+ thread.start_new_thread(task2, (i,))
+done.acquire()
+print 'all tasks done'
diff --git a/Lib/dos_8x3/test_typ.py b/Lib/dos_8x3/test_typ.py
new file mode 100755
index 0000000..51c76dc
--- /dev/null
+++ b/Lib/dos_8x3/test_typ.py
@@ -0,0 +1,182 @@
+# Python test set -- part 6, built-in types
+
+from test_support import *
+
+print '6. Built-in types'
+
+print '6.1 Truth value testing'
+if None: raise TestFailed, 'None is true instead of false'
+if 0: raise TestFailed, '0 is true instead of false'
+if 0L: raise TestFailed, '0L is true instead of false'
+if 0.0: raise TestFailed, '0.0 is true instead of false'
+if '': raise TestFailed, '\'\' is true instead of false'
+if (): raise TestFailed, '() is true instead of false'
+if []: raise TestFailed, '[] is true instead of false'
+if {}: raise TestFailed, '{} is true instead of false'
+if not 1: raise TestFailed, '1 is false instead of true'
+if not 1L: raise TestFailed, '1L is false instead of true'
+if not 1.0: raise TestFailed, '1.0 is false instead of true'
+if not 'x': raise TestFailed, '\'x\' is false instead of true'
+if not (1, 1): raise TestFailed, '(1, 1) is false instead of true'
+if not [1]: raise TestFailed, '[1] is false instead of true'
+if not {'x': 1}: raise TestFailed, '{\'x\': 1} is false instead of true'
+def f(): pass
+class C: pass
+import sys
+x = C()
+if not f: raise TestFailed, 'f is false instead of true'
+if not C: raise TestFailed, 'C is false instead of true'
+if not sys: raise TestFailed, 'sys is false instead of true'
+if not x: raise TestFailed, 'x is false instead of true'
+
+print '6.2 Boolean operations'
+if 0 or 0: raise TestFailed, '0 or 0 is true instead of false'
+if 1 and 1: pass
+else: raise TestFailed, '1 and 1 is false instead of false'
+if not 1: raise TestFailed, 'not 1 is true instead of false'
+
+print '6.3 Comparisons'
+if 0 < 1 <= 1 == 1 >= 1 > 0 <> 1: pass
+else: raise TestFailed, 'int comparisons failed'
+if 0L < 1L <= 1L == 1L >= 1L > 0L <> 1L: pass
+else: raise TestFailed, 'long int comparisons failed'
+if 0.0 < 1.0 <= 1.0 == 1.0 >= 1.0 > 0.0 <> 1.0: pass
+else: raise TestFailed, 'float comparisons failed'
+if '' < 'a' <= 'a' == 'a' < 'abc' < 'abd' < 'b': pass
+else: raise TestFailed, 'string comparisons failed'
+if 0 in [0] and 0 not in [1]: pass
+else: raise TestFailed, 'membership test failed'
+if None is None and [] is not []: pass
+else: raise TestFailed, 'identity test failed'
+
+print '6.4 Numeric types (mostly conversions)'
+if 0 <> 0L or 0 <> 0.0 or 0L <> 0.0: raise TestFailed, 'mixed comparisons'
+if 1 <> 1L or 1 <> 1.0 or 1L <> 1.0: raise TestFailed, 'mixed comparisons'
+if -1 <> -1L or -1 <> -1.0 or -1L <> -1.0:
+ raise TestFailed, 'int/long/float value not equal'
+if int(1.9) == 1 == int(1.1) and int(-1.1) == -1 == int(-1.9): pass
+else: raise TestFailed, 'int() does not round properly'
+if long(1.9) == 1L == long(1.1) and long(-1.1) == -1L == long(-1.9): pass
+else: raise TestFailed, 'long() does not round properly'
+if float(1) == 1.0 and float(-1) == -1.0 and float(0) == 0.0: pass
+else: raise TestFailed, 'float() does not work properly'
+print '6.4.1 32-bit integers'
+if 12 + 24 <> 36: raise TestFailed, 'int op'
+if 12 + (-24) <> -12: raise TestFailed, 'int op'
+if (-12) + 24 <> 12: raise TestFailed, 'int op'
+if (-12) + (-24) <> -36: raise TestFailed, 'int op'
+if not 12 < 24: raise TestFailed, 'int op'
+if not -24 < -12: raise TestFailed, 'int op'
+# Test for a particular bug in integer multiply
+xsize, ysize, zsize = 238, 356, 4
+if not (xsize*ysize*zsize == zsize*xsize*ysize == 338912):
+ raise TestFailed, 'int mul commutativity'
+print '6.4.2 Long integers'
+if 12L + 24L <> 36L: raise TestFailed, 'long op'
+if 12L + (-24L) <> -12L: raise TestFailed, 'long op'
+if (-12L) + 24L <> 12L: raise TestFailed, 'long op'
+if (-12L) + (-24L) <> -36L: raise TestFailed, 'long op'
+if not 12L < 24L: raise TestFailed, 'long op'
+if not -24L < -12L: raise TestFailed, 'long op'
+print '6.4.3 Floating point numbers'
+if 12.0 + 24.0 <> 36.0: raise TestFailed, 'float op'
+if 12.0 + (-24.0) <> -12.0: raise TestFailed, 'float op'
+if (-12.0) + 24.0 <> 12.0: raise TestFailed, 'float op'
+if (-12.0) + (-24.0) <> -36.0: raise TestFailed, 'float op'
+if not 12.0 < 24.0: raise TestFailed, 'float op'
+if not -24.0 < -12.0: raise TestFailed, 'float op'
+
+print '6.5 Sequence types'
+
+print '6.5.1 Strings'
+if len('') <> 0: raise TestFailed, 'len(\'\')'
+if len('a') <> 1: raise TestFailed, 'len(\'a\')'
+if len('abcdef') <> 6: raise TestFailed, 'len(\'abcdef\')'
+if 'xyz' + 'abcde' <> 'xyzabcde': raise TestFailed, 'string concatenation'
+if 'xyz'*3 <> 'xyzxyzxyz': raise TestFailed, 'string repetition *3'
+if 0*'abcde' <> '': raise TestFailed, 'string repetition 0*'
+if min('abc') <> 'a' or max('abc') <> 'c': raise TestFailed, 'min/max string'
+if 'a' in 'abc' and 'b' in 'abc' and 'c' in 'abc' and 'd' not in 'abc': pass
+else: raise TestFailed, 'in/not in string'
+x = 'x'*103
+if '%s!'%x != x+'!': raise TestFailed, 'nasty string formatting bug'
+
+print '6.5.2 Tuples'
+if len(()) <> 0: raise TestFailed, 'len(())'
+if len((1,)) <> 1: raise TestFailed, 'len((1,))'
+if len((1,2,3,4,5,6)) <> 6: raise TestFailed, 'len((1,2,3,4,5,6))'
+if (1,2)+(3,4) <> (1,2,3,4): raise TestFailed, 'tuple concatenation'
+if (1,2)*3 <> (1,2,1,2,1,2): raise TestFailed, 'tuple repetition *3'
+if 0*(1,2,3) <> (): raise TestFailed, 'tuple repetition 0*'
+if min((1,2)) <> 1 or max((1,2)) <> 2: raise TestFailed, 'min/max tuple'
+if 0 in (0,1,2) and 1 in (0,1,2) and 2 in (0,1,2) and 3 not in (0,1,2): pass
+else: raise TestFailed, 'in/not in tuple'
+
+print '6.5.3 Lists'
+if len([]) <> 0: raise TestFailed, 'len([])'
+if len([1,]) <> 1: raise TestFailed, 'len([1,])'
+if len([1,2,3,4,5,6]) <> 6: raise TestFailed, 'len([1,2,3,4,5,6])'
+if [1,2]+[3,4] <> [1,2,3,4]: raise TestFailed, 'list concatenation'
+if [1,2]*3 <> [1,2,1,2,1,2]: raise TestFailed, 'list repetition *3'
+if 0*[1,2,3] <> []: raise TestFailed, 'list repetition 0*'
+if min([1,2]) <> 1 or max([1,2]) <> 2: raise TestFailed, 'min/max list'
+if 0 in [0,1,2] and 1 in [0,1,2] and 2 in [0,1,2] and 3 not in [0,1,2]: pass
+else: raise TestFailed, 'in/not in list'
+
+print '6.5.3a Additional list operations'
+a = [0,1,2,3,4]
+a[0] = 5
+a[1] = 6
+a[2] = 7
+if a <> [5,6,7,3,4]: raise TestFailed, 'list item assignment [0], [1], [2]'
+a[-2] = 8
+a[-1] = 9
+if a <> [5,6,7,8,9]: raise TestFailed, 'list item assignment [-2], [-1]'
+a[:2] = [0,4]
+a[-3:] = []
+a[1:1] = [1,2,3]
+if a <> [0,1,2,3,4]: raise TestFailed, 'list slice assignment'
+del a[1:4]
+if a <> [0,4]: raise TestFailed, 'list slice deletion'
+del a[0]
+if a <> [4]: raise TestFailed, 'list item deletion [0]'
+del a[-1]
+if a <> []: raise TestFailed, 'list item deletion [-1]'
+a.append(0)
+a.append(1)
+a.append(2)
+if a <> [0,1,2]: raise TestFailed, 'list append'
+a.insert(0, -2)
+a.insert(1, -1)
+a.insert(2,0)
+if a <> [-2,-1,0,0,1,2]: raise TestFailed, 'list insert'
+if a.count(0) <> 2: raise TestFailed, ' list count'
+if a.index(0) <> 2: raise TestFailed, 'list index'
+a.remove(0)
+if a <> [-2,-1,0,1,2]: raise TestFailed, 'list remove'
+a.reverse()
+if a <> [2,1,0,-1,-2]: raise TestFailed, 'list reverse'
+a.sort()
+if a <> [-2,-1,0,1,2]: raise TestFailed, 'list sort'
+def revcmp(a, b): return cmp(b, a)
+a.sort(revcmp)
+if a <> [2,1,0,-1,-2]: raise TestFailed, 'list sort with cmp func'
+
+print '6.6 Mappings == Dictionaries'
+d = {}
+if d.keys() <> []: raise TestFailed, '{}.keys()'
+if d.has_key('a') <> 0: raise TestFailed, '{}.has_key(\'a\')'
+if len(d) <> 0: raise TestFailed, 'len({})'
+d = {'a': 1, 'b': 2}
+if len(d) <> 2: raise TestFailed, 'len(dict)'
+k = d.keys()
+k.sort()
+if k <> ['a', 'b']: raise TestFailed, 'dict keys()'
+if d.has_key('a') and d.has_key('b') and not d.has_key('c'): pass
+else: raise TestFailed, 'dict keys()'
+if d['a'] <> 1 or d['b'] <> 2: raise TestFailed, 'dict item'
+d['c'] = 3
+d['a'] = 4
+if d['c'] <> 3 or d['a'] <> 4: raise TestFailed, 'dict item assignment'
+del d['b']
+if d <> {'a': 4, 'c': 3}: raise TestFailed, 'dict item deletion'
diff --git a/Lib/dos_8x3/tracebac.py b/Lib/dos_8x3/tracebac.py
new file mode 100755
index 0000000..8d2dfdc
--- /dev/null
+++ b/Lib/dos_8x3/tracebac.py
@@ -0,0 +1,125 @@
+# Format and print Python stack traces
+
+import linecache
+import string
+import sys
+import types
+
+def _print(file, str='', terminator='\n'):
+ file.write(str+terminator)
+
+
+def print_tb(tb, limit=None, file=None):
+ if not file:
+ file = sys.stderr
+ if limit is None:
+ if hasattr(sys, 'tracebacklimit'):
+ limit = sys.tracebacklimit
+ n = 0
+ while tb is not None and (limit is None or n < limit):
+ f = tb.tb_frame
+ lineno = tb.tb_lineno
+ co = f.f_code
+ filename = co.co_filename
+ name = co.co_name
+ _print(file,
+ ' File "%s", line %d, in %s' % (filename,lineno,name))
+ line = linecache.getline(filename, lineno)
+ if line: _print(file, ' ' + string.strip(line))
+ tb = tb.tb_next
+ n = n+1
+
+def format_tb(tb, limit = None):
+ list = []
+ for filename, lineno, name, line in extract_tb(tb, limit):
+ item = ' File "%s", line %d, in %s\n' % (filename,lineno,name)
+ if line:
+ item = item + ' %s\n' % string.strip(line)
+ list.append(item)
+ return list
+
+def extract_tb(tb, limit = None):
+ if limit is None:
+ if hasattr(sys, 'tracebacklimit'):
+ limit = sys.tracebacklimit
+ list = []
+ n = 0
+ while tb is not None and (limit is None or n < limit):
+ f = tb.tb_frame
+ lineno = tb.tb_lineno
+ co = f.f_code
+ filename = co.co_filename
+ name = co.co_name
+ line = linecache.getline(filename, lineno)
+ if line: line = string.strip(line)
+ else: line = None
+ list.append(filename, lineno, name, line)
+ tb = tb.tb_next
+ n = n+1
+ return list
+
+
+def print_exception(etype, value, tb, limit=None, file=None):
+ if not file:
+ file = sys.stderr
+ if tb:
+ _print(file, 'Traceback (innermost last):')
+ print_tb(tb, limit, file)
+ lines = format_exception_only(etype, value)
+ for line in lines[:-1]:
+ _print(file, line, ' ')
+ _print(file, lines[-1], '')
+
+def format_exception(etype, value, tb, limit = None):
+ if tb:
+ list = ['Traceback (innermost last):\n']
+ list = list + format_tb(tb, limit)
+ list = list + format_exception_only(etype, value)
+ return list
+
+def format_exception_only(etype, value):
+ list = []
+ if type(etype) == types.ClassType:
+ stype = etype.__name__
+ else:
+ stype = etype
+ if value is None:
+ list.append(str(stype) + '\n')
+ else:
+ if etype is SyntaxError:
+ try:
+ msg, (filename, lineno, offset, line) = value
+ except:
+ pass
+ else:
+ if not filename: filename = "<string>"
+ list.append(' File "%s", line %d\n' %
+ (filename, lineno))
+ i = 0
+ while i < len(line) and \
+ line[i] in string.whitespace:
+ i = i+1
+ list.append(' %s\n' % string.strip(line))
+ s = ' '
+ for c in line[i:offset-1]:
+ if c in string.whitespace:
+ s = s + c
+ else:
+ s = s + ' '
+ list.append('%s^\n' % s)
+ value = msg
+ list.append('%s: %s\n' % (str(stype), str(value)))
+ return list
+
+
+def print_exc(limit=None, file=None):
+ if not file:
+ file = sys.stderr
+ print_exception(sys.exc_type, sys.exc_value, sys.exc_traceback,
+ limit, file)
+
+def print_last(limit=None, file=None):
+ if not file:
+ file = sys.stderr
+ print_exception(sys.last_type, sys.last_value, sys.last_traceback,
+ limit, file)
diff --git a/Lib/dos_8x3/userdict.py b/Lib/dos_8x3/userdict.py
new file mode 100755
index 0000000..f6b2f82
--- /dev/null
+++ b/Lib/dos_8x3/userdict.py
@@ -0,0 +1,18 @@
+# A more or less complete user-defined wrapper around dictionary objects
+
+class UserDict:
+ def __init__(self): self.data = {}
+ def __repr__(self): return repr(self.data)
+ def __cmp__(self, dict):
+ if type(dict) == type(self.data):
+ return cmp(self.data, dict)
+ else:
+ return cmp(self.data, dict.data)
+ def __len__(self): return len(self.data)
+ def __getitem__(self, key): return self.data[key]
+ def __setitem__(self, key, item): self.data[key] = item
+ def __delitem__(self, key): del self.data[key]
+ def keys(self): return self.data.keys()
+ def items(self): return self.data.items()
+ def values(self): return self.data.values()
+ def has_key(self, key): return self.data.has_key(key)
diff --git a/Lib/dos_8x3/userlist.py b/Lib/dos_8x3/userlist.py
new file mode 100755
index 0000000..1f19ad9
--- /dev/null
+++ b/Lib/dos_8x3/userlist.py
@@ -0,0 +1,50 @@
+# A more or less complete user-defined wrapper around list objects
+
+class UserList:
+ def __init__(self, list = None):
+ self.data = []
+ if list is not None:
+ if type(list) == type(self.data):
+ self.data[:] = list
+ else:
+ self.data[:] = list.data[:]
+ def __repr__(self): return repr(self.data)
+ def __cmp__(self, list):
+ if type(list) == type(self.data):
+ return cmp(self.data, list)
+ else:
+ return cmp(self.data, list.data)
+ def __len__(self): return len(self.data)
+ def __getitem__(self, i): return self.data[i]
+ def __setitem__(self, i, item): self.data[i] = item
+ def __delitem__(self, i): del self.data[i]
+ def __getslice__(self, i, j):
+ userlist = UserList()
+ userlist.data[:] = self.data[i:j]
+ return userlist
+ def __setslice__(self, i, j, list):
+ if type(list) == type(self.data):
+ self.data[i:j] = list
+ else:
+ self.data[i:j] = list.data
+ def __delslice__(self, i, j): del self.data[i:j]
+ def __add__(self, list):
+ if type(list) == type(self.data):
+ return self.__class__(self.data + list)
+ else:
+ return self.__class__(self.data + list.data)
+ def __radd__(self, list):
+ if type(list) == type(self.data):
+ return self.__class__(list + self.data)
+ else:
+ return self.__class__(list.data + self.data)
+ def __mul__(self, n):
+ return self.__class__(self.data*n)
+ __rmul__ = __mul__
+ def append(self, item): self.data.append(item)
+ def insert(self, i, item): self.data.insert(i, item)
+ def remove(self, item): self.data.remove(item)
+ def count(self, item): return self.data.count(item)
+ def index(self, item): return self.data.index(item)
+ def reverse(self): self.data.reverse()
+ def sort(self, *args): apply(self.data.sort, args)
diff --git a/Lib/dos_8x3/whatsoun.py b/Lib/dos_8x3/whatsoun.py
new file mode 100755
index 0000000..b7b349c
--- /dev/null
+++ b/Lib/dos_8x3/whatsoun.py
@@ -0,0 +1,270 @@
+# This module contains several routines that help recognizing sound
+# files.
+#
+# Function whathdr() recognizes various types of sound file headers.
+# It understands almost all headers that SOX can decode.
+#
+# The return tuple contains the following items, in this order:
+# - file type (as SOX understands it)
+# - sampling rate (0 if unknown or hard to decode)
+# - number of channels (0 if unknown or hard to decode)
+# - number of frames in the file (-1 if unknown or hard to decode)
+# - number of bits/sample, or 'U' for U-LAW, or 'A' for A-LAW
+#
+# If the file doesn't have a recognizable type, it returns None.
+# If the file can't be opened, IOError is raised.
+#
+# To compute the total time, divide the number of frames by the
+# sampling rate (a frame contains a sample for each channel).
+#
+# Function whatraw() calls the "whatsound" program and interprets its
+# output. You'll have to guess the sampling rate by listening though!
+#
+# Function what() calls whathdr() and if it doesn't recognize the file
+# then calls whatraw().
+#
+# Finally, the function test() is a simple main program that calls
+# what() for all files mentioned on the argument list. For directory
+# arguments it calls what() for all files in that directory. Default
+# argument is "." (testing all files in the current directory). The
+# option -r tells it to recurse down directories found inside
+# explicitly given directories.
+#
+# The file structure is top-down except that the test program and its
+# subroutine come last.
+
+
+#------------------------------------------------------#
+# Guess the type of any sound file, raw or with header #
+#------------------------------------------------------#
+
+def what(filename):
+ res = whathdr(filename)
+ if not res:
+ res = whatraw(filename)
+ return res
+
+
+#-----------------------------#
+# Guess the type of raw sound #
+#-----------------------------#
+
+def whatraw(filename):
+ # Assume it's always 1 channel, byte-sized samples
+ # Don't assume anything about the rate
+ import os
+ from stat import ST_SIZE
+ # XXX "whatsound" should be part of the distribution somehow...
+ cmd = 'whatsound ' + filename + ' 2>/dev/null'
+ cmd = 'PATH=$PATH:/ufs/guido/bin/sgi\n' + cmd
+ pipe = os.popen(cmd, 'r')
+ data = pipe.read()
+ sts = pipe.close()
+ if sts:
+ return None
+ if data[:13] == '-t raw -b -s ':
+ type = 'sb'
+ sample_size = 8
+ elif data[:13] == '-t raw -b -u ':
+ type = 'ub'
+ sample_size = 8
+ elif data[:13] == '-t raw -b -U ':
+ type = 'ul'
+ sample_size = 'U'
+ else:
+ return None
+ try:
+ frame_count = os.stat(filename)[ST_SIZE]
+ except IOError:
+ frame_count = -1
+ return type, 0, 1, frame_count, sample_size
+
+
+#-------------------------#
+# Recognize sound headers #
+#-------------------------#
+
+def whathdr(filename):
+ f = open(filename, 'r')
+ h = f.read(512)
+ for tf in tests:
+ res = tf(h, f)
+ if res:
+ return res
+ return None
+
+
+#-----------------------------------#
+# Subroutines per sound header type #
+#-----------------------------------#
+
+tests = []
+
+def test_aifc(h, f):
+ import aifc
+ if h[:4] <> 'FORM':
+ return None
+ if h[8:12] == 'AIFC':
+ fmt = 'aifc'
+ elif h[8:12] == 'AIFF':
+ fmt = 'aiff'
+ else:
+ return None
+ f.seek(0)
+ try:
+ a = aifc.openfp(f, 'r')
+ except (EOFError, aifc.Error):
+ return None
+ return (fmt, a.getframerate(), a.getnchannels(), \
+ a.getnframes(), 8*a.getsampwidth())
+
+tests.append(test_aifc)
+
+
+def test_au(h, f):
+ if h[:4] == '.snd':
+ f = get_long_be
+ elif h[:4] in ('\0ds.', 'dns.'):
+ f = get_long_le
+ else:
+ return None
+ type = 'au'
+ hdr_size = f(h[4:8])
+ data_size = f(h[8:12])
+ encoding = f(h[12:16])
+ rate = f(h[16:20])
+ nchannels = f(h[20:24])
+ sample_size = 1 # default
+ if encoding == 1:
+ sample_bits = 'U'
+ elif encoding == 2:
+ sample_bits = 8
+ elif encoding == 3:
+ sample_bits = 16
+ sample_size = 2
+ else:
+ sample_bits = '?'
+ frame_size = sample_size * nchannels
+ return type, rate, nchannels, data_size/frame_size, sample_bits
+
+tests.append(test_au)
+
+
+def test_hcom(h, f):
+ if h[65:69] <> 'FSSD' or h[128:132] <> 'HCOM':
+ return None
+ divisor = get_long_be(h[128+16:128+20])
+ return 'hcom', 22050/divisor, 1, -1, 8
+
+tests.append(test_hcom)
+
+
+def test_voc(h, f):
+ if h[:20] <> 'Creative Voice File\032':
+ return None
+ sbseek = get_short_le(h[20:22])
+ rate = 0
+ if 0 <= sbseek < 500 and h[sbseek] == '\1':
+ ratecode = ord(h[sbseek+4])
+ rate = int(1000000.0 / (256 - ratecode))
+ return 'voc', rate, 1, -1, 8
+
+tests.append(test_voc)
+
+
+def test_wav(h, f):
+ # 'RIFF' <len> 'WAVE' 'fmt ' <len>
+ if h[:4] <> 'RIFF' or h[8:12] <> 'WAVE' or h[12:16] <> 'fmt ':
+ return None
+ style = get_short_le(h[20:22])
+ nchannels = get_short_le(h[22:24])
+ rate = get_long_le(h[24:28])
+ sample_bits = get_short_le(h[34:36])
+ return 'wav', rate, nchannels, -1, sample_bits
+
+tests.append(test_wav)
+
+
+def test_8svx(h, f):
+ if h[:4] <> 'FORM' or h[8:12] <> '8SVX':
+ return None
+ # Should decode it to get #channels -- assume always 1
+ return '8svx', 0, 1, 0, 8
+
+tests.append(test_8svx)
+
+
+def test_sndt(h, f):
+ if h[:5] == 'SOUND':
+ nsamples = get_long_le(h[8:12])
+ rate = get_short_le(h[20:22])
+ return 'sndt', rate, 1, nsamples, 8
+
+tests.append(test_sndt)
+
+
+def test_sndr(h, f):
+ if h[:2] == '\0\0':
+ rate = get_short_le(h[2:4])
+ if 4000 <= rate <= 25000:
+ return 'sndr', rate, 1, -1, 8
+
+tests.append(test_sndr)
+
+
+#---------------------------------------------#
+# Subroutines to extract numbers from strings #
+#---------------------------------------------#
+
+def get_long_be(s):
+ return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3])
+
+def get_long_le(s):
+ return (ord(s[3])<<24) | (ord(s[2])<<16) | (ord(s[1])<<8) | ord(s[0])
+
+def get_short_be(s):
+ return (ord(s[0])<<8) | ord(s[1])
+
+def get_short_le(s):
+ return (ord(s[1])<<8) | ord(s[0])
+
+
+#--------------------#
+# Small test program #
+#--------------------#
+
+def test():
+ import sys
+ recursive = 0
+ if sys.argv[1:] and sys.argv[1] == '-r':
+ del sys.argv[1:2]
+ recursive = 1
+ try:
+ if sys.argv[1:]:
+ testall(sys.argv[1:], recursive, 1)
+ else:
+ testall(['.'], recursive, 1)
+ except KeyboardInterrupt:
+ sys.stderr.write('\n[Interrupted]\n')
+ sys.exit(1)
+
+def testall(list, recursive, toplevel):
+ import sys
+ import os
+ for filename in list:
+ if os.path.isdir(filename):
+ print filename + '/:',
+ if recursive or toplevel:
+ print 'recursing down:'
+ import glob
+ names = glob.glob(os.path.join(filename, '*'))
+ testall(names, recursive, 0)
+ else:
+ print '*** directory (use -r) ***'
+ else:
+ print filename + ':',
+ sys.stdout.flush()
+ try:
+ print what(filename)
+ except IOError:
+ print '*** not found ***'