diff options
329 files changed, 73432 insertions, 0 deletions
diff --git a/lib/jython/LICENSE.txt b/lib/jython/LICENSE.txt new file mode 100644 index 000000000..5287f75e6 --- /dev/null +++ b/lib/jython/LICENSE.txt @@ -0,0 +1,144 @@ +HISTORY OF THE SOFTWARE +======================= + +JPython was created in late 1997 by Jim Hugunin. Jim was also the +primary developer while he was at CNRI. In February 1999 Barry Warsaw +took over as primary developer and released JPython version 1.1. +In October 2000 Barry helped move the software to SourceForge +where it was renamed to Jython. Jython 2.0 is developed by a group +of volunteers. + + +The standard library is covered by the BeOpen / CNRI license. See the +Lib/LICENSE file for details. + +The oro regular expresion matcher is covered by the apache license. +See the org/apache/LICENSE file for details. + +The zxJDBC package was written by Brian Zimmer and originally licensed +under the GNU Public License. The package is now covered by the Jython +Software License. + +Jython changes Software License. +================================ + +Copyright (c) 2000, Jython Developers +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + - Neither the name of the Jython Developers nor the names of + its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + + +JPython Software License. +========================= + +______________________________________________________________________ + +IMPORTANT: PLEASE READ THE FOLLOWING AGREEMENT CAREFULLY. + +BY CLICKING ON THE "ACCEPT" BUTTON WHERE INDICATED, OR BY INSTALLING, +COPYING OR OTHERWISE USING THE SOFTWARE, YOU ARE DEEMED TO HAVE AGREED TO +THE TERMS AND CONDITIONS OF THIS AGREEMENT. + +______________________________________________________________________ + +JPython version 1.1.x + + 1. This LICENSE AGREEMENT is between the Corporation for National Research + Initiatives, having an office at 1895 Preston White Drive, Reston, VA + 20191 ("CNRI"), and the Individual or Organization ("Licensee") + accessing and using JPython version 1.1.x in source or binary form and + its associated documentation as provided herein ("Software"). + + 2. Subject to the terms and conditions of this License Agreement, CNRI + hereby grants Licensee a non-exclusive, non-transferable, royalty-free, + world-wide license to reproduce, analyze, test, perform and/or display + publicly, prepare derivative works, distribute, and otherwise use the + Software alone or in any derivative version, provided, however, that + CNRI's License Agreement and CNRI's notice of copyright, i.e., + "Copyright ©1996-1999 Corporation for National Research Initiatives; + All Rights Reserved" are both retained in the Software, alone or in any + derivative version prepared by Licensee. + + Alternatively, in lieu of CNRI's License Agreement, Licensee may + substitute the following text (omitting the quotes), provided, however, + that such text is displayed prominently in the Software alone or in any + derivative version prepared by Licensee: "JPython (Version 1.1.x) is + made available subject to the terms and conditions in CNRI's License + Agreement. This Agreement may be located on the Internet using the + following unique, persistent identifier (known as a handle): + 1895.22/1006. The License may also be obtained from a proxy server on + the Web using the following URL: http://hdl.handle.net/1895.22/1006." + + 3. In the event Licensee prepares a derivative work that is based on or + incorporates the Software or any part thereof, and wants to make the + derivative work available to the public as provided herein, then + Licensee hereby agrees to indicate in any such work, in a prominently + visible way, the nature of the modifications made to CNRI's Software. + + 4. Licensee may not use CNRI trademarks or trade name, including JPython + or CNRI, in a trademark sense to endorse or promote products or + services of Licensee, or any third party. Licensee may use the mark + JPython in connection with Licensee's derivative versions that are + based on or incorporate the Software, but only in the form + "JPython-based ___________________," or equivalent. + + 5. CNRI is making the Software available to Licensee on an "AS IS" basis. + CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY + OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND DISCLAIMS ANY + REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY + PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE + ANY THIRD PARTY RIGHTS. + + 6. CNRI SHALL NOT BE LIABLE TO LICENSEE OR OTHER USERS OF THE SOFTWARE FOR + ANY INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF + USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY DERIVATIVE + THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. SOME STATES DO NOT + ALLOW THE LIMITATION OR EXCLUSION OF LIABILITY SO THE ABOVE DISCLAIMER + MAY NOT APPLY TO LICENSEE. + + 7. This License Agreement may be terminated by CNRI (i) immediately upon + written notice from CNRI of any material breach by the Licensee, if the + nature of the breach is such that it cannot be promptly remedied; or + (ii) sixty (60) days following notice from CNRI to Licensee of a + material remediable breach, if Licensee has not remedied such breach + within that sixty-day period. + + 8. This License Agreement shall be governed by and interpreted in all + respects by the law of the State of Virginia, excluding conflict of law + provisions. Nothing in this Agreement shall be deemed to create any + relationship of agency, partnership, or joint venture between CNRI and + Licensee. + + 9. By clicking on the "ACCEPT" button where indicated, or by installing, + copying or otherwise using the Software, Licensee agrees to be bound by + the terms and conditions of this License Agreement. + + [ACCEPT BUTTON] + diff --git a/lib/jython/Lib/BaseHTTPServer.py b/lib/jython/Lib/BaseHTTPServer.py new file mode 100644 index 000000000..5f3a8d7cf --- /dev/null +++ b/lib/jython/Lib/BaseHTTPServer.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"
+
+__all__ = ["HTTPServer", "BaseHTTPRequestHandler"]
+
+import sys
+import time
+import socket # For gethostbyaddr()
+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):
+
+ allow_reuse_address = 1 # Seems to make sense in testing environment
+
+ def server_bind(self):
+ """Override server_bind to store the server name."""
+ SocketServer.TCPServer.server_bind(self)
+ host, port = self.socket.getsockname()
+ self.server_name = socket.getfqdn(host)
+ 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 do_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/" + sys.version.split()[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 parse_request(self):
+ """Parse a request (internal).
+
+ The request should be stored in self.raw_request; the results
+ are in self.command, self.path, self.request_version and
+ self.headers.
+
+ Return value is 1 for success, 0 for failure; on failure, an
+ error is sent back.
+
+ """
+ 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 = requestline.split()
+ if len(words) == 3:
+ [command, path, version] = words
+ if version[:5] != 'HTTP/':
+ self.send_error(400, "Bad request version (%s)" % `version`)
+ return 0
+ elif len(words) == 2:
+ [command, path] = words
+ if command != 'GET':
+ self.send_error(400,
+ "Bad HTTP/0.9 request type (%s)" % `command`)
+ return 0
+ else:
+ self.send_error(400, "Bad request syntax (%s)" % `requestline`)
+ return 0
+ self.command, self.path, self.request_version = command, path, version
+ self.headers = self.MessageClass(self.rfile, 0)
+ return 1
+
+ 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()
+ if not self.parse_request(): # An error code has been sent, just exit
+ return
+ mname = 'do_' + self.command
+ if not hasattr(self, mname):
+ self.send_error(501, "Unsupported method (%s)" % `self.command`)
+ 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][0]
+ 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
+ return socket.getfqdn(host)
+
+ # 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 = int(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/jython/Lib/CGIHTTPServer.py b/lib/jython/Lib/CGIHTTPServer.py new file mode 100644 index 000000000..cc196fc69 --- /dev/null +++ b/lib/jython/Lib/CGIHTTPServer.py @@ -0,0 +1,305 @@ +"""CGI-savvy HTTP Server.
+
+This module builds on SimpleHTTPServer by implementing GET and POST
+requests to cgi-bin scripts.
+
+If the os.fork() function is not present (e.g. on Windows),
+os.popen2() is used as a fallback, with slightly altered semantics; if
+that function is not present either (e.g. on Macintosh), only Python
+scripts are supported, and they are executed by the current process.
+
+In all cases, the implementation is intentionally naive -- all
+requests are executed sychronously.
+
+SECURITY WARNING: DON'T USE THIS CODE UNLESS YOU ARE INSIDE A FIREWALL
+-- it may execute arbitrary Python code or external programs.
+
+"""
+
+
+__version__ = "0.4"
+
+__all__ = ["CGIHTTPRequestHandler"]
+
+import os
+import sys
+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.
+
+ """
+
+ # Determine platform specifics
+ have_fork = hasattr(os, 'fork')
+ have_popen2 = hasattr(os, 'popen2')
+
+ # Make rfile unbuffered -- we need to read one line and then pass
+ # the rest to a subprocess, so we can't use buffered input.
+ rbufsize = 0
+
+ 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 self.path corresponds to a CGI script.
+
+ Return a tuple (dir, rest) if self.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 is_executable(self, path):
+ """Test whether argument path is an executable file."""
+ return executable(path)
+
+ def is_python(self, path):
+ """Test whether argument path is a Python script."""
+ head, tail = os.path.splitext(path)
+ return tail.lower() in (".py", ".pyw")
+
+ def run_cgi(self):
+ """Execute a CGI script."""
+ dir, rest = self.cgi_info
+ i = rest.rfind('?')
+ if i >= 0:
+ rest, query = rest[:i], rest[i+1:]
+ else:
+ query = ''
+ i = rest.find('/')
+ 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
+ ispy = self.is_python(scriptname)
+ if not ispy:
+ if not (self.have_fork or self.have_popen2):
+ self.send_error(403, "CGI script is not a Python script (%s)" %
+ `scriptname`)
+ return
+ if not self.is_executable(scriptfile):
+ self.send_error(403, "CGI script is not executable (%s)" %
+ `scriptname`)
+ return
+
+ # 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]
+ # XXX AUTH_TYPE
+ # XXX REMOTE_USER
+ # XXX REMOTE_IDENT
+ if self.headers.typeheader is None:
+ env['CONTENT_TYPE'] = self.headers.type
+ else:
+ env['CONTENT_TYPE'] = self.headers.typeheader
+ length = self.headers.getheader('content-length')
+ if length:
+ env['CONTENT_LENGTH'] = length
+ accept = []
+ for line in self.headers.getallmatchingheaders('accept'):
+ if line[:1] in "\t\n\r ":
+ accept.append(line.strip())
+ else:
+ accept = accept + line[7:].split(',')
+ env['HTTP_ACCEPT'] = ','.join(accept)
+ ua = self.headers.getheader('user-agent')
+ if ua:
+ env['HTTP_USER_AGENT'] = ua
+ co = filter(None, self.headers.getheaders('cookie'))
+ if co:
+ env['HTTP_COOKIE'] = ', '.join(co)
+ # XXX Other HTTP_* headers
+ if not self.have_fork:
+ # Since we're setting the env in the parent, provide empty
+ # values to override previously set values
+ for k in ('QUERY_STRING', 'REMOTE_HOST', 'CONTENT_LENGTH',
+ 'HTTP_USER_AGENT', 'HTTP_COOKIE'):
+ env.setdefault(k, "")
+
+ self.send_response(200, "Script output follows")
+
+ decoded_query = query.replace('+', ' ')
+
+ if self.have_fork:
+ # Unix -- fork as we should
+ args = [script]
+ if '=' not in decoded_query:
+ args.append(decoded_query)
+ nobody = nobody_uid()
+ 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", sts)
+ return
+ # Child
+ try:
+ try:
+ os.setuid(nobody)
+ except os.error:
+ pass
+ os.dup2(self.rfile.fileno(), 0)
+ os.dup2(self.wfile.fileno(), 1)
+ os.execve(scriptfile, args, env)
+ except:
+ self.server.handle_error(self.request, self.client_address)
+ os._exit(127)
+
+ elif self.have_popen2:
+ # Windows -- use popen2 to create a subprocess
+ import shutil
+ os.environ.update(env)
+ cmdline = scriptfile
+ if self.is_python(scriptfile):
+ interp = sys.executable
+ if interp.lower().endswith("w.exe"):
+ # On Windows, use python.exe, not python.exe
+ interp = interp[:-5] = interp[-4:]
+ cmdline = "%s %s" % (interp, cmdline)
+ if '=' not in query and '"' not in query:
+ cmdline = '%s "%s"' % (cmdline, query)
+ self.log_error("command: %s", cmdline)
+ try:
+ nbytes = int(length)
+ except:
+ nbytes = 0
+ fi, fo = os.popen2(cmdline)
+ if self.command.lower() == "post" and nbytes > 0:
+ data = self.rfile.read(nbytes)
+ fi.write(data)
+ fi.close()
+ shutil.copyfileobj(fo, self.wfile)
+ sts = fo.close()
+ if sts:
+ self.log_error("CGI script exit status %#x", sts)
+ else:
+ self.log_error("CGI script exited OK")
+
+ else:
+ # Other O.S. -- execute script in this process
+ os.environ.update(env)
+ save_argv = sys.argv
+ save_stdin = sys.stdin
+ save_stdout = sys.stdout
+ save_stderr = sys.stderr
+ try:
+ try:
+ sys.argv = [scriptfile]
+ if '=' not in decoded_query:
+ sys.argv.append(decoded_query)
+ sys.stdout = self.wfile
+ sys.stdin = self.rfile
+ execfile(scriptfile, {"__name__": "__main__"})
+ finally:
+ sys.argv = save_argv
+ sys.stdin = save_stdin
+ sys.stdout = save_stdout
+ sys.stderr = save_stderr
+ except SystemExit, sts:
+ self.log_error("CGI script exit status %s", str(sts))
+ else:
+ self.log_error("CGI script exited OK")
+
+
+nobody = None
+
+def nobody_uid():
+ """Internal routine to get nobody's uid"""
+ global nobody
+ if nobody:
+ return nobody
+ try:
+ import pwd
+ except ImportError:
+ return -1
+ try:
+ nobody = pwd.getpwnam('nobody')[2]
+ except KeyError:
+ 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):
+ SimpleHTTPServer.test(HandlerClass, ServerClass)
+
+
+if __name__ == '__main__':
+ test()
diff --git a/lib/jython/Lib/ConfigParser.py b/lib/jython/Lib/ConfigParser.py new file mode 100644 index 000000000..96186f297 --- /dev/null +++ b/lib/jython/Lib/ConfigParser.py @@ -0,0 +1,480 @@ +"""Configuration file parser.
+
+A setup file consists of sections, lead by a "[section]" header,
+and followed by "name: value" entries, with continuations and such in
+the style of RFC 822.
+
+The option values can contain format strings which refer to other values in
+the same section, or values in a special [DEFAULT] section.
+
+For example:
+
+ something: %(dir)s/whatever
+
+would resolve the "%(dir)s" to the value of dir. All reference
+expansions are done late, on demand.
+
+Intrinsic defaults can be specified by passing them into the
+ConfigParser constructor as a dictionary.
+
+class:
+
+ConfigParser -- responsible for for parsing a list of
+ configuration files, and managing the parsed database.
+
+ methods:
+
+ __init__(defaults=None)
+ create the parser and specify a dictionary of intrinsic defaults. The
+ keys must be strings, the values must be appropriate for %()s string
+ interpolation. Note that `__name__' is always an intrinsic default;
+ it's value is the section's name.
+
+ sections()
+ return all the configuration section names, sans DEFAULT
+
+ has_section(section)
+ return whether the given section exists
+
+ has_option(section, option)
+ return whether the given option exists in the given section
+
+ options(section)
+ return list of configuration options for the named section
+
+ has_option(section, option)
+ return whether the given section has the given option
+
+ read(filenames)
+ read and parse the list of named configuration files, given by
+ name. A single filename is also allowed. Non-existing files
+ are ignored.
+
+ readfp(fp, filename=None)
+ read and parse one configuration file, given as a file object.
+ The filename defaults to fp.name; it is only used in error
+ messages (if fp has no `name' attribute, the string `<???>' is used).
+
+ get(section, option, raw=0, vars=None)
+ return a string value for the named option. All % interpolations are
+ expanded in the return values, based on the defaults passed into the
+ constructor and the DEFAULT section. Additional substitutions may be
+ provided using the `vars' argument, which must be a dictionary whose
+ contents override any pre-existing defaults.
+
+ getint(section, options)
+ like get(), but convert value to an integer
+
+ getfloat(section, options)
+ like get(), but convert value to a float
+
+ getboolean(section, options)
+ like get(), but convert value to a boolean (currently defined as 0 or
+ 1, only)
+
+ remove_section(section)
+ remove the given file section and all its options
+
+ remove_option(section, option)
+ remove the given option from the given section
+
+ set(section, option, value)
+ set the given option
+
+ write(fp)
+ write the configuration state in .ini format
+"""
+
+import sys
+import string
+import re
+
+__all__ = ["NoSectionError","DuplicateSectionError","NoOptionError",
+ "InterpolationError","InterpolationDepthError","ParsingError",
+ "MissingSectionHeaderError","ConfigParser",
+ "MAX_INTERPOLATION_DEPTH"]
+
+DEFAULTSECT = "DEFAULT"
+
+MAX_INTERPOLATION_DEPTH = 10
+
+
+
+# exception classes
+class Error(Exception):
+ def __init__(self, msg=''):
+ self._msg = msg
+ Exception.__init__(self, msg)
+ def __repr__(self):
+ return self._msg
+ __str__ = __repr__
+
+class NoSectionError(Error):
+ def __init__(self, section):
+ Error.__init__(self, 'No section: %s' % section)
+ self.section = section
+
+class DuplicateSectionError(Error):
+ def __init__(self, section):
+ Error.__init__(self, "Section %s already exists" % section)
+ self.section = section
+
+class NoOptionError(Error):
+ def __init__(self, option, section):
+ Error.__init__(self, "No option `%s' in section: %s" %
+ (option, section))
+ self.option = option
+ self.section = section
+
+class InterpolationError(Error):
+ def __init__(self, reference, option, section, rawval):
+ Error.__init__(self,
+ "Bad value substitution:\n"
+ "\tsection: [%s]\n"
+ "\toption : %s\n"
+ "\tkey : %s\n"
+ "\trawval : %s\n"
+ % (section, option, reference, rawval))
+ self.reference = reference
+ self.option = option
+ self.section = section
+
+class InterpolationDepthError(Error):
+ def __init__(self, option, section, rawval):
+ Error.__init__(self,
+ "Value interpolation too deeply recursive:\n"
+ "\tsection: [%s]\n"
+ "\toption : %s\n"
+ "\trawval : %s\n"
+ % (section, option, rawval))
+ self.option = option
+ self.section = section
+
+class ParsingError(Error):
+ def __init__(self, filename):
+ Error.__init__(self, 'File contains parsing errors: %s' % filename)
+ self.filename = filename
+ self.errors = []
+
+ def append(self, lineno, line):
+ self.errors.append((lineno, line))
+ self._msg = self._msg + '\n\t[line %2d]: %s' % (lineno, line)
+
+class MissingSectionHeaderError(ParsingError):
+ def __init__(self, filename, lineno, line):
+ Error.__init__(
+ self,
+ 'File contains no section headers.\nfile: %s, line: %d\n%s' %
+ (filename, lineno, line))
+ self.filename = filename
+ self.lineno = lineno
+ self.line = line
+
+
+
+class ConfigParser:
+ def __init__(self, defaults=None):
+ self.__sections = {}
+ if defaults is None:
+ self.__defaults = {}
+ else:
+ self.__defaults = defaults
+
+ def defaults(self):
+ return self.__defaults
+
+ def sections(self):
+ """Return a list of section names, excluding [DEFAULT]"""
+ # self.__sections will never have [DEFAULT] in it
+ return self.__sections.keys()
+
+ def add_section(self, section):
+ """Create a new section in the configuration.
+
+ Raise DuplicateSectionError if a section by the specified name
+ already exists.
+ """
+ if self.__sections.has_key(section):
+ raise DuplicateSectionError(section)
+ self.__sections[section] = {}
+
+ def has_section(self, section):
+ """Indicate whether the named section is present in the configuration.
+
+ The DEFAULT section is not acknowledged.
+ """
+ return section in self.sections()
+
+ def options(self, section):
+ """Return a list of option names for the given section name."""
+ try:
+ opts = self.__sections[section].copy()
+ except KeyError:
+ raise NoSectionError(section)
+ opts.update(self.__defaults)
+ if opts.has_key('__name__'):
+ del opts['__name__']
+ return opts.keys()
+
+ def has_option(self, section, option):
+ """Return whether the given section has the given option."""
+ return option in self.options(section)
+
+ def read(self, filenames):
+ """Read and parse a filename or a list of filenames.
+
+ Files that cannot be opened are silently ignored; this is
+ designed so that you can specify a list of potential
+ configuration file locations (e.g. current directory, user's
+ home directory, systemwide directory), and all existing
+ configuration files in the list will be read. A single
+ filename may also be given.
+ """
+ if type(filenames) in [type(''), type(u'')]:
+ filenames = [filenames]
+ for filename in filenames:
+ try:
+ fp = open(filename)
+ except IOError:
+ continue
+ self.__read(fp, filename)
+ fp.close()
+
+ def readfp(self, fp, filename=None):
+ """Like read() but the argument must be a file-like object.
+
+ The `fp' argument must have a `readline' method. Optional
+ second argument is the `filename', which if not given, is
+ taken from fp.name. If fp has no `name' attribute, `<???>' is
+ used.
+
+ """
+ if filename is None:
+ try:
+ filename = fp.name
+ except AttributeError:
+ filename = '<???>'
+ self.__read(fp, filename)
+
+ def get(self, section, option, raw=0, vars=None):
+ """Get an option value for a given section.
+
+ All % interpolations are expanded in the return values, based on the
+ defaults passed into the constructor, unless the optional argument
+ `raw' is true. Additional substitutions may be provided using the
+ `vars' argument, which must be a dictionary whose contents overrides
+ any pre-existing defaults.
+
+ The section DEFAULT is special.
+ """
+ try:
+ sectdict = self.__sections[section].copy()
+ except KeyError:
+ if section == DEFAULTSECT:
+ sectdict = {}
+ else:
+ raise NoSectionError(section)
+ d = self.__defaults.copy()
+ d.update(sectdict)
+ # Update with the entry specific variables
+ if vars:
+ d.update(vars)
+ option = self.optionxform(option)
+ try:
+ rawval = d[option]
+ except KeyError:
+ raise NoOptionError(option, section)
+
+ if raw:
+ return rawval
+
+ # do the string interpolation
+ value = rawval # Make it a pretty variable name
+ depth = 0
+ while depth < 10: # Loop through this until it's done
+ depth = depth + 1
+ if value.find("%(") >= 0:
+ try:
+ value = value % d
+ except KeyError, key:
+ raise InterpolationError(key, option, section, rawval)
+ else:
+ break
+ if value.find("%(") >= 0:
+ raise InterpolationDepthError(option, section, rawval)
+ return value
+
+ def __get(self, section, conv, option):
+ return conv(self.get(section, option))
+
+ def getint(self, section, option):
+ return self.__get(section, string.atoi, option)
+
+ def getfloat(self, section, option):
+ return self.__get(section, string.atof, option)
+
+ def getboolean(self, section, option):
+ v = self.get(section, option)
+ val = int(v)
+ if val not in (0, 1):
+ raise ValueError, 'Not a boolean: %s' % v
+ return val
+
+ def optionxform(self, optionstr):
+ return optionstr.lower()
+
+ def has_option(self, section, option):
+ """Check for the existence of a given option in a given section."""
+ if not section or section == "DEFAULT":
+ return self.__defaults.has_key(option)
+ elif not self.has_section(section):
+ return 0
+ else:
+ option = self.optionxform(option)
+ return self.__sections[section].has_key(option)
+
+ def set(self, section, option, value):
+ """Set an option."""
+ if not section or section == "DEFAULT":
+ sectdict = self.__defaults
+ else:
+ try:
+ sectdict = self.__sections[section]
+ except KeyError:
+ raise NoSectionError(section)
+ option = self.optionxform(option)
+ sectdict[option] = value
+
+ def write(self, fp):
+ """Write an .ini-format representation of the configuration state."""
+ if self.__defaults:
+ fp.write("[DEFAULT]\n")
+ for (key, value) in self.__defaults.items():
+ fp.write("%s = %s\n" % (key, value))
+ fp.write("\n")
+ for section in self.sections():
+ fp.write("[" + section + "]\n")
+ sectdict = self.__sections[section]
+ for (key, value) in sectdict.items():
+ if key == "__name__":
+ continue
+ fp.write("%s = %s\n" % (key, value))
+ fp.write("\n")
+
+ def remove_option(self, section, option):
+ """Remove an option."""
+ if not section or section == "DEFAULT":
+ sectdict = self.__defaults
+ else:
+ try:
+ sectdict = self.__sections[section]
+ except KeyError:
+ raise NoSectionError(section)
+ option = self.optionxform(option)
+ existed = sectdict.has_key(option)
+ if existed:
+ del sectdict[option]
+ return existed
+
+ def remove_section(self, section):
+ """Remove a file section."""
+ if self.__sections.has_key(section):
+ del self.__sections[section]
+ return 1
+ else:
+ return 0
+
+ #
+ # Regular expressions for parsing section headers and options. Note a
+ # slight semantic change from the previous version, because of the use
+ # of \w, _ is allowed in section header names.
+ SECTCRE = re.compile(
+ r'\[' # [
+ r'(?P<header>[^]]+)' # very permissive!
+ r'\]' # ]
+ )
+ OPTCRE = re.compile(
+ r'(?P<option>[]\-[\w_.*,(){}]+)' # a lot of stuff found by IvL
+ r'[ \t]*(?P<vi>[:=])[ \t]*' # any number of space/tab,
+ # followed by separator
+ # (either : or =), followed
+ # by any # space/tab
+ r'(?P<value>.*)$' # everything up to eol
+ )
+
+ def __read(self, fp, fpname):
+ """Parse a sectioned setup file.
+
+ The sections in setup file contains a title line at the top,
+ indicated by a name in square brackets (`[]'), plus key/value
+ options lines, indicated by `name: value' format lines.
+ Continuation are represented by an embedded newline then
+ leading whitespace. Blank lines, lines beginning with a '#',
+ and just about everything else is ignored.
+ """
+ cursect = None # None, or a dictionary
+ optname = None
+ lineno = 0
+ e = None # None, or an exception
+ while 1:
+ line = fp.readline()
+ if not line:
+ break
+ lineno = lineno + 1
+ # comment or blank line?
+ if line.strip() == '' or line[0] in '#;':
+ continue
+ if line.split()[0].lower() == 'rem' \
+ and line[0] in "rR": # no leading whitespace
+ continue
+ # continuation line?
+ if line[0] in ' \t' and cursect is not None and optname:
+ value = line.strip()
+ if value:
+ k = self.optionxform(optname)
+ cursect[k] = "%s\n%s" % (cursect[k], value)
+ # a section header or option header?
+ else:
+ # is it a section header?
+ mo = self.SECTCRE.match(line)
+ if mo:
+ sectname = mo.group('header')
+ if self.__sections.has_key(sectname):
+ cursect = self.__sections[sectname]
+ elif sectname == DEFAULTSECT:
+ cursect = self.__defaults
+ else:
+ cursect = {'__name__': sectname}
+ self.__sections[sectname] = cursect
+ # So sections can't start with a continuation line
+ optname = None
+ # no section header in the file?
+ elif cursect is None:
+ raise MissingSectionHeaderError(fpname, lineno, `line`)
+ # an option line?
+ else:
+ mo = self.OPTCRE.match(line)
+ if mo:
+ optname, vi, optval = mo.group('option', 'vi', 'value')
+ if vi in ('=', ':') and ';' in optval:
+ # ';' is a comment delimiter only if it follows
+ # a spacing character
+ pos = optval.find(';')
+ if pos and optval[pos-1] in string.whitespace:
+ optval = optval[:pos]
+ optval = optval.strip()
+ # allow empty values
+ if optval == '""':
+ optval = ''
+ cursect[self.optionxform(optname)] = optval
+ else:
+ # a non-fatal parsing error occurred. set up the
+ # exception but keep going. the exception will be
+ # raised at the end of the file and will contain a
+ # list of all bogus lines
+ if not e:
+ e = ParsingError(fpname)
+ e.append(lineno, `line`)
+ # if any parsing errors occurred, raise an exception
+ if e:
+ raise e
diff --git a/lib/jython/Lib/Cookie.py b/lib/jython/Lib/Cookie.py new file mode 100644 index 000000000..cfba529dd --- /dev/null +++ b/lib/jython/Lib/Cookie.py @@ -0,0 +1,734 @@ +#!/usr/bin/env python
+#
+
+####
+# Copyright 2000 by Timothy O'Malley <timo@alum.mit.edu>
+#
+# All Rights Reserved
+#
+# Permission to use, copy, modify, and distribute this software
+# and its documentation for any purpose and without fee is hereby
+# granted, provided that the above copyright notice appear in all
+# copies and that both that copyright notice and this permission
+# notice appear in supporting documentation, and that the name of
+# Timothy O'Malley not be used in advertising or publicity
+# pertaining to distribution of the software without specific, written
+# prior permission.
+#
+# Timothy O'Malley DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+# SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS, IN NO EVENT SHALL Timothy O'Malley BE LIABLE FOR
+# ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+#
+####
+#
+# Id: Cookie.py,v 2.29 2000/08/23 05:28:49 timo Exp
+# by Timothy O'Malley <timo@alum.mit.edu>
+#
+# Cookie.py is a Python module for the handling of HTTP
+# cookies as a Python dictionary. See RFC 2109 for more
+# information on cookies.
+#
+# The original idea to treat Cookies as a dictionary came from
+# Dave Mitchell (davem@magnet.com) in 1995, when he released the
+# first version of nscookie.py.
+#
+####
+
+r"""
+Here's a sample session to show how to use this module.
+At the moment, this is the only documentation.
+
+The Basics
+----------
+
+Importing is easy..
+
+ >>> import Cookie
+
+Most of the time you start by creating a cookie. Cookies come in
+three flavors, each with slighly different encoding semanitcs, but
+more on that later.
+
+ >>> C = Cookie.SimpleCookie()
+ >>> C = Cookie.SerialCookie()
+ >>> C = Cookie.SmartCookie()
+
+[Note: Long-time users of Cookie.py will remember using
+Cookie.Cookie() to create an Cookie object. Although deprecated, it
+is still supported by the code. See the Backward Compatibility notes
+for more information.]
+
+Once you've created your Cookie, you can add values just as if it were
+a dictionary.
+
+ >>> C = Cookie.SmartCookie()
+ >>> C["fig"] = "newton"
+ >>> C["sugar"] = "wafer"
+ >>> print C
+ Set-Cookie: sugar=wafer;
+ Set-Cookie: fig=newton;
+
+Notice that the printable representation of a Cookie is the
+appropriate format for a Set-Cookie: header. This is the
+default behavior. You can change the header and printed
+attributes by using the the .output() function
+
+ >>> C = Cookie.SmartCookie()
+ >>> C["rocky"] = "road"
+ >>> C["rocky"]["path"] = "/cookie"
+ >>> print C.output(header="Cookie:")
+ Cookie: rocky=road; Path=/cookie;
+ >>> print C.output(attrs=[], header="Cookie:")
+ Cookie: rocky=road;
+
+The load() method of a Cookie extracts cookies from a string. In a
+CGI script, you would use this method to extract the cookies from the
+HTTP_COOKIE environment variable.
+
+ >>> C = Cookie.SmartCookie()
+ >>> C.load("chips=ahoy; vienna=finger")
+ >>> print C
+ Set-Cookie: vienna=finger;
+ Set-Cookie: chips=ahoy;
+
+The load() method is darn-tootin smart about identifying cookies
+within a string. Escaped quotation marks, nested semicolons, and other
+such trickeries do not confuse it.
+
+ >>> C = Cookie.SmartCookie()
+ >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";')
+ >>> print C
+ Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;";
+
+Each element of the Cookie also supports all of the RFC 2109
+Cookie attributes. Here's an example which sets the Path
+attribute.
+
+ >>> C = Cookie.SmartCookie()
+ >>> C["oreo"] = "doublestuff"
+ >>> C["oreo"]["path"] = "/"
+ >>> print C
+ Set-Cookie: oreo=doublestuff; Path=/;
+
+Each dictionary element has a 'value' attribute, which gives you
+back the value associated with the key.
+
+ >>> C = Cookie.SmartCookie()
+ >>> C["twix"] = "none for you"
+ >>> C["twix"].value
+ 'none for you'
+
+
+A Bit More Advanced
+-------------------
+
+As mentioned before, there are three different flavors of Cookie
+objects, each with different encoding/decoding semantics. This
+section briefly discusses the differences.
+
+SimpleCookie
+
+The SimpleCookie expects that all values should be standard strings.
+Just to be sure, SimpleCookie invokes the str() builtin to convert
+the value to a string, when the values are set dictionary-style.
+
+ >>> C = Cookie.SimpleCookie()
+ >>> C["number"] = 7
+ >>> C["string"] = "seven"
+ >>> C["number"].value
+ '7'
+ >>> C["string"].value
+ 'seven'
+ >>> print C
+ Set-Cookie: number=7;
+ Set-Cookie: string=seven;
+
+
+SerialCookie
+
+The SerialCookie expects that all values should be serialized using
+cPickle (or pickle, if cPickle isn't available). As a result of
+serializing, SerialCookie can save almost any Python object to a
+value, and recover the exact same object when the cookie has been
+returned. (SerialCookie can yield some strange-looking cookie
+values, however.)
+
+ >>> C = Cookie.SerialCookie()
+ >>> C["number"] = 7
+ >>> C["string"] = "seven"
+ >>> C["number"].value
+ 7
+ >>> C["string"].value
+ 'seven'
+ >>> print C
+ Set-Cookie: number="I7\012.";
+ Set-Cookie: string="S'seven'\012p1\012.";
+
+Be warned, however, if SerialCookie cannot de-serialize a value (because
+it isn't a valid pickle'd object), IT WILL RAISE AN EXCEPTION.
+
+
+SmartCookie
+
+The SmartCookie combines aspects of each of the other two flavors.
+When setting a value in a dictionary-fashion, the SmartCookie will
+serialize (ala cPickle) the value *if and only if* it isn't a
+Python string. String objects are *not* serialized. Similarly,
+when the load() method parses out values, it attempts to de-serialize
+the value. If it fails, then it fallsback to treating the value
+as a string.
+
+ >>> C = Cookie.SmartCookie()
+ >>> C["number"] = 7
+ >>> C["string"] = "seven"
+ >>> C["number"].value
+ 7
+ >>> C["string"].value
+ 'seven'
+ >>> print C
+ Set-Cookie: number="I7\012.";
+ Set-Cookie: string=seven;
+
+
+Backwards Compatibility
+-----------------------
+
+In order to keep compatibilty with earlier versions of Cookie.py,
+it is still possible to use Cookie.Cookie() to create a Cookie. In
+fact, this simply returns a SmartCookie.
+
+ >>> C = Cookie.Cookie()
+ >>> print C.__class__.__name__
+ SmartCookie
+
+
+Finis.
+""" #"
+# ^
+# |----helps out font-lock
+
+#
+# Import our required modules
+#
+import string, sys
+from UserDict import UserDict
+
+try:
+ from cPickle import dumps, loads
+except ImportError:
+ from pickle import dumps, loads
+
+try:
+ import re
+except ImportError:
+ raise ImportError, "Cookie.py requires 're' from Python 1.5 or later"
+
+__all__ = ["CookieError","BaseCookie","SimpleCookie","SerialCookie",
+ "SmartCookie","Cookie"]
+
+#
+# Define an exception visible to External modules
+#
+class CookieError(Exception):
+ pass
+
+
+# These quoting routines conform to the RFC2109 specification, which in
+# turn references the character definitions from RFC2068. They provide
+# a two-way quoting algorithm. Any non-text character is translated
+# into a 4 character sequence: a forward-slash followed by the
+# three-digit octal equivalent of the character. Any '\' or '"' is
+# quoted with a preceeding '\' slash.
+#
+# These are taken from RFC2068 and RFC2109.
+# _LegalChars is the list of chars which don't require "'s
+# _Translator hash-table for fast quoting
+#
+_LegalChars = string.letters + string.digits + "!#$%&'*+-.^_`|~"
+_Translator = {
+ '\000' : '\\000', '\001' : '\\001', '\002' : '\\002',
+ '\003' : '\\003', '\004' : '\\004', '\005' : '\\005',
+ '\006' : '\\006', '\007' : '\\007', '\010' : '\\010',
+ '\011' : '\\011', '\012' : '\\012', '\013' : '\\013',
+ '\014' : '\\014', '\015' : '\\015', '\016' : '\\016',
+ '\017' : '\\017', '\020' : '\\020', '\021' : '\\021',
+ '\022' : '\\022', '\023' : '\\023', '\024' : '\\024',
+ '\025' : '\\025', '\026' : '\\026', '\027' : '\\027',
+ '\030' : '\\030', '\031' : '\\031', '\032' : '\\032',
+ '\033' : '\\033', '\034' : '\\034', '\035' : '\\035',
+ '\036' : '\\036', '\037' : '\\037',
+
+ '"' : '\\"', '\\' : '\\\\',
+
+ '\177' : '\\177', '\200' : '\\200', '\201' : '\\201',
+ '\202' : '\\202', '\203' : '\\203', '\204' : '\\204',
+ '\205' : '\\205', '\206' : '\\206', '\207' : '\\207',
+ '\210' : '\\210', '\211' : '\\211', '\212' : '\\212',
+ '\213' : '\\213', '\214' : '\\214', '\215' : '\\215',
+ '\216' : '\\216', '\217' : '\\217', '\220' : '\\220',
+ '\221' : '\\221', '\222' : '\\222', '\223' : '\\223',
+ '\224' : '\\224', '\225' : '\\225', '\226' : '\\226',
+ '\227' : '\\227', '\230' : '\\230', '\231' : '\\231',
+ '\232' : '\\232', '\233' : '\\233', '\234' : '\\234',
+ '\235' : '\\235', '\236' : '\\236', '\237' : '\\237',
+ '\240' : '\\240', '\241' : '\\241', '\242' : '\\242',
+ '\243' : '\\243', '\244' : '\\244', '\245' : '\\245',
+ '\246' : '\\246', '\247' : '\\247', '\250' : '\\250',
+ '\251' : '\\251', '\252' : '\\252', '\253' : '\\253',
+ '\254' : '\\254', '\255' : '\\255', '\256' : '\\256',
+ '\257' : '\\257', '\260' : '\\260', '\261' : '\\261',
+ '\262' : '\\262', '\263' : '\\263', '\264' : '\\264',
+ '\265' : '\\265', '\266' : '\\266', '\267' : '\\267',
+ '\270' : '\\270', '\271' : '\\271', '\272' : '\\272',
+ '\273' : '\\273', '\274' : '\\274', '\275' : '\\275',
+ '\276' : '\\276', '\277' : '\\277', '\300' : '\\300',
+ '\301' : '\\301', '\302' : '\\302', '\303' : '\\303',
+ '\304' : '\\304', '\305' : '\\305', '\306' : '\\306',
+ '\307' : '\\307', '\310' : '\\310', '\311' : '\\311',
+ '\312' : '\\312', '\313' : '\\313', '\314' : '\\314',
+ '\315' : '\\315', '\316' : '\\316', '\317' : '\\317',
+ '\320' : '\\320', '\321' : '\\321', '\322' : '\\322',
+ '\323' : '\\323', '\324' : '\\324', '\325' : '\\325',
+ '\326' : '\\326', '\327' : '\\327', '\330' : '\\330',
+ '\331' : '\\331', '\332' : '\\332', '\333' : '\\333',
+ '\334' : '\\334', '\335' : '\\335', '\336' : '\\336',
+ '\337' : '\\337', '\340' : '\\340', '\341' : '\\341',
+ '\342' : '\\342', '\343' : '\\343', '\344' : '\\344',
+ '\345' : '\\345', '\346' : '\\346', '\347' : '\\347',
+ '\350' : '\\350', '\351' : '\\351', '\352' : '\\352',
+ '\353' : '\\353', '\354' : '\\354', '\355' : '\\355',
+ '\356' : '\\356', '\357' : '\\357', '\360' : '\\360',
+ '\361' : '\\361', '\362' : '\\362', '\363' : '\\363',
+ '\364' : '\\364', '\365' : '\\365', '\366' : '\\366',
+ '\367' : '\\367', '\370' : '\\370', '\371' : '\\371',
+ '\372' : '\\372', '\373' : '\\373', '\374' : '\\374',
+ '\375' : '\\375', '\376' : '\\376', '\377' : '\\377'
+ }
+
+def _quote(str, LegalChars=_LegalChars,
+ join=string.join, idmap=string._idmap, translate=string.translate):
+ #
+ # If the string does not need to be double-quoted,
+ # then just return the string. Otherwise, surround
+ # the string in doublequotes and precede quote (with a \)
+ # special characters.
+ #
+ if "" == translate(str, idmap, LegalChars):
+ return str
+ else:
+ return '"' + join( map(_Translator.get, str, str), "" ) + '"'
+# end _quote
+
+
+_OctalPatt = re.compile(r"\\[0-3][0-7][0-7]")
+_QuotePatt = re.compile(r"[\\].")
+
+def _unquote(str, join=string.join, atoi=string.atoi):
+ # If there aren't any doublequotes,
+ # then there can't be any special characters. See RFC 2109.
+ if len(str) < 2:
+ return str
+ if str[0] != '"' or str[-1] != '"':
+ return str
+
+ # We have to assume that we must decode this string.
+ # Down to work.
+
+ # Remove the "s
+ str = str[1:-1]
+
+ # Check for special sequences. Examples:
+ # \012 --> \n
+ # \" --> "
+ #
+ i = 0
+ n = len(str)
+ res = []
+ while 0 <= i < n:
+ Omatch = _OctalPatt.search(str, i)
+ Qmatch = _QuotePatt.search(str, i)
+ if not Omatch and not Qmatch: # Neither matched
+ res.append(str[i:])
+ break
+ # else:
+ j = k = -1
+ if Omatch: j = Omatch.start(0)
+ if Qmatch: k = Qmatch.start(0)
+ if Qmatch and ( not Omatch or k < j ): # QuotePatt matched
+ res.append(str[i:k])
+ res.append(str[k+1])
+ i = k+2
+ else: # OctalPatt matched
+ res.append(str[i:j])
+ res.append( chr( atoi(str[j+1:j+4], 8) ) )
+ i = j+4
+ return join(res, "")
+# end _unquote
+
+# The _getdate() routine is used to set the expiration time in
+# the cookie's HTTP header. By default, _getdate() returns the
+# current time in the appropriate "expires" format for a
+# Set-Cookie header. The one optional argument is an offset from
+# now, in seconds. For example, an offset of -3600 means "one hour ago".
+# The offset may be a floating point number.
+#
+
+_weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+
+_monthname = [None,
+ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
+ 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
+
+def _getdate(future=0, weekdayname=_weekdayname, monthname=_monthname):
+ from time import gmtime, time
+ now = time()
+ year, month, day, hh, mm, ss, wd, y, z = gmtime(now + future)
+ return "%s, %02d-%3s-%4d %02d:%02d:%02d GMT" % \
+ (weekdayname[wd], day, monthname[month], year, hh, mm, ss)
+
+
+#
+# A class to hold ONE key,value pair.
+# In a cookie, each such pair may have several attributes.
+# so this class is used to keep the attributes associated
+# with the appropriate key,value pair.
+# This class also includes a coded_value attribute, which
+# is used to hold the network representation of the
+# value. This is most useful when Python objects are
+# pickled for network transit.
+#
+
+class Morsel(UserDict):
+ # RFC 2109 lists these attributes as reserved:
+ # path comment domain
+ # max-age secure version
+ #
+ # For historical reasons, these attributes are also reserved:
+ # expires
+ #
+ # This dictionary provides a mapping from the lowercase
+ # variant on the left to the appropriate traditional
+ # formatting on the right.
+ _reserved = { "expires" : "expires",
+ "path" : "Path",
+ "comment" : "Comment",
+ "domain" : "Domain",
+ "max-age" : "Max-Age",
+ "secure" : "secure",
+ "version" : "Version",
+ }
+ _reserved_keys = _reserved.keys()
+
+ def __init__(self):
+ # Set defaults
+ self.key = self.value = self.coded_value = None
+ UserDict.__init__(self)
+
+ # Set default attributes
+ for K in self._reserved_keys:
+ UserDict.__setitem__(self, K, "")
+ # end __init__
+
+ def __setitem__(self, K, V):
+ K = string.lower(K)
+ if not K in self._reserved_keys:
+ raise CookieError("Invalid Attribute %s" % K)
+ UserDict.__setitem__(self, K, V)
+ # end __setitem__
+
+ def isReservedKey(self, K):
+ return string.lower(K) in self._reserved_keys
+ # end isReservedKey
+
+ def set(self, key, val, coded_val,
+ LegalChars=_LegalChars,
+ idmap=string._idmap, translate=string.translate ):
+ # First we verify that the key isn't a reserved word
+ # Second we make sure it only contains legal characters
+ if string.lower(key) in self._reserved_keys:
+ raise CookieError("Attempt to set a reserved key: %s" % key)
+ if "" != translate(key, idmap, LegalChars):
+ raise CookieError("Illegal key value: %s" % key)
+
+ # It's a good key, so save it.
+ self.key = key
+ self.value = val
+ self.coded_value = coded_val
+ # end set
+
+ def output(self, attrs=None, header = "Set-Cookie:"):
+ return "%s %s" % ( header, self.OutputString(attrs) )
+
+ __str__ = output
+
+ def __repr__(self):
+ return '<%s: %s=%s>' % (self.__class__.__name__,
+ self.key, repr(self.value) )
+
+ def js_output(self, attrs=None):
+ # Print javascript
+ return """
+ <SCRIPT LANGUAGE="JavaScript">
+ <!-- begin hiding
+ document.cookie = \"%s\"
+ // end hiding -->
+ </script>
+ """ % ( self.OutputString(attrs), )
+ # end js_output()
+
+ def OutputString(self, attrs=None):
+ # Build up our result
+ #
+ result = []
+ RA = result.append
+
+ # First, the key=value pair
+ RA("%s=%s;" % (self.key, self.coded_value))
+
+ # Now add any defined attributes
+ if attrs is None:
+ attrs = self._reserved_keys
+ for K,V in self.items():
+ if V == "": continue
+ if K not in attrs: continue
+ if K == "expires" and type(V) == type(1):
+ RA("%s=%s;" % (self._reserved[K], _getdate(V)))
+ elif K == "max-age" and type(V) == type(1):
+ RA("%s=%d;" % (self._reserved[K], V))
+ elif K == "secure":
+ RA("%s;" % self._reserved[K])
+ else:
+ RA("%s=%s;" % (self._reserved[K], V))
+
+ # Return the result
+ return string.join(result, " ")
+ # end OutputString
+# end Morsel class
+
+
+
+#
+# Pattern for finding cookie
+#
+# This used to be strict parsing based on the RFC2109 and RFC2068
+# specifications. I have since discovered that MSIE 3.0x doesn't
+# follow the character rules outlined in those specs. As a
+# result, the parsing rules here are less strict.
+#
+
+_LegalCharsPatt = r"[\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\=]"
+_CookiePattern = re.compile(
+ r"(?x)" # This is a Verbose pattern
+ r"(?P<key>" # Start of group 'key'
+ ""+ _LegalCharsPatt +"+?" # Any word of at least one letter, nongreedy
+ r")" # End of group 'key'
+ r"\s*=\s*" # Equal Sign
+ r"(?P<val>" # Start of group 'val'
+ r'"(?:[^\\"]|\\.)*"' # Any doublequoted string
+ r"|" # or
+ ""+ _LegalCharsPatt +"*" # Any word or empty string
+ r")" # End of group 'val'
+ r"\s*;?" # Probably ending in a semi-colon
+ )
+
+
+# At long last, here is the cookie class.
+# Using this class is almost just like using a dictionary.
+# See this module's docstring for example usage.
+#
+class BaseCookie(UserDict):
+ # A container class for a set of Morsels
+ #
+
+ def value_decode(self, val):
+ """real_value, coded_value = value_decode(STRING)
+ Called prior to setting a cookie's value from the network
+ representation. The VALUE is the value read from HTTP
+ header.
+ Override this function to modify the behavior of cookies.
+ """
+ return val, val
+ # end value_encode
+
+ def value_encode(self, val):
+ """real_value, coded_value = value_encode(VALUE)
+ Called prior to setting a cookie's value from the dictionary
+ representation. The VALUE is the value being assigned.
+ Override this function to modify the behavior of cookies.
+ """
+ strval = str(val)
+ return strval, strval
+ # end value_encode
+
+ def __init__(self, input=None):
+ UserDict.__init__(self)
+ if input: self.load(input)
+ # end __init__
+
+ def __set(self, key, real_value, coded_value):
+ """Private method for setting a cookie's value"""
+ M = self.get(key, Morsel())
+ M.set(key, real_value, coded_value)
+ UserDict.__setitem__(self, key, M)
+ # end __set
+
+ def __setitem__(self, key, value):
+ """Dictionary style assignment."""
+ rval, cval = self.value_encode(value)
+ self.__set(key, rval, cval)
+ # end __setitem__
+
+ def output(self, attrs=None, header="Set-Cookie:", sep="\n"):
+ """Return a string suitable for HTTP."""
+ result = []
+ for K,V in self.items():
+ result.append( V.output(attrs, header) )
+ return string.join(result, sep)
+ # end output
+
+ __str__ = output
+
+ def __repr__(self):
+ L = []
+ for K,V in self.items():
+ L.append( '%s=%s' % (K,repr(V.value) ) )
+ return '<%s: %s>' % (self.__class__.__name__, string.join(L))
+
+ def js_output(self, attrs=None):
+ """Return a string suitable for JavaScript."""
+ result = []
+ for K,V in self.items():
+ result.append( V.js_output(attrs) )
+ return string.join(result, "")
+ # end js_output
+
+ def load(self, rawdata):
+ """Load cookies from a string (presumably HTTP_COOKIE) or
+ from a dictionary. Loading cookies from a dictionary 'd'
+ is equivalent to calling:
+ map(Cookie.__setitem__, d.keys(), d.values())
+ """
+ if type(rawdata) == type(""):
+ self.__ParseString(rawdata)
+ else:
+ self.update(rawdata)
+ return
+ # end load()
+
+ def __ParseString(self, str, patt=_CookiePattern):
+ i = 0 # Our starting point
+ n = len(str) # Length of string
+ M = None # current morsel
+
+ while 0 <= i < n:
+ # Start looking for a cookie
+ match = patt.search(str, i)
+ if not match: break # No more cookies
+
+ K,V = match.group("key"), match.group("val")
+ i = match.end(0)
+
+ # Parse the key, value in case it's metainfo
+ if K[0] == "$":
+ # We ignore attributes which pertain to the cookie
+ # mechanism as a whole. See RFC 2109.
+ # (Does anyone care?)
+ if M:
+ M[ K[1:] ] = V
+ elif string.lower(K) in Morsel._reserved_keys:
+ if M:
+ M[ K ] = _unquote(V)
+ else:
+ rval, cval = self.value_decode(V)
+ self.__set(K, rval, cval)
+ M = self[K]
+ # end __ParseString
+# end BaseCookie class
+
+class SimpleCookie(BaseCookie):
+ """SimpleCookie
+ SimpleCookie supports strings as cookie values. When setting
+ the value using the dictionary assignment notation, SimpleCookie
+ calls the builtin str() to convert the value to a string. Values
+ received from HTTP are kept as strings.
+ """
+ def value_decode(self, val):
+ return _unquote( val ), val
+ def value_encode(self, val):
+ strval = str(val)
+ return strval, _quote( strval )
+# end SimpleCookie
+
+class SerialCookie(BaseCookie):
+ """SerialCookie
+ SerialCookie supports arbitrary objects as cookie values. All
+ values are serialized (using cPickle) before being sent to the
+ client. All incoming values are assumed to be valid Pickle
+ representations. IF AN INCOMING VALUE IS NOT IN A VALID PICKLE
+ FORMAT, THEN AN EXCEPTION WILL BE RAISED.
+
+ Note: Large cookie values add overhead because they must be
+ retransmitted on every HTTP transaction.
+
+ Note: HTTP has a 2k limit on the size of a cookie. This class
+ does not check for this limit, so be careful!!!
+ """
+ def value_decode(self, val):
+ # This could raise an exception!
+ return loads( _unquote(val) ), val
+ def value_encode(self, val):
+ return val, _quote( dumps(val) )
+# end SerialCookie
+
+class SmartCookie(BaseCookie):
+ """SmartCookie
+ SmartCookie supports arbitrary objects as cookie values. If the
+ object is a string, then it is quoted. If the object is not a
+ string, however, then SmartCookie will use cPickle to serialize
+ the object into a string representation.
+
+ Note: Large cookie values add overhead because they must be
+ retransmitted on every HTTP transaction.
+
+ Note: HTTP has a 2k limit on the size of a cookie. This class
+ does not check for this limit, so be careful!!!
+ """
+ def value_decode(self, val):
+ strval = _unquote(val)
+ try:
+ return loads(strval), val
+ except:
+ return strval, val
+ def value_encode(self, val):
+ if type(val) == type(""):
+ return val, _quote(val)
+ else:
+ return val, _quote( dumps(val) )
+# end SmartCookie
+
+
+###########################################################
+# Backwards Compatibility: Don't break any existing code!
+
+# We provide Cookie() as an alias for SmartCookie()
+Cookie = SmartCookie
+
+#
+###########################################################
+
+def _test():
+ import doctest, Cookie
+ return doctest.testmod(Cookie)
+
+if __name__ == "__main__":
+ _test()
+
+
+#Local Variables:
+#tab-width: 4
+#end:
diff --git a/lib/jython/Lib/LICENSE b/lib/jython/Lib/LICENSE new file mode 100644 index 000000000..04a048468 --- /dev/null +++ b/lib/jython/Lib/LICENSE @@ -0,0 +1,232 @@ +A. HISTORY OF THE SOFTWARE
+==========================
+
+Python was created in the early 1990s by Guido van Rossum at Stichting
+Mathematisch Centrum (CWI) in the Netherlands as a successor of a
+language called ABC. Guido is Python's principal author, although it
+includes many contributions from others. The last version released
+from CWI was Python 1.2. In 1995, Guido continued his work on Python
+at the Corporation for National Research Initiatives (CNRI) in Reston,
+Virginia where he released several versions of the software. Python
+1.6 was the last of the versions released by CNRI. In 2000, Guido and
+the Python core development team moved to BeOpen.com to form the
+BeOpen PythonLabs team. Python 2.0 was the first and only release
+from BeOpen.com.
+
+Following the release of Python 1.6, and after Guido van Rossum left
+CNRI to work with commercial software developers, it became clear that
+the ability to use Python with software available under the GNU Public
+License (GPL) was very desirable. CNRI and the Free Software
+Foundation (FSF) interacted to develop enabling wording changes to the
+Python license. Python 1.6.1 is essentially the same as Python 1.6,
+with a few minor bug fixes, and with a different license that enables
+later versions to be GPL-compatible. Python 2.1 is a derivative work
+of Python 1.6.1, as well as of Python 2.0.
+
+After Python 2.0 was released by BeOpen.com, Guido van Rossum and the
+other PythonLabs developers joined Digital Creations. All
+intellectual property added from this point on, starting with Python
+2.1 and its alpha and beta releases, is owned by the Python Software
+Foundation (PSF), a non-profit modeled after the Apache Software
+Foundation. See http://www.python.org/psf/ for more information about
+the PSF.
+
+Thanks to the many outside volunteers who have worked under Guido's
+direction to make these releases possible.
+
+
+B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
+===============================================================
+
+PSF LICENSE AGREEMENT
+---------------------
+
+1. This LICENSE AGREEMENT is between the Python Software Foundation
+("PSF"), and the Individual or Organization ("Licensee") accessing and
+otherwise using Python 2.1.1 software in source or binary form and its
+associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, PSF
+hereby grants Licensee a nonexclusive, royalty-free, world-wide
+license to reproduce, analyze, test, perform and/or display publicly,
+prepare derivative works, distribute, and otherwise use Python 2.1.1
+alone or in any derivative version, provided, however, that PSF's
+License Agreement and PSF's notice of copyright, i.e., "Copyright (c)
+2001 Python Software Foundation; All Rights Reserved" are retained in
+Python 2.1.1 alone or in any derivative version prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on
+or incorporates Python 2.1.1 or any part thereof, and wants to make
+the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to Python 2.1.1.
+
+4. PSF is making Python 2.1.1 available to Licensee on an "AS IS"
+basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 2.1.1 WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+2.1.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.1.1,
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any
+relationship of agency, partnership, or joint venture between PSF and
+Licensee. This License Agreement does not grant permission to use PSF
+trademarks or trade name in a trademark sense to endorse or promote
+products or services of Licensee, or any third party.
+
+8. By copying, installing or otherwise using Python 2.1.1, Licensee
+agrees to be bound by the terms and conditions of this License
+Agreement.
+
+
+BEOPEN.COM TERMS AND CONDITIONS FOR PYTHON 2.0
+----------------------------------------------
+
+BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
+
+1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
+office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
+Individual or Organization ("Licensee") accessing and otherwise using
+this software in source or binary form and its associated
+documentation ("the Software").
+
+2. Subject to the terms and conditions of this BeOpen Python License
+Agreement, BeOpen hereby grants Licensee a non-exclusive,
+royalty-free, world-wide license to reproduce, analyze, test, perform
+and/or display publicly, prepare derivative works, distribute, and
+otherwise use the Software alone or in any derivative version,
+provided, however, that the BeOpen Python License is retained in the
+Software, alone or in any derivative version prepared by Licensee.
+
+3. BeOpen is making the Software available to Licensee on an "AS IS"
+basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
+SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
+AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
+DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+5. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+6. This License Agreement shall be governed by and interpreted in all
+respects by the law of the State of California, excluding conflict of
+law provisions. Nothing in this License Agreement shall be deemed to
+create any relationship of agency, partnership, or joint venture
+between BeOpen and Licensee. This License Agreement does not grant
+permission to use BeOpen trademarks or trade names in a trademark
+sense to endorse or promote products or services of Licensee, or any
+third party. As an exception, the "BeOpen Python" logos available at
+http://www.pythonlabs.com/logos.html may be used according to the
+permissions granted on that web page.
+
+7. By copying, installing or otherwise using the software, Licensee
+agrees to be bound by the terms and conditions of this License
+Agreement.
+
+
+CNRI OPEN SOURCE GPL-COMPATIBLE LICENSE AGREEMENT
+-------------------------------------------------
+
+1. This LICENSE AGREEMENT is between the Corporation for National
+Research Initiatives, having an office at 1895 Preston White Drive,
+Reston, VA 20191 ("CNRI"), and the Individual or Organization
+("Licensee") accessing and otherwise using Python 1.6.1 software in
+source or binary form and its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, CNRI
+hereby grants Licensee a nonexclusive, royalty-free, world-wide
+license to reproduce, analyze, test, perform and/or display publicly,
+prepare derivative works, distribute, and otherwise use Python 1.6.1
+alone or in any derivative version, provided, however, that CNRI's
+License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
+1995-2001 Corporation for National Research Initiatives; All Rights
+Reserved" are retained in Python 1.6.1 alone or in any derivative
+version prepared by Licensee. Alternately, in lieu of CNRI's License
+Agreement, Licensee may substitute the following text (omitting the
+quotes): "Python 1.6.1 is made available subject to the terms and
+conditions in CNRI's License Agreement. This Agreement together with
+Python 1.6.1 may be located on the Internet using the following
+unique, persistent identifier (known as a handle): 1895.22/1013. This
+Agreement may also be obtained from a proxy server on the Internet
+using the following URL: http://hdl.handle.net/1895.22/1013".
+
+3. In the event Licensee prepares a derivative work that is based on
+or incorporates Python 1.6.1 or any part thereof, and wants to make
+the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to Python 1.6.1.
+
+4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
+basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. This License Agreement shall be governed by the federal
+intellectual property law of the United States, including without
+limitation the federal copyright law, and, to the extent such
+U.S. federal law does not apply, by the law of the Commonwealth of
+Virginia, excluding Virginia's conflict of law provisions.
+Notwithstanding the foregoing, with regard to derivative works based
+on Python 1.6.1 that incorporate non-separable material that was
+previously distributed under the GNU General Public License (GPL), the
+law of the Commonwealth of Virginia shall govern this License
+Agreement only as to issues arising under or with respect to
+Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
+License Agreement shall be deemed to create any relationship of
+agency, partnership, or joint venture between CNRI and Licensee. This
+License Agreement does not grant permission to use CNRI trademarks or
+trade name in a trademark sense to endorse or promote products or
+services of Licensee, or any third party.
+
+8. By clicking on the "ACCEPT" button where indicated, or by copying,
+installing or otherwise using Python 1.6.1, Licensee agrees to be
+bound by the terms and conditions of this License Agreement.
+
+ ACCEPT
+
+
+CWI PERMISSIONS STATEMENT AND DISCLAIMER
+----------------------------------------
+
+Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
+The Netherlands. All rights reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/lib/jython/Lib/MimeWriter.py b/lib/jython/Lib/MimeWriter.py new file mode 100644 index 000000000..7b6fcc37f --- /dev/null +++ b/lib/jython/Lib/MimeWriter.py @@ -0,0 +1,128 @@ +"""Generic MIME writer.
+
+Classes:
+
+MimeWriter - the only thing here.
+
+"""
+
+
+import mimetools
+
+__all__ = ["MimeWriter"]
+
+class MimeWriter:
+
+ """Generic MIME writer.
+
+ Methods:
+
+ __init__()
+ addheader()
+ flushheaders()
+ startbody()
+ startmultipartbody()
+ nextpart()
+ lastpart()
+
+ A MIME writer is much more primitive than a MIME parser. It
+ doesn't seek around on the output file, and it doesn't use large
+ amounts of buffer space, so you have to write the parts in the
+ order they should occur on the output file. It does buffer the
+ headers you add, allowing you to rearrange their order.
+
+ General usage is:
+
+ f = <open the output file>
+ w = MimeWriter(f)
+ ...call w.addheader(key, value) 0 or more times...
+
+ followed by either:
+
+ f = w.startbody(content_type)
+ ...call f.write(data) for body data...
+
+ or:
+
+ w.startmultipartbody(subtype)
+ for each part:
+ subwriter = w.nextpart()
+ ...use the subwriter's methods to create the subpart...
+ w.lastpart()
+
+ The subwriter is another MimeWriter instance, and should be
+ treated in the same way as the toplevel MimeWriter. This way,
+ writing recursive body parts is easy.
+
+ Warning: don't forget to call lastpart()!
+
+ XXX There should be more state so calls made in the wrong order
+ are detected.
+
+ Some special cases:
+
+ - startbody() just returns the file passed to the constructor;
+ but don't use this knowledge, as it may be changed.
+
+ - startmultipartbody() actually returns a file as well;
+ this can be used to write the initial 'if you can read this your
+ mailer is not MIME-aware' message.
+
+ - If you call flushheaders(), the headers accumulated so far are
+ written out (and forgotten); this is useful if you don't need a
+ body part at all, e.g. for a subpart of type message/rfc822
+ that's (mis)used to store some header-like information.
+
+ - Passing a keyword argument 'prefix=<flag>' to addheader(),
+ start*body() affects where the header is inserted; 0 means
+ append at the end, 1 means insert at the start; default is
+ append for addheader(), but insert for start*body(), which use
+ it to determine where the Content-Type header goes.
+
+ """
+
+ def __init__(self, fp):
+ self._fp = fp
+ self._headers = []
+
+ def addheader(self, key, value, prefix=0):
+ lines = value.split("\n")
+ while lines and not lines[-1]: del lines[-1]
+ while lines and not lines[0]: del lines[0]
+ for i in range(1, len(lines)):
+ lines[i] = " " + lines[i].strip()
+ value = "\n".join(lines) + "\n"
+ line = key + ": " + value
+ if prefix:
+ self._headers.insert(0, line)
+ else:
+ self._headers.append(line)
+
+ def flushheaders(self):
+ self._fp.writelines(self._headers)
+ self._headers = []
+
+ def startbody(self, ctype, plist=[], prefix=1):
+ for name, value in plist:
+ ctype = ctype + ';\n %s=\"%s\"' % (name, value)
+ self.addheader("Content-Type", ctype, prefix=prefix)
+ self.flushheaders()
+ self._fp.write("\n")
+ return self._fp
+
+ def startmultipartbody(self, subtype, boundary=None, plist=[], prefix=1):
+ self._boundary = boundary or mimetools.choose_boundary()
+ return self.startbody("multipart/" + subtype,
+ [("boundary", self._boundary)] + plist,
+ prefix=prefix)
+
+ def nextpart(self):
+ self._fp.write("\n--" + self._boundary + "\n")
+ return self.__class__(self._fp)
+
+ def lastpart(self):
+ self._fp.write("\n--" + self._boundary + "--\n")
+
+
+if __name__ == '__main__':
+ import test.test_MimeWriter
diff --git a/lib/jython/Lib/Queue.py b/lib/jython/Lib/Queue.py new file mode 100644 index 000000000..01774fb33 --- /dev/null +++ b/lib/jython/Lib/Queue.py @@ -0,0 +1,132 @@ +"""A multi-producer, multi-consumer queue."""
+
+class Empty(Exception):
+ "Exception raised by Queue.get(block=0)/get_nowait()."
+ pass
+
+class Full(Exception):
+ "Exception raised by Queue.put(block=0)/put_nowait()."
+ pass
+
+class Queue:
+ def __init__(self, maxsize=0):
+ """Initialize a queue object with a given maximum size.
+
+ If maxsize is <= 0, the queue size is infinite.
+ """
+ import thread
+ self._init(maxsize)
+ self.mutex = thread.allocate_lock()
+ self.esema = thread.allocate_lock()
+ self.esema.acquire()
+ self.fsema = thread.allocate_lock()
+
+ def qsize(self):
+ """Return the approximate size of the queue (not reliable!)."""
+ self.mutex.acquire()
+ n = self._qsize()
+ self.mutex.release()
+ return n
+
+ def empty(self):
+ """Return 1 if the queue is empty, 0 otherwise (not reliable!)."""
+ self.mutex.acquire()
+ n = self._empty()
+ self.mutex.release()
+ return n
+
+ def full(self):
+ """Return 1 if the queue is full, 0 otherwise (not reliable!)."""
+ self.mutex.acquire()
+ n = self._full()
+ self.mutex.release()
+ return n
+
+ def put(self, item, block=1):
+ """Put an item into the queue.
+
+ If optional arg 'block' is 1 (the default), block if
+ necessary until a free slot is available. Otherwise (block
+ is 0), put an item on the queue if a free slot is immediately
+ available, else raise the Full exception.
+ """
+ if block:
+ self.fsema.acquire()
+ elif not self.fsema.acquire(0):
+ raise Full
+ self.mutex.acquire()
+ was_empty = self._empty()
+ self._put(item)
+ if was_empty:
+ self.esema.release()
+ if not self._full():
+ self.fsema.release()
+ self.mutex.release()
+
+ def put_nowait(self, item):
+ """Put an item into the queue without blocking.
+
+ Only enqueue the item if a free slot is immediately available.
+ Otherwise raise the Full exception.
+ """
+ return self.put(item, 0)
+
+ def get(self, block=1):
+ """Remove and return an item from the queue.
+
+ If optional arg 'block' is 1 (the default), block if
+ necessary until an item is available. Otherwise (block is 0),
+ return an item if one is immediately available, else raise the
+ Empty exception.
+ """
+ if block:
+ self.esema.acquire()
+ elif not self.esema.acquire(0):
+ raise Empty
+ self.mutex.acquire()
+ was_full = self._full()
+ item = self._get()
+ if was_full:
+ self.fsema.release()
+ if not self._empty():
+ self.esema.release()
+ self.mutex.release()
+ return item
+
+ def get_nowait(self):
+ """Remove and return an item from the queue without blocking.
+
+ Only get an item if one is immediately available. Otherwise
+ raise the Empty exception.
+ """
+ return self.get(0)
+
+ # 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 whether 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/jython/Lib/SimpleHTTPServer.py b/lib/jython/Lib/SimpleHTTPServer.py new file mode 100644 index 000000000..83fd09667 --- /dev/null +++ b/lib/jython/Lib/SimpleHTTPServer.py @@ -0,0 +1,198 @@ +"""Simple HTTP Server.
+
+This module builds on BaseHTTPServer by implementing the standard GET
+and HEAD requests in a fairly straightforward manner.
+
+"""
+
+
+__version__ = "0.6"
+
+__all__ = ["SimpleHTTPRequestHandler"]
+
+import os
+import posixpath
+import BaseHTTPServer
+import urllib
+import cgi
+import shutil
+import mimetypes
+from StringIO import StringIO
+
+
+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)
+ f = None
+ if os.path.isdir(path):
+ for index in "index.html", "index.htm":
+ index = os.path.join(path, index)
+ if os.path.exists(index):
+ path = index
+ break
+ else:
+ return self.list_directory(path)
+ ctype = self.guess_type(path)
+ if ctype.startswith('text/'):
+ mode = 'r'
+ else:
+ mode = 'rb'
+ try:
+ f = open(path, mode)
+ except IOError:
+ self.send_error(404, "File not found")
+ return None
+ self.send_response(200)
+ self.send_header("Content-type", ctype)
+ self.end_headers()
+ return f
+
+ def list_directory(self, path):
+ """Helper to produce a directory listing (absent index.html).
+
+ Return value is either a file object, or None (indicating an
+ error). In either case, the headers are sent, making the
+ interface the same as for send_head().
+
+ """
+ try:
+ list = os.listdir(path)
+ except os.error:
+ self.send_error(404, "No permission to list directory")
+ return None
+ list.sort(lambda a, b: cmp(a.lower(), b.lower()))
+ f = StringIO()
+ f.write("<title>Directory listing for %s</title>\n" % self.path)
+ f.write("<h2>Directory listing for %s</h2>\n" % self.path)
+ f.write("<hr>\n<ul>\n")
+ for name in list:
+ fullname = os.path.join(path, name)
+ displayname = linkname = name = cgi.escape(name)
+ # Append / for directories or @ for symbolic links
+ if os.path.isdir(fullname):
+ displayname = name + "/"
+ linkname = name + "/"
+ if os.path.islink(fullname):
+ displayname = name + "@"
+ # Note: a link to a directory displays with @ and links with /
+ f.write('<li><a href="%s">%s</a>\n' % (linkname, displayname))
+ f.write("</ul>\n<hr>\n")
+ f.seek(0)
+ self.send_response(200)
+ self.send_header("Content-type", "text/html")
+ 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(urllib.unquote(path))
+ words = path.split('/')
+ 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.
+
+ """
+ shutil.copyfileobj(source, outputfile)
+
+ 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 = ext.lower()
+ if self.extensions_map.has_key(ext):
+ return self.extensions_map[ext]
+ else:
+ return self.extensions_map['']
+
+ extensions_map = mimetypes.types_map.copy()
+ extensions_map.update({
+ '': 'application/octet-stream', # Default
+ '.py': 'text/plain',
+ '.c': 'text/plain',
+ '.h': 'text/plain',
+ })
+
+
+def test(HandlerClass = SimpleHTTPRequestHandler,
+ ServerClass = BaseHTTPServer.HTTPServer):
+ BaseHTTPServer.test(HandlerClass, ServerClass)
+
+
+if __name__ == '__main__':
+ test()
diff --git a/lib/jython/Lib/SocketServer.py b/lib/jython/Lib/SocketServer.py new file mode 100644 index 000000000..fb7262c61 --- /dev/null +++ b/lib/jython/Lib/SocketServer.py @@ -0,0 +1,566 @@ +"""Generic socket server classes.
+
+This module tries to capture the various aspects of defining a server:
+
+For socket-based servers:
+
+- 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)
+
+For request-based servers (including socket-based):
+
+- 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 five classes in an inheritance diagram, four of which represent
+synchronous servers of four types:
+
+ +------------+
+ | BaseServer |
+ +------------+
+ |
+ v
+ +-----------+ +------------------+
+ | 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
+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 cannot 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?
+
+BaseServer:
+- split generic "request" functionality out into BaseServer class.
+ Copyright (C) 2000 Luke Kenneth Casson Leighton <lkcl@samba.org>
+
+ example: read entries from a SQL database (requires overriding
+ get_request() to return a table entry from the database).
+ entry is processed by a RequestHandlerClass.
+
+"""
+
+# Author of the BaseServer patch: Luke Kenneth Casson Leighton
+
+# XXX Warning!
+# There is a test suite for this module, but it cannot be run by the
+# standard regression test.
+# To run it manually, run Lib/test/test_socketserver.py.
+
+__version__ = "0.4"
+
+
+import socket
+import sys
+import os
+
+__all__ = ["TCPServer","UDPServer","ForkingUDPServer","ForkingTCPServer",
+ "ThreadingUDPServer","ThreadingTCPServer","BaseRequestHandler",
+ "StreamRequestHandler","DatagramRequestHandler",
+ "ThreadingMixIn", "ForkingMixIn"]
+if hasattr(socket, "AF_UNIX"):
+ __all__.extend(["UnixStreamServer","UnixDatagramServer",
+ "ThreadingUnixStreamServer",
+ "ThreadingUnixDatagramServer"])
+
+class BaseServer:
+
+ """Base class for server classes.
+
+ Methods for the caller:
+
+ - __init__(server_address, RequestHandlerClass)
+ - serve_forever()
+ - handle_request() # if you do not 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)
+ - server_close()
+ - process_request(request, client_address)
+ - close_request(request)
+ - 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
+ - reuse_address
+
+ Instance variables:
+
+ - RequestHandlerClass
+ - socket
+
+ """
+
+ def __init__(self, server_address, RequestHandlerClass):
+ """Constructor. May be extended, do not override."""
+ self.server_address = server_address
+ self.RequestHandlerClass = RequestHandlerClass
+
+ def server_activate(self):
+ """Called by constructor to activate the server.
+
+ May be overridden.
+
+ """
+ pass
+
+ 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."""
+ try:
+ request, client_address = self.get_request()
+ except socket.error:
+ return
+ if self.verify_request(request, client_address):
+ try:
+ self.process_request(request, client_address)
+ except:
+ self.handle_error(request, client_address)
+ self.close_request(request)
+
+ 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)
+ self.close_request(request)
+
+ def server_close(self):
+ """Called to clean-up the server.
+
+ May be overridden.
+
+ """
+ pass
+
+ def finish_request(self, request, client_address):
+ """Finish one request by instantiating RequestHandlerClass."""
+ self.RequestHandlerClass(request, client_address, self)
+
+ def close_request(self, request):
+ """Called to clean up an individual request."""
+ pass
+
+ def handle_error(self, request, client_address):
+ """Handle an error gracefully. May be overridden.
+
+ The default is to print a traceback and continue.
+
+ """
+ print '-'*40
+ print 'Exception happened during processing of request from',
+ print client_address
+ import traceback
+ traceback.print_exc() # XXX But this goes to stderr!
+ print '-'*40
+
+
+class TCPServer(BaseServer):
+
+ """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)
+ - close_request(request)
+ - 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)
+ - reuse_address
+
+ Instance variables:
+
+ - server_address
+ - RequestHandlerClass
+ - socket
+
+ """
+
+ address_family = socket.AF_INET
+
+ socket_type = socket.SOCK_STREAM
+
+ request_queue_size = 5
+
+ allow_reuse_address = 0
+
+ def __init__(self, server_address, RequestHandlerClass):
+ """Constructor. May be extended, do not override."""
+ BaseServer.__init__(self, server_address, 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.
+
+ """
+ if self.allow_reuse_address:
+ self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ 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 server_close(self):
+ """Called to clean-up the server.
+
+ May be overridden.
+
+ """
+ self.socket.close()
+
+ def fileno(self):
+ """Return socket file number.
+
+ Interface required by select().
+
+ """
+ return self.socket.fileno()
+
+ def get_request(self):
+ """Get the request and client address from the socket.
+
+ May be overridden.
+
+ """
+ return self.socket.accept()
+
+ def close_request(self, request):
+ """Called to clean up an individual request."""
+ request.close()
+
+
+class UDPServer(TCPServer):
+
+ """UDP server class."""
+
+ allow_reuse_address = 0
+
+ socket_type = socket.SOCK_DGRAM
+
+ max_packet_size = 8192
+
+ def get_request(self):
+ data, client_addr = self.socket.recvfrom(self.max_packet_size)
+ return (data, self.socket), client_addr
+
+ def server_activate(self):
+ # No need to call listen() for UDP.
+ pass
+
+ def close_request(self, request):
+ # No need to close anything.
+ pass
+
+class ForkingMixIn:
+
+ """Mix-in class to handle each request in a new process."""
+
+ active_children = None
+ max_children = 40
+
+ def collect_children(self):
+ """Internal routine to wait for died children."""
+ while self.active_children:
+ if len(self.active_children) < self.max_children:
+ options = os.WNOHANG
+ else:
+ # If the maximum number of children are already
+ # running, block while waiting for a child to exit
+ options = 0
+ try:
+ pid, status = os.waitpid(0, options)
+ except os.error:
+ pid = None
+ 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)
+ self.close_request(request)
+ 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 threading
+ t = threading.Thread(target = self.finish_request,
+ args = (request, client_address))
+ t.start()
+
+
+class ForkingUDPServer(ForkingMixIn, UDPServer): pass
+class ForkingTCPServer(ForkingMixIn, TCPServer): pass
+
+class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
+class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
+
+if hasattr(socket, 'AF_UNIX'):
+
+ class UnixStreamServer(TCPServer):
+ address_family = socket.AF_UNIX
+
+ class UnixDatagramServer(UDPServer):
+ address_family = socket.AF_UNIX
+
+ class ThreadingUnixStreamServer(ThreadingMixIn, UnixStreamServer): pass
+
+ class ThreadingUnixDatagramServer(ThreadingMixIn, UnixDatagramServer): 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_address, 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."""
+
+ # Default buffer sizes for rfile, wfile.
+ # We default rfile to buffered because otherwise it could be
+ # really slow for large data (a getc() call per byte); we make
+ # wfile unbuffered because (a) often after a write() we want to
+ # read and we need to flush the line; (b) big writes to unbuffered
+ # files are typically optimized by stdio even when big reads
+ # aren't.
+ rbufsize = -1
+ wbufsize = 0
+
+ def setup(self):
+ self.connection = self.request
+ self.rfile = self.connection.makefile('rb', self.rbufsize)
+ self.wfile = self.connection.makefile('wb', self.wbufsize)
+
+ def finish(self):
+ self.wfile.flush()
+ self.wfile.close()
+ self.rfile.close()
+
+
+class DatagramRequestHandler(BaseRequestHandler):
+
+ # XXX Regrettably, I cannot get this working on Linux;
+ # s.recvfrom() doesn't return a meaningful client address.
+
+ """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.sendto(self.wfile.getvalue(), self.client_address)
diff --git a/lib/jython/Lib/StringIO.py b/lib/jython/Lib/StringIO.py new file mode 100644 index 000000000..89796f2f1 --- /dev/null +++ b/lib/jython/Lib/StringIO.py @@ -0,0 +1,208 @@ +"""File-like objects that read from or write to a string buffer.
+
+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.truncate([size]) # truncate file at to at most size (default: current pos)
+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).
+- There's also a much faster implementation in C, called cStringIO, but
+ it's not subclassable.
+- 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).
+"""
+
+try:
+ from errno import EINVAL
+except ImportError:
+ EINVAL = 22
+
+__all__ = ["StringIO"]
+
+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):
+ if self.closed:
+ raise ValueError, "I/O operation on closed file"
+ return 0
+
+ def seek(self, pos, mode = 0):
+ if self.closed:
+ raise ValueError, "I/O operation on closed file"
+ if self.buflist:
+ self.buf += ''.join(self.buflist)
+ self.buflist = []
+ if mode == 1:
+ pos += self.pos
+ elif mode == 2:
+ pos += self.len
+ self.pos = max(0, pos)
+
+ def tell(self):
+ if self.closed:
+ raise ValueError, "I/O operation on closed file"
+ return self.pos
+
+ def read(self, n = -1):
+ if self.closed:
+ raise ValueError, "I/O operation on closed file"
+ if self.buflist:
+ self.buf += ''.join(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, length=None):
+ if self.closed:
+ raise ValueError, "I/O operation on closed file"
+ if self.buflist:
+ self.buf += ''.join(self.buflist)
+ self.buflist = []
+ i = self.buf.find('\n', self.pos)
+ if i < 0:
+ newpos = self.len
+ else:
+ newpos = i+1
+ if length is not None:
+ if self.pos + length < newpos:
+ newpos = self.pos + length
+ r = self.buf[self.pos:newpos]
+ self.pos = newpos
+ return r
+
+ def readlines(self, sizehint = 0):
+ total = 0
+ lines = []
+ line = self.readline()
+ while line:
+ lines.append(line)
+ total += len(line)
+ if 0 < sizehint <= total:
+ break
+ line = self.readline()
+ return lines
+
+ def truncate(self, size=None):
+ if self.closed:
+ raise ValueError, "I/O operation on closed file"
+ if size is None:
+ size = self.pos
+ elif size < 0:
+ raise IOError(EINVAL, "Negative size not allowed")
+ elif size < self.pos:
+ self.pos = size
+ self.buf = self.getvalue()[:size]
+
+ def write(self, s):
+ if self.closed:
+ raise ValueError, "I/O operation on closed file"
+ 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 += ''.join(self.buflist)
+ self.buflist = []
+ self.buflist = [self.buf[:self.pos], s, self.buf[newpos:]]
+ self.buf = ''
+ if newpos > self.len:
+ self.len = newpos
+ else:
+ self.buflist.append(s)
+ self.len = newpos
+ self.pos = newpos
+
+ def writelines(self, list):
+ self.write(''.join(list))
+
+ def flush(self):
+ if self.closed:
+ raise ValueError, "I/O operation on closed file"
+
+ def getvalue(self):
+ if self.buflist:
+ self.buf += ''.join(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/jython/Lib/UserDict.py b/lib/jython/Lib/UserDict.py new file mode 100644 index 000000000..5f94757ed --- /dev/null +++ b/lib/jython/Lib/UserDict.py @@ -0,0 +1,42 @@ +"""A more or less complete user-defined wrapper around dictionary objects."""
+
+class UserDict:
+ def __init__(self, dict=None):
+ self.data = {}
+ if dict is not None: self.update(dict)
+ def __repr__(self): return repr(self.data)
+ def __cmp__(self, dict):
+ if isinstance(dict, UserDict):
+ return cmp(self.data, dict.data)
+ else:
+ return cmp(self.data, dict)
+ 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 clear(self): self.data.clear()
+ def copy(self):
+ if self.__class__ is UserDict:
+ return UserDict(self.data)
+ import copy
+ return copy.copy(self)
+ 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)
+ def update(self, dict):
+ if isinstance(dict, UserDict):
+ self.data.update(dict.data)
+ elif isinstance(dict, type(self.data)):
+ self.data.update(dict)
+ else:
+ for k, v in dict.items():
+ self.data[k] = v
+ def get(self, key, failobj=None):
+ return self.data.get(key, failobj)
+ def setdefault(self, key, failobj=None):
+ if not self.data.has_key(key):
+ self.data[key] = failobj
+ return self.data[key]
+ def popitem(self):
+ return self.data.popitem()
diff --git a/lib/jython/Lib/UserList.py b/lib/jython/Lib/UserList.py new file mode 100644 index 000000000..6d195a1f6 --- /dev/null +++ b/lib/jython/Lib/UserList.py @@ -0,0 +1,85 @@ +"""A more or less complete user-defined wrapper around list objects."""
+
+class UserList:
+ def __init__(self, initlist=None):
+ self.data = []
+ if initlist is not None:
+ # XXX should this accept an arbitrary sequence?
+ if type(initlist) == type(self.data):
+ self.data[:] = initlist
+ elif isinstance(initlist, UserList):
+ self.data[:] = initlist.data[:]
+ else:
+ self.data = list(initlist)
+ def __repr__(self): return repr(self.data)
+ def __lt__(self, other): return self.data < self.__cast(other)
+ def __le__(self, other): return self.data <= self.__cast(other)
+ def __eq__(self, other): return self.data == self.__cast(other)
+ def __ne__(self, other): return self.data != self.__cast(other)
+ def __gt__(self, other): return self.data > self.__cast(other)
+ def __ge__(self, other): return self.data >= self.__cast(other)
+ def __cast(self, other):
+ if isinstance(other, UserList): return other.data
+ else: return other
+ def __cmp__(self, other):
+ raise RuntimeError, "UserList.__cmp__() is obsolete"
+ def __contains__(self, item): return item in self.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):
+ i = max(i, 0); j = max(j, 0)
+ return self.__class__(self.data[i:j])
+ def __setslice__(self, i, j, other):
+ i = max(i, 0); j = max(j, 0)
+ if isinstance(other, UserList):
+ self.data[i:j] = other.data
+ elif isinstance(other, type(self.data)):
+ self.data[i:j] = other
+ else:
+ self.data[i:j] = list(other)
+ def __delslice__(self, i, j):
+ i = max(i, 0); j = max(j, 0)
+ del self.data[i:j]
+ def __add__(self, other):
+ if isinstance(other, UserList):
+ return self.__class__(self.data + other.data)
+ elif isinstance(other, type(self.data)):
+ return self.__class__(self.data + other)
+ else:
+ return self.__class__(self.data + list(other))
+ def __radd__(self, other):
+ if isinstance(other, UserList):
+ return self.__class__(other.data + self.data)
+ elif isinstance(other, type(self.data)):
+ return self.__class__(other + self.data)
+ else:
+ return self.__class__(list(other) + self.data)
+ def __iadd__(self, other):
+ if isinstance(other, UserList):
+ self.data += other.data
+ elif isinstance(other, type(self.data)):
+ self.data += other
+ else:
+ self.data += list(other)
+ return self
+ def __mul__(self, n):
+ return self.__class__(self.data*n)
+ __rmul__ = __mul__
+ def __imul__(self, n):
+ self.data *= n
+ return self
+ def append(self, item): self.data.append(item)
+ def insert(self, i, item): self.data.insert(i, item)
+ def pop(self, i=-1): return self.data.pop(i)
+ 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)
+ def extend(self, other):
+ if isinstance(other, UserList):
+ self.data.extend(other.data)
+ else:
+ self.data.extend(other)
diff --git a/lib/jython/Lib/UserString.py b/lib/jython/Lib/UserString.py new file mode 100644 index 000000000..9d0c7be21 --- /dev/null +++ b/lib/jython/Lib/UserString.py @@ -0,0 +1,173 @@ +#!/usr/bin/env python
+## vim:ts=4:et:nowrap
+"""A user-defined wrapper around string objects
+
+Note: string objects have grown methods in Python 1.6
+This module requires Python 1.6 or later.
+"""
+from types import StringType, UnicodeType
+import sys
+
+__all__ = ["UserString","MutableString"]
+
+class UserString:
+ def __init__(self, seq):
+ if isinstance(seq, StringType) or isinstance(seq, UnicodeType):
+ self.data = seq
+ elif isinstance(seq, UserString):
+ self.data = seq.data[:]
+ else:
+ self.data = str(seq)
+ def __str__(self): return str(self.data)
+ def __repr__(self): return repr(self.data)
+ def __int__(self): return int(self.data)
+ def __long__(self): return long(self.data)
+ def __float__(self): return float(self.data)
+ def __complex__(self): return complex(self.data)
+ def __hash__(self): return hash(self.data)
+
+ def __cmp__(self, string):
+ if isinstance(string, UserString):
+ return cmp(self.data, string.data)
+ else:
+ return cmp(self.data, string)
+ def __contains__(self, char):
+ return char in self.data
+
+ def __len__(self): return len(self.data)
+ def __getitem__(self, index): return self.__class__(self.data[index])
+ def __getslice__(self, start, end):
+ start = max(start, 0); end = max(end, 0)
+ return self.__class__(self.data[start:end])
+
+ def __add__(self, other):
+ if isinstance(other, UserString):
+ return self.__class__(self.data + other.data)
+ elif isinstance(other, StringType) or isinstance(other, UnicodeType):
+ return self.__class__(self.data + other)
+ else:
+ return self.__class__(self.data + str(other))
+ def __radd__(self, other):
+ if isinstance(other, StringType) or isinstance(other, UnicodeType):
+ return self.__class__(other + self.data)
+ else:
+ return self.__class__(str(other) + self.data)
+ def __iadd__(self, other):
+ if isinstance(other, UserString):
+ self.data += other.data
+ elif isinstance(other, StringType) or isinstance(other, UnicodeType):
+ self.data += other
+ else:
+ self.data += str(other)
+ return self
+ def __mul__(self, n):
+ return self.__class__(self.data*n)
+ __rmul__ = __mul__
+ def __imul__(self, n):
+ self.data *= n
+ return self
+
+ # the following methods are defined in alphabetical order:
+ def capitalize(self): return self.__class__(self.data.capitalize())
+ def center(self, width): return self.__class__(self.data.center(width))
+ def count(self, sub, start=0, end=sys.maxint):
+ return self.data.count(sub, start, end)
+ def encode(self, encoding=None, errors=None): # XXX improve this?
+ if encoding:
+ if errors:
+ return self.__class__(self.data.encode(encoding, errors))
+ else:
+ return self.__class__(self.data.encode(encoding))
+ else:
+ return self.__class__(self.data.encode())
+ def endswith(self, suffix, start=0, end=sys.maxint):
+ return self.data.endswith(suffix, start, end)
+ def expandtabs(self, tabsize=8):
+ return self.__class__(self.data.expandtabs(tabsize))
+ def find(self, sub, start=0, end=sys.maxint):
+ return self.data.find(sub, start, end)
+ def index(self, sub, start=0, end=sys.maxint):
+ return self.data.index(sub, start, end)
+ def isalpha(self): return self.data.isalpha()
+ def isalnum(self): return self.data.isalnum()
+ def isdecimal(self): return self.data.isdecimal()
+ def isdigit(self): return self.data.isdigit()
+ def islower(self): return self.data.islower()
+ def isnumeric(self): return self.data.isnumeric()
+ def isspace(self): return self.data.isspace()
+ def istitle(self): return self.data.istitle()
+ def isupper(self): return self.data.isupper()
+ def join(self, seq): return self.data.join(seq)
+ def ljust(self, width): return self.__class__(self.data.ljust(width))
+ def lower(self): return self.__class__(self.data.lower())
+ def lstrip(self): return self.__class__(self.data.lstrip())
+ def replace(self, old, new, maxsplit=-1):
+ return self.__class__(self.data.replace(old, new, maxsplit))
+ def rfind(self, sub, start=0, end=sys.maxint):
+ return self.data.rfind(sub, start, end)
+ def rindex(self, sub, start=0, end=sys.maxint):
+ return self.data.rindex(sub, start, end)
+ def rjust(self, width): return self.__class__(self.data.rjust(width))
+ def rstrip(self): return self.__class__(self.data.rstrip())
+ def split(self, sep=None, maxsplit=-1):
+ return self.data.split(sep, maxsplit)
+ def splitlines(self, keepends=0): return self.data.splitlines(keepends)
+ def startswith(self, prefix, start=0, end=sys.maxint):
+ return self.data.startswith(prefix, start, end)
+ def strip(self): return self.__class__(self.data.strip())
+ def swapcase(self): return self.__class__(self.data.swapcase())
+ def title(self): return self.__class__(self.data.title())
+ def translate(self, *args):
+ return self.__class__(self.data.translate(*args))
+ def upper(self): return self.__class__(self.data.upper())
+
+class MutableString(UserString):
+ """mutable string objects
+
+ Python strings are immutable objects. This has the advantage, that
+ strings may be used as dictionary keys. If this property isn't needed
+ and you insist on changing string values in place instead, you may cheat
+ and use MutableString.
+
+ But the purpose of this class is an educational one: to prevent
+ people from inventing their own mutable string class derived
+ from UserString and than forget thereby to remove (override) the
+ __hash__ method inherited from ^UserString. This would lead to
+ errors that would be very hard to track down.
+
+ A faster and better solution is to rewrite your program using lists."""
+ def __init__(self, string=""):
+ self.data = string
+ def __hash__(self):
+ raise TypeError, "unhashable type (it is mutable)"
+ def __setitem__(self, index, sub):
+ if index < 0 or index >= len(self.data): raise IndexError
+ self.data = self.data[:index] + sub + self.data[index+1:]
+ def __delitem__(self, index):
+ if index < 0 or index >= len(self.data): raise IndexError
+ self.data = self.data[:index] + self.data[index+1:]
+ def __setslice__(self, start, end, sub):
+ start = max(start, 0); end = max(end, 0)
+ if isinstance(sub, UserString):
+ self.data = self.data[:start]+sub.data+self.data[end:]
+ elif isinstance(sub, StringType) or isinstance(sub, UnicodeType):
+ self.data = self.data[:start]+sub+self.data[end:]
+ else:
+ self.data = self.data[:start]+str(sub)+self.data[end:]
+ def __delslice__(self, start, end):
+ start = max(start, 0); end = max(end, 0)
+ self.data = self.data[:start] + self.data[end:]
+ def immutable(self):
+ return UserString(self.data)
+
+if __name__ == "__main__":
+ # execute the regression test to stdout, if called as a script:
+ import os
+ called_in_dir, called_as = os.path.split(sys.argv[0])
+ called_in_dir = os.path.abspath(called_in_dir)
+ called_as, py = os.path.splitext(called_as)
+ sys.path.append(os.path.join(called_in_dir, 'test'))
+ if '-q' in sys.argv:
+ import test_support
+ test_support.verbose = 0
+ __import__('test_' + called_as.lower())
diff --git a/lib/jython/Lib/__future__.py b/lib/jython/Lib/__future__.py new file mode 100644 index 000000000..54ffabd66 --- /dev/null +++ b/lib/jython/Lib/__future__.py @@ -0,0 +1,69 @@ +"""Record of phased-in incompatible language changes.
+
+Each line is of the form:
+
+ FeatureName = "_Feature(" OptionalRelease "," MandatoryRelease ")"
+
+where, normally, OptionalRelease < MandatoryRelease, and both are 5-tuples
+of the same form as sys.version_info:
+
+ (PY_MAJOR_VERSION, # the 2 in 2.1.0a3; an int
+ PY_MINOR_VERSION, # the 1; an int
+ PY_MICRO_VERSION, # the 0; an int
+ PY_RELEASE_LEVEL, # "alpha", "beta", "candidate" or "final"; string
+ PY_RELEASE_SERIAL # the 3; an int
+ )
+
+OptionalRelease records the first release in which
+
+ from __future__ import FeatureName
+
+was accepted.
+
+In the case of MandatoryReleases that have not yet occurred,
+MandatoryRelease predicts the release in which the feature will become part
+of the language.
+
+Else MandatoryRelease records when the feature became part of the language;
+in releases at or after that, modules no longer need
+
+ from __future__ import FeatureName
+
+to use the feature in question, but may continue to use such imports.
+
+MandatoryRelease may also be None, meaning that a planned feature got
+dropped.
+
+Instances of class _Feature have two corresponding methods,
+.getOptionalRelease() and .getMandatoryRelease().
+
+No feature line is ever to be deleted from this file.
+"""
+
+class _Feature:
+ def __init__(self, optionalRelease, mandatoryRelease):
+ self.optional = optionalRelease
+ self.mandatory = mandatoryRelease
+
+ def getOptionalRelease(self):
+ """Return first release in which this feature was recognized.
+
+ This is a 5-tuple, of the same form as sys.version_info.
+ """
+
+ return self.optional
+
+ def getMandatoryRelease(self):
+ """Return release in which this feature will become mandatory.
+
+ This is a 5-tuple, of the same form as sys.version_info, or, if
+ the feature was dropped, is None.
+ """
+
+ return self.mandatory
+
+ def __repr__(self):
+ return "Feature(" + `self.getOptionalRelease()` + ", " + \
+ `self.getMandatoryRelease()` + ")"
+
+nested_scopes = _Feature((2, 1, 0, "beta", 1), (2, 2, 0, "final", 0))
diff --git a/lib/jython/Lib/anydbm.py b/lib/jython/Lib/anydbm.py new file mode 100644 index 000000000..167336f26 --- /dev/null +++ b/lib/jython/Lib/anydbm.py @@ -0,0 +1,86 @@ +"""Generic interface to all dbm clones.
+
+Instead of
+
+ import dbm
+ d = dbm.open(file, 'w', 0666)
+
+use
+
+ import anydbm
+ d = anydbm.open(file, 'w')
+
+The returned object is a dbhash, gdbm, dbm or dumbdbm object,
+dependent on the type of database being opened (determined by whichdb
+module) in the case of an existing dbm. If the dbm does not exist and
+the create or new flag ('c' or 'n') was specified, the dbm type will
+be determined by the availability of the modules (tested in the above
+order).
+
+It has the following interface (key and data are strings):
+
+ d[key] = data # store data at key (may override data at
+ # existing key)
+ data = d[key] # retrieve data at key (raise KeyError if no
+ # such key)
+ del d[key] # delete data stored at key (raises KeyError
+ # if no such key)
+ flag = d.has_key(key) # true if the key exists
+ list = d.keys() # return a list of all existing keys (slow!)
+
+Future versions may change the order in which implementations are
+tested for existence, add interfaces to other dbm-like
+implementations.
+
+The open function has an optional second argument. This can be 'r',
+for read-only access, 'w', for read-write access of an existing
+database, 'c' for read-write access to a new or existing database, and
+'n' for read-write access to a new database. The default is 'r'.
+
+Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it
+only if it doesn't exist; and 'n' always creates a new database.
+
+"""
+
+try:
+ class error(Exception):
+ pass
+except:
+ error = "anydbm.error"
+
+_names = ['dbhash', 'gdbm', 'dbm', 'dumbdbm']
+_errors = [error]
+_defaultmod = None
+
+for _name in _names:
+ try:
+ _mod = __import__(_name)
+ except ImportError:
+ continue
+ if not _defaultmod:
+ _defaultmod = _mod
+ _errors.append(_mod.error)
+
+if not _defaultmod:
+ raise ImportError, "no dbm clone found; tried %s" % _names
+
+error = tuple(_errors)
+
+def open(file, flag = 'r', mode = 0666):
+ # guess the type of an existing database
+ from whichdb import whichdb
+ result=whichdb(file)
+ if result is None:
+ # db doesn't exist
+ if 'c' in flag or 'n' in flag:
+ # file doesn't exist and the new
+ # flag was used so use default type
+ mod = _defaultmod
+ else:
+ raise error, "need 'c' or 'n' flag to open new db"
+ elif result == "":
+ # db type cannot be determined
+ raise error, "db type could not be determined"
+ else:
+ mod = __import__(result)
+ return mod.open(file, flag, mode)
diff --git a/lib/jython/Lib/atexit.py b/lib/jython/Lib/atexit.py new file mode 100644 index 000000000..8a1c10405 --- /dev/null +++ b/lib/jython/Lib/atexit.py @@ -0,0 +1,54 @@ +"""
+atexit.py - allow programmer to define multiple exit functions to be executed
+upon normal program termination.
+
+One public function, register, is defined.
+"""
+
+__all__ = ["register"]
+
+_exithandlers = []
+def _run_exitfuncs():
+ """run any registered exit functions
+
+ _exithandlers is traversed in reverse order so functions are executed
+ last in, first out.
+ """
+
+ while _exithandlers:
+ func, targs, kargs = _exithandlers.pop()
+ apply(func, targs, kargs)
+
+def register(func, *targs, **kargs):
+ """register a function to be executed upon normal program termination
+
+ func - function to be called at exit
+ targs - optional arguments to pass to func
+ kargs - optional keyword arguments to pass to func
+ """
+ _exithandlers.append((func, targs, kargs))
+
+import sys
+try:
+ x = sys.exitfunc
+except AttributeError:
+ sys.exitfunc = _run_exitfuncs
+else:
+ # if x isn't our own exit func executive, assume it's another
+ # registered exit function - append it to our list...
+ if x != _run_exitfuncs:
+ register(x)
+del sys
+
+if __name__ == "__main__":
+ def x1():
+ print "running x1"
+ def x2(n):
+ print "running x2(%s)" % `n`
+ def x3(n, kwd=None):
+ print "running x3(%s, kwd=%s)" % (`n`, `kwd`)
+
+ register(x1)
+ register(x2, 12)
+ register(x3, 5, "bar")
+ register(x3, "no kwd args")
diff --git a/lib/jython/Lib/base64.py b/lib/jython/Lib/base64.py new file mode 100644 index 000000000..db212518e --- /dev/null +++ b/lib/jython/Lib/base64.py @@ -0,0 +1,81 @@ +#! /usr/bin/env python
+
+"""Conversions to/from base64 transport encoding as per RFC-1521."""
+
+# Modified 04-Oct-95 by Jack to use binascii module
+
+import binascii
+
+__all__ = ["encode","decode","encodestring","decodestring"]
+
+MAXLINESIZE = 76 # Excluding the CRLF
+MAXBINSIZE = (MAXLINESIZE/4)*3
+
+def encode(input, output):
+ """Encode a file."""
+ while 1:
+ s = input.read(MAXBINSIZE)
+ if not s: break
+ while len(s) < MAXBINSIZE:
+ ns = input.read(MAXBINSIZE-len(s))
+ if not ns: break
+ s = s + ns
+ line = binascii.b2a_base64(s)
+ output.write(line)
+
+def decode(input, output):
+ """Decode a file."""
+ while 1:
+ line = input.readline()
+ if not line: break
+ s = binascii.a2b_base64(line)
+ output.write(s)
+
+def encodestring(s):
+ """Encode a string."""
+ import StringIO
+ f = StringIO.StringIO(s)
+ g = StringIO.StringIO()
+ encode(f, g)
+ return g.getvalue()
+
+def decodestring(s):
+ """Decode a string."""
+ import StringIO
+ f = StringIO.StringIO(s)
+ g = StringIO.StringIO()
+ decode(f, g)
+ return g.getvalue()
+
+def test():
+ """Small test program"""
+ import sys, getopt
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], 'deut')
+ except getopt.error, msg:
+ sys.stdout = sys.stderr
+ print msg
+ print """usage: %s [-d|-e|-u|-t] [file|-]
+ -d, -u: decode
+ -e: encode (default)
+ -t: encode and decode string 'Aladdin:open sesame'"""%sys.argv[0]
+ sys.exit(2)
+ func = encode
+ for o, a in opts:
+ if o == '-e': func = encode
+ if o == '-d': func = decode
+ if o == '-u': func = decode
+ if o == '-t': test1(); return
+ if args and args[0] != '-':
+ func(open(args[0], 'rb'), sys.stdout)
+ else:
+ func(sys.stdin, sys.stdout)
+
+def test1():
+ s0 = "Aladdin:open sesame"
+ s1 = encodestring(s0)
+ s2 = decodestring(s1)
+ print s0, `s1`, s2
+
+if __name__ == '__main__':
+ test()
diff --git a/lib/jython/Lib/bdb.py b/lib/jython/Lib/bdb.py new file mode 100644 index 000000000..8f1367def --- /dev/null +++ b/lib/jython/Lib/bdb.py @@ -0,0 +1,565 @@ +"""Debugger basics"""
+
+import sys
+import os
+import types
+
+__all__ = ["BdbQuit","Bdb","Breakpoint"]
+
+BdbQuit = 'bdb.BdbQuit' # Exception to give up completely
+
+
+class Bdb:
+
+ """Generic Python debugger base class.
+
+ This class takes care of details of the trace facility;
+ a derived class should implement user interaction.
+ The standard debugger class (pdb.Pdb) is an example.
+ """
+
+ def __init__(self):
+ self.breaks = {}
+ self.fncache = {}
+
+ def canonic(self, filename):
+ canonic = self.fncache.get(filename)
+ if not canonic:
+ canonic = os.path.abspath(filename)
+ self.fncache[filename] = canonic
+ return canonic
+
+ def reset(self):
+ import linecache
+ linecache.checkcache()
+ self.botframe = None
+ self.stopframe = None
+ self.returnframe = None
+ self.quitting = 0
+
+ def trace_dispatch(self, frame, event, arg):
+ if self.quitting:
+ return # None
+ if event == 'line':
+ return self.dispatch_line(frame)
+ if event == 'call':
+ return self.dispatch_call(frame, arg)
+ if event == 'return':
+ return self.dispatch_return(frame, arg)
+ if event == 'exception':
+ return self.dispatch_exception(frame, arg)
+ print 'bdb.Bdb.dispatch: unknown debugging event:', `event`
+ return self.trace_dispatch
+
+ def dispatch_line(self, frame):
+ if self.stop_here(frame) or self.break_here(frame):
+ self.user_line(frame)
+ if self.quitting: raise BdbQuit
+ return self.trace_dispatch
+
+ def dispatch_call(self, frame, arg):
+ # XXX 'arg' is no longer used
+ if self.botframe is None:
+ # First call of dispatch since reset()
+ self.botframe = frame
+ return self.trace_dispatch
+ if not (self.stop_here(frame) or self.break_anywhere(frame)):
+ # No need to trace this function
+ return # None
+ self.user_call(frame, arg)
+ if self.quitting: raise BdbQuit
+ return self.trace_dispatch
+
+ def dispatch_return(self, frame, arg):
+ if self.stop_here(frame) or frame == self.returnframe:
+ self.user_return(frame, arg)
+ if self.quitting: raise BdbQuit
+
+ def dispatch_exception(self, frame, arg):
+ if self.stop_here(frame):
+ self.user_exception(frame, arg)
+ if self.quitting: raise BdbQuit
+ return self.trace_dispatch
+
+ # Normally derived classes don't override the following
+ # methods, but they may if they want to redefine the
+ # definition of stopping and breakpoints.
+
+ def stop_here(self, frame):
+ if self.stopframe is None:
+ return 1
+ if frame is self.stopframe:
+ return 1
+ while frame is not None and frame is not self.stopframe:
+ if frame is self.botframe:
+ return 1
+ frame = frame.f_back
+ return 0
+
+ def break_here(self, frame):
+ filename = self.canonic(frame.f_code.co_filename)
+ if not self.breaks.has_key(filename):
+ return 0
+ lineno = frame.f_lineno
+ if not lineno in self.breaks[filename]:
+ return 0
+ # flag says ok to delete temp. bp
+ (bp, flag) = effective(filename, lineno, frame)
+ if bp:
+ self.currentbp = bp.number
+ if (flag and bp.temporary):
+ self.do_clear(str(bp.number))
+ return 1
+ else:
+ return 0
+
+ def do_clear(self, arg):
+ raise NotImplementedError, "subclass of bdb must implement do_clear()"
+
+ def break_anywhere(self, frame):
+ return self.breaks.has_key(
+ self.canonic(frame.f_code.co_filename))
+
+ # Derived classes should override the user_* methods
+ # to gain control.
+
+ def user_call(self, frame, argument_list):
+ """This method is called when there is the remote possibility
+ that we ever need to stop in this function."""
+ pass
+
+ def user_line(self, frame):
+ """This method is called when we stop or break at this line."""
+ pass
+
+ def user_return(self, frame, return_value):
+ """This method is called when a return trap is set here."""
+ pass
+
+ def user_exception(self, frame, (exc_type, exc_value, exc_traceback)):
+ """This method is called if an exception occurs,
+ but only if we are to stop at or just below this level."""
+ pass
+
+ # Derived classes and clients can call the following methods
+ # to affect the stepping state.
+
+ def set_step(self):
+ """Stop after one line of code."""
+ self.stopframe = None
+ self.returnframe = None
+ self.quitting = 0
+
+ def set_next(self, frame):
+ """Stop on the next line in or below the given frame."""
+ self.stopframe = frame
+ self.returnframe = None
+ self.quitting = 0
+
+ def set_return(self, frame):
+ """Stop when returning from the given frame."""
+ self.stopframe = frame.f_back
+ self.returnframe = frame
+ self.quitting = 0
+
+ def set_trace(self):
+ """Start debugging from here."""
+ try:
+ 1 + ''
+ except:
+ frame = sys.exc_info()[2].tb_frame.f_back
+ self.reset()
+ while frame:
+ frame.f_trace = self.trace_dispatch
+ self.botframe = frame
+ frame = frame.f_back
+ self.set_step()
+ sys.settrace(self.trace_dispatch)
+
+ def set_continue(self):
+ # Don't stop except at breakpoints or when finished
+ self.stopframe = self.botframe
+ self.returnframe = None
+ self.quitting = 0
+ if not self.breaks:
+ # no breakpoints; run without debugger overhead
+ sys.settrace(None)
+ try:
+ 1 + '' # raise an exception
+ except:
+ frame = sys.exc_info()[2].tb_frame.f_back
+ while frame and frame is not self.botframe:
+ del frame.f_trace
+ frame = frame.f_back
+
+ def set_quit(self):
+ self.stopframe = self.botframe
+ self.returnframe = None
+ self.quitting = 1
+ sys.settrace(None)
+
+ # Derived classes and clients can call the following methods
+ # to manipulate breakpoints. These methods return an
+ # error message is something went wrong, None if all is well.
+ # Set_break prints out the breakpoint line and file:lineno.
+ # Call self.get_*break*() to see the breakpoints or better
+ # for bp in Breakpoint.bpbynumber: if bp: bp.bpprint().
+
+ def set_break(self, filename, lineno, temporary=0, cond = None):
+ filename = self.canonic(filename)
+ import linecache # Import as late as possible
+ line = linecache.getline(filename, lineno)
+ if not line:
+ return 'Line %s:%d does not exist' % (filename,
+ lineno)
+ if not self.breaks.has_key(filename):
+ self.breaks[filename] = []
+ list = self.breaks[filename]
+ if not lineno in list:
+ list.append(lineno)
+ bp = Breakpoint(filename, lineno, temporary, cond)
+
+ def clear_break(self, filename, lineno):
+ filename = self.canonic(filename)
+ if not self.breaks.has_key(filename):
+ return 'There are no breakpoints in %s' % filename
+ if lineno not in self.breaks[filename]:
+ return 'There is no breakpoint at %s:%d' % (filename,
+ lineno)
+ # If there's only one bp in the list for that file,line
+ # pair, then remove the breaks entry
+ for bp in Breakpoint.bplist[filename, lineno][:]:
+ bp.deleteMe()
+ if not Breakpoint.bplist.has_key((filename, lineno)):
+ self.breaks[filename].remove(lineno)
+ if not self.breaks[filename]:
+ del self.breaks[filename]
+
+ def clear_bpbynumber(self, arg):
+ try:
+ number = int(arg)
+ except:
+ return 'Non-numeric breakpoint number (%s)' % arg
+ try:
+ bp = Breakpoint.bpbynumber[number]
+ except IndexError:
+ return 'Breakpoint number (%d) out of range' % number
+ if not bp:
+ return 'Breakpoint (%d) already deleted' % number
+ self.clear_break(bp.file, bp.line)
+
+ def clear_all_file_breaks(self, filename):
+ filename = self.canonic(filename)
+ if not self.breaks.has_key(filename):
+ return 'There are no breakpoints in %s' % filename
+ for line in self.breaks[filename]:
+ blist = Breakpoint.bplist[filename, line]
+ for bp in blist:
+ bp.deleteMe()
+ del self.breaks[filename]
+
+ def clear_all_breaks(self):
+ if not self.breaks:
+ return 'There are no breakpoints'
+ for bp in Breakpoint.bpbynumber:
+ if bp:
+ bp.deleteMe()
+ self.breaks = {}
+
+ def get_break(self, filename, lineno):
+ filename = self.canonic(filename)
+ return self.breaks.has_key(filename) and \
+ lineno in self.breaks[filename]
+
+ def get_breaks(self, filename, lineno):
+ filename = self.canonic(filename)
+ return self.breaks.has_key(filename) and \
+ lineno in self.breaks[filename] and \
+ Breakpoint.bplist[filename, lineno] or []
+
+ def get_file_breaks(self, filename):
+ filename = self.canonic(filename)
+ if self.breaks.has_key(filename):
+ return self.breaks[filename]
+ else:
+ return []
+
+ def get_all_breaks(self):
+ return self.breaks
+
+ # Derived classes and clients can call the following method
+ # to get a data structure representing a stack trace.
+
+ def get_stack(self, f, t):
+ stack = []
+ if t and t.tb_frame is f:
+ t = t.tb_next
+ while f is not None:
+ stack.append((f, f.f_lineno))
+ if f is self.botframe:
+ break
+ f = f.f_back
+ stack.reverse()
+ i = max(0, len(stack) - 1)
+ while t is not None:
+ stack.append((t.tb_frame, t.tb_lineno))
+ t = t.tb_next
+ return stack, i
+
+ #
+
+ def format_stack_entry(self, frame_lineno, lprefix=': '):
+ import linecache, repr
+ frame, lineno = frame_lineno
+ filename = self.canonic(frame.f_code.co_filename)
+ s = filename + '(' + `lineno` + ')'
+ if frame.f_code.co_name:
+ s = s + frame.f_code.co_name
+ else:
+ s = s + "<lambda>"
+ if frame.f_locals.has_key('__args__'):
+ args = frame.f_locals['__args__']
+ else:
+ args = None
+ if args:
+ s = s + repr.repr(args)
+ else:
+ s = s + '()'
+ if frame.f_locals.has_key('__return__'):
+ rv = frame.f_locals['__return__']
+ s = s + '->'
+ s = s + repr.repr(rv)
+ line = linecache.getline(filename, lineno)
+ if line: s = s + lprefix + line.strip()
+ return s
+
+ # The following two methods can be called by clients to use
+ # a debugger to debug a statement, given as a string.
+
+ def run(self, cmd, globals=None, locals=None):
+ if globals is None:
+ import __main__
+ globals = __main__.__dict__
+ if locals is None:
+ locals = globals
+ self.reset()
+ sys.settrace(self.trace_dispatch)
+ if not isinstance(cmd, types.CodeType):
+ cmd = cmd+'\n'
+ try:
+ try:
+ exec cmd in globals, locals
+ except BdbQuit:
+ pass
+ finally:
+ self.quitting = 1
+ sys.settrace(None)
+
+ def runeval(self, expr, globals=None, locals=None):
+ if globals is None:
+ import __main__
+ globals = __main__.__dict__
+ if locals is None:
+ locals = globals
+ self.reset()
+ sys.settrace(self.trace_dispatch)
+ if not isinstance(expr, types.CodeType):
+ expr = expr+'\n'
+ try:
+ try:
+ return eval(expr, globals, locals)
+ except BdbQuit:
+ pass
+ finally:
+ self.quitting = 1
+ sys.settrace(None)
+
+ def runctx(self, cmd, globals, locals):
+ # B/W compatibility
+ self.run(cmd, globals, locals)
+
+ # This method is more useful to debug a single function call.
+
+ def runcall(self, func, *args):
+ self.reset()
+ sys.settrace(self.trace_dispatch)
+ res = None
+ try:
+ try:
+ res = apply(func, args)
+ except BdbQuit:
+ pass
+ finally:
+ self.quitting = 1
+ sys.settrace(None)
+ return res
+
+
+def set_trace():
+ Bdb().set_trace()
+
+
+class Breakpoint:
+
+ """Breakpoint class
+
+ Implements temporary breakpoints, ignore counts, disabling and
+ (re)-enabling, and conditionals.
+
+ Breakpoints are indexed by number through bpbynumber and by
+ the file,line tuple using bplist. The former points to a
+ single instance of class Breakpoint. The latter points to a
+ list of such instances since there may be more than one
+ breakpoint per line.
+
+ """
+
+ # XXX Keeping state in the class is a mistake -- this means
+ # you cannot have more than one active Bdb instance.
+
+ next = 1 # Next bp to be assigned
+ bplist = {} # indexed by (file, lineno) tuple
+ bpbynumber = [None] # Each entry is None or an instance of Bpt
+ # index 0 is unused, except for marking an
+ # effective break .... see effective()
+
+ def __init__(self, file, line, temporary=0, cond = None):
+ self.file = file # This better be in canonical form!
+ self.line = line
+ self.temporary = temporary
+ self.cond = cond
+ self.enabled = 1
+ self.ignore = 0
+ self.hits = 0
+ self.number = Breakpoint.next
+ Breakpoint.next = Breakpoint.next + 1
+ # Build the two lists
+ self.bpbynumber.append(self)
+ if self.bplist.has_key((file, line)):
+ self.bplist[file, line].append(self)
+ else:
+ self.bplist[file, line] = [self]
+
+
+ def deleteMe(self):
+ index = (self.file, self.line)
+ self.bpbynumber[self.number] = None # No longer in list
+ self.bplist[index].remove(self)
+ if not self.bplist[index]:
+ # No more bp for this f:l combo
+ del self.bplist[index]
+
+ def enable(self):
+ self.enabled = 1
+
+ def disable(self):
+ self.enabled = 0
+
+ def bpprint(self):
+ if self.temporary:
+ disp = 'del '
+ else:
+ disp = 'keep '
+ if self.enabled:
+ disp = disp + 'yes'
+ else:
+ disp = disp + 'no '
+ print '%-4dbreakpoint %s at %s:%d' % (self.number, disp,
+ self.file, self.line)
+ if self.cond:
+ print '\tstop only if %s' % (self.cond,)
+ if self.ignore:
+ print '\tignore next %d hits' % (self.ignore)
+ if (self.hits):
+ if (self.hits > 1): ss = 's'
+ else: ss = ''
+ print ('\tbreakpoint already hit %d time%s' %
+ (self.hits, ss))
+
+# -----------end of Breakpoint class----------
+
+# Determines if there is an effective (active) breakpoint at this
+# line of code. Returns breakpoint number or 0 if none
+def effective(file, line, frame):
+ """Determine which breakpoint for this file:line is to be acted upon.
+
+ Called only if we know there is a bpt at this
+ location. Returns breakpoint that was triggered and a flag
+ that indicates if it is ok to delete a temporary bp.
+
+ """
+ possibles = Breakpoint.bplist[file,line]
+ for i in range(0, len(possibles)):
+ b = possibles[i]
+ if b.enabled == 0:
+ continue
+ # Count every hit when bp is enabled
+ b.hits = b.hits + 1
+ if not b.cond:
+ # If unconditional, and ignoring,
+ # go on to next, else break
+ if b.ignore > 0:
+ b.ignore = b.ignore -1
+ continue
+ else:
+ # breakpoint and marker that's ok
+ # to delete if temporary
+ return (b,1)
+ else:
+ # Conditional bp.
+ # Ignore count applies only to those bpt hits where the
+ # condition evaluates to true.
+ try:
+ val = eval(b.cond, frame.f_globals,
+ frame.f_locals)
+ if val:
+ if b.ignore > 0:
+ b.ignore = b.ignore -1
+ # continue
+ else:
+ return (b,1)
+ # else:
+ # continue
+ except:
+ # if eval fails, most conservative
+ # thing is to stop on breakpoint
+ # regardless of ignore count.
+ # Don't delete temporary,
+ # as another hint to user.
+ return (b,0)
+ return (None, None)
+
+# -------------------- testing --------------------
+
+class Tdb(Bdb):
+ def user_call(self, frame, args):
+ name = frame.f_code.co_name
+ if not name: name = '???'
+ print '+++ call', name, args
+ def user_line(self, frame):
+ import linecache
+ name = frame.f_code.co_name
+ if not name: name = '???'
+ fn = self.canonic(frame.f_code.co_filename)
+ line = linecache.getline(fn, frame.f_lineno)
+ print '+++', fn, frame.f_lineno, name, ':', line.strip()
+ def user_return(self, frame, retval):
+ print '+++ return', retval
+ def user_exception(self, frame, exc_stuff):
+ print '+++ exception', exc_stuff
+ self.set_continue()
+
+def foo(n):
+ print 'foo(', n, ')'
+ x = bar(n*10)
+ print 'bar returned', x
+
+def bar(a):
+ print 'bar(', a, ')'
+ return a/2
+
+def test():
+ t = Tdb()
+ t.run('import bdb; bdb.foo(10)')
+
+# end
diff --git a/lib/jython/Lib/binhex.py b/lib/jython/Lib/binhex.py new file mode 100644 index 000000000..81bb1e30e --- /dev/null +++ b/lib/jython/Lib/binhex.py @@ -0,0 +1,531 @@ +"""Macintosh binhex compression/decompression.
+
+easy interface:
+binhex(inputfilename, outputfilename)
+hexbin(inputfilename, outputfilename)
+"""
+
+#
+# Jack Jansen, CWI, August 1995.
+#
+# The module is supposed to be as compatible as possible. Especially the
+# easy interface should work "as expected" on any platform.
+# XXXX Note: currently, textfiles appear in mac-form on all platforms.
+# We seem to lack a simple character-translate in python.
+# (we should probably use ISO-Latin-1 on all but the mac platform).
+# XXXX The simple routines are too simple: they expect to hold the complete
+# files in-core. Should be fixed.
+# XXXX It would be nice to handle AppleDouble format on unix
+# (for servers serving macs).
+# XXXX I don't understand what happens when you get 0x90 times the same byte on
+# input. The resulting code (xx 90 90) would appear to be interpreted as an
+# escaped *value* of 0x90. All coders I've seen appear to ignore this nicety...
+#
+import sys
+import os
+import struct
+import binascii
+
+__all__ = ["binhex","hexbin","Error"]
+
+class Error(Exception):
+ pass
+
+# States (what have we written)
+[_DID_HEADER, _DID_DATA, _DID_RSRC] = range(3)
+
+# Various constants
+REASONABLY_LARGE=32768 # Minimal amount we pass the rle-coder
+LINELEN=64
+RUNCHAR=chr(0x90) # run-length introducer
+
+#
+# This code is no longer byte-order dependent
+
+#
+# Workarounds for non-mac machines.
+if os.name == 'mac':
+ import macfs
+ import MacOS
+ try:
+ openrf = MacOS.openrf
+ except AttributeError:
+ # Backward compatibility
+ openrf = open
+
+ def FInfo():
+ return macfs.FInfo()
+
+ def getfileinfo(name):
+ finfo = macfs.FSSpec(name).GetFInfo()
+ dir, file = os.path.split(name)
+ # XXXX Get resource/data sizes
+ fp = open(name, 'rb')
+ fp.seek(0, 2)
+ dlen = fp.tell()
+ fp = openrf(name, '*rb')
+ fp.seek(0, 2)
+ rlen = fp.tell()
+ return file, finfo, dlen, rlen
+
+ def openrsrc(name, *mode):
+ if not mode:
+ mode = '*rb'
+ else:
+ mode = '*' + mode[0]
+ return openrf(name, mode)
+
+else:
+ #
+ # Glue code for non-macintosh usage
+ #
+
+ class FInfo:
+ def __init__(self):
+ self.Type = '????'
+ self.Creator = '????'
+ self.Flags = 0
+
+ def getfileinfo(name):
+ finfo = FInfo()
+ # Quick check for textfile
+ fp = open(name)
+ data = open(name).read(256)
+ for c in data:
+ if not c.isspace() and (c<' ' or ord(c) > 0177):
+ break
+ else:
+ finfo.Type = 'TEXT'
+ fp.seek(0, 2)
+ dsize = fp.tell()
+ fp.close()
+ dir, file = os.path.split(name)
+ file = file.replace(':', '-', 1)
+ return file, finfo, dsize, 0
+
+ class openrsrc:
+ def __init__(self, *args):
+ pass
+
+ def read(self, *args):
+ return ''
+
+ def write(self, *args):
+ pass
+
+ def close(self):
+ pass
+
+class _Hqxcoderengine:
+ """Write data to the coder in 3-byte chunks"""
+
+ def __init__(self, ofp):
+ self.ofp = ofp
+ self.data = ''
+ self.hqxdata = ''
+ self.linelen = LINELEN-1
+
+ def write(self, data):
+ self.data = self.data + data
+ datalen = len(self.data)
+ todo = (datalen/3)*3
+ data = self.data[:todo]
+ self.data = self.data[todo:]
+ if not data:
+ return
+ self.hqxdata = self.hqxdata + binascii.b2a_hqx(data)
+ self._flush(0)
+
+ def _flush(self, force):
+ first = 0
+ while first <= len(self.hqxdata)-self.linelen:
+ last = first + self.linelen
+ self.ofp.write(self.hqxdata[first:last]+'\n')
+ self.linelen = LINELEN
+ first = last
+ self.hqxdata = self.hqxdata[first:]
+ if force:
+ self.ofp.write(self.hqxdata + ':\n')
+
+ def close(self):
+ if self.data:
+ self.hqxdata = \
+ self.hqxdata + binascii.b2a_hqx(self.data)
+ self._flush(1)
+ self.ofp.close()
+ del self.ofp
+
+class _Rlecoderengine:
+ """Write data to the RLE-coder in suitably large chunks"""
+
+ def __init__(self, ofp):
+ self.ofp = ofp
+ self.data = ''
+
+ def write(self, data):
+ self.data = self.data + data
+ if len(self.data) < REASONABLY_LARGE:
+ return
+ rledata = binascii.rlecode_hqx(self.data)
+ self.ofp.write(rledata)
+ self.data = ''
+
+ def close(self):
+ if self.data:
+ rledata = binascii.rlecode_hqx(self.data)
+ self.ofp.write(rledata)
+ self.ofp.close()
+ del self.ofp
+
+class BinHex:
+ def __init__(self, (name, finfo, dlen, rlen), ofp):
+ if type(ofp) == type(''):
+ ofname = ofp
+ ofp = open(ofname, 'w')
+ if os.name == 'mac':
+ fss = macfs.FSSpec(ofname)
+ fss.SetCreatorType('BnHq', 'TEXT')
+ ofp.write('(This file must be converted with BinHex 4.0)\n\n:')
+ hqxer = _Hqxcoderengine(ofp)
+ self.ofp = _Rlecoderengine(hqxer)
+ self.crc = 0
+ if finfo is None:
+ finfo = FInfo()
+ self.dlen = dlen
+ self.rlen = rlen
+ self._writeinfo(name, finfo)
+ self.state = _DID_HEADER
+
+ def _writeinfo(self, name, finfo):
+ name = name
+ nl = len(name)
+ if nl > 63:
+ raise Error, 'Filename too long'
+ d = chr(nl) + name + '\0'
+ d2 = finfo.Type + finfo.Creator
+
+ # Force all structs to be packed with big-endian
+ d3 = struct.pack('>h', finfo.Flags)
+ d4 = struct.pack('>ii', self.dlen, self.rlen)
+ info = d + d2 + d3 + d4
+ self._write(info)
+ self._writecrc()
+
+ def _write(self, data):
+ self.crc = binascii.crc_hqx(data, self.crc)
+ self.ofp.write(data)
+
+ def _writecrc(self):
+ # XXXX Should this be here??
+ # self.crc = binascii.crc_hqx('\0\0', self.crc)
+ self.ofp.write(struct.pack('>h', self.crc))
+ self.crc = 0
+
+ def write(self, data):
+ if self.state != _DID_HEADER:
+ raise Error, 'Writing data at the wrong time'
+ self.dlen = self.dlen - len(data)
+ self._write(data)
+
+ def close_data(self):
+ if self.dlen != 0:
+ raise Error, 'Incorrect data size, diff='+`self.rlen`
+ self._writecrc()
+ self.state = _DID_DATA
+
+ def write_rsrc(self, data):
+ if self.state < _DID_DATA:
+ self.close_data()
+ if self.state != _DID_DATA:
+ raise Error, 'Writing resource data at the wrong time'
+ self.rlen = self.rlen - len(data)
+ self._write(data)
+
+ def close(self):
+ if self.state < _DID_DATA:
+ self.close_data()
+ if self.state != _DID_DATA:
+ raise Error, 'Close at the wrong time'
+ if self.rlen != 0:
+ raise Error, \
+ "Incorrect resource-datasize, diff="+`self.rlen`
+ self._writecrc()
+ self.ofp.close()
+ self.state = None
+ del self.ofp
+
+def binhex(inp, out):
+ """(infilename, outfilename) - Create binhex-encoded copy of a file"""
+ finfo = getfileinfo(inp)
+ ofp = BinHex(finfo, out)
+
+ ifp = open(inp, 'rb')
+ # XXXX Do textfile translation on non-mac systems
+ while 1:
+ d = ifp.read(128000)
+ if not d: break
+ ofp.write(d)
+ ofp.close_data()
+ ifp.close()
+
+ ifp = openrsrc(inp, 'rb')
+ while 1:
+ d = ifp.read(128000)
+ if not d: break
+ ofp.write_rsrc(d)
+ ofp.close()
+ ifp.close()
+
+class _Hqxdecoderengine:
+ """Read data via the decoder in 4-byte chunks"""
+
+ def __init__(self, ifp):
+ self.ifp = ifp
+ self.eof = 0
+
+ def read(self, totalwtd):
+ """Read at least wtd bytes (or until EOF)"""
+ decdata = ''
+ wtd = totalwtd
+ #
+ # The loop here is convoluted, since we don't really now how
+ # much to decode: there may be newlines in the incoming data.
+ while wtd > 0:
+ if self.eof: return decdata
+ wtd = ((wtd+2)/3)*4
+ data = self.ifp.read(wtd)
+ #
+ # Next problem: there may not be a complete number of
+ # bytes in what we pass to a2b. Solve by yet another
+ # loop.
+ #
+ while 1:
+ try:
+ decdatacur, self.eof = \
+ binascii.a2b_hqx(data)
+ break
+ except binascii.Incomplete:
+ pass
+ newdata = self.ifp.read(1)
+ if not newdata:
+ raise Error, \
+ 'Premature EOF on binhex file'
+ data = data + newdata
+ decdata = decdata + decdatacur
+ wtd = totalwtd - len(decdata)
+ if not decdata and not self.eof:
+ raise Error, 'Premature EOF on binhex file'
+ return decdata
+
+ def close(self):
+ self.ifp.close()
+
+class _Rledecoderengine:
+ """Read data via the RLE-coder"""
+
+ def __init__(self, ifp):
+ self.ifp = ifp
+ self.pre_buffer = ''
+ self.post_buffer = ''
+ self.eof = 0
+
+ def read(self, wtd):
+ if wtd > len(self.post_buffer):
+ self._fill(wtd-len(self.post_buffer))
+ rv = self.post_buffer[:wtd]
+ self.post_buffer = self.post_buffer[wtd:]
+ return rv
+
+ def _fill(self, wtd):
+ self.pre_buffer = self.pre_buffer + self.ifp.read(wtd+4)
+ if self.ifp.eof:
+ self.post_buffer = self.post_buffer + \
+ binascii.rledecode_hqx(self.pre_buffer)
+ self.pre_buffer = ''
+ return
+
+ #
+ # Obfuscated code ahead. We have to take care that we don't
+ # end up with an orphaned RUNCHAR later on. So, we keep a couple
+ # of bytes in the buffer, depending on what the end of
+ # the buffer looks like:
+ # '\220\0\220' - Keep 3 bytes: repeated \220 (escaped as \220\0)
+ # '?\220' - Keep 2 bytes: repeated something-else
+ # '\220\0' - Escaped \220: Keep 2 bytes.
+ # '?\220?' - Complete repeat sequence: decode all
+ # otherwise: keep 1 byte.
+ #
+ mark = len(self.pre_buffer)
+ if self.pre_buffer[-3:] == RUNCHAR + '\0' + RUNCHAR:
+ mark = mark - 3
+ elif self.pre_buffer[-1] == RUNCHAR:
+ mark = mark - 2
+ elif self.pre_buffer[-2:] == RUNCHAR + '\0':
+ mark = mark - 2
+ elif self.pre_buffer[-2] == RUNCHAR:
+ pass # Decode all
+ else:
+ mark = mark - 1
+
+ self.post_buffer = self.post_buffer + \
+ binascii.rledecode_hqx(self.pre_buffer[:mark])
+ self.pre_buffer = self.pre_buffer[mark:]
+
+ def close(self):
+ self.ifp.close()
+
+class HexBin:
+ def __init__(self, ifp):
+ if type(ifp) == type(''):
+ ifp = open(ifp)
+ #
+ # Find initial colon.
+ #
+ while 1:
+ ch = ifp.read(1)
+ if not ch:
+ raise Error, "No binhex data found"
+ # Cater for \r\n terminated lines (which show up as \n\r, hence
+ # all lines start with \r)
+ if ch == '\r':
+ continue
+ if ch == ':':
+ break
+ if ch != '\n':
+ dummy = ifp.readline()
+
+ hqxifp = _Hqxdecoderengine(ifp)
+ self.ifp = _Rledecoderengine(hqxifp)
+ self.crc = 0
+ self._readheader()
+
+ def _read(self, len):
+ data = self.ifp.read(len)
+ self.crc = binascii.crc_hqx(data, self.crc)
+ return data
+
+ def _checkcrc(self):
+ filecrc = struct.unpack('>h', self.ifp.read(2))[0] & 0xffff
+ #self.crc = binascii.crc_hqx('\0\0', self.crc)
+ # XXXX Is this needed??
+ self.crc = self.crc & 0xffff
+ if filecrc != self.crc:
+ raise Error, 'CRC error, computed %x, read %x' \
+ %(self.crc, filecrc)
+ self.crc = 0
+
+ def _readheader(self):
+ len = self._read(1)
+ fname = self._read(ord(len))
+ rest = self._read(1+4+4+2+4+4)
+ self._checkcrc()
+
+ type = rest[1:5]
+ creator = rest[5:9]
+ flags = struct.unpack('>h', rest[9:11])[0]
+ self.dlen = struct.unpack('>l', rest[11:15])[0]
+ self.rlen = struct.unpack('>l', rest[15:19])[0]
+
+ self.FName = fname
+ self.FInfo = FInfo()
+ self.FInfo.Creator = creator
+ self.FInfo.Type = type
+ self.FInfo.Flags = flags
+
+ self.state = _DID_HEADER
+
+ def read(self, *n):
+ if self.state != _DID_HEADER:
+ raise Error, 'Read data at wrong time'
+ if n:
+ n = n[0]
+ n = min(n, self.dlen)
+ else:
+ n = self.dlen
+ rv = ''
+ while len(rv) < n:
+ rv = rv + self._read(n-len(rv))
+ self.dlen = self.dlen - n
+ return rv
+
+ def close_data(self):
+ if self.state != _DID_HEADER:
+ raise Error, 'close_data at wrong time'
+ if self.dlen:
+ dummy = self._read(self.dlen)
+ self._checkcrc()
+ self.state = _DID_DATA
+
+ def read_rsrc(self, *n):
+ if self.state == _DID_HEADER:
+ self.close_data()
+ if self.state != _DID_DATA:
+ raise Error, 'Read resource data at wrong time'
+ if n:
+ n = n[0]
+ n = min(n, self.rlen)
+ else:
+ n = self.rlen
+ self.rlen = self.rlen - n
+ return self._read(n)
+
+ def close(self):
+ if self.rlen:
+ dummy = self.read_rsrc(self.rlen)
+ self._checkcrc()
+ self.state = _DID_RSRC
+ self.ifp.close()
+
+def hexbin(inp, out):
+ """(infilename, outfilename) - Decode binhexed file"""
+ ifp = HexBin(inp)
+ finfo = ifp.FInfo
+ if not out:
+ out = ifp.FName
+ if os.name == 'mac':
+ ofss = macfs.FSSpec(out)
+ out = ofss.as_pathname()
+
+ ofp = open(out, 'wb')
+ # XXXX Do translation on non-mac systems
+ while 1:
+ d = ifp.read(128000)
+ if not d: break
+ ofp.write(d)
+ ofp.close()
+ ifp.close_data()
+
+ d = ifp.read_rsrc(128000)
+ if d:
+ ofp = openrsrc(out, 'wb')
+ ofp.write(d)
+ while 1:
+ d = ifp.read_rsrc(128000)
+ if not d: break
+ ofp.write(d)
+ ofp.close()
+
+ if os.name == 'mac':
+ nfinfo = ofss.GetFInfo()
+ nfinfo.Creator = finfo.Creator
+ nfinfo.Type = finfo.Type
+ nfinfo.Flags = finfo.Flags
+ ofss.SetFInfo(nfinfo)
+
+ ifp.close()
+
+def _test():
+ if os.name == 'mac':
+ fss, ok = macfs.PromptGetFile('File to convert:')
+ if not ok:
+ sys.exit(0)
+ fname = fss.as_pathname()
+ else:
+ fname = sys.argv[1]
+ binhex(fname, fname+'.hqx')
+ hexbin(fname+'.hqx', fname+'.viahqx')
+ #hexbin(fname, fname+'.unpacked')
+ sys.exit(1)
+
+if __name__ == '__main__':
+ _test()
diff --git a/lib/jython/Lib/bisect.py b/lib/jython/Lib/bisect.py new file mode 100644 index 000000000..8648a3986 --- /dev/null +++ b/lib/jython/Lib/bisect.py @@ -0,0 +1,78 @@ +"""Bisection algorithms."""
+
+def insort_right(a, x, lo=0, hi=None):
+ """Insert item x in list a, and keep it sorted assuming a is sorted.
+
+ If x is already in a, insert it to the right of the rightmost x.
+
+ Optional args lo (default 0) and hi (default len(a)) bound the
+ slice of a to be searched.
+ """
+
+ if hi is None:
+ hi = len(a)
+ while lo < hi:
+ mid = (lo+hi)/2
+ if x < a[mid]: hi = mid
+ else: lo = mid+1
+ a.insert(lo, x)
+
+insort = insort_right # backward compatibility
+
+def bisect_right(a, x, lo=0, hi=None):
+ """Return the index where to insert item x in list a, assuming a is sorted.
+
+ The return value i is such that all e in a[:i] have e <= x, and all e in
+ a[i:] have e > x. So if x already appears in the list, i points just
+ beyond the rightmost x already there.
+
+ Optional args lo (default 0) and hi (default len(a)) bound the
+ slice of a to be searched.
+ """
+
+ if hi is None:
+ hi = len(a)
+ while lo < hi:
+ mid = (lo+hi)/2
+ if x < a[mid]: hi = mid
+ else: lo = mid+1
+ return lo
+
+bisect = bisect_right # backward compatibility
+
+def insort_left(a, x, lo=0, hi=None):
+ """Insert item x in list a, and keep it sorted assuming a is sorted.
+
+ If x is already in a, insert it to the left of the leftmost x.
+
+ Optional args lo (default 0) and hi (default len(a)) bound the
+ slice of a to be searched.
+ """
+
+ if hi is None:
+ hi = len(a)
+ while lo < hi:
+ mid = (lo+hi)/2
+ if a[mid] < x: lo = mid+1
+ else: hi = mid
+ a.insert(lo, x)
+
+
+def bisect_left(a, x, lo=0, hi=None):
+ """Return the index where to insert item x in list a, assuming a is sorted.
+
+ The return value i is such that all e in a[:i] have e < x, and all e in
+ a[i:] have e >= x. So if x already appears in the list, i points just
+ before the leftmost x already there.
+
+ Optional args lo (default 0) and hi (default len(a)) bound the
+ slice of a to be searched.
+ """
+
+ if hi is None:
+ hi = len(a)
+ while lo < hi:
+ mid = (lo+hi)/2
+ if a[mid] < x: lo = mid+1
+ else: hi = mid
+ return lo
diff --git a/lib/jython/Lib/calendar.py b/lib/jython/Lib/calendar.py new file mode 100644 index 000000000..16f3a14c4 --- /dev/null +++ b/lib/jython/Lib/calendar.py @@ -0,0 +1,209 @@ +"""Calendar printing functions
+
+Note when comparing these calendars to the ones printed by cal(1): By
+default, these calendars have Monday as the first day of the week, and
+Sunday as the last (the European convention). Use setfirstweekday() to
+set the first day of the week (0=Monday, 6=Sunday)."""
+
+# Revision 2: uses functions from built-in time module
+
+# Import functions and variables from time module
+from time import localtime, mktime
+
+__all__ = ["error","setfirstweekday","firstweekday","isleap",
+ "leapdays","weekday","monthrange","monthcalendar",
+ "prmonth","month","prcal","calendar","timegm"]
+
+# Exception raised for bad input (with string parameter for details)
+error = ValueError
+
+# Constants for months referenced later
+January = 1
+February = 2
+
+# Number of days per month (except for February in leap years)
+mdays = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
+
+# Full and abbreviated names of weekdays
+day_name = ['Monday', 'Tuesday', 'Wednesday', 'Thursday',
+ 'Friday', 'Saturday', 'Sunday']
+day_abbr = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+
+# Full and abbreviated names of months (1-based arrays!!!)
+month_name = ['', 'January', 'February', 'March', 'April',
+ 'May', 'June', 'July', 'August',
+ 'September', 'October', 'November', 'December']
+month_abbr = [' ', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
+ 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
+
+# Constants for weekdays
+(MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) = range(7)
+
+_firstweekday = 0 # 0 = Monday, 6 = Sunday
+
+def firstweekday():
+ return _firstweekday
+
+def setfirstweekday(weekday):
+ """Set weekday (Monday=0, Sunday=6) to start each week."""
+ global _firstweekday
+ if not MONDAY <= weekday <= SUNDAY:
+ raise ValueError, \
+ 'bad weekday number; must be 0 (Monday) to 6 (Sunday)'
+ _firstweekday = weekday
+
+def isleap(year):
+ """Return 1 for leap years, 0 for non-leap years."""
+ return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
+
+def leapdays(y1, y2):
+ """Return number of leap years in range [y1, y2).
+ Assume y1 <= y2."""
+ y1 -= 1
+ y2 -= 1
+ return (y2/4 - y1/4) - (y2/100 - y1/100) + (y2/400 - y1/400)
+
+def weekday(year, month, day):
+ """Return weekday (0-6 ~ Mon-Sun) for year (1970-...), month (1-12),
+ day (1-31)."""
+ secs = mktime((year, month, day, 0, 0, 0, 0, 0, 0))
+ tuple = localtime(secs)
+ return tuple[6]
+
+def monthrange(year, month):
+ """Return weekday (0-6 ~ Mon-Sun) and number of days (28-31) for
+ year, month."""
+ if not 1 <= month <= 12:
+ raise ValueError, 'bad month number'
+ day1 = weekday(year, month, 1)
+ ndays = mdays[month] + (month == February and isleap(year))
+ return day1, ndays
+
+def monthcalendar(year, month):
+ """Return a matrix representing a month's calendar.
+ Each row represents a week; days outside this month are zero."""
+ day1, ndays = monthrange(year, month)
+ rows = []
+ r7 = range(7)
+ day = (_firstweekday - day1 + 6) % 7 - 5 # for leading 0's in first week
+ while day <= ndays:
+ row = [0, 0, 0, 0, 0, 0, 0]
+ for i in r7:
+ if 1 <= day <= ndays: row[i] = day
+ day = day + 1
+ rows.append(row)
+ return rows
+
+def _center(str, width):
+ """Center a string in a field."""
+ n = width - len(str)
+ if n <= 0:
+ return str
+ return ' '*((n+1)/2) + str + ' '*((n)/2)
+
+def prweek(theweek, width):
+ """Print a single week (no newline)."""
+ print week(theweek, width),
+
+def week(theweek, width):
+ """Returns a single week in a string (no newline)."""
+ days = []
+ for day in theweek:
+ if day == 0:
+ s = ''
+ else:
+ s = '%2i' % day # right-align single-digit days
+ days.append(_center(s, width))
+ return ' '.join(days)
+
+def weekheader(width):
+ """Return a header for a week."""
+ if width >= 9:
+ names = day_name
+ else:
+ names = day_abbr
+ days = []
+ for i in range(_firstweekday, _firstweekday + 7):
+ days.append(_center(names[i%7][:width], width))
+ return ' '.join(days)
+
+def prmonth(theyear, themonth, w=0, l=0):
+ """Print a month's calendar."""
+ print month(theyear, themonth, w, l),
+
+def month(theyear, themonth, w=0, l=0):
+ """Return a month's calendar string (multi-line)."""
+ w = max(2, w)
+ l = max(1, l)
+ s = (_center(month_name[themonth] + ' ' + `theyear`,
+ 7 * (w + 1) - 1).rstrip() +
+ '\n' * l + weekheader(w).rstrip() + '\n' * l)
+ for aweek in monthcalendar(theyear, themonth):
+ s = s + week(aweek, w).rstrip() + '\n' * l
+ return s[:-l] + '\n'
+
+# Spacing of month columns for 3-column year calendar
+_colwidth = 7*3 - 1 # Amount printed by prweek()
+_spacing = 6 # Number of spaces between columns
+
+def format3c(a, b, c, colwidth=_colwidth, spacing=_spacing):
+ """Prints 3-column formatting for year calendars"""
+ print format3cstring(a, b, c, colwidth, spacing)
+
+def format3cstring(a, b, c, colwidth=_colwidth, spacing=_spacing):
+ """Returns a string formatted from 3 strings, centered within 3 columns."""
+ return (_center(a, colwidth) + ' ' * spacing + _center(b, colwidth) +
+ ' ' * spacing + _center(c, colwidth))
+
+def prcal(year, w=0, l=0, c=_spacing):
+ """Print a year's calendar."""
+ print calendar(year, w, l, c),
+
+def calendar(year, w=0, l=0, c=_spacing):
+ """Returns a year's calendar as a multi-line string."""
+ w = max(2, w)
+ l = max(1, l)
+ c = max(2, c)
+ colwidth = (w + 1) * 7 - 1
+ s = _center(`year`, colwidth * 3 + c * 2).rstrip() + '\n' * l
+ header = weekheader(w)
+ header = format3cstring(header, header, header, colwidth, c).rstrip()
+ for q in range(January, January+12, 3):
+ s = (s + '\n' * l +
+ format3cstring(month_name[q], month_name[q+1], month_name[q+2],
+ colwidth, c).rstrip() +
+ '\n' * l + header + '\n' * l)
+ data = []
+ height = 0
+ for amonth in range(q, q + 3):
+ cal = monthcalendar(year, amonth)
+ if len(cal) > height:
+ height = len(cal)
+ data.append(cal)
+ for i in range(height):
+ weeks = []
+ for cal in data:
+ if i >= len(cal):
+ weeks.append('')
+ else:
+ weeks.append(week(cal[i], w))
+ s = s + format3cstring(weeks[0], weeks[1], weeks[2],
+ colwidth, c).rstrip() + '\n' * l
+ return s[:-l] + '\n'
+
+EPOCH = 1970
+def timegm(tuple):
+ """Unrelated but handy function to calculate Unix timestamp from GMT."""
+ year, month, day, hour, minute, second = tuple[:6]
+ assert year >= EPOCH
+ assert 1 <= month <= 12
+ days = 365*(year-EPOCH) + leapdays(EPOCH, year)
+ for i in range(1, month):
+ days = days + mdays[i]
+ if month > 2 and isleap(year):
+ days = days + 1
+ days = days + day - 1
+ hours = days*24 + hour
+ minutes = hours*60 + minute
+ seconds = minutes*60 + second
+ return seconds
diff --git a/lib/jython/Lib/cgi.py b/lib/jython/Lib/cgi.py new file mode 100644 index 000000000..df2e93646 --- /dev/null +++ b/lib/jython/Lib/cgi.py @@ -0,0 +1,1000 @@ +#! /usr/local/bin/python
+
+# NOTE: the above "/usr/local/bin/python" is NOT a mistake. It is
+# intentionally NOT "/usr/bin/env python". On many systems
+# (e.g. Solaris), /usr/local/bin is not in $PATH as passed to CGI
+# scripts, and /usr/local/bin is the default directory where Python is
+# installed, so /usr/bin/env would be unable to find python. Granted,
+# binary installations by Linux vendors often install Python in
+# /usr/bin. So let those vendors patch cgi.py to match their choice
+# of installation.
+
+"""Support module for CGI (Common Gateway Interface) scripts.
+
+This module defines a number of utilities for use by CGI scripts
+written in Python.
+"""
+
+# XXX Perhaps there should be a slimmed version that doesn't contain
+# all those backwards compatible and debugging classes and functions?
+
+# History
+# -------
+#
+# Michael McLay started this module. Steve Majewski changed the
+# interface to SvFormContentDict and FormContentDict. The multipart
+# parsing was inspired by code submitted by Andreas Paepcke. Guido van
+# Rossum rewrote, reformatted and documented the module and is currently
+# responsible for its maintenance.
+#
+
+__version__ = "2.5"
+
+
+# Imports
+# =======
+
+import sys
+import os
+import urllib
+import mimetools
+import rfc822
+import UserDict
+from StringIO import StringIO
+
+__all__ = ["MiniFieldStorage", "FieldStorage", "FormContentDict",
+ "SvFormContentDict", "InterpFormContentDict", "FormContent",
+ "parse", "parse_qs", "parse_qsl", "parse_multipart",
+ "parse_header", "print_exception", "print_environ",
+ "print_form", "print_directory", "print_arguments",
+ "print_environ_usage", "escape"]
+
+# Logging support
+# ===============
+
+logfile = "" # Filename to log to, if not empty
+logfp = None # File object to log to, if not None
+
+def initlog(*allargs):
+ """Write a log message, if there is a log file.
+
+ Even though this function is called initlog(), you should always
+ use log(); log is a variable that is set either to initlog
+ (initially), to dolog (once the log file has been opened), or to
+ nolog (when logging is disabled).
+
+ The first argument is a format string; the remaining arguments (if
+ any) are arguments to the % operator, so e.g.
+ log("%s: %s", "a", "b")
+ will write "a: b" to the log file, followed by a newline.
+
+ If the global logfp is not None, it should be a file object to
+ which log data is written.
+
+ If the global logfp is None, the global logfile may be a string
+ giving a filename to open, in append mode. This file should be
+ world writable!!! If the file can't be opened, logging is
+ silently disabled (since there is no safe place where we could
+ send an error message).
+
+ """
+ global logfp, log
+ if logfile and not logfp:
+ try:
+ logfp = open(logfile, "a")
+ except IOError:
+ pass
+ if not logfp:
+ log = nolog
+ else:
+ log = dolog
+ apply(log, allargs)
+
+def dolog(fmt, *args):
+ """Write a log message to the log file. See initlog() for docs."""
+ logfp.write(fmt%args + "\n")
+
+def nolog(*allargs):
+ """Dummy function, assigned to log when logging is disabled."""
+ pass
+
+log = initlog # The current logging function
+
+
+# Parsing functions
+# =================
+
+# Maximum input we will accept when REQUEST_METHOD is POST
+# 0 ==> unlimited input
+maxlen = 0
+
+def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
+ """Parse a query in the environment or from a file (default stdin)
+
+ Arguments, all optional:
+
+ fp : file pointer; default: sys.stdin
+
+ environ : environment dictionary; default: os.environ
+
+ keep_blank_values: flag indicating whether blank values in
+ URL encoded forms should be treated as blank strings.
+ A true value indicates that blanks should be retained as
+ blank strings. The default false value indicates that
+ blank values are to be ignored and treated as if they were
+ not included.
+
+ strict_parsing: flag indicating what to do with parsing errors.
+ If false (the default), errors are silently ignored.
+ If true, errors raise a ValueError exception.
+ """
+ if not fp:
+ fp = sys.stdin
+ if not environ.has_key('REQUEST_METHOD'):
+ environ['REQUEST_METHOD'] = 'GET' # For testing stand-alone
+ if environ['REQUEST_METHOD'] == 'POST':
+ ctype, pdict = parse_header(environ['CONTENT_TYPE'])
+ if ctype == 'multipart/form-data':
+ return parse_multipart(fp, pdict)
+ elif ctype == 'application/x-www-form-urlencoded':
+ clength = int(environ['CONTENT_LENGTH'])
+ if maxlen and clength > maxlen:
+ raise ValueError, 'Maximum content length exceeded'
+ qs = fp.read(clength)
+ else:
+ qs = '' # Unknown content-type
+ if environ.has_key('QUERY_STRING'):
+ if qs: qs = qs + '&'
+ qs = qs + environ['QUERY_STRING']
+ elif sys.argv[1:]:
+ if qs: qs = qs + '&'
+ qs = qs + sys.argv[1]
+ environ['QUERY_STRING'] = qs # XXX Shouldn't, really
+ elif environ.has_key('QUERY_STRING'):
+ qs = environ['QUERY_STRING']
+ else:
+ if sys.argv[1:]:
+ qs = sys.argv[1]
+ else:
+ qs = ""
+ environ['QUERY_STRING'] = qs # XXX Shouldn't, really
+ return parse_qs(qs, keep_blank_values, strict_parsing)
+
+
+def parse_qs(qs, keep_blank_values=0, strict_parsing=0):
+ """Parse a query given as a string argument.
+
+ Arguments:
+
+ qs: URL-encoded query string to be parsed
+
+ keep_blank_values: flag indicating whether blank values in
+ URL encoded queries should be treated as blank strings.
+ A true value indicates that blanks should be retained as
+ blank strings. The default false value indicates that
+ blank values are to be ignored and treated as if they were
+ not included.
+
+ strict_parsing: flag indicating what to do with parsing errors.
+ If false (the default), errors are silently ignored.
+ If true, errors raise a ValueError exception.
+ """
+ dict = {}
+ for name, value in parse_qsl(qs, keep_blank_values, strict_parsing):
+ if dict.has_key(name):
+ dict[name].append(value)
+ else:
+ dict[name] = [value]
+ return dict
+
+def parse_qsl(qs, keep_blank_values=0, strict_parsing=0):
+ """Parse a query given as a string argument.
+
+ Arguments:
+
+ qs: URL-encoded query string to be parsed
+
+ keep_blank_values: flag indicating whether blank values in
+ URL encoded queries should be treated as blank strings. A
+ true value indicates that blanks should be retained as blank
+ strings. The default false value indicates that blank values
+ are to be ignored and treated as if they were not included.
+
+ strict_parsing: flag indicating what to do with parsing errors. If
+ false (the default), errors are silently ignored. If true,
+ errors raise a ValueError exception.
+
+ Returns a list, as G-d intended.
+ """
+ pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')]
+ r = []
+ for name_value in pairs:
+ nv = name_value.split('=', 1)
+ if len(nv) != 2:
+ if strict_parsing:
+ raise ValueError, "bad query field: %s" % `name_value`
+ continue
+ if len(nv[1]) or keep_blank_values:
+ name = urllib.unquote(nv[0].replace('+', ' '))
+ value = urllib.unquote(nv[1].replace('+', ' '))
+ r.append((name, value))
+
+ return r
+
+
+def parse_multipart(fp, pdict):
+ """Parse multipart input.
+
+ Arguments:
+ fp : input file
+ pdict: dictionary containing other parameters of conten-type header
+
+ Returns a dictionary just like parse_qs(): keys are the field names, each
+ value is a list of values for that field. This is easy to use but not
+ much good if you are expecting megabytes to be uploaded -- in that case,
+ use the FieldStorage class instead which is much more flexible. Note
+ that content-type is the raw, unparsed contents of the content-type
+ header.
+
+ XXX This does not parse nested multipart parts -- use FieldStorage for
+ that.
+
+ XXX This should really be subsumed by FieldStorage altogether -- no
+ point in having two implementations of the same parsing algorithm.
+
+ """
+ if pdict.has_key('boundary'):
+ boundary = pdict['boundary']
+ else:
+ boundary = ""
+ nextpart = "--" + boundary
+ lastpart = "--" + boundary + "--"
+ partdict = {}
+ terminator = ""
+
+ while terminator != lastpart:
+ bytes = -1
+ data = None
+ if terminator:
+ # At start of next part. Read headers first.
+ headers = mimetools.Message(fp)
+ clength = headers.getheader('content-length')
+ if clength:
+ try:
+ bytes = int(clength)
+ except ValueError:
+ pass
+ if bytes > 0:
+ if maxlen and bytes > maxlen:
+ raise ValueError, 'Maximum content length exceeded'
+ data = fp.read(bytes)
+ else:
+ data = ""
+ # Read lines until end of part.
+ lines = []
+ while 1:
+ line = fp.readline()
+ if not line:
+ terminator = lastpart # End outer loop
+ break
+ if line[:2] == "--":
+ terminator = line.strip()
+ if terminator in (nextpart, lastpart):
+ break
+ lines.append(line)
+ # Done with part.
+ if data is None:
+ continue
+ if bytes < 0:
+ if lines:
+ # Strip final line terminator
+ line = lines[-1]
+ if line[-2:] == "\r\n":
+ line = line[:-2]
+ elif line[-1:] == "\n":
+ line = line[:-1]
+ lines[-1] = line
+ data = "".join(lines)
+ line = headers['content-disposition']
+ if not line:
+ continue
+ key, params = parse_header(line)
+ if key != 'form-data':
+ continue
+ if params.has_key('name'):
+ name = params['name']
+ else:
+ continue
+ if partdict.has_key(name):
+ partdict[name].append(data)
+ else:
+ partdict[name] = [data]
+
+ return partdict
+
+
+def parse_header(line):
+ """Parse a Content-type like header.
+
+ Return the main content-type and a dictionary of options.
+
+ """
+ plist = map(lambda x: x.strip(), line.split(';'))
+ key = plist[0].lower()
+ del plist[0]
+ pdict = {}
+ for p in plist:
+ i = p.find('=')
+ if i >= 0:
+ name = p[:i].strip().lower()
+ value = p[i+1:].strip()
+ if len(value) >= 2 and value[0] == value[-1] == '"':
+ value = value[1:-1]
+ pdict[name] = value
+ return key, pdict
+
+
+# Classes for field storage
+# =========================
+
+class MiniFieldStorage:
+
+ """Like FieldStorage, for use when no file uploads are possible."""
+
+ # Dummy attributes
+ filename = None
+ list = None
+ type = None
+ file = None
+ type_options = {}
+ disposition = None
+ disposition_options = {}
+ headers = {}
+
+ def __init__(self, name, value):
+ """Constructor from field name and value."""
+ self.name = name
+ self.value = value
+ # self.file = StringIO(value)
+
+ def __repr__(self):
+ """Return printable representation."""
+ return "MiniFieldStorage(%s, %s)" % (`self.name`, `self.value`)
+
+
+class FieldStorage:
+
+ """Store a sequence of fields, reading multipart/form-data.
+
+ This class provides naming, typing, files stored on disk, and
+ more. At the top level, it is accessible like a dictionary, whose
+ keys are the field names. (Note: None can occur as a field name.)
+ The items are either a Python list (if there's multiple values) or
+ another FieldStorage or MiniFieldStorage object. If it's a single
+ object, it has the following attributes:
+
+ name: the field name, if specified; otherwise None
+
+ filename: the filename, if specified; otherwise None; this is the
+ client side filename, *not* the file name on which it is
+ stored (that's a temporary file you don't deal with)
+
+ value: the value as a *string*; for file uploads, this
+ transparently reads the file every time you request the value
+
+ file: the file(-like) object from which you can read the data;
+ None if the data is stored a simple string
+
+ type: the content-type, or None if not specified
+
+ type_options: dictionary of options specified on the content-type
+ line
+
+ disposition: content-disposition, or None if not specified
+
+ disposition_options: dictionary of corresponding options
+
+ headers: a dictionary(-like) object (sometimes rfc822.Message or a
+ subclass thereof) containing *all* headers
+
+ The class is subclassable, mostly for the purpose of overriding
+ the make_file() method, which is called internally to come up with
+ a file open for reading and writing. This makes it possible to
+ override the default choice of storing all files in a temporary
+ directory and unlinking them as soon as they have been opened.
+
+ """
+
+ def __init__(self, fp=None, headers=None, outerboundary="",
+ environ=os.environ, keep_blank_values=0, strict_parsing=0):
+ """Constructor. Read multipart/* until last part.
+
+ Arguments, all optional:
+
+ fp : file pointer; default: sys.stdin
+ (not used when the request method is GET)
+
+ headers : header dictionary-like object; default:
+ taken from environ as per CGI spec
+
+ outerboundary : terminating multipart boundary
+ (for internal use only)
+
+ environ : environment dictionary; default: os.environ
+
+ keep_blank_values: flag indicating whether blank values in
+ URL encoded forms should be treated as blank strings.
+ A true value indicates that blanks should be retained as
+ blank strings. The default false value indicates that
+ blank values are to be ignored and treated as if they were
+ not included.
+
+ strict_parsing: flag indicating what to do with parsing errors.
+ If false (the default), errors are silently ignored.
+ If true, errors raise a ValueError exception.
+
+ """
+ method = 'GET'
+ self.keep_blank_values = keep_blank_values
+ self.strict_parsing = strict_parsing
+ if environ.has_key('REQUEST_METHOD'):
+ method = environ['REQUEST_METHOD'].upper()
+ if method == 'GET' or method == 'HEAD':
+ if environ.has_key('QUERY_STRING'):
+ qs = environ['QUERY_STRING']
+ elif sys.argv[1:]:
+ qs = sys.argv[1]
+ else:
+ qs = ""
+ fp = StringIO(qs)
+ if headers is None:
+ headers = {'content-type':
+ "application/x-www-form-urlencoded"}
+ if headers is None:
+ headers = {}
+ if method == 'POST':
+ # Set default content-type for POST to what's traditional
+ headers['content-type'] = "application/x-www-form-urlencoded"
+ if environ.has_key('CONTENT_TYPE'):
+ headers['content-type'] = environ['CONTENT_TYPE']
+ if environ.has_key('CONTENT_LENGTH'):
+ headers['content-length'] = environ['CONTENT_LENGTH']
+ self.fp = fp or sys.stdin
+ self.headers = headers
+ self.outerboundary = outerboundary
+
+ # Process content-disposition header
+ cdisp, pdict = "", {}
+ if self.headers.has_key('content-disposition'):
+ cdisp, pdict = parse_header(self.headers['content-disposition'])
+ self.disposition = cdisp
+ self.disposition_options = pdict
+ self.name = None
+ if pdict.has_key('name'):
+ self.name = pdict['name']
+ self.filename = None
+ if pdict.has_key('filename'):
+ self.filename = pdict['filename']
+
+ # Process content-type header
+ #
+ # Honor any existing content-type header. But if there is no
+ # content-type header, use some sensible defaults. Assume
+ # outerboundary is "" at the outer level, but something non-false
+ # inside a multi-part. The default for an inner part is text/plain,
+ # but for an outer part it should be urlencoded. This should catch
+ # bogus clients which erroneously forget to include a content-type
+ # header.
+ #
+ # See below for what we do if there does exist a content-type header,
+ # but it happens to be something we don't understand.
+ if self.headers.has_key('content-type'):
+ ctype, pdict = parse_header(self.headers['content-type'])
+ elif self.outerboundary or method != 'POST':
+ ctype, pdict = "text/plain", {}
+ else:
+ ctype, pdict = 'application/x-www-form-urlencoded', {}
+ self.type = ctype
+ self.type_options = pdict
+ self.innerboundary = ""
+ if pdict.has_key('boundary'):
+ self.innerboundary = pdict['boundary']
+ clen = -1
+ if self.headers.has_key('content-length'):
+ try:
+ clen = int(self.headers['content-length'])
+ except:
+ pass
+ if maxlen and clen > maxlen:
+ raise ValueError, 'Maximum content length exceeded'
+ self.length = clen
+
+ self.list = self.file = None
+ self.done = 0
+ if ctype == 'application/x-www-form-urlencoded':
+ self.read_urlencoded()
+ elif ctype[:10] == 'multipart/':
+ self.read_multi(environ, keep_blank_values, strict_parsing)
+ else:
+ self.read_single()
+
+ def __repr__(self):
+ """Return a printable representation."""
+ return "FieldStorage(%s, %s, %s)" % (
+ `self.name`, `self.filename`, `self.value`)
+
+ def __getattr__(self, name):
+ if name != 'value':
+ raise AttributeError, name
+ if self.file:
+ self.file.seek(0)
+ value = self.file.read()
+ self.file.seek(0)
+ elif self.list is not None:
+ value = self.list
+ else:
+ value = None
+ return value
+
+ def __getitem__(self, key):
+ """Dictionary style indexing."""
+ if self.list is None:
+ raise TypeError, "not indexable"
+ found = []
+ for item in self.list:
+ if item.name == key: found.append(item)
+ if not found:
+ raise KeyError, key
+ if len(found) == 1:
+ return found[0]
+ else:
+ return found
+
+ def getvalue(self, key, default=None):
+ """Dictionary style get() method, including 'value' lookup."""
+ if self.has_key(key):
+ value = self[key]
+ if type(value) is type([]):
+ return map(lambda v: v.value, value)
+ else:
+ return value.value
+ else:
+ return default
+
+ def keys(self):
+ """Dictionary style keys() method."""
+ if self.list is None:
+ raise TypeError, "not indexable"
+ keys = []
+ for item in self.list:
+ if item.name not in keys: keys.append(item.name)
+ return keys
+
+ def has_key(self, key):
+ """Dictionary style has_key() method."""
+ if self.list is None:
+ raise TypeError, "not indexable"
+ for item in self.list:
+ if item.name == key: return 1
+ return 0
+
+ def __len__(self):
+ """Dictionary style len(x) support."""
+ return len(self.keys())
+
+ def read_urlencoded(self):
+ """Internal: read data in query string format."""
+ qs = self.fp.read(self.length)
+ self.list = list = []
+ for key, value in parse_qsl(qs, self.keep_blank_values,
+ self.strict_parsing):
+ list.append(MiniFieldStorage(key, value))
+ self.skip_lines()
+
+ FieldStorageClass = None
+
+ def read_multi(self, environ, keep_blank_values, strict_parsing):
+ """Internal: read a part that is itself multipart."""
+ self.list = []
+ klass = self.FieldStorageClass or self.__class__
+ part = klass(self.fp, {}, self.innerboundary,
+ environ, keep_blank_values, strict_parsing)
+ # Throw first part away
+ while not part.done:
+ headers = rfc822.Message(self.fp)
+ part = klass(self.fp, headers, self.innerboundary,
+ environ, keep_blank_values, strict_parsing)
+ self.list.append(part)
+ self.skip_lines()
+
+ def read_single(self):
+ """Internal: read an atomic part."""
+ if self.length >= 0:
+ self.read_binary()
+ self.skip_lines()
+ else:
+ self.read_lines()
+ self.file.seek(0)
+
+ bufsize = 8*1024 # I/O buffering size for copy to file
+
+ def read_binary(self):
+ """Internal: read binary data."""
+ self.file = self.make_file('b')
+ todo = self.length
+ if todo >= 0:
+ while todo > 0:
+ data = self.fp.read(min(todo, self.bufsize))
+ if not data:
+ self.done = -1
+ break
+ self.file.write(data)
+ todo = todo - len(data)
+
+ def read_lines(self):
+ """Internal: read lines until EOF or outerboundary."""
+ self.file = self.make_file('')
+ if self.outerboundary:
+ self.read_lines_to_outerboundary()
+ else:
+ self.read_lines_to_eof()
+
+ def read_lines_to_eof(self):
+ """Internal: read lines until EOF."""
+ while 1:
+ line = self.fp.readline()
+ if not line:
+ self.done = -1
+ break
+ self.file.write(line)
+
+ def read_lines_to_outerboundary(self):
+ """Internal: read lines until outerboundary."""
+ next = "--" + self.outerboundary
+ last = next + "--"
+ delim = ""
+ while 1:
+ line = self.fp.readline()
+ if not line:
+ self.done = -1
+ break
+ if line[:2] == "--":
+ strippedline = line.strip()
+ if strippedline == next:
+ break
+ if strippedline == last:
+ self.done = 1
+ break
+ odelim = delim
+ if line[-2:] == "\r\n":
+ delim = "\r\n"
+ line = line[:-2]
+ elif line[-1] == "\n":
+ delim = "\n"
+ line = line[:-1]
+ else:
+ delim = ""
+ self.file.write(odelim + line)
+
+ def skip_lines(self):
+ """Internal: skip lines until outer boundary if defined."""
+ if not self.outerboundary or self.done:
+ return
+ next = "--" + self.outerboundary
+ last = next + "--"
+ while 1:
+ line = self.fp.readline()
+ if not line:
+ self.done = -1
+ break
+ if line[:2] == "--":
+ strippedline = line.strip()
+ if strippedline == next:
+ break
+ if strippedline == last:
+ self.done = 1
+ break
+
+ def make_file(self, binary=None):
+ """Overridable: return a readable & writable file.
+
+ The file will be used as follows:
+ - data is written to it
+ - seek(0)
+ - data is read from it
+
+ The 'binary' argument is unused -- the file is always opened
+ in binary mode.
+
+ This version opens a temporary file for reading and writing,
+ and immediately deletes (unlinks) it. The trick (on Unix!) is
+ that the file can still be used, but it can't be opened by
+ another process, and it will automatically be deleted when it
+ is closed or when the current process terminates.
+
+ If you want a more permanent file, you derive a class which
+ overrides this method. If you want a visible temporary file
+ that is nevertheless automatically deleted when the script
+ terminates, try defining a __del__ method in a derived class
+ which unlinks the temporary files you have created.
+
+ """
+ import tempfile
+ return tempfile.TemporaryFile("w+b")
+
+
+
+# Backwards Compatibility Classes
+# ===============================
+
+class FormContentDict(UserDict.UserDict):
+ """Form content as dictionary with a list of values per field.
+
+ form = FormContentDict()
+
+ form[key] -> [value, value, ...]
+ form.has_key(key) -> Boolean
+ form.keys() -> [key, key, ...]
+ form.values() -> [[val, val, ...], [val, val, ...], ...]
+ form.items() -> [(key, [val, val, ...]), (key, [val, val, ...]), ...]
+ form.dict == {key: [val, val, ...], ...}
+
+ """
+ def __init__(self, environ=os.environ):
+ self.dict = self.data = parse(environ=environ)
+ self.query_string = environ['QUERY_STRING']
+
+
+class SvFormContentDict(FormContentDict):
+ """Form content as dictionary expecting a single value per field.
+
+ If you only expect a single value for each field, then form[key]
+ will return that single value. It will raise an IndexError if
+ that expectation is not true. If you expect a field to have
+ possible multiple values, than you can use form.getlist(key) to
+ get all of the values. values() and items() are a compromise:
+ they return single strings where there is a single value, and
+ lists of strings otherwise.
+
+ """
+ def __getitem__(self, key):
+ if len(self.dict[key]) > 1:
+ raise IndexError, 'expecting a single value'
+ return self.dict[key][0]
+ def getlist(self, key):
+ return self.dict[key]
+ def values(self):
+ result = []
+ for value in self.dict.values():
+ if len(value) == 1:
+ result.append(value[0])
+ else: result.append(value)
+ return result
+ def items(self):
+ result = []
+ for key, value in self.dict.items():
+ if len(value) == 1:
+ result.append((key, value[0]))
+ else: result.append((key, value))
+ return result
+
+
+class InterpFormContentDict(SvFormContentDict):
+ """This class is present for backwards compatibility only."""
+ def __getitem__(self, key):
+ v = SvFormContentDict.__getitem__(self, key)
+ if v[0] in '0123456789+-.':
+ try: return int(v)
+ except ValueError:
+ try: return float(v)
+ except ValueError: pass
+ return v.strip()
+ def values(self):
+ result = []
+ for key in self.keys():
+ try:
+ result.append(self[key])
+ except IndexError:
+ result.append(self.dict[key])
+ return result
+ def items(self):
+ result = []
+ for key in self.keys():
+ try:
+ result.append((key, self[key]))
+ except IndexError:
+ result.append((key, self.dict[key]))
+ return result
+
+
+class FormContent(FormContentDict):
+ """This class is present for backwards compatibility only."""
+ def values(self, key):
+ if self.dict.has_key(key) :return self.dict[key]
+ else: return None
+ def indexed_value(self, key, location):
+ if self.dict.has_key(key):
+ if len(self.dict[key]) > location:
+ return self.dict[key][location]
+ else: return None
+ else: return None
+ def value(self, key):
+ if self.dict.has_key(key): return self.dict[key][0]
+ else: return None
+ def length(self, key):
+ return len(self.dict[key])
+ def stripped(self, key):
+ if self.dict.has_key(key): return self.dict[key][0].strip()
+ else: return None
+ def pars(self):
+ return self.dict
+
+
+# Test/debug code
+# ===============
+
+def test(environ=os.environ):
+ """Robust test CGI script, usable as main program.
+
+ Write minimal HTTP headers and dump all information provided to
+ the script in HTML form.
+
+ """
+ import traceback
+ print "Content-type: text/html"
+ print
+ sys.stderr = sys.stdout
+ try:
+ form = FieldStorage() # Replace with other classes to test those
+ print_directory()
+ print_arguments()
+ print_form(form)
+ print_environ(environ)
+ print_environ_usage()
+ def f():
+ exec "testing print_exception() -- <I>italics?</I>"
+ def g(f=f):
+ f()
+ print "<H3>What follows is a test, not an actual exception:</H3>"
+ g()
+ except:
+ print_exception()
+
+ print "<H1>Second try with a small maxlen...</H1>"
+
+ global maxlen
+ maxlen = 50
+ try:
+ form = FieldStorage() # Replace with other classes to test those
+ print_directory()
+ print_arguments()
+ print_form(form)
+ print_environ(environ)
+ except:
+ print_exception()
+
+def print_exception(type=None, value=None, tb=None, limit=None):
+ if type is None:
+ type, value, tb = sys.exc_info()
+ import traceback
+ print
+ print "<H3>Traceback (most recent call last):</H3>"
+ list = traceback.format_tb(tb, limit) + \
+ traceback.format_exception_only(type, value)
+ print "<PRE>%s<B>%s</B></PRE>" % (
+ escape("".join(list[:-1])),
+ escape(list[-1]),
+ )
+ del tb
+
+def print_environ(environ=os.environ):
+ """Dump the shell environment as HTML."""
+ keys = environ.keys()
+ keys.sort()
+ print
+ print "<H3>Shell Environment:</H3>"
+ print "<DL>"
+ for key in keys:
+ print "<DT>", escape(key), "<DD>", escape(environ[key])
+ print "</DL>"
+ print
+
+def print_form(form):
+ """Dump the contents of a form as HTML."""
+ keys = form.keys()
+ keys.sort()
+ print
+ print "<H3>Form Contents:</H3>"
+ if not keys:
+ print "<P>No form fields."
+ print "<DL>"
+ for key in keys:
+ print "<DT>" + escape(key) + ":",
+ value = form[key]
+ print "<i>" + escape(`type(value)`) + "</i>"
+ print "<DD>" + escape(`value`)
+ print "</DL>"
+ print
+
+def print_directory():
+ """Dump the current directory as HTML."""
+ print
+ print "<H3>Current Working Directory:</H3>"
+ try:
+ pwd = os.getcwd()
+ except os.error, msg:
+ print "os.error:", escape(str(msg))
+ else:
+ print escape(pwd)
+ print
+
+def print_arguments():
+ print
+ print "<H3>Command Line Arguments:</H3>"
+ print
+ print sys.argv
+ print
+
+def print_environ_usage():
+ """Dump a list of environment variables used by CGI as HTML."""
+ print """
+<H3>These environment variables could have been set:</H3>
+<UL>
+<LI>AUTH_TYPE
+<LI>CONTENT_LENGTH
+<LI>CONTENT_TYPE
+<LI>DATE_GMT
+<LI>DATE_LOCAL
+<LI>DOCUMENT_NAME
+<LI>DOCUMENT_ROOT
+<LI>DOCUMENT_URI
+<LI>GATEWAY_INTERFACE
+<LI>LAST_MODIFIED
+<LI>PATH
+<LI>PATH_INFO
+<LI>PATH_TRANSLATED
+<LI>QUERY_STRING
+<LI>REMOTE_ADDR
+<LI>REMOTE_HOST
+<LI>REMOTE_IDENT
+<LI>REMOTE_USER
+<LI>REQUEST_METHOD
+<LI>SCRIPT_NAME
+<LI>SERVER_NAME
+<LI>SERVER_PORT
+<LI>SERVER_PROTOCOL
+<LI>SERVER_ROOT
+<LI>SERVER_SOFTWARE
+</UL>
+In addition, HTTP headers sent by the server may be passed in the
+environment as well. Here are some common variable names:
+<UL>
+<LI>HTTP_ACCEPT
+<LI>HTTP_CONNECTION
+<LI>HTTP_HOST
+<LI>HTTP_PRAGMA
+<LI>HTTP_REFERER
+<LI>HTTP_USER_AGENT
+</UL>
+"""
+
+
+# Utilities
+# =========
+
+def escape(s, quote=None):
+ """Replace special characters '&', '<' and '>' by SGML entities."""
+ s = s.replace("&", "&") # Must be done first!
+ s = s.replace("<", "<")
+ s = s.replace(">", ">")
+ if quote:
+ s = s.replace('"', """)
+ return s
+
+
+# Invoke mainline
+# ===============
+
+# Call test() when this file is run as a script (not imported as a module)
+if __name__ == '__main__':
+ test()
diff --git a/lib/jython/Lib/cmd.py b/lib/jython/Lib/cmd.py new file mode 100644 index 000000000..6718ede99 --- /dev/null +++ b/lib/jython/Lib/cmd.py @@ -0,0 +1,198 @@ +"""A generic class to build line-oriented command interpreters.
+
+Interpreters constructed with this class obey the following conventions:
+
+1. End of file on input is processed as the command 'EOF'.
+2. A command is parsed out of each line by collecting the prefix composed
+ of characters in the identchars member.
+3. A command `foo' is dispatched to a method 'do_foo()'; the do_ method
+ is passed a single argument consisting of the remainder of the line.
+4. Typing an empty line repeats the last command. (Actually, it calls the
+ method `emptyline', which may be overridden in a subclass.)
+5. There is a predefined `help' method. Given an argument `topic', it
+ calls the command `help_topic'. With no arguments, it lists all topics
+ with defined help_ functions, broken into up to three topics; documented
+ commands, miscellaneous help topics, and undocumented commands.
+6. The command '?' is a synonym for `help'. The command '!' is a synonym
+ for `shell', if a do_shell method exists.
+
+The `default' method may be overridden to intercept commands for which there
+is no do_ method.
+
+The data member `self.ruler' sets the character used to draw separator lines
+in the help messages. If empty, no ruler line is drawn. It defaults to "=".
+
+If the value of `self.intro' is nonempty when the cmdloop method is called,
+it is printed out on interpreter startup. This value may be overridden
+via an optional argument to the cmdloop() method.
+
+The data members `self.doc_header', `self.misc_header', and
+`self.undoc_header' set the headers used for the help function's
+listings of documented functions, miscellaneous topics, and undocumented
+functions respectively.
+
+These interpreters use raw_input; thus, if the readline module is loaded,
+they automatically support Emacs-like command history and editing features.
+"""
+
+import string, sys
+
+__all__ = ["Cmd"]
+
+PROMPT = '(Cmd) '
+IDENTCHARS = string.letters + string.digits + '_'
+
+class Cmd:
+ prompt = PROMPT
+ identchars = IDENTCHARS
+ ruler = '='
+ lastcmd = ''
+ cmdqueue = []
+ intro = None
+ doc_leader = ""
+ doc_header = "Documented commands (type help <topic>):"
+ misc_header = "Miscellaneous help topics:"
+ undoc_header = "Undocumented commands:"
+ nohelp = "*** No help on %s"
+ use_rawinput = 1
+
+ def __init__(self): pass
+
+ def cmdloop(self, intro=None):
+ self.preloop()
+ if intro is not None:
+ self.intro = intro
+ if self.intro:
+ print self.intro
+ stop = None
+ while not stop:
+ if self.cmdqueue:
+ line = self.cmdqueue[0]
+ del self.cmdqueue[0]
+ else:
+ if self.use_rawinput:
+ try:
+ line = raw_input(self.prompt)
+ except EOFError:
+ line = 'EOF'
+ else:
+ sys.stdout.write(self.prompt)
+ line = sys.stdin.readline()
+ if not len(line):
+ line = 'EOF'
+ else:
+ line = line[:-1] # chop \n
+ line = self.precmd(line)
+ stop = self.onecmd(line)
+ stop = self.postcmd(stop, line)
+ self.postloop()
+
+ def precmd(self, line):
+ return line
+
+ def postcmd(self, stop, line):
+ return stop
+
+ def preloop(self):
+ pass
+
+ def postloop(self):
+ pass
+
+ def onecmd(self, line):
+ line = line.strip()
+ if not line:
+ return self.emptyline()
+ elif line[0] == '?':
+ line = 'help ' + line[1:]
+ elif line[0] == '!':
+ if hasattr(self, 'do_shell'):
+ line = 'shell ' + line[1:]
+ else:
+ return self.default(line)
+ self.lastcmd = line
+ i, n = 0, len(line)
+ while i < n and line[i] in self.identchars: i = i+1
+ cmd, arg = line[:i], line[i:].strip()
+ if cmd == '':
+ return self.default(line)
+ else:
+ try:
+ func = getattr(self, 'do_' + cmd)
+ except AttributeError:
+ return self.default(line)
+ return func(arg)
+
+ def emptyline(self):
+ if self.lastcmd:
+ return self.onecmd(self.lastcmd)
+
+ def default(self, line):
+ print '*** Unknown syntax:', line
+
+ def do_help(self, arg):
+ if arg:
+ # XXX check arg syntax
+ try:
+ func = getattr(self, 'help_' + arg)
+ except:
+ try:
+ doc=getattr(self, 'do_' + arg).__doc__
+ if doc:
+ print doc
+ return
+ except:
+ pass
+ print self.nohelp % (arg,)
+ return
+ func()
+ else:
+ # Inheritance says we have to look in class and
+ # base classes; order is not important.
+ names = []
+ classes = [self.__class__]
+ while classes:
+ aclass = classes[0]
+ if aclass.__bases__:
+ classes = classes + list(aclass.__bases__)
+ names = names + dir(aclass)
+ del classes[0]
+ cmds_doc = []
+ cmds_undoc = []
+ help = {}
+ for name in names:
+ if name[:5] == 'help_':
+ help[name[5:]]=1
+ names.sort()
+ # There can be duplicates if routines overridden
+ prevname = ''
+ for name in names:
+ if name[:3] == 'do_':
+ if name == prevname:
+ continue
+ prevname = name
+ cmd=name[3:]
+ if help.has_key(cmd):
+ cmds_doc.append(cmd)
+ del help[cmd]
+ elif getattr(self, name).__doc__:
+ cmds_doc.append(cmd)
+ else:
+ cmds_undoc.append(cmd)
+ print self.doc_leader
+ self.print_topics(self.doc_header, cmds_doc, 15,80)
+ self.print_topics(self.misc_header, help.keys(),15,80)
+ self.print_topics(self.undoc_header, cmds_undoc, 15,80)
+
+ def print_topics(self, header, cmds, cmdlen, maxcol):
+ if cmds:
+ print header
+ if self.ruler:
+ print self.ruler * len(header)
+ (cmds_per_line,junk)=divmod(maxcol,cmdlen)
+ col=cmds_per_line
+ for cmd in cmds:
+ if col==0: print
+ print (("%-"+`cmdlen`+"s") % cmd),
+ col = (col+1) % cmds_per_line
+ print "\n"
diff --git a/lib/jython/Lib/code.py b/lib/jython/Lib/code.py new file mode 100644 index 000000000..f88a509e1 --- /dev/null +++ b/lib/jython/Lib/code.py @@ -0,0 +1,308 @@ +"""Utilities needed to emulate Python's interactive interpreter.
+
+"""
+
+# Inspired by similar code by Jeff Epler and Fredrik Lundh.
+
+
+import sys
+import traceback
+from codeop import compile_command
+
+__all__ = ["InteractiveInterpreter","InteractiveConsole","interact",
+ "compile_command"]
+
+def softspace(file, newvalue):
+ oldvalue = 0
+ try:
+ oldvalue = file.softspace
+ except AttributeError:
+ pass
+ try:
+ file.softspace = newvalue
+ except TypeError: # "attribute-less object" or "read-only attributes"
+ pass
+ return oldvalue
+
+class InteractiveInterpreter:
+ """Base class for InteractiveConsole.
+
+ This class deals with parsing and interpreter state (the user's
+ namespace); it doesn't deal with input buffering or prompting or
+ input file naming (the filename is always passed in explicitly).
+
+ """
+
+ def __init__(self, locals=None):
+ """Constructor.
+
+ The optional 'locals' argument specifies the dictionary in
+ which code will be executed; it defaults to a newly created
+ dictionary with key "__name__" set to "__console__" and key
+ "__doc__" set to None.
+
+ """
+ if locals is None:
+ locals = {"__name__": "__console__", "__doc__": None}
+ self.locals = locals
+
+ def runsource(self, source, filename="<input>", symbol="single"):
+ """Compile and run some source in the interpreter.
+
+ Arguments are as for compile_command().
+
+ One several things can happen:
+
+ 1) The input is incorrect; compile_command() raised an
+ exception (SyntaxError or OverflowError). A syntax traceback
+ will be printed by calling the showsyntaxerror() method.
+
+ 2) The input is incomplete, and more input is required;
+ compile_command() returned None. Nothing happens.
+
+ 3) The input is complete; compile_command() returned a code
+ object. The code is executed by calling self.runcode() (which
+ also handles run-time exceptions, except for SystemExit).
+
+ The return value is 1 in case 2, 0 in the other cases (unless
+ an exception is raised). The return value can be used to
+ decide whether to use sys.ps1 or sys.ps2 to prompt the next
+ line.
+
+ """
+ try:
+ code = compile_command(source, filename, symbol)
+ except (OverflowError, SyntaxError, ValueError):
+ # Case 1
+ self.showsyntaxerror(filename)
+ return 0
+
+ if code is None:
+ # Case 2
+ return 1
+
+ # Case 3
+ self.runcode(code)
+ return 0
+
+ def runcode(self, code):
+ """Execute a code object.
+
+ When an exception occurs, self.showtraceback() is called to
+ display a traceback. All exceptions are caught except
+ SystemExit, which is reraised.
+
+ A note about KeyboardInterrupt: this exception may occur
+ elsewhere in this code, and may not always be caught. The
+ caller should be prepared to deal with it.
+
+ """
+ try:
+ exec code in self.locals
+ except SystemExit:
+ raise
+ except:
+ self.showtraceback()
+ else:
+ if softspace(sys.stdout, 0):
+ print
+
+ def showsyntaxerror(self, filename=None):
+ """Display the syntax error that just occurred.
+
+ This doesn't display a stack trace because there isn't one.
+
+ If a filename is given, it is stuffed in the exception instead
+ of what was there before (because Python's parser always uses
+ "<string>" when reading from a string).
+
+ The output is written by self.write(), below.
+
+ """
+ type, value, sys.last_traceback = sys.exc_info()
+ sys.last_type = type
+ sys.last_value = value
+ if filename and type is SyntaxError:
+ # Work hard to stuff the correct filename in the exception
+ try:
+ msg, (dummy_filename, lineno, offset, line) = value
+ except:
+ # Not the format we expect; leave it alone
+ pass
+ else:
+ # Stuff in the right filename
+ try:
+ # Assume SyntaxError is a class exception
+ value = SyntaxError(msg, (filename, lineno, offset, line))
+ except:
+ # If that failed, assume SyntaxError is a string
+ value = msg, (filename, lineno, offset, line)
+ list = traceback.format_exception_only(type, value)
+ map(self.write, list)
+
+ def showtraceback(self):
+ """Display the exception that just occurred.
+
+ We remove the first stack item because it is our own code.
+
+ The output is written by self.write(), below.
+
+ """
+ try:
+ type, value, tb = sys.exc_info()
+ sys.last_type = type
+ sys.last_value = value
+ sys.last_traceback = tb
+ tblist = traceback.extract_tb(tb)
+ del tblist[:1]
+ list = traceback.format_list(tblist)
+ if list:
+ list.insert(0, "Traceback (most recent call last):\n")
+ list[len(list):] = traceback.format_exception_only(type, value)
+ finally:
+ tblist = tb = None
+ map(self.write, list)
+
+ def write(self, data):
+ """Write a string.
+
+ The base implementation writes to sys.stderr; a subclass may
+ replace this with a different implementation.
+
+ """
+ sys.stderr.write(data)
+
+
+class InteractiveConsole(InteractiveInterpreter):
+ """Closely emulate the behavior of the interactive Python interpreter.
+
+ This class builds on InteractiveInterpreter and adds prompting
+ using the familiar sys.ps1 and sys.ps2, and input buffering.
+
+ """
+
+ def __init__(self, locals=None, filename="<console>"):
+ """Constructor.
+
+ The optional locals argument will be passed to the
+ InteractiveInterpreter base class.
+
+ The optional filename argument should specify the (file)name
+ of the input stream; it will show up in tracebacks.
+
+ """
+ InteractiveInterpreter.__init__(self, locals)
+ self.filename = filename
+ self.resetbuffer()
+
+ def resetbuffer(self):
+ """Reset the input buffer."""
+ self.buffer = []
+
+ def interact(self, banner=None):
+ """Closely emulate the interactive Python console.
+
+ The optional banner argument specify the banner to print
+ before the first interaction; by default it prints a banner
+ similar to the one printed by the real Python interpreter,
+ followed by the current class name in parentheses (so as not
+ to confuse this with the real interpreter -- since it's so
+ close!).
+
+ """
+ try:
+ sys.ps1
+ except AttributeError:
+ sys.ps1 = ">>> "
+ try:
+ sys.ps2
+ except AttributeError:
+ sys.ps2 = "... "
+ cprt = 'Type "copyright", "credits" or "license" for more information.'
+ if banner is None:
+ self.write("Python %s on %s\n%s\n(%s)\n" %
+ (sys.version, sys.platform, cprt,
+ self.__class__.__name__))
+ else:
+ self.write("%s\n" % str(banner))
+ more = 0
+ while 1:
+ try:
+ if more:
+ prompt = sys.ps2
+ else:
+ prompt = sys.ps1
+ try:
+ line = self.raw_input(prompt)
+ except EOFError:
+ self.write("\n")
+ break
+ else:
+ more = self.push(line)
+ except KeyboardInterrupt:
+ self.write("\nKeyboardInterrupt\n")
+ self.resetbuffer()
+ more = 0
+
+ def push(self, line):
+ """Push a line to the interpreter.
+
+ The line should not have a trailing newline; it may have
+ internal newlines. The line is appended to a buffer and the
+ interpreter's runsource() method is called with the
+ concatenated contents of the buffer as source. If this
+ indicates that the command was executed or invalid, the buffer
+ is reset; otherwise, the command is incomplete, and the buffer
+ is left as it was after the line was appended. The return
+ value is 1 if more input is required, 0 if the line was dealt
+ with in some way (this is the same as runsource()).
+
+ """
+ self.buffer.append(line)
+ source = "\n".join(self.buffer)
+ more = self.runsource(source, self.filename)
+ if not more:
+ self.resetbuffer()
+ return more
+
+ def raw_input(self, prompt=""):
+ """Write a prompt and read a line.
+
+ The returned line does not include the trailing newline.
+ When the user enters the EOF key sequence, EOFError is raised.
+
+ The base implementation uses the built-in function
+ raw_input(); a subclass may replace this with a different
+ implementation.
+
+ """
+ return raw_input(prompt)
+
+
+def interact(banner=None, readfunc=None, local=None):
+ """Closely emulate the interactive Python interpreter.
+
+ This is a backwards compatible interface to the InteractiveConsole
+ class. When readfunc is not specified, it attempts to import the
+ readline module to enable GNU readline if it is available.
+
+ Arguments (all optional, all default to None):
+
+ banner -- passed to InteractiveConsole.interact()
+ readfunc -- if not None, replaces InteractiveConsole.raw_input()
+ local -- passed to InteractiveInterpreter.__init__()
+
+ """
+ console = InteractiveConsole(local)
+ if readfunc is not None:
+ console.raw_input = readfunc
+ else:
+ try:
+ import readline
+ except:
+ pass
+ console.interact(banner)
+
+
+if __name__ == '__main__':
+ interact()
diff --git a/lib/jython/Lib/codecs.py b/lib/jython/Lib/codecs.py new file mode 100644 index 000000000..e04e9dd03 --- /dev/null +++ b/lib/jython/Lib/codecs.py @@ -0,0 +1,570 @@ +""" codecs -- Python Codec Registry, API and helpers.
+
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+
+"""#"
+
+import struct,types,__builtin__
+
+### Registry and builtin stateless codec functions
+
+try:
+ from _codecs import *
+except ImportError,why:
+ raise SystemError,\
+ 'Failed to load the builtin codecs: %s' % why
+
+__all__ = ["register","lookup","open","EncodedFile","BOM","BOM_BE",
+ "BOM_LE","BOM32_BE","BOM32_LE","BOM64_BE","BOM64_LE"]
+
+### Constants
+
+#
+# Byte Order Mark (BOM) and its possible values (BOM_BE, BOM_LE)
+#
+BOM = struct.pack('=H',0xFEFF)
+#
+BOM_BE = BOM32_BE = '\376\377'
+# corresponds to Unicode U+FEFF in UTF-16 on big endian
+# platforms == ZERO WIDTH NO-BREAK SPACE
+BOM_LE = BOM32_LE = '\377\376'
+# corresponds to Unicode U+FFFE in UTF-16 on little endian
+# platforms == defined as being an illegal Unicode character
+
+#
+# 64-bit Byte Order Marks
+#
+BOM64_BE = '\000\000\376\377'
+# corresponds to Unicode U+0000FEFF in UCS-4
+BOM64_LE = '\377\376\000\000'
+# corresponds to Unicode U+0000FFFE in UCS-4
+
+
+### Codec base classes (defining the API)
+
+class Codec:
+
+ """ Defines the interface for stateless encoders/decoders.
+
+ The .encode()/.decode() methods may implement different error
+ handling schemes by providing the errors argument. These
+ string values are defined:
+
+ 'strict' - raise a ValueError error (or a subclass)
+ 'ignore' - ignore the character and continue with the next
+ 'replace' - replace with a suitable replacement character;
+ Python will use the official U+FFFD REPLACEMENT
+ CHARACTER for the builtin Unicode codecs.
+
+ """
+ def encode(self,input,errors='strict'):
+
+ """ Encodes the object input and returns a tuple (output
+ object, length consumed).
+
+ errors defines the error handling to apply. It defaults to
+ 'strict' handling.
+
+ The method may not store state in the Codec instance. Use
+ StreamCodec for codecs which have to keep state in order to
+ make encoding/decoding efficient.
+
+ The encoder must be able to handle zero length input and
+ return an empty object of the output object type in this
+ situation.
+
+ """
+ raise NotImplementedError
+
+ def decode(self,input,errors='strict'):
+
+ """ Decodes the object input and returns a tuple (output
+ object, length consumed).
+
+ input must be an object which provides the bf_getreadbuf
+ buffer slot. Python strings, buffer objects and memory
+ mapped files are examples of objects providing this slot.
+
+ errors defines the error handling to apply. It defaults to
+ 'strict' handling.
+
+ The method may not store state in the Codec instance. Use
+ StreamCodec for codecs which have to keep state in order to
+ make encoding/decoding efficient.
+
+ The decoder must be able to handle zero length input and
+ return an empty object of the output object type in this
+ situation.
+
+ """
+ raise NotImplementedError
+
+#
+# The StreamWriter and StreamReader class provide generic working
+# interfaces which can be used to implement new encodings submodules
+# very easily. See encodings/utf_8.py for an example on how this is
+# done.
+#
+
+class StreamWriter(Codec):
+
+ def __init__(self,stream,errors='strict'):
+
+ """ Creates a StreamWriter instance.
+
+ stream must be a file-like object open for writing
+ (binary) data.
+
+ The StreamWriter may implement different error handling
+ schemes by providing the errors keyword argument. These
+ parameters are defined:
+
+ 'strict' - raise a ValueError (or a subclass)
+ 'ignore' - ignore the character and continue with the next
+ 'replace'- replace with a suitable replacement character
+
+ """
+ self.stream = stream
+ self.errors = errors
+
+ def write(self, object):
+
+ """ Writes the object's contents encoded to self.stream.
+ """
+ data, consumed = self.encode(object,self.errors)
+ self.stream.write(data)
+
+ def writelines(self, list):
+
+ """ Writes the concatenated list of strings to the stream
+ using .write().
+ """
+ self.write(''.join(list))
+
+ def reset(self):
+
+ """ Flushes and resets the codec buffers used for keeping state.
+
+ Calling this method should ensure that the data on the
+ output is put into a clean state, that allows appending
+ of new fresh data without having to rescan the whole
+ stream to recover state.
+
+ """
+ pass
+
+ def __getattr__(self,name,
+
+ getattr=getattr):
+
+ """ Inherit all other methods from the underlying stream.
+ """
+ return getattr(self.stream,name)
+
+###
+
+class StreamReader(Codec):
+
+ def __init__(self,stream,errors='strict'):
+
+ """ Creates a StreamReader instance.
+
+ stream must be a file-like object open for reading
+ (binary) data.
+
+ The StreamReader may implement different error handling
+ schemes by providing the errors keyword argument. These
+ parameters are defined:
+
+ 'strict' - raise a ValueError (or a subclass)
+ 'ignore' - ignore the character and continue with the next
+ 'replace'- replace with a suitable replacement character;
+
+ """
+ self.stream = stream
+ self.errors = errors
+
+ def read(self, size=-1):
+
+ """ Decodes data from the stream self.stream and returns the
+ resulting object.
+
+ size indicates the approximate maximum number of bytes to
+ read from the stream for decoding purposes. The decoder
+ can modify this setting as appropriate. The default value
+ -1 indicates to read and decode as much as possible. size
+ is intended to prevent having to decode huge files in one
+ step.
+
+ The method should use a greedy read strategy meaning that
+ it should read as much data as is allowed within the
+ definition of the encoding and the given size, e.g. if
+ optional encoding endings or state markers are available
+ on the stream, these should be read too.
+
+ """
+ # Unsliced reading:
+ if size < 0:
+ return self.decode(self.stream.read(), self.errors)[0]
+
+ # Sliced reading:
+ read = self.stream.read
+ decode = self.decode
+ data = read(size)
+ i = 0
+ while 1:
+ try:
+ object, decodedbytes = decode(data, self.errors)
+ except ValueError,why:
+ # This method is slow but should work under pretty much
+ # all conditions; at most 10 tries are made
+ i = i + 1
+ newdata = read(1)
+ if not newdata or i > 10:
+ raise
+ data = data + newdata
+ else:
+ return object
+
+ def readline(self, size=None):
+
+ """ Read one line from the input stream and return the
+ decoded data.
+
+ Note: Unlike the .readlines() method, this method inherits
+ the line breaking knowledge from the underlying stream's
+ .readline() method -- there is currently no support for
+ line breaking using the codec decoder due to lack of line
+ buffering. Sublcasses should however, if possible, try to
+ implement this method using their own knowledge of line
+ breaking.
+
+ size, if given, is passed as size argument to the stream's
+ .readline() method.
+
+ """
+ if size is None:
+ line = self.stream.readline()
+ else:
+ line = self.stream.readline(size)
+ return self.decode(line,self.errors)[0]
+
+
+ def readlines(self, sizehint=0):
+
+ """ Read all lines available on the input stream
+ and return them as list of lines.
+
+ Line breaks are implemented using the codec's decoder
+ method and are included in the list entries.
+
+ sizehint, if given, is passed as size argument to the
+ stream's .read() method.
+
+ """
+ if sizehint is None:
+ data = self.stream.read()
+ else:
+ data = self.stream.read(sizehint)
+ return self.decode(data,self.errors)[0].splitlines(1)
+
+ def reset(self):
+
+ """ Resets the codec buffers used for keeping state.
+
+ Note that no stream repositioning should take place.
+ This method is primarily intended to be able to recover
+ from decoding errors.
+
+ """
+ pass
+
+ def __getattr__(self,name,
+
+ getattr=getattr):
+
+ """ Inherit all other methods from the underlying stream.
+ """
+ return getattr(self.stream,name)
+
+###
+
+class StreamReaderWriter:
+
+ """ StreamReaderWriter instances allow wrapping streams which
+ work in both read and write modes.
+
+ The design is such that one can use the factory functions
+ returned by the codec.lookup() function to construct the
+ instance.
+
+ """
+ # Optional attributes set by the file wrappers below
+ encoding = 'unknown'
+
+ def __init__(self,stream,Reader,Writer,errors='strict'):
+
+ """ Creates a StreamReaderWriter instance.
+
+ stream must be a Stream-like object.
+
+ Reader, Writer must be factory functions or classes
+ providing the StreamReader, StreamWriter interface resp.
+
+ Error handling is done in the same way as defined for the
+ StreamWriter/Readers.
+
+ """
+ self.stream = stream
+ self.reader = Reader(stream, errors)
+ self.writer = Writer(stream, errors)
+ self.errors = errors
+
+ def read(self,size=-1):
+
+ return self.reader.read(size)
+
+ def readline(self, size=None):
+
+ return self.reader.readline(size)
+
+ def readlines(self, sizehint=None):
+
+ return self.reader.readlines(sizehint)
+
+ def write(self,data):
+
+ return self.writer.write(data)
+
+ def writelines(self,list):
+
+ return self.writer.writelines(list)
+
+ def reset(self):
+
+ self.reader.reset()
+ self.writer.reset()
+
+ def __getattr__(self,name,
+
+ getattr=getattr):
+
+ """ Inherit all other methods from the underlying stream.
+ """
+ return getattr(self.stream,name)
+
+###
+
+class StreamRecoder:
+
+ """ StreamRecoder instances provide a frontend - backend
+ view of encoding data.
+
+ They use the complete set of APIs returned by the
+ codecs.lookup() function to implement their task.
+
+ Data written to the stream is first decoded into an
+ intermediate format (which is dependent on the given codec
+ combination) and then written to the stream using an instance
+ of the provided Writer class.
+
+ In the other direction, data is read from the stream using a
+ Reader instance and then return encoded data to the caller.
+
+ """
+ # Optional attributes set by the file wrappers below
+ data_encoding = 'unknown'
+ file_encoding = 'unknown'
+
+ def __init__(self,stream,encode,decode,Reader,Writer,errors='strict'):
+
+ """ Creates a StreamRecoder instance which implements a two-way
+ conversion: encode and decode work on the frontend (the
+ input to .read() and output of .write()) while
+ Reader and Writer work on the backend (reading and
+ writing to the stream).
+
+ You can use these objects to do transparent direct
+ recodings from e.g. latin-1 to utf-8 and back.
+
+ stream must be a file-like object.
+
+ encode, decode must adhere to the Codec interface, Reader,
+ Writer must be factory functions or classes providing the
+ StreamReader, StreamWriter interface resp.
+
+ encode and decode are needed for the frontend translation,
+ Reader and Writer for the backend translation. Unicode is
+ used as intermediate encoding.
+
+ Error handling is done in the same way as defined for the
+ StreamWriter/Readers.
+
+ """
+ self.stream = stream
+ self.encode = encode
+ self.decode = decode
+ self.reader = Reader(stream, errors)
+ self.writer = Writer(stream, errors)
+ self.errors = errors
+
+ def read(self,size=-1):
+
+ data = self.reader.read(size)
+ data, bytesencoded = self.encode(data, self.errors)
+ return data
+
+ def readline(self,size=None):
+
+ if size is None:
+ data = self.reader.readline()
+ else:
+ data = self.reader.readline(size)
+ data, bytesencoded = self.encode(data, self.errors)
+ return data
+
+ def readlines(self,sizehint=None):
+
+ if sizehint is None:
+ data = self.reader.read()
+ else:
+ data = self.reader.read(sizehint)
+ data, bytesencoded = self.encode(data, self.errors)
+ return data.splitlines(1)
+
+ def write(self,data):
+
+ data, bytesdecoded = self.decode(data, self.errors)
+ return self.writer.write(data)
+
+ def writelines(self,list):
+
+ data = ''.join(list)
+ data, bytesdecoded = self.decode(data, self.errors)
+ return self.writer.write(data)
+
+ def reset(self):
+
+ self.reader.reset()
+ self.writer.reset()
+
+ def __getattr__(self,name,
+
+ getattr=getattr):
+
+ """ Inherit all other methods from the underlying stream.
+ """
+ return getattr(self.stream,name)
+
+### Shortcuts
+
+def open(filename, mode='rb', encoding=None, errors='strict', buffering=1):
+
+ """ Open an encoded file using the given mode and return
+ a wrapped version providing transparent encoding/decoding.
+
+ Note: The wrapped version will only accept the object format
+ defined by the codecs, i.e. Unicode objects for most builtin
+ codecs. Output is also codec dependent and will usually by
+ Unicode as well.
+
+ Files are always opened in binary mode, even if no binary mode
+ was specified. Thisis done to avoid data loss due to encodings
+ using 8-bit values. The default file mode is 'rb' meaning to
+ open the file in binary read mode.
+
+ encoding specifies the encoding which is to be used for the
+ the file.
+
+ errors may be given to define the error handling. It defaults
+ to 'strict' which causes ValueErrors to be raised in case an
+ encoding error occurs.
+
+ buffering has the same meaning as for the builtin open() API.
+ It defaults to line buffered.
+
+ The returned wrapped file object provides an extra attribute
+ .encoding which allows querying the used encoding. This
+ attribute is only available if an encoding was specified as
+ parameter.
+
+ """
+ if encoding is not None and \
+ 'b' not in mode:
+ # Force opening of the file in binary mode
+ mode = mode + 'b'
+ file = __builtin__.open(filename, mode, buffering)
+ if encoding is None:
+ return file
+ (e,d,sr,sw) = lookup(encoding)
+ srw = StreamReaderWriter(file, sr, sw, errors)
+ # Add attributes to simplify introspection
+ srw.encoding = encoding
+ return srw
+
+def EncodedFile(file, data_encoding, file_encoding=None, errors='strict'):
+
+ """ Return a wrapped version of file which provides transparent
+ encoding translation.
+
+ Strings written to the wrapped file are interpreted according
+ to the given data_encoding and then written to the original
+ file as string using file_encoding. The intermediate encoding
+ will usually be Unicode but depends on the specified codecs.
+
+ Strings are read from the file using file_encoding and then
+ passed back to the caller as string using data_encoding.
+
+ If file_encoding is not given, it defaults to data_encoding.
+
+ errors may be given to define the error handling. It defaults
+ to 'strict' which causes ValueErrors to be raised in case an
+ encoding error occurs.
+
+ The returned wrapped file object provides two extra attributes
+ .data_encoding and .file_encoding which reflect the given
+ parameters of the same name. The attributes can be used for
+ introspection by Python programs.
+
+ """
+ if file_encoding is None:
+ file_encoding = data_encoding
+ encode, decode = lookup(data_encoding)[:2]
+ Reader, Writer = lookup(file_encoding)[2:]
+ sr = StreamRecoder(file,
+ encode,decode,Reader,Writer,
+ errors)
+ # Add attributes to simplify introspection
+ sr.data_encoding = data_encoding
+ sr.file_encoding = file_encoding
+ return sr
+
+### Helpers for charmap-based codecs
+
+def make_identity_dict(rng):
+
+ """ make_identity_dict(rng) -> dict
+
+ Return a dictionary where elements of the rng sequence are
+ mapped to themselves.
+
+ """
+ res = {}
+ for i in rng:
+ res[i]=i
+ return res
+
+### Tests
+
+if __name__ == '__main__':
+
+ import sys
+
+ # Make stdout translate Latin-1 output into UTF-8 output
+ sys.stdout = EncodedFile(sys.stdout, 'latin-1', 'utf-8')
+
+ # Have stdin translate Latin-1 input into UTF-8 input
+ sys.stdin = EncodedFile(sys.stdin, 'utf-8', 'latin-1')
diff --git a/lib/jython/Lib/colorsys.py b/lib/jython/Lib/colorsys.py new file mode 100644 index 000000000..4e8c13c94 --- /dev/null +++ b/lib/jython/Lib/colorsys.py @@ -0,0 +1,123 @@ +"""Conversion functions between RGB and other color systems.
+
+This modules provides two functions for each color system ABC:
+
+ rgb_to_abc(r, g, b) --> a, b, c
+ abc_to_rgb(a, b, c) --> r, g, b
+
+All inputs and outputs are triples of floats in the range [0.0...1.0].
+Inputs outside this range may cause exceptions or invalid outputs.
+
+Supported color systems:
+RGB: Red, Green, Blue components
+YIQ: used by composite video signals
+HLS: Hue, Luminance, Saturation
+HSV: Hue, Saturation, Value
+"""
+# References:
+# XXX Where's the literature?
+
+__all__ = ["rgb_to_yiq","yiq_to_rgb","rgb_to_hls","hls_to_rgb",
+ "rgb_to_hsv","hsv_to_rgb"]
+
+# Some floating point constants
+
+ONE_THIRD = 1.0/3.0
+ONE_SIXTH = 1.0/6.0
+TWO_THIRD = 2.0/3.0
+
+
+# YIQ: used by composite video signals (linear combinations of RGB)
+# Y: perceived grey level (0.0 == black, 1.0 == white)
+# I, Q: color components
+
+def rgb_to_yiq(r, g, b):
+ y = 0.30*r + 0.59*g + 0.11*b
+ i = 0.60*r - 0.28*g - 0.32*b
+ q = 0.21*r - 0.52*g + 0.31*b
+ return (y, i, q)
+
+def yiq_to_rgb(y, i, q):
+ r = y + 0.948262*i + 0.624013*q
+ g = y - 0.276066*i - 0.639810*q
+ b = y - 1.105450*i + 1.729860*q
+ if r < 0.0: r = 0.0
+ if g < 0.0: g = 0.0
+ if b < 0.0: b = 0.0
+ if r > 1.0: r = 1.0
+ if g > 1.0: g = 1.0
+ if b > 1.0: b = 1.0
+ return (r, g, b)
+
+
+# HLS: Hue, Luminance, S???
+# H: position in the spectrum
+# L: ???
+# S: ???
+
+def rgb_to_hls(r, g, b):
+ maxc = max(r, g, b)
+ minc = min(r, g, b)
+ # XXX Can optimize (maxc+minc) and (maxc-minc)
+ l = (minc+maxc)/2.0
+ if minc == maxc: return 0.0, l, 0.0
+ if l <= 0.5: s = (maxc-minc) / (maxc+minc)
+ else: s = (maxc-minc) / (2.0-maxc-minc)
+ rc = (maxc-r) / (maxc-minc)
+ gc = (maxc-g) / (maxc-minc)
+ bc = (maxc-b) / (maxc-minc)
+ if r == maxc: h = bc-gc
+ elif g == maxc: h = 2.0+rc-bc
+ else: h = 4.0+gc-rc
+ h = (h/6.0) % 1.0
+ return h, l, s
+
+def hls_to_rgb(h, l, s):
+ if s == 0.0: return l, l, l
+ if l <= 0.5: m2 = l * (1.0+s)
+ else: m2 = l+s-(l*s)
+ m1 = 2.0*l - m2
+ return (_v(m1, m2, h+ONE_THIRD), _v(m1, m2, h), _v(m1, m2, h-ONE_THIRD))
+
+def _v(m1, m2, hue):
+ hue = hue % 1.0
+ if hue < ONE_SIXTH: return m1 + (m2-m1)*hue*6.0
+ if hue < 0.5: return m2
+ if hue < TWO_THIRD: return m1 + (m2-m1)*(TWO_THIRD-hue)*6.0
+ return m1
+
+
+# HSV: Hue, Saturation, Value(?)
+# H: position in the spectrum
+# S: ???
+# V: ???
+
+def rgb_to_hsv(r, g, b):
+ maxc = max(r, g, b)
+ minc = min(r, g, b)
+ v = maxc
+ if minc == maxc: return 0.0, 0.0, v
+ s = (maxc-minc) / maxc
+ rc = (maxc-r) / (maxc-minc)
+ gc = (maxc-g) / (maxc-minc)
+ bc = (maxc-b) / (maxc-minc)
+ if r == maxc: h = bc-gc
+ elif g == maxc: h = 2.0+rc-bc
+ else: h = 4.0+gc-rc
+ h = (h/6.0) % 1.0
+ return h, s, v
+
+def hsv_to_rgb(h, s, v):
+ if s == 0.0: return v, v, v
+ i = int(h*6.0) # XXX assume int() truncates!
+ f = (h*6.0) - i
+ p = v*(1.0 - s)
+ q = v*(1.0 - s*f)
+ t = v*(1.0 - s*(1.0-f))
+ if i%6 == 0: return v, t, p
+ if i == 1: return q, v, p
+ if i == 2: return p, v, t
+ if i == 3: return p, q, v
+ if i == 4: return t, p, v
+ if i == 5: return v, p, q
+ # Cannot get here
diff --git a/lib/jython/Lib/commands.py b/lib/jython/Lib/commands.py new file mode 100644 index 000000000..02b4e5ae7 --- /dev/null +++ b/lib/jython/Lib/commands.py @@ -0,0 +1,84 @@ +"""Execute shell commands via os.popen() and return status, output.
+
+Interface summary:
+
+ import commands
+
+ outtext = commands.getoutput(cmd)
+ (exitstatus, outtext) = commands.getstatusoutput(cmd)
+ outtext = commands.getstatus(file) # returns output of "ls -ld file"
+
+A trailing newline is removed from the output string.
+
+Encapsulates the basic operation:
+
+ pipe = os.popen('{ ' + cmd + '; } 2>&1', 'r')
+ text = pipe.read()
+ sts = pipe.close()
+
+ [Note: it would be nice to add functions to interpret the exit status.]
+"""
+
+__all__ = ["getstatusoutput","getoutput","getstatus"]
+
+# Module 'commands'
+#
+# Various tools for executing commands and looking at their output and status.
+#
+# NB This only works (and is only relevant) for UNIX.
+
+
+# Get 'ls -l' status for an object into a string
+#
+def getstatus(file):
+ """Return output of "ls -ld <file>" in a string."""
+ return getoutput('ls -ld' + mkarg(file))
+
+
+# Get the output from a shell command into a string.
+# The exit status is ignored; a trailing newline is stripped.
+# Assume the command will work with '{ ... ; } 2>&1' around it..
+#
+def getoutput(cmd):
+ """Return output (stdout or stderr) of executing cmd in a shell."""
+ return getstatusoutput(cmd)[1]
+
+
+# Ditto but preserving the exit status.
+# Returns a pair (sts, output)
+#
+def getstatusoutput(cmd):
+ """Return (status, output) of executing cmd in a shell."""
+ import os
+ pipe = os.popen('{ ' + cmd + '; } 2>&1', 'r')
+ text = pipe.read()
+ sts = pipe.close()
+ if sts is None: sts = 0
+ if text[-1:] == '\n': text = text[:-1]
+ return sts, text
+
+
+# Make command argument from directory and pathname (prefix space, add quotes).
+#
+def mk2arg(head, x):
+ import os
+ return mkarg(os.path.join(head, x))
+
+
+# Make a shell command argument from a string.
+# Return a string beginning with a space followed by a shell-quoted
+# version of the argument.
+# Two strategies: enclose in single quotes if it contains none;
+# otherwise, enclose in double quotes and prefix quotable characters
+# with backslash.
+#
+def mkarg(x):
+ if '\'' not in x:
+ return ' \'' + x + '\''
+ s = ' "'
+ for c in x:
+ if c in '\\$"`':
+ s = s + '\\'
+ s = s + c
+ s = s + '"'
+ return s
diff --git a/lib/jython/Lib/compileall.py b/lib/jython/Lib/compileall.py new file mode 100644 index 000000000..1ffa3ee04 --- /dev/null +++ b/lib/jython/Lib/compileall.py @@ -0,0 +1,130 @@ +"""Module/script to "compile" all .py files to .pyc (or .pyo) file.
+
+When called as a script with arguments, this compiles the directories
+given as arguments recursively; the -l option prevents it from
+recursing into directories.
+
+Without arguments, if compiles all modules on sys.path, without
+recursing into subdirectories. (Even though it should do so for
+packages -- for now, you'll have to deal with packages separately.)
+
+See module py_compile for details of the actual byte-compilation.
+
+"""
+
+import os
+import stat
+import sys
+import py_compile
+
+__all__ = ["compile_dir","compile_path"]
+
+def compile_dir(dir, maxlevels=10, ddir=None, force=0):
+ """Byte-compile all modules in the given directory tree.
+
+ Arguments (only dir is required):
+
+ dir: the directory to byte-compile
+ maxlevels: maximum recursion level (default 10)
+ ddir: if given, purported directory name (this is the
+ directory name that will show up in error messages)
+ force: if 1, force compilation, even if timestamps are up-to-date
+
+ """
+ print 'Listing', dir, '...'
+ try:
+ names = os.listdir(dir)
+ except os.error:
+ print "Can't list", dir
+ names = []
+ names.sort()
+ success = 1
+ for name in names:
+ fullname = os.path.join(dir, name)
+ if ddir:
+ dfile = os.path.join(ddir, name)
+ else:
+ dfile = None
+ if os.path.isfile(fullname):
+ head, tail = name[:-3], name[-3:]
+ if tail == '.py':
+ cfile = fullname + (__debug__ and 'c' or 'o')
+ ftime = os.stat(fullname)[stat.ST_MTIME]
+ try: ctime = os.stat(cfile)[stat.ST_MTIME]
+ except os.error: ctime = 0
+ if (ctime > ftime) and not force: continue
+ print 'Compiling', fullname, '...'
+ try:
+ py_compile.compile(fullname, None, dfile)
+ except KeyboardInterrupt:
+ raise KeyboardInterrupt
+ 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
+ success = 0
+ 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, dfile, force)
+ return success
+
+def compile_path(skip_curdir=1, maxlevels=0, force=0):
+ """Byte-compile all module on sys.path.
+
+ Arguments (all optional):
+
+ skip_curdir: if true, skip current directory (default true)
+ maxlevels: max recursion level (default 0)
+ force: as for compile_dir() (default 0)
+
+ """
+ success = 1
+ for dir in sys.path:
+ if (not dir or dir == os.curdir) and skip_curdir:
+ print 'Skipping current directory'
+ else:
+ success = success and compile_dir(dir, maxlevels, None, force)
+ return success
+
+def main():
+ """Script main program."""
+ import getopt
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], 'lfd:')
+ except getopt.error, msg:
+ print msg
+ print "usage: compileall [-l] [-f] [-d destdir] [directory ...]"
+ print "-l: don't recurse down"
+ print "-f: force rebuild even if timestamps are up-to-date"
+ print "-d destdir: purported directory name for error messages"
+ print "if no directory arguments, -l sys.path is assumed"
+ sys.exit(2)
+ maxlevels = 10
+ ddir = None
+ force = 0
+ for o, a in opts:
+ if o == '-l': maxlevels = 0
+ if o == '-d': ddir = a
+ if o == '-f': force = 1
+ if ddir:
+ if len(args) != 1:
+ print "-d destdir require exactly one directory argument"
+ sys.exit(2)
+ success = 1
+ try:
+ if args:
+ for dir in args:
+ success = success and compile_dir(dir, maxlevels, ddir, force)
+ else:
+ success = compile_path()
+ except KeyboardInterrupt:
+ print "\n[interrupt]"
+ success = 0
+ return success
+
+if __name__ == '__main__':
+ sys.exit(not main())
diff --git a/lib/jython/Lib/copy.py b/lib/jython/Lib/copy.py new file mode 100644 index 000000000..617acdf20 --- /dev/null +++ b/lib/jython/Lib/copy.py @@ -0,0 +1,330 @@ +"""Generic (shallow and deep) copying operations.
+
+Interface summary:
+
+ import copy
+
+ x = copy.copy(y) # make a shallow copy of y
+ x = copy.deepcopy(y) # make a deep copy of y
+
+For module specific errors, copy.error is raised.
+
+The difference between shallow and deep copying is only relevant for
+compound objects (objects that contain other objects, like lists or
+class instances).
+
+- A shallow copy constructs a new compound object and then (to the
+ extent possible) inserts *the same objects* into in that the
+ original contains.
+
+- A deep copy constructs a new compound object and then, recursively,
+ inserts *copies* into it of the objects found in the original.
+
+Two problems often exist with deep copy operations that don't exist
+with shallow copy operations:
+
+ a) recursive objects (compound objects that, directly or indirectly,
+ contain a reference to themselves) may cause a recursive loop
+
+ b) because deep copy copies *everything* it may copy too much, e.g.
+ administrative data structures that should be shared even between
+ copies
+
+Python's deep copy operation avoids these problems by:
+
+ a) keeping a table of objects already copied during the current
+ copying pass
+
+ b) letting user-defined classes override the copying operation or the
+ set of components copied
+
+This version does not copy types like module, class, function, method,
+nor stack trace, stack frame, nor file, socket, window, nor array, nor
+any similar types.
+
+Classes can use the same interfaces to control copying that they use
+to control pickling: they can define methods called __getinitargs__(),
+__getstate__() and __setstate__(). See the documentation for module
+"pickle" for information on these methods.
+"""
+
+# XXX need to support copy_reg here too...
+
+import types
+
+class Error(Exception):
+ pass
+error = Error # backward compatibility
+
+try:
+ from org.python.core import PyStringMap
+except ImportError:
+ PyStringMap = None
+
+__all__ = ["Error","error","copy","deepcopy"]
+
+def copy(x):
+ """Shallow copy operation on arbitrary Python objects.
+
+ See the module's __doc__ string for more info.
+ """
+
+ try:
+ copierfunction = _copy_dispatch[type(x)]
+ except KeyError:
+ try:
+ copier = x.__copy__
+ except AttributeError:
+ raise error, \
+ "un(shallow)copyable object of type %s" % type(x)
+ y = copier()
+ else:
+ y = copierfunction(x)
+ return y
+
+_copy_dispatch = d = {}
+
+def _copy_atomic(x):
+ return x
+d[types.NoneType] = _copy_atomic
+d[types.IntType] = _copy_atomic
+d[types.LongType] = _copy_atomic
+d[types.FloatType] = _copy_atomic
+d[types.StringType] = _copy_atomic
+d[types.UnicodeType] = _copy_atomic
+try:
+ d[types.CodeType] = _copy_atomic
+except AttributeError:
+ pass
+d[types.TypeType] = _copy_atomic
+d[types.XRangeType] = _copy_atomic
+d[types.ClassType] = _copy_atomic
+
+def _copy_list(x):
+ return x[:]
+d[types.ListType] = _copy_list
+
+def _copy_tuple(x):
+ return x[:]
+d[types.TupleType] = _copy_tuple
+
+def _copy_dict(x):
+ return x.copy()
+d[types.DictionaryType] = _copy_dict
+if PyStringMap is not None:
+ d[PyStringMap] = _copy_dict
+
+def _copy_inst(x):
+ if hasattr(x, '__copy__'):
+ return x.__copy__()
+ if hasattr(x, '__getinitargs__'):
+ args = x.__getinitargs__()
+ y = apply(x.__class__, args)
+ else:
+ if hasattr(x.__class__, '__del__'):
+ y = _EmptyClassDel()
+ else:
+ y = _EmptyClass()
+ y.__class__ = x.__class__
+ if hasattr(x, '__getstate__'):
+ state = x.__getstate__()
+ else:
+ state = x.__dict__
+ if hasattr(y, '__setstate__'):
+ y.__setstate__(state)
+ else:
+ y.__dict__.update(state)
+ return y
+d[types.InstanceType] = _copy_inst
+
+del d
+
+def deepcopy(x, memo = None):
+ """Deep copy operation on arbitrary Python objects.
+
+ See the module's __doc__ string for more info.
+ """
+
+ if memo is None:
+ memo = {}
+ d = id(x)
+ if memo.has_key(d):
+ return memo[d]
+ try:
+ copierfunction = _deepcopy_dispatch[type(x)]
+ except KeyError:
+ try:
+ copier = x.__deepcopy__
+ except AttributeError:
+ raise error, \
+ "un-deep-copyable object of type %s" % type(x)
+ y = copier(memo)
+ else:
+ y = copierfunction(x, memo)
+ memo[d] = y
+ return y
+
+_deepcopy_dispatch = d = {}
+
+def _deepcopy_atomic(x, memo):
+ return x
+d[types.NoneType] = _deepcopy_atomic
+d[types.IntType] = _deepcopy_atomic
+d[types.LongType] = _deepcopy_atomic
+d[types.FloatType] = _deepcopy_atomic
+d[types.StringType] = _deepcopy_atomic
+d[types.UnicodeType] = _deepcopy_atomic
+d[types.CodeType] = _deepcopy_atomic
+d[types.TypeType] = _deepcopy_atomic
+d[types.XRangeType] = _deepcopy_atomic
+
+def _deepcopy_list(x, memo):
+ y = []
+ memo[id(x)] = y
+ for a in x:
+ y.append(deepcopy(a, memo))
+ return y
+d[types.ListType] = _deepcopy_list
+
+def _deepcopy_tuple(x, memo):
+ y = []
+ for a in x:
+ y.append(deepcopy(a, memo))
+ d = id(x)
+ try:
+ return memo[d]
+ except KeyError:
+ pass
+ for i in range(len(x)):
+ if x[i] is not y[i]:
+ y = tuple(y)
+ break
+ else:
+ y = x
+ memo[d] = y
+ return y
+d[types.TupleType] = _deepcopy_tuple
+
+def _deepcopy_dict(x, memo):
+ y = {}
+ memo[id(x)] = y
+ for key in x.keys():
+ y[deepcopy(key, memo)] = deepcopy(x[key], memo)
+ return y
+d[types.DictionaryType] = _deepcopy_dict
+if PyStringMap is not None:
+ d[PyStringMap] = _deepcopy_dict
+
+def _keep_alive(x, memo):
+ """Keeps a reference to the object x in the memo.
+
+ Because we remember objects by their id, we have
+ to assure that possibly temporary objects are kept
+ alive by referencing them.
+ We store a reference at the id of the memo, which should
+ normally not be used unless someone tries to deepcopy
+ the memo itself...
+ """
+ try:
+ memo[id(memo)].append(x)
+ except KeyError:
+ # aha, this is the first one :-)
+ memo[id(memo)]=[x]
+
+def _deepcopy_inst(x, memo):
+ if hasattr(x, '__deepcopy__'):
+ return x.__deepcopy__(memo)
+ if hasattr(x, '__getinitargs__'):
+ args = x.__getinitargs__()
+ _keep_alive(args, memo)
+ args = deepcopy(args, memo)
+ y = apply(x.__class__, args)
+ else:
+ if hasattr(x.__class__, '__del__'):
+ y = _EmptyClassDel()
+ else:
+ y = _EmptyClass()
+ y.__class__ = x.__class__
+ memo[id(x)] = y
+ if hasattr(x, '__getstate__'):
+ state = x.__getstate__()
+ _keep_alive(state, memo)
+ else:
+ state = x.__dict__
+ state = deepcopy(state, memo)
+ if hasattr(y, '__setstate__'):
+ y.__setstate__(state)
+ else:
+ y.__dict__.update(state)
+ return y
+d[types.InstanceType] = _deepcopy_inst
+
+del d
+
+del types
+
+# Helper for instance creation without calling __init__
+class _EmptyClass:
+ pass
+
+# Helper for instance creation without calling __init__. Used when
+# the source class contains a __del__ attribute.
+class _EmptyClassDel:
+ def __del__(self):
+ pass
+
+def _test():
+ l = [None, 1, 2L, 3.14, 'xyzzy', (1, 2L), [3.14, 'abc'],
+ {'abc': 'ABC'}, (), [], {}]
+ l1 = copy(l)
+ print l1==l
+ l1 = map(copy, l)
+ print l1==l
+ l1 = deepcopy(l)
+ print l1==l
+ class C:
+ def __init__(self, arg=None):
+ self.a = 1
+ self.arg = arg
+ if __name__ == '__main__':
+ import sys
+ file = sys.argv[0]
+ else:
+ file = __file__
+ self.fp = open(file)
+ self.fp.close()
+ def __getstate__(self):
+ return {'a': self.a, 'arg': self.arg}
+ def __setstate__(self, state):
+ for key in state.keys():
+ setattr(self, key, state[key])
+ def __deepcopy__(self, memo = None):
+ new = self.__class__(deepcopy(self.arg, memo))
+ new.a = self.a
+ return new
+ c = C('argument sketch')
+ l.append(c)
+ l2 = copy(l)
+ print l == l2
+ print l
+ print l2
+ l2 = deepcopy(l)
+ print l == l2
+ print l
+ print l2
+ l.append({l[1]: l, 'xyz': l[2]})
+ l3 = copy(l)
+ import repr
+ print map(repr.repr, l)
+ print map(repr.repr, l1)
+ print map(repr.repr, l2)
+ print map(repr.repr, l3)
+ l3 = deepcopy(l)
+ import repr
+ print map(repr.repr, l)
+ print map(repr.repr, l1)
+ print map(repr.repr, l2)
+ print map(repr.repr, l3)
+
+if __name__ == '__main__':
+ _test()
diff --git a/lib/jython/Lib/copy_reg.py b/lib/jython/Lib/copy_reg.py new file mode 100644 index 000000000..78f1a2c98 --- /dev/null +++ b/lib/jython/Lib/copy_reg.py @@ -0,0 +1,35 @@ +"""Helper to provide extensibility for pickle/cPickle.
+
+This is only useful to add pickle support for extension types defined in
+C, not for instances of user-defined classes.
+"""
+
+from types import ClassType as _ClassType
+
+__all__ = ["pickle","constructor"]
+
+dispatch_table = {}
+safe_constructors = {}
+
+def pickle(ob_type, pickle_function, constructor_ob=None):
+ if type(ob_type) is _ClassType:
+ raise TypeError("copy_reg is not intended for use with classes")
+
+ if not callable(pickle_function):
+ raise TypeError("reduction functions must be callable")
+ dispatch_table[ob_type] = pickle_function
+
+ if constructor_ob is not None:
+ constructor(constructor_ob)
+
+def constructor(object):
+ if not callable(object):
+ raise TypeError("constructors must be callable")
+ safe_constructors[object] = 1
+
+# Example: provide pickling support for complex numbers.
+
+def pickle_complex(c):
+ return complex, (c.real, c.imag)
+
+pickle(type(1j), pickle_complex, complex)
diff --git a/lib/jython/Lib/dbexts.py b/lib/jython/Lib/dbexts.py new file mode 100644 index 000000000..1496ea557 --- /dev/null +++ b/lib/jython/Lib/dbexts.py @@ -0,0 +1,690 @@ +# $Id: dbexts.py,v 1.4 2001/12/29 18:00:15 bzimmer Exp $
+
+"""
+This script provides platform independence by wrapping Python
+Database API 2.0 compatible drivers to allow seamless database
+usage across implementations.
+
+In order to use the C version, you need mxODBC and mxDateTime.
+In order to use the Java version, you need zxJDBC.
+
+>>> import dbexts
+>>> d = dbexts.dbexts() # use the default db
+>>> d.isql('select count(*) count from player')
+
+count
+-------
+13569.0
+
+1 row affected
+
+>>> r = d.raw('select count(*) count from player')
+>>> r
+([('count', 3, 17, None, 15, 0, 1)], [(13569.0,)])
+>>>
+
+The configuration file follows the following format in a file name dbexts.ini:
+
+[default]
+name=mysql
+
+[jdbc]
+name=mysql
+url=jdbc:mysql://localhost/ziclix
+user=
+pwd=
+driver=org.gjt.mm.mysql.Driver
+datahandler=com.ziclix.python.sql.handler.MySQLDataHandler
+
+[jdbc]
+name=pg
+url=jdbc:postgresql://localhost:5432/ziclix
+user=bzimmer
+pwd=
+driver=org.postgresql.Driver
+datahandler=com.ziclix.python.sql.handler.PostgresqlDataHandler
+"""
+
+import os, string, re
+
+__author__ = "brian zimmer (bzimmer@ziclix.com)"
+__version__ = "$Revision: 1.4 $"[11:-2]
+
+__OS__ = os.name
+
+choose = lambda bool, a, b: (bool and [a] or [b])[0]
+
+def console(rows, headers=()):
+ """Format the results into a list of strings (one for each row):
+
+ <header>
+ <headersep>
+ <row1>
+ <row2>
+ ...
+
+ headers may be given as list of strings.
+
+ Columns are separated by colsep; the header is separated from
+ the result set by a line of headersep characters.
+
+ The function calls stringify to format the value data into a string.
+ It defaults to calling str() and striping leading and trailing whitespace.
+
+ - copied and modified from mxODBC
+ """
+
+ # Check row entry lengths
+ output = []
+ headers = map(string.upper, list(map(lambda x: x or "", headers)))
+ collen = map(len,headers)
+ output.append(headers)
+ if rows and len(rows) > 0:
+ for row in rows:
+ row = map(lambda x: str(x), row)
+ for i in range(len(row)):
+ entry = row[i]
+ if collen[i] < len(entry):
+ collen[i] = len(entry)
+ output.append(row)
+ if len(output) == 1:
+ affected = "0 rows affected"
+ elif len(output) == 2:
+ affected = "1 row affected"
+ else:
+ affected = "%d rows affected" % (len(output) - 1)
+
+ # Format output
+ for i in range(len(output)):
+ row = output[i]
+ l = []
+ for j in range(len(row)):
+ l.append('%-*s' % (collen[j],row[j]))
+ output[i] = string.join(l, " | ")
+
+ # Insert header separator
+ totallen = len(output[0])
+ output[1:1] = ["-"*(totallen/len("-"))]
+ output.append("\n" + affected)
+ return output
+
+def html(rows, headers=()):
+ output = []
+ output.append('<table class="results">')
+ output.append('<tr class="headers">')
+ headers = map(lambda x: '<td class="header">%s</td>' % (x.upper()), list(headers))
+ map(output.append, headers)
+ output.append('</tr>')
+ if rows and len(rows) > 0:
+ for row in rows:
+ output.append('<tr class="row">')
+ row = map(lambda x: '<td class="value">%s</td>' % (x), row)
+ map(output.append, row)
+ output.append('</tr>')
+ output.append('</table>')
+ return output
+
+comments = lambda x: re.compile("{.*?}", re.S).sub("", x, 0)
+
+class ex_proxy:
+ """Wraps mxODBC to provide proxy support for zxJDBC's additional parameters."""
+ def __init__(self, c):
+ self.c = c
+ def __getattr__(self, name):
+ if name == "execute":
+ return self.execute
+ elif name == "gettypeinfo":
+ return self.gettypeinfo
+ else:
+ return getattr(self.c, name)
+ def execute(self, sql, params=None, bindings=None, maxrows=None):
+ if params:
+ self.c.execute(sql, params)
+ else:
+ self.c.execute(sql)
+ def gettypeinfo(self, typeid=None):
+ if typeid:
+ self.c.gettypeinfo(typeid)
+
+class executor:
+ """Handles the insertion of values given dynamic data."""
+ def __init__(self, table, cols):
+ self.cols = cols
+ self.table = table
+ if self.cols:
+ self.sql = "insert into %s (%s) values (%s)" % (table, ",".join(self.cols), ",".join(("?",) * len(self.cols)))
+ else:
+ self.sql = "insert into %s values (%%s)" % (table)
+ def execute(self, db, rows, bindings):
+ assert rows and len(rows) > 0, "must have at least one row"
+ if self.cols:
+ sql = self.sql
+ else:
+ sql = self.sql % (",".join(("?",) * len(rows[0])))
+ db.raw(sql, rows, bindings)
+
+def connect(dbname):
+ return dbexts(dbname)
+
+def lookup(dbname):
+ return dbexts(jndiname=dbname)
+
+class dbexts:
+ def __init__(self, dbname=None, cfg=None, formatter=console, autocommit=1, jndiname=None, out=None):
+ self.verbose = 1
+ self.results = None
+ self.headers = None
+ self.datahandler = None
+ self.autocommit = autocommit
+ self.formatter = formatter
+ self.out = out
+ self.lastrowid = None
+ self.updatecount = None
+
+ if not jndiname:
+ if cfg == None:
+ fn = os.path.join(os.path.split(__file__)[0], "dbexts.ini")
+ if not os.path.exists(fn):
+ fn = os.path.join(os.environ['HOME'], ".dbexts")
+ self.dbs = IniParser(fn)
+ elif isinstance(cfg, IniParser):
+ self.dbs = cfg
+ else:
+ self.dbs = IniParser(cfg)
+ if dbname == None: dbname = self.dbs[("default", "name")]
+
+ if __OS__ == 'java':
+
+ from com.ziclix.python.sql import zxJDBC
+ database = zxJDBC
+ if not jndiname:
+ t = self.dbs[("jdbc", dbname)]
+ self.dburl, dbuser, dbpwd, jdbcdriver = t['url'], t['user'], t['pwd'], t['driver']
+ if t.has_key("datahandler"):
+ try:
+ datahandlerclass = string.split(t['datahandler'], ".")[-1]
+ self.datahandler = __import__(t['datahandler'], globals(), locals(), datahandlerclass)
+ except:
+ pass
+ keys = filter(lambda x: x not in ['url', 'user', 'pwd', 'driver', 'datahandler', 'name'], t.keys())
+ props = {}
+ for a in keys:
+ props[a] = t[a]
+ self.db = apply(database.connect, (self.dburl, dbuser, dbpwd, jdbcdriver), props)
+ else:
+ self.db = database.lookup(jndiname)
+ self.db.autocommit = 0
+
+ elif __OS__ == 'nt':
+
+ for modname in ["mx.ODBC.Windows", "ODBC.Windows"]:
+ try:
+ database = __import__(modname, globals(), locals(), "Windows")
+ break
+ except:
+ continue
+ else:
+ raise ImportError("unable to find appropriate mxODBC module")
+
+ t = self.dbs[("odbc", dbname)]
+ self.dburl, dbuser, dbpwd = t['url'], t['user'], t['pwd']
+ self.db = database.Connect(self.dburl, dbuser, dbpwd, clear_auto_commit=1)
+
+ for a in database.sqltype.keys():
+ setattr(self, database.sqltype[a], a)
+ del database
+
+ def __str__(self):
+ return self.dburl
+
+ def __repr__(self):
+ return self.dburl
+
+ def __getattr__(self, name):
+ if "cfg" == name:
+ return self.dbs.cfg
+
+ def close(self):
+ """ close the connection to the database """
+ self.db.close()
+
+ def begin(self):
+ """ reset ivars and return a new cursor, possibly binding an auxiliary datahandler """
+ self.headers, self.results = None, None
+ c = self.db.cursor()
+ if __OS__ == 'java':
+ if self.datahandler: c.datahandler = self.datahandler(c.datahandler)
+ else:
+ c = ex_proxy(c)
+ return c
+
+ def commit(self, cursor=None):
+ """ commit the cursor and create the result set """
+ if cursor and cursor.description:
+ self.headers = cursor.description
+ self.results = cursor.fetchall()
+ if hasattr(cursor, "nextset"):
+ s = cursor.nextset()
+ while s:
+ f = cursor.fetchall()
+ if f: self.results = choose(self.results is None, [], self.results) + f
+ s = cursor.nextset()
+ if hasattr(cursor, "lastrowid"): self.lastrowid = cursor.lastrowid
+ if hasattr(cursor, "updatecount"): self.updatecount = cursor.updatecount
+ if self.autocommit or cursor is None: self.db.commit()
+ if cursor: cursor.close()
+
+ def rollback(self):
+ """ rollback the cursor """
+ self.db.rollback()
+
+ def display(self):
+ """ using the formatter, display the results """
+ if self.formatter and self.verbose > 0:
+ res = self.results
+ if res:
+ print >> self.out, ""
+ for a in self.formatter(res, map(lambda x: x[0], self.headers)):
+ print >> self.out, a
+ print >> self.out, ""
+
+ def __execute__(self, sql, params=None, bindings=None, maxrows=None):
+ """ the primary execution method """
+ cur = self.begin()
+ try:
+ if bindings:
+ cur.execute(sql, params, bindings, maxrows=maxrows)
+ elif params:
+ cur.execute(sql, params, maxrows=maxrows)
+ else:
+ cur.execute(sql, maxrows=maxrows)
+ finally:
+ self.commit(cur)
+
+ def isql(self, sql, params=None, bindings=None, maxrows=None):
+ """ execute and display the sql """
+ self.raw(sql, params, bindings, maxrows=maxrows)
+ self.display()
+
+ def raw(self, sql, params=None, bindings=None, delim=None, comments=comments, maxrows=None):
+ """ execute the sql and return a tuple of (headers, results) """
+ if delim:
+ headers = []
+ results = []
+ if comments: sql = comments(sql)
+ statements = filter(lambda x: len(x) > 0, map(string.strip, string.split(sql, delim)))
+ for a in statements:
+ self.__execute__(a, params, bindings, maxrows=maxrows)
+ headers.append(self.headers)
+ results.append(self.results)
+ self.headers = headers
+ self.results = results
+ else:
+ self.__execute__(sql, params, bindings, maxrows=maxrows)
+ return (self.headers, self.results)
+
+ def callproc(self, procname, params=None, bindings=None, maxrows=None):
+ """ execute a stored procedure """
+ cur = self.begin()
+ try:
+ cur.callproc(procname, params=params, bindings=bindings, maxrows=maxrows)
+ finally:
+ self.commit(cur)
+ self.display()
+
+ def pk(self, table, owner=None, schema=None):
+ """ display the table's primary keys """
+ cur = self.begin()
+ cur.primarykeys(schema, owner, table)
+ self.commit(cur)
+ self.display()
+
+ def fk(self, primary_table=None, foreign_table=None, owner=None, schema=None):
+ """ display the table's foreign keys """
+ cur = self.begin()
+ if primary_table and foreign_table:
+ cur.foreignkeys(schema, owner, primary_table, schema, owner, foreign_table)
+ elif primary_table:
+ cur.foreignkeys(schema, owner, primary_table, schema, owner, None)
+ elif foreign_table:
+ cur.foreignkeys(schema, owner, None, schema, owner, foreign_table)
+ self.commit(cur)
+ self.display()
+
+ def table(self, table=None, types=("TABLE",), owner=None, schema=None):
+ """If no table argument, displays a list of all tables. If a table argument,
+ displays the columns of the given table."""
+ cur = self.begin()
+ if table:
+ cur.columns(schema, owner, table, None)
+ else:
+ cur.tables(schema, owner, None, types)
+ self.commit(cur)
+ self.display()
+
+ def proc(self, proc=None, owner=None, schema=None):
+ """If no proc argument, displays a list of all procedures. If a proc argument,
+ displays the parameters of the given procedure."""
+ cur = self.begin()
+ if proc:
+ cur.procedurecolumns(schema, owner, proc, None)
+ else:
+ cur.procedures(schema, owner, None)
+ self.commit(cur)
+ self.display()
+
+ def stat(self, table, qualifier=None, owner=None, unique=0, accuracy=0):
+ """ display the table's indicies """
+ cur = self.begin()
+ cur.statistics(qualifier, owner, table, unique, accuracy)
+ self.commit(cur)
+ self.display()
+
+ def typeinfo(self, sqltype=None):
+ """ display the types available for the database """
+ cur = self.begin()
+ cur.gettypeinfo(sqltype)
+ self.commit(cur)
+ self.display()
+
+ def tabletypeinfo(self):
+ """ display the table types available for the database """
+ cur = self.begin()
+ cur.gettabletypeinfo()
+ self.commit(cur)
+ self.display()
+
+ def schema(self, table, full=0, sort=1, owner=None):
+ """Displays a Schema object for the table. If full is true, then generates
+ references to the table in addition to the standard fields. If sort is true,
+ sort all the items in the schema, else leave them in db dependent order."""
+ print >> self.out, str(Schema(self, table, owner, full, sort))
+
+ def bulkcopy(self, dst, table, include=[], exclude=[], autobatch=0, executor=executor):
+ """Returns a Bulkcopy object using the given table."""
+ if type(dst) == type(""):
+ dst = dbexts(dst, cfg=self.dbs)
+ bcp = Bulkcopy(dst, table, include=include, exclude=exclude, autobatch=autobatch, executor=executor)
+ return bcp
+
+ def bcp(self, src, table, where='(1=1)', params=[], include=[], exclude=[], autobatch=0, executor=executor):
+ """Bulkcopy of rows from a src database to the current database for a given table and where clause."""
+ if type(src) == type(""):
+ src = dbexts(src, cfg=self.dbs)
+ bcp = self.bulkcopy(self, table, include, exclude, autobatch, executor)
+ num = bcp.transfer(src, where, params)
+ return num
+
+ def unload(self, filename, sql, delimiter=",", includeheaders=1):
+ """ Unloads the delimited results of the query to the file specified, optionally including headers. """
+ u = Unload(self, filename, delimiter, includeheaders)
+ u.unload(sql)
+
+class Bulkcopy:
+ """The idea for a bcp class came from http://object-craft.com.au/projects/sybase"""
+ def __init__(self, dst, table, include=[], exclude=[], autobatch=0, executor=executor):
+ self.dst = dst
+ self.table = table
+ self.total = 0
+ self.rows = []
+ self.autobatch = autobatch
+ self.bindings = {}
+
+ include = map(lambda x: string.lower(x), include)
+ exclude = map(lambda x: string.lower(x), exclude)
+
+ _verbose = self.dst.verbose
+ self.dst.verbose = 0
+ try:
+ self.dst.table(self.table)
+ if self.dst.results:
+ colmap = {}
+ for a in self.dst.results:
+ colmap[a[3].lower()] = a[4]
+ cols = self.__filter__(colmap.keys(), include, exclude)
+ for a in zip(range(len(cols)), cols):
+ self.bindings[a[0]] = colmap[a[1]]
+ colmap = None
+ else:
+ cols = self.__filter__(include, include, exclude)
+ finally:
+ self.dst.verbose = _verbose
+
+ self.executor = executor(table, cols)
+
+ def __str__(self):
+ return "[%s].[%s]" % (self.dst, self.table)
+
+ def __repr__(self):
+ return "[%s].[%s]" % (self.dst, self.table)
+
+ def __getattr__(self, name):
+ if name == 'columns':
+ return self.executor.cols
+
+ def __filter__(self, values, include, exclude):
+ cols = map(string.lower, values)
+ if exclude:
+ cols = filter(lambda x, ex=exclude: x not in ex, cols)
+ if include:
+ cols = filter(lambda x, inc=include: x in inc, cols)
+ return cols
+
+ def format(self, column, type):
+ self.bindings[column] = type
+
+ def done(self):
+ if len(self.rows) > 0:
+ return self.batch()
+ return 0
+
+ def batch(self):
+ self.executor.execute(self.dst, self.rows, self.bindings)
+ cnt = len(self.rows)
+ self.total += cnt
+ self.rows = []
+ return cnt
+
+ def rowxfer(self, line):
+ self.rows.append(line)
+ if self.autobatch: self.batch()
+
+ def transfer(self, src, where="(1=1)", params=[]):
+ sql = "select %s from %s where %s" % (string.join(self.columns, ", "), self.table, where)
+ h, d = src.raw(sql, params)
+ if d:
+ map(self.rowxfer, d)
+ return self.done()
+ return 0
+
+class Unload:
+ """Unloads a sql statement to a file with optional formatting of each value."""
+ def __init__(self, db, filename, delimiter=",", includeheaders=1):
+ self.db = db
+ self.filename = filename
+ self.delimiter = delimiter
+ self.includeheaders = includeheaders
+ self.formatters = {}
+
+ def format(self, o):
+ if not o:
+ return ""
+ o = str(o)
+ if o.find(",") != -1:
+ o = "\"\"%s\"\"" % (o)
+ return o
+
+ def unload(self, sql, mode="w"):
+ headers, results = self.db.raw(sql)
+ w = open(self.filename, mode)
+ if self.includeheaders:
+ w.write("%s\n" % (string.join(map(lambda x: x[0], headers), self.delimiter)))
+ if results:
+ for a in results:
+ w.write("%s\n" % (string.join(map(self.format, a), self.delimiter)))
+ w.flush()
+ w.close()
+
+class Schema:
+ """Produces a Schema object which represents the database schema for a table"""
+ def __init__(self, db, table, owner=None, full=0, sort=1):
+ self.db = db
+ self.table = table
+ self.owner = owner
+ self.full = full
+ self.sort = sort
+ _verbose = self.db.verbose
+ self.db.verbose = 0
+ try:
+ if table: self.computeschema()
+ finally:
+ self.db.verbose = _verbose
+
+ def computeschema(self):
+ self.db.table(self.table, owner=self.owner)
+ self.columns = []
+ # (column name, type_name, size, nullable)
+ if self.db.results:
+ self.columns = map(lambda x: (x[3], x[5], x[6], x[10]), self.db.results)
+ if self.sort: self.columns.sort(lambda x, y: cmp(x[0], y[0]))
+
+ self.db.fk(None, self.table)
+ # (pk table name, pk column name, fk column name, fk name, pk name)
+ self.imported = []
+ if self.db.results:
+ self.imported = map(lambda x: (x[2], x[3], x[7], x[11], x[12]), self.db.results)
+ if self.sort: self.imported.sort(lambda x, y: cmp(x[2], y[2]))
+
+ self.exported = []
+ if self.full:
+ self.db.fk(self.table, None)
+ # (pk column name, fk table name, fk column name, fk name, pk name)
+ if self.db.results:
+ self.exported = map(lambda x: (x[3], x[6], x[7], x[11], x[12]), self.db.results)
+ if self.sort: self.exported.sort(lambda x, y: cmp(x[1], y[1]))
+
+ self.db.pk(self.table)
+ self.primarykeys = []
+ if self.db.results:
+ # (column name, key_seq, pk name)
+ self.primarykeys = map(lambda x: (x[3], x[4], x[5]), self.db.results)
+ if self.sort: self.primarykeys.sort(lambda x, y: cmp(x[1], y[1]))
+
+ self.db.stat(self.table)
+ # (non-unique, name, type, pos, column name, asc)
+ self.indices = []
+ if self.db.results:
+ idxdict = {}
+ # mxODBC returns a row of None's, so filter it out
+ idx = map(lambda x: (x[3], string.strip(x[5]), x[6], x[7], x[8]), filter(lambda x: x[5], self.db.results))
+ def cckmp(x, y):
+ c = cmp(x[1], y[1])
+ if c == 0: c = cmp(x[3], y[3])
+ return c
+ # sort this regardless, this gets the indicies lined up
+ idx.sort(cckmp)
+ for a in idx:
+ if not idxdict.has_key(a[1]):
+ idxdict[a[1]] = []
+ idxdict[a[1]].append(a)
+ self.indices = idxdict.values()
+ if self.sort: self.indices.sort(lambda x, y: cmp(x[0][1], y[0][1]))
+
+ def __str__(self):
+ d = []
+ d.append("Table")
+ d.append(" " + self.table)
+ d.append("\nPrimary Keys")
+ for a in self.primarykeys:
+ d.append(" %s {%s}" % (a[0], a[2]))
+ d.append("\nImported (Foreign) Keys")
+ for a in self.imported:
+ d.append(" %s (%s.%s) {%s}" % (a[2], a[0], a[1], a[3]))
+ if self.full:
+ d.append("\nExported (Referenced) Keys")
+ for a in self.exported:
+ d.append(" %s (%s.%s) {%s}" % (a[0], a[1], a[2], a[3]))
+ d.append("\nColumns")
+ for a in self.columns:
+ nullable = choose(a[3], "nullable", "non-nullable")
+ d.append(" %-20s %s(%s), %s" % (a[0], a[1], a[2], nullable))
+ d.append("\nIndices")
+ for a in self.indices:
+ unique = choose(a[0][0], "non-unique", "unique")
+ cname = string.join(map(lambda x: x[4], a), ", ")
+ d.append(" %s index {%s} on (%s)" % (unique, a[0][1], cname))
+ return string.join(d, "\n")
+
+class IniParser:
+ def __init__(self, cfg, key='name'):
+ self.key = key
+ self.records = {}
+ self.ctypeRE = re.compile("\[(jdbc|odbc|default)\]")
+ self.entryRE = re.compile("([a-zA-Z]+)[ \t]*=[ \t]*(.*)")
+ self.cfg = cfg
+ self.parse()
+
+ def parse(self):
+ fp = open(self.cfg, "r")
+ data = fp.readlines()
+ fp.close()
+ lines = filter(lambda x: len(x) > 0 and x[0] not in ['#', ';'], map(string.strip, data))
+ current = None
+ for i in range(len(lines)):
+ line = lines[i]
+ g = self.ctypeRE.match(line)
+ if g: # a section header
+ current = {}
+ if not self.records.has_key(g.group(1)):
+ self.records[g.group(1)] = []
+ self.records[g.group(1)].append(current)
+ else:
+ g = self.entryRE.match(line)
+ if g:
+ current[g.group(1)] = g.group(2)
+
+ def __getitem__(self, (ctype, skey)):
+ if skey == self.key: return self.records[ctype][0][skey]
+ t = filter(lambda x, p=self.key, s=skey: x[p] == s, self.records[ctype])
+ if not t or len(t) > 1:
+ raise KeyError, "invalid key ('%s', '%s')" % (ctype, skey)
+ return t[0]
+
+def random_table_name(prefix, num_chars):
+ import random
+ d = [prefix, '_']
+ i = 0
+ while i < num_chars:
+ d.append(chr(int(100 * random.random()) % 26 + ord('A')))
+ i += 1
+ return string.join(d, "")
+
+class ResultSetRow:
+ def __init__(self, rs, row):
+ self.row = row
+ self.rs = rs
+ def __getitem__(self, i):
+ if type(i) == type(""):
+ i = self.rs.index(i)
+ return self.row[i]
+ def __getslice__(self, i, j):
+ if type(i) == type(""): i = self.rs.index(i)
+ if type(j) == type(""): j = self.rs.index(j)
+ return self.row[i:j]
+ def __len__(self):
+ return len(self.row)
+ def __repr__(self):
+ return str(self.row)
+
+class ResultSet:
+ def __init__(self, headers, results=[]):
+ self.headers = map(lambda x: x.upper(), headers)
+ self.results = results
+ def index(self, i):
+ return self.headers.index(string.upper(i))
+ def __getitem__(self, i):
+ return ResultSetRow(self, self.results[i])
+ def __getslice__(self, i, j):
+ return map(lambda x, rs=self: ResultSetRow(rs, x), self.results[i:j])
+ def __repr__(self):
+ return "<%s instance {cols [%d], rows [%d]} at %s>" % (self.__class__, len(self.headers), len(self.results), id(self))
diff --git a/lib/jython/Lib/difflib.py b/lib/jython/Lib/difflib.py new file mode 100644 index 000000000..505fea2ec --- /dev/null +++ b/lib/jython/Lib/difflib.py @@ -0,0 +1,781 @@ +#! /usr/bin/env python
+
+"""
+Module difflib -- helpers for computing deltas between objects.
+
+Function get_close_matches(word, possibilities, n=3, cutoff=0.6):
+
+ Use SequenceMatcher to return list of the best "good enough" matches.
+
+ word is a sequence for which close matches are desired (typically a
+ string).
+
+ possibilities is a list of sequences against which to match word
+ (typically a list of strings).
+
+ Optional arg n (default 3) is the maximum number of close matches to
+ return. n must be > 0.
+
+ Optional arg cutoff (default 0.6) is a float in [0, 1]. Possibilities
+ that don't score at least that similar to word are ignored.
+
+ The best (no more than n) matches among the possibilities are returned
+ in a list, sorted by similarity score, most similar first.
+
+ >>> get_close_matches("appel", ["ape", "apple", "peach", "puppy"])
+ ['apple', 'ape']
+ >>> import keyword
+ >>> get_close_matches("wheel", keyword.kwlist)
+ ['while']
+ >>> get_close_matches("apple", keyword.kwlist)
+ []
+ >>> get_close_matches("accept", keyword.kwlist)
+ ['except']
+
+Class SequenceMatcher
+
+SequenceMatcher is a flexible class for comparing pairs of sequences of any
+type, so long as the sequence elements are hashable. The basic algorithm
+predates, and is a little fancier than, an algorithm published in the late
+1980's by Ratcliff and Obershelp under the hyperbolic name "gestalt pattern
+matching". The basic idea is to find the longest contiguous matching
+subsequence that contains no "junk" elements (R-O doesn't address junk).
+The same idea is then applied recursively to the pieces of the sequences to
+the left and to the right of the matching subsequence. This does not yield
+minimal edit sequences, but does tend to yield matches that "look right"
+to people.
+
+Example, comparing two strings, and considering blanks to be "junk":
+
+>>> s = SequenceMatcher(lambda x: x == " ",
+... "private Thread currentThread;",
+... "private volatile Thread currentThread;")
+>>>
+
+.ratio() returns a float in [0, 1], measuring the "similarity" of the
+sequences. As a rule of thumb, a .ratio() value over 0.6 means the
+sequences are close matches:
+
+>>> print round(s.ratio(), 3)
+0.866
+>>>
+
+If you're only interested in where the sequences match,
+.get_matching_blocks() is handy:
+
+>>> for block in s.get_matching_blocks():
+... print "a[%d] and b[%d] match for %d elements" % block
+a[0] and b[0] match for 8 elements
+a[8] and b[17] match for 6 elements
+a[14] and b[23] match for 15 elements
+a[29] and b[38] match for 0 elements
+
+Note that the last tuple returned by .get_matching_blocks() is always a
+dummy, (len(a), len(b), 0), and this is the only case in which the last
+tuple element (number of elements matched) is 0.
+
+If you want to know how to change the first sequence into the second, use
+.get_opcodes():
+
+>>> for opcode in s.get_opcodes():
+... print "%6s a[%d:%d] b[%d:%d]" % opcode
+ equal a[0:8] b[0:8]
+insert a[8:8] b[8:17]
+ equal a[8:14] b[17:23]
+ equal a[14:29] b[23:38]
+
+See Tools/scripts/ndiff.py for a fancy human-friendly file differencer,
+which uses SequenceMatcher both to view files as sequences of lines, and
+lines as sequences of characters.
+
+See also function get_close_matches() in this module, which shows how
+simple code building on SequenceMatcher can be used to do useful work.
+
+Timing: Basic R-O is cubic time worst case and quadratic time expected
+case. SequenceMatcher is quadratic time for the worst case and has
+expected-case behavior dependent in a complicated way on how many
+elements the sequences have in common; best case time is linear.
+
+SequenceMatcher methods:
+
+__init__(isjunk=None, a='', b='')
+ Construct a SequenceMatcher.
+
+ Optional arg isjunk is None (the default), or a one-argument function
+ that takes a sequence element and returns true iff the element is junk.
+ None is equivalent to passing "lambda x: 0", i.e. no elements are
+ considered to be junk. For example, pass
+ lambda x: x in " \\t"
+ if you're comparing lines as sequences of characters, and don't want to
+ synch up on blanks or hard tabs.
+
+ Optional arg a is the first of two sequences to be compared. By
+ default, an empty string. The elements of a must be hashable.
+
+ Optional arg b is the second of two sequences to be compared. By
+ default, an empty string. The elements of b must be hashable.
+
+set_seqs(a, b)
+ Set the two sequences to be compared.
+
+ >>> s = SequenceMatcher()
+ >>> s.set_seqs("abcd", "bcde")
+ >>> s.ratio()
+ 0.75
+
+set_seq1(a)
+ Set the first sequence to be compared.
+
+ The second sequence to be compared is not changed.
+
+ >>> s = SequenceMatcher(None, "abcd", "bcde")
+ >>> s.ratio()
+ 0.75
+ >>> s.set_seq1("bcde")
+ >>> s.ratio()
+ 1.0
+ >>>
+
+ SequenceMatcher computes and caches detailed information about the
+ second sequence, so if you want to compare one sequence S against many
+ sequences, use .set_seq2(S) once and call .set_seq1(x) repeatedly for
+ each of the other sequences.
+
+ See also set_seqs() and set_seq2().
+
+set_seq2(b)
+ Set the second sequence to be compared.
+
+ The first sequence to be compared is not changed.
+
+ >>> s = SequenceMatcher(None, "abcd", "bcde")
+ >>> s.ratio()
+ 0.75
+ >>> s.set_seq2("abcd")
+ >>> s.ratio()
+ 1.0
+ >>>
+
+ SequenceMatcher computes and caches detailed information about the
+ second sequence, so if you want to compare one sequence S against many
+ sequences, use .set_seq2(S) once and call .set_seq1(x) repeatedly for
+ each of the other sequences.
+
+ See also set_seqs() and set_seq1().
+
+find_longest_match(alo, ahi, blo, bhi)
+ Find longest matching block in a[alo:ahi] and b[blo:bhi].
+
+ If isjunk is not defined:
+
+ Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where
+ alo <= i <= i+k <= ahi
+ blo <= j <= j+k <= bhi
+ and for all (i',j',k') meeting those conditions,
+ k >= k'
+ i <= i'
+ and if i == i', j <= j'
+
+ In other words, of all maximal matching blocks, return one that starts
+ earliest in a, and of all those maximal matching blocks that start
+ earliest in a, return the one that starts earliest in b.
+
+ >>> s = SequenceMatcher(None, " abcd", "abcd abcd")
+ >>> s.find_longest_match(0, 5, 0, 9)
+ (0, 4, 5)
+
+ If isjunk is defined, first the longest matching block is determined as
+ above, but with the additional restriction that no junk element appears
+ in the block. Then that block is extended as far as possible by
+ matching (only) junk elements on both sides. So the resulting block
+ never matches on junk except as identical junk happens to be adjacent
+ to an "interesting" match.
+
+ Here's the same example as before, but considering blanks to be junk.
+ That prevents " abcd" from matching the " abcd" at the tail end of the
+ second sequence directly. Instead only the "abcd" can match, and
+ matches the leftmost "abcd" in the second sequence:
+
+ >>> s = SequenceMatcher(lambda x: x==" ", " abcd", "abcd abcd")
+ >>> s.find_longest_match(0, 5, 0, 9)
+ (1, 0, 4)
+
+ If no blocks match, return (alo, blo, 0).
+
+ >>> s = SequenceMatcher(None, "ab", "c")
+ >>> s.find_longest_match(0, 2, 0, 1)
+ (0, 0, 0)
+
+get_matching_blocks()
+ Return list of triples describing matching subsequences.
+
+ Each triple is of the form (i, j, n), and means that
+ a[i:i+n] == b[j:j+n]. The triples are monotonically increasing in i
+ and in j.
+
+ The last triple is a dummy, (len(a), len(b), 0), and is the only triple
+ with n==0.
+
+ >>> s = SequenceMatcher(None, "abxcd", "abcd")
+ >>> s.get_matching_blocks()
+ [(0, 0, 2), (3, 2, 2), (5, 4, 0)]
+
+get_opcodes()
+ Return list of 5-tuples describing how to turn a into b.
+
+ Each tuple is of the form (tag, i1, i2, j1, j2). The first tuple has
+ i1 == j1 == 0, and remaining tuples have i1 == the i2 from the tuple
+ preceding it, and likewise for j1 == the previous j2.
+
+ The tags are strings, with these meanings:
+
+ 'replace': a[i1:i2] should be replaced by b[j1:j2]
+ 'delete': a[i1:i2] should be deleted.
+ Note that j1==j2 in this case.
+ 'insert': b[j1:j2] should be inserted at a[i1:i1].
+ Note that i1==i2 in this case.
+ 'equal': a[i1:i2] == b[j1:j2]
+
+ >>> a = "qabxcd"
+ >>> b = "abycdf"
+ >>> s = SequenceMatcher(None, a, b)
+ >>> for tag, i1, i2, j1, j2 in s.get_opcodes():
+ ... print ("%7s a[%d:%d] (%s) b[%d:%d] (%s)" %
+ ... (tag, i1, i2, a[i1:i2], j1, j2, b[j1:j2]))
+ delete a[0:1] (q) b[0:0] ()
+ equal a[1:3] (ab) b[0:2] (ab)
+ replace a[3:4] (x) b[2:3] (y)
+ equal a[4:6] (cd) b[3:5] (cd)
+ insert a[6:6] () b[5:6] (f)
+
+ratio()
+ Return a measure of the sequences' similarity (float in [0,1]).
+
+ Where T is the total number of elements in both sequences, and M is the
+ number of matches, this is 2,0*M / T. Note that this is 1 if the
+ sequences are identical, and 0 if they have nothing in common.
+
+ .ratio() is expensive to compute if you haven't already computed
+ .get_matching_blocks() or .get_opcodes(), in which case you may want to
+ try .quick_ratio() or .real_quick_ratio() first to get an upper bound.
+
+ >>> s = SequenceMatcher(None, "abcd", "bcde")
+ >>> s.ratio()
+ 0.75
+ >>> s.quick_ratio()
+ 0.75
+ >>> s.real_quick_ratio()
+ 1.0
+
+quick_ratio()
+ Return an upper bound on .ratio() relatively quickly.
+
+ This isn't defined beyond that it is an upper bound on .ratio(), and
+ is faster to compute.
+
+real_quick_ratio():
+ Return an upper bound on ratio() very quickly.
+
+ This isn't defined beyond that it is an upper bound on .ratio(), and
+ is faster to compute than either .ratio() or .quick_ratio().
+"""
+
+TRACE = 0
+
+class SequenceMatcher:
+ def __init__(self, isjunk=None, a='', b=''):
+ """Construct a SequenceMatcher.
+
+ Optional arg isjunk is None (the default), or a one-argument
+ function that takes a sequence element and returns true iff the
+ element is junk. None is equivalent to passing "lambda x: 0", i.e.
+ no elements are considered to be junk. For example, pass
+ lambda x: x in " \\t"
+ if you're comparing lines as sequences of characters, and don't
+ want to synch up on blanks or hard tabs.
+
+ Optional arg a is the first of two sequences to be compared. By
+ default, an empty string. The elements of a must be hashable. See
+ also .set_seqs() and .set_seq1().
+
+ Optional arg b is the second of two sequences to be compared. By
+ default, an empty string. The elements of b must be hashable. See
+ also .set_seqs() and .set_seq2().
+ """
+
+ # Members:
+ # a
+ # first sequence
+ # b
+ # second sequence; differences are computed as "what do
+ # we need to do to 'a' to change it into 'b'?"
+ # b2j
+ # for x in b, b2j[x] is a list of the indices (into b)
+ # at which x appears; junk elements do not appear
+ # b2jhas
+ # b2j.has_key
+ # fullbcount
+ # for x in b, fullbcount[x] == the number of times x
+ # appears in b; only materialized if really needed (used
+ # only for computing quick_ratio())
+ # matching_blocks
+ # a list of (i, j, k) triples, where a[i:i+k] == b[j:j+k];
+ # ascending & non-overlapping in i and in j; terminated by
+ # a dummy (len(a), len(b), 0) sentinel
+ # opcodes
+ # a list of (tag, i1, i2, j1, j2) tuples, where tag is
+ # one of
+ # 'replace' a[i1:i2] should be replaced by b[j1:j2]
+ # 'delete' a[i1:i2] should be deleted
+ # 'insert' b[j1:j2] should be inserted
+ # 'equal' a[i1:i2] == b[j1:j2]
+ # isjunk
+ # a user-supplied function taking a sequence element and
+ # returning true iff the element is "junk" -- this has
+ # subtle but helpful effects on the algorithm, which I'll
+ # get around to writing up someday <0.9 wink>.
+ # DON'T USE! Only __chain_b uses this. Use isbjunk.
+ # isbjunk
+ # for x in b, isbjunk(x) == isjunk(x) but much faster;
+ # it's really the has_key method of a hidden dict.
+ # DOES NOT WORK for x in a!
+
+ self.isjunk = isjunk
+ self.a = self.b = None
+ self.set_seqs(a, b)
+
+ def set_seqs(self, a, b):
+ """Set the two sequences to be compared.
+
+ >>> s = SequenceMatcher()
+ >>> s.set_seqs("abcd", "bcde")
+ >>> s.ratio()
+ 0.75
+ """
+
+ self.set_seq1(a)
+ self.set_seq2(b)
+
+ def set_seq1(self, a):
+ """Set the first sequence to be compared.
+
+ The second sequence to be compared is not changed.
+
+ >>> s = SequenceMatcher(None, "abcd", "bcde")
+ >>> s.ratio()
+ 0.75
+ >>> s.set_seq1("bcde")
+ >>> s.ratio()
+ 1.0
+ >>>
+
+ SequenceMatcher computes and caches detailed information about the
+ second sequence, so if you want to compare one sequence S against
+ many sequences, use .set_seq2(S) once and call .set_seq1(x)
+ repeatedly for each of the other sequences.
+
+ See also set_seqs() and set_seq2().
+ """
+
+ if a is self.a:
+ return
+ self.a = a
+ self.matching_blocks = self.opcodes = None
+
+ def set_seq2(self, b):
+ """Set the second sequence to be compared.
+
+ The first sequence to be compared is not changed.
+
+ >>> s = SequenceMatcher(None, "abcd", "bcde")
+ >>> s.ratio()
+ 0.75
+ >>> s.set_seq2("abcd")
+ >>> s.ratio()
+ 1.0
+ >>>
+
+ SequenceMatcher computes and caches detailed information about the
+ second sequence, so if you want to compare one sequence S against
+ many sequences, use .set_seq2(S) once and call .set_seq1(x)
+ repeatedly for each of the other sequences.
+
+ See also set_seqs() and set_seq1().
+ """
+
+ if b is self.b:
+ return
+ self.b = b
+ self.matching_blocks = self.opcodes = None
+ self.fullbcount = None
+ self.__chain_b()
+
+ # For each element x in b, set b2j[x] to a list of the indices in
+ # b where x appears; the indices are in increasing order; note that
+ # the number of times x appears in b is len(b2j[x]) ...
+ # when self.isjunk is defined, junk elements don't show up in this
+ # map at all, which stops the central find_longest_match method
+ # from starting any matching block at a junk element ...
+ # also creates the fast isbjunk function ...
+ # note that this is only called when b changes; so for cross-product
+ # kinds of matches, it's best to call set_seq2 once, then set_seq1
+ # repeatedly
+
+ def __chain_b(self):
+ # Because isjunk is a user-defined (not C) function, and we test
+ # for junk a LOT, it's important to minimize the number of calls.
+ # Before the tricks described here, __chain_b was by far the most
+ # time-consuming routine in the whole module! If anyone sees
+ # Jim Roskind, thank him again for profile.py -- I never would
+ # have guessed that.
+ # The first trick is to build b2j ignoring the possibility
+ # of junk. I.e., we don't call isjunk at all yet. Throwing
+ # out the junk later is much cheaper than building b2j "right"
+ # from the start.
+ b = self.b
+ self.b2j = b2j = {}
+ self.b2jhas = b2jhas = b2j.has_key
+ for i in xrange(len(b)):
+ elt = b[i]
+ if b2jhas(elt):
+ b2j[elt].append(i)
+ else:
+ b2j[elt] = [i]
+
+ # Now b2j.keys() contains elements uniquely, and especially when
+ # the sequence is a string, that's usually a good deal smaller
+ # than len(string). The difference is the number of isjunk calls
+ # saved.
+ isjunk, junkdict = self.isjunk, {}
+ if isjunk:
+ for elt in b2j.keys():
+ if isjunk(elt):
+ junkdict[elt] = 1 # value irrelevant; it's a set
+ del b2j[elt]
+
+ # Now for x in b, isjunk(x) == junkdict.has_key(x), but the
+ # latter is much faster. Note too that while there may be a
+ # lot of junk in the sequence, the number of *unique* junk
+ # elements is probably small. So the memory burden of keeping
+ # this dict alive is likely trivial compared to the size of b2j.
+ self.isbjunk = junkdict.has_key
+
+ def find_longest_match(self, alo, ahi, blo, bhi):
+ """Find longest matching block in a[alo:ahi] and b[blo:bhi].
+
+ If isjunk is not defined:
+
+ Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where
+ alo <= i <= i+k <= ahi
+ blo <= j <= j+k <= bhi
+ and for all (i',j',k') meeting those conditions,
+ k >= k'
+ i <= i'
+ and if i == i', j <= j'
+
+ In other words, of all maximal matching blocks, return one that
+ starts earliest in a, and of all those maximal matching blocks that
+ start earliest in a, return the one that starts earliest in b.
+
+ >>> s = SequenceMatcher(None, " abcd", "abcd abcd")
+ >>> s.find_longest_match(0, 5, 0, 9)
+ (0, 4, 5)
+
+ If isjunk is defined, first the longest matching block is
+ determined as above, but with the additional restriction that no
+ junk element appears in the block. Then that block is extended as
+ far as possible by matching (only) junk elements on both sides. So
+ the resulting block never matches on junk except as identical junk
+ happens to be adjacent to an "interesting" match.
+
+ Here's the same example as before, but considering blanks to be
+ junk. That prevents " abcd" from matching the " abcd" at the tail
+ end of the second sequence directly. Instead only the "abcd" can
+ match, and matches the leftmost "abcd" in the second sequence:
+
+ >>> s = SequenceMatcher(lambda x: x==" ", " abcd", "abcd abcd")
+ >>> s.find_longest_match(0, 5, 0, 9)
+ (1, 0, 4)
+
+ If no blocks match, return (alo, blo, 0).
+
+ >>> s = SequenceMatcher(None, "ab", "c")
+ >>> s.find_longest_match(0, 2, 0, 1)
+ (0, 0, 0)
+ """
+
+ # CAUTION: stripping common prefix or suffix would be incorrect.
+ # E.g.,
+ # ab
+ # acab
+ # Longest matching block is "ab", but if common prefix is
+ # stripped, it's "a" (tied with "b"). UNIX(tm) diff does so
+ # strip, so ends up claiming that ab is changed to acab by
+ # inserting "ca" in the middle. That's minimal but unintuitive:
+ # "it's obvious" that someone inserted "ac" at the front.
+ # Windiff ends up at the same place as diff, but by pairing up
+ # the unique 'b's and then matching the first two 'a's.
+
+ a, b, b2j, isbjunk = self.a, self.b, self.b2j, self.isbjunk
+ besti, bestj, bestsize = alo, blo, 0
+ # find longest junk-free match
+ # during an iteration of the loop, j2len[j] = length of longest
+ # junk-free match ending with a[i-1] and b[j]
+ j2len = {}
+ nothing = []
+ for i in xrange(alo, ahi):
+ # look at all instances of a[i] in b; note that because
+ # b2j has no junk keys, the loop is skipped if a[i] is junk
+ j2lenget = j2len.get
+ newj2len = {}
+ for j in b2j.get(a[i], nothing):
+ # a[i] matches b[j]
+ if j < blo:
+ continue
+ if j >= bhi:
+ break
+ k = newj2len[j] = j2lenget(j-1, 0) + 1
+ if k > bestsize:
+ besti, bestj, bestsize = i-k+1, j-k+1, k
+ j2len = newj2len
+
+ # Now that we have a wholly interesting match (albeit possibly
+ # empty!), we may as well suck up the matching junk on each
+ # side of it too. Can't think of a good reason not to, and it
+ # saves post-processing the (possibly considerable) expense of
+ # figuring out what to do with it. In the case of an empty
+ # interesting match, this is clearly the right thing to do,
+ # because no other kind of match is possible in the regions.
+ while besti > alo and bestj > blo and \
+ isbjunk(b[bestj-1]) and \
+ a[besti-1] == b[bestj-1]:
+ besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
+ while besti+bestsize < ahi and bestj+bestsize < bhi and \
+ isbjunk(b[bestj+bestsize]) and \
+ a[besti+bestsize] == b[bestj+bestsize]:
+ bestsize = bestsize + 1
+
+ if TRACE:
+ print "get_matching_blocks", alo, ahi, blo, bhi
+ print " returns", besti, bestj, bestsize
+ return besti, bestj, bestsize
+
+ def get_matching_blocks(self):
+ """Return list of triples describing matching subsequences.
+
+ Each triple is of the form (i, j, n), and means that
+ a[i:i+n] == b[j:j+n]. The triples are monotonically increasing in
+ i and in j.
+
+ The last triple is a dummy, (len(a), len(b), 0), and is the only
+ triple with n==0.
+
+ >>> s = SequenceMatcher(None, "abxcd", "abcd")
+ >>> s.get_matching_blocks()
+ [(0, 0, 2), (3, 2, 2), (5, 4, 0)]
+ """
+
+ if self.matching_blocks is not None:
+ return self.matching_blocks
+ self.matching_blocks = []
+ la, lb = len(self.a), len(self.b)
+ self.__helper(0, la, 0, lb, self.matching_blocks)
+ self.matching_blocks.append( (la, lb, 0) )
+ if TRACE:
+ print '*** matching blocks', self.matching_blocks
+ return self.matching_blocks
+
+ # builds list of matching blocks covering a[alo:ahi] and
+ # b[blo:bhi], appending them in increasing order to answer
+
+ def __helper(self, alo, ahi, blo, bhi, answer):
+ i, j, k = x = self.find_longest_match(alo, ahi, blo, bhi)
+ # a[alo:i] vs b[blo:j] unknown
+ # a[i:i+k] same as b[j:j+k]
+ # a[i+k:ahi] vs b[j+k:bhi] unknown
+ if k:
+ if alo < i and blo < j:
+ self.__helper(alo, i, blo, j, answer)
+ answer.append(x)
+ if i+k < ahi and j+k < bhi:
+ self.__helper(i+k, ahi, j+k, bhi, answer)
+
+ def get_opcodes(self):
+ """Return list of 5-tuples describing how to turn a into b.
+
+ Each tuple is of the form (tag, i1, i2, j1, j2). The first tuple
+ has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the
+ tuple preceding it, and likewise for j1 == the previous j2.
+
+ The tags are strings, with these meanings:
+
+ 'replace': a[i1:i2] should be replaced by b[j1:j2]
+ 'delete': a[i1:i2] should be deleted.
+ Note that j1==j2 in this case.
+ 'insert': b[j1:j2] should be inserted at a[i1:i1].
+ Note that i1==i2 in this case.
+ 'equal': a[i1:i2] == b[j1:j2]
+
+ >>> a = "qabxcd"
+ >>> b = "abycdf"
+ >>> s = SequenceMatcher(None, a, b)
+ >>> for tag, i1, i2, j1, j2 in s.get_opcodes():
+ ... print ("%7s a[%d:%d] (%s) b[%d:%d] (%s)" %
+ ... (tag, i1, i2, a[i1:i2], j1, j2, b[j1:j2]))
+ delete a[0:1] (q) b[0:0] ()
+ equal a[1:3] (ab) b[0:2] (ab)
+ replace a[3:4] (x) b[2:3] (y)
+ equal a[4:6] (cd) b[3:5] (cd)
+ insert a[6:6] () b[5:6] (f)
+ """
+
+ if self.opcodes is not None:
+ return self.opcodes
+ i = j = 0
+ self.opcodes = answer = []
+ for ai, bj, size in self.get_matching_blocks():
+ # invariant: we've pumped out correct diffs to change
+ # a[:i] into b[:j], and the next matching block is
+ # a[ai:ai+size] == b[bj:bj+size]. So we need to pump
+ # out a diff to change a[i:ai] into b[j:bj], pump out
+ # the matching block, and move (i,j) beyond the match
+ tag = ''
+ if i < ai and j < bj:
+ tag = 'replace'
+ elif i < ai:
+ tag = 'delete'
+ elif j < bj:
+ tag = 'insert'
+ if tag:
+ answer.append( (tag, i, ai, j, bj) )
+ i, j = ai+size, bj+size
+ # the list of matching blocks is terminated by a
+ # sentinel with size 0
+ if size:
+ answer.append( ('equal', ai, i, bj, j) )
+ return answer
+
+ def ratio(self):
+ """Return a measure of the sequences' similarity (float in [0,1]).
+
+ Where T is the total number of elements in both sequences, and
+ M is the number of matches, this is 2,0*M / T.
+ Note that this is 1 if the sequences are identical, and 0 if
+ they have nothing in common.
+
+ .ratio() is expensive to compute if you haven't already computed
+ .get_matching_blocks() or .get_opcodes(), in which case you may
+ want to try .quick_ratio() or .real_quick_ratio() first to get an
+ upper bound.
+
+ >>> s = SequenceMatcher(None, "abcd", "bcde")
+ >>> s.ratio()
+ 0.75
+ >>> s.quick_ratio()
+ 0.75
+ >>> s.real_quick_ratio()
+ 1.0
+ """
+
+ matches = reduce(lambda sum, triple: sum + triple[-1],
+ self.get_matching_blocks(), 0)
+ return 2.0 * matches / (len(self.a) + len(self.b))
+
+ def quick_ratio(self):
+ """Return an upper bound on ratio() relatively quickly.
+
+ This isn't defined beyond that it is an upper bound on .ratio(), and
+ is faster to compute.
+ """
+
+ # viewing a and b as multisets, set matches to the cardinality
+ # of their intersection; this counts the number of matches
+ # without regard to order, so is clearly an upper bound
+ if self.fullbcount is None:
+ self.fullbcount = fullbcount = {}
+ for elt in self.b:
+ fullbcount[elt] = fullbcount.get(elt, 0) + 1
+ fullbcount = self.fullbcount
+ # avail[x] is the number of times x appears in 'b' less the
+ # number of times we've seen it in 'a' so far ... kinda
+ avail = {}
+ availhas, matches = avail.has_key, 0
+ for elt in self.a:
+ if availhas(elt):
+ numb = avail[elt]
+ else:
+ numb = fullbcount.get(elt, 0)
+ avail[elt] = numb - 1
+ if numb > 0:
+ matches = matches + 1
+ return 2.0 * matches / (len(self.a) + len(self.b))
+
+ def real_quick_ratio(self):
+ """Return an upper bound on ratio() very quickly.
+
+ This isn't defined beyond that it is an upper bound on .ratio(), and
+ is faster to compute than either .ratio() or .quick_ratio().
+ """
+
+ la, lb = len(self.a), len(self.b)
+ # can't have more matches than the number of elements in the
+ # shorter sequence
+ return 2.0 * min(la, lb) / (la + lb)
+
+def get_close_matches(word, possibilities, n=3, cutoff=0.6):
+ """Use SequenceMatcher to return list of the best "good enough" matches.
+
+ word is a sequence for which close matches are desired (typically a
+ string).
+
+ possibilities is a list of sequences against which to match word
+ (typically a list of strings).
+
+ Optional arg n (default 3) is the maximum number of close matches to
+ return. n must be > 0.
+
+ Optional arg cutoff (default 0.6) is a float in [0, 1]. Possibilities
+ that don't score at least that similar to word are ignored.
+
+ The best (no more than n) matches among the possibilities are returned
+ in a list, sorted by similarity score, most similar first.
+
+ >>> get_close_matches("appel", ["ape", "apple", "peach", "puppy"])
+ ['apple', 'ape']
+ >>> import keyword
+ >>> get_close_matches("wheel", keyword.kwlist)
+ ['while']
+ >>> get_close_matches("apple", keyword.kwlist)
+ []
+ >>> get_close_matches("accept", keyword.kwlist)
+ ['except']
+ """
+
+ if not n > 0:
+ raise ValueError("n must be > 0: " + `n`)
+ if not 0.0 <= cutoff <= 1.0:
+ raise ValueError("cutoff must be in [0.0, 1.0]: " + `cutoff`)
+ result = []
+ s = SequenceMatcher()
+ s.set_seq2(word)
+ for x in possibilities:
+ s.set_seq1(x)
+ if s.real_quick_ratio() >= cutoff and \
+ s.quick_ratio() >= cutoff and \
+ s.ratio() >= cutoff:
+ result.append((s.ratio(), x))
+ # Sort by score.
+ result.sort()
+ # Retain only the best n.
+ result = result[-n:]
+ # Move best-scorer to head of list.
+ result.reverse()
+ # Strip scores.
+ return [x for score, x in result]
+
+def _test():
+ import doctest, difflib
+ return doctest.testmod(difflib)
+
+if __name__ == "__main__":
+ _test()
diff --git a/lib/jython/Lib/dircache.py b/lib/jython/Lib/dircache.py new file mode 100644 index 000000000..b95cb98a7 --- /dev/null +++ b/lib/jython/Lib/dircache.py @@ -0,0 +1,44 @@ +"""Read and cache directory listings.
+
+The listdir() routine returns a sorted list of the files in a directory,
+using a cache to avoid reading the directory more often than necessary.
+The annotate() routine appends slashes to directories."""
+
+import os
+
+__all__ = ["listdir", "opendir", "annotate", "reset"]
+
+cache = {}
+
+def reset():
+ """Reset the cache completely."""
+ global cache
+ cache = {}
+
+def listdir(path):
+ """List directory contents, using cache."""
+ try:
+ cached_mtime, list = cache[path]
+ del cache[path]
+ except KeyError:
+ cached_mtime, list = -1, []
+ try:
+ mtime = os.stat(path)[8]
+ except os.error:
+ return []
+ if mtime != cached_mtime:
+ try:
+ list = os.listdir(path)
+ except os.error:
+ return []
+ list.sort()
+ cache[path] = mtime, list
+ return list
+
+opendir = listdir # XXX backward compatibility
+
+def annotate(head, list):
+ """Add '/' suffixes to directories."""
+ for i in range(len(list)):
+ if os.path.isdir(os.path.join(head, list[i])):
+ list[i] = list[i] + '/'
diff --git a/lib/jython/Lib/doctest.py b/lib/jython/Lib/doctest.py new file mode 100644 index 000000000..d7a48b68f --- /dev/null +++ b/lib/jython/Lib/doctest.py @@ -0,0 +1,1118 @@ +# Module doctest version 0.9.7
+# Released to the public domain 16-Jan-2001,
+# by Tim Peters (tim.one@home.com).
+
+# Provided as-is; use at your own risk; no warranty; no promises; enjoy!
+
+"""Module doctest -- a framework for running examples in docstrings.
+
+NORMAL USAGE
+
+In normal use, end each module M with:
+
+def _test():
+ import doctest, M # replace M with your module's name
+ return doctest.testmod(M) # ditto
+
+if __name__ == "__main__":
+ _test()
+
+Then running the module as a script will cause the examples in the
+docstrings to get executed and verified:
+
+python M.py
+
+This won't display anything unless an example fails, in which case the
+failing example(s) and the cause(s) of the failure(s) are printed to stdout
+(why not stderr? because stderr is a lame hack <0.2 wink>), and the final
+line of output is "Test failed.".
+
+Run it with the -v switch instead:
+
+python M.py -v
+
+and a detailed report of all examples tried is printed to stdout, along
+with assorted summaries at the end.
+
+You can force verbose mode by passing "verbose=1" to testmod, or prohibit
+it by passing "verbose=0". In either of those cases, sys.argv is not
+examined by testmod.
+
+In any case, testmod returns a 2-tuple of ints (f, t), where f is the
+number of docstring examples that failed and t is the total number of
+docstring examples attempted.
+
+
+WHICH DOCSTRINGS ARE EXAMINED?
+
++ M.__doc__.
+
++ f.__doc__ for all functions f in M.__dict__.values(), except those
+ with private names.
+
++ C.__doc__ for all classes C in M.__dict__.values(), except those with
+ private names.
+
++ If M.__test__ exists and "is true", it must be a dict, and
+ each entry maps a (string) name to a function object, class object, or
+ string. Function and class object docstrings found from M.__test__
+ are searched even if the name is private, and strings are searched
+ directly as if they were docstrings. In output, a key K in M.__test__
+ appears with name
+ <name of M>.__test__.K
+
+Any classes found are recursively searched similarly, to test docstrings in
+their contained methods and nested classes. Private names reached from M's
+globals are skipped, but all names reached from M.__test__ are searched.
+
+By default, a name is considered to be private if it begins with an
+underscore (like "_my_func") but doesn't both begin and end with (at least)
+two underscores (like "__init__"). You can change the default by passing
+your own "isprivate" function to testmod.
+
+If you want to test docstrings in objects with private names too, stuff
+them into an M.__test__ dict, or see ADVANCED USAGE below (e.g., pass your
+own isprivate function to Tester's constructor, or call the rundoc method
+of a Tester instance).
+
+Warning: imports can cause trouble; e.g., if you do
+
+from XYZ import XYZclass
+
+then XYZclass is a name in M.__dict__ too, and doctest has no way to know
+that XYZclass wasn't *defined* in M. So it may try to execute the examples
+in XYZclass's docstring, and those in turn may require a different set of
+globals to work correctly. I prefer to do "import *"- friendly imports,
+a la
+
+import XYY
+_XYZclass = XYZ.XYZclass
+del XYZ
+
+or (Python 2.0)
+
+from XYZ import XYZclass as _XYZclass
+
+and then the leading underscore stops testmod from going nuts. You may
+prefer the method in the next section.
+
+
+WHAT'S THE EXECUTION CONTEXT?
+
+By default, each time testmod finds a docstring to test, it uses a *copy*
+of M's globals (so that running tests on a module doesn't change the
+module's real globals, and so that one test in M can't leave behind crumbs
+that accidentally allow another test to work). This means examples can
+freely use any names defined at top-level in M. It also means that sloppy
+imports (see above) can cause examples in external docstrings to use
+globals inappropriate for them.
+
+You can force use of your own dict as the execution context by passing
+"globs=your_dict" to testmod instead. Presumably this would be a copy of
+M.__dict__ merged with the globals from other imported modules.
+
+
+WHAT IF I WANT TO TEST A WHOLE PACKAGE?
+
+Piece o' cake, provided the modules do their testing from docstrings.
+Here's the test.py I use for the world's most elaborate Rational/
+floating-base-conversion pkg (which I'll distribute some day):
+
+from Rational import Cvt
+from Rational import Format
+from Rational import machprec
+from Rational import Rat
+from Rational import Round
+from Rational import utils
+
+modules = (Cvt,
+ Format,
+ machprec,
+ Rat,
+ Round,
+ utils)
+
+def _test():
+ import doctest
+ import sys
+ verbose = "-v" in sys.argv
+ for mod in modules:
+ doctest.testmod(mod, verbose=verbose, report=0)
+ doctest.master.summarize()
+
+if __name__ == "__main__":
+ _test()
+
+IOW, it just runs testmod on all the pkg modules. testmod remembers the
+names and outcomes (# of failures, # of tries) for each item it's seen, and
+passing "report=0" prevents it from printing a summary in verbose mode.
+Instead, the summary is delayed until all modules have been tested, and
+then "doctest.master.summarize()" forces the summary at the end.
+
+So this is very nice in practice: each module can be tested individually
+with almost no work beyond writing up docstring examples, and collections
+of modules can be tested too as a unit with no more work than the above.
+
+
+WHAT ABOUT EXCEPTIONS?
+
+No problem, as long as the only output generated by the example is the
+traceback itself. For example:
+
+ >>> [1, 2, 3].remove(42)
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in ?
+ ValueError: list.remove(x): x not in list
+ >>>
+
+Note that only the exception type and value are compared (specifically,
+only the last line in the traceback).
+
+
+ADVANCED USAGE
+
+doctest.testmod() captures the testing policy I find most useful most
+often. You may want other policies.
+
+testmod() actually creates a local instance of class doctest.Tester, runs
+appropriate methods of that class, and merges the results into global
+Tester instance doctest.master.
+
+You can create your own instances of doctest.Tester, and so build your own
+policies, or even run methods of doctest.master directly. See
+doctest.Tester.__doc__ for details.
+
+
+SO WHAT DOES A DOCSTRING EXAMPLE LOOK LIKE ALREADY!?
+
+Oh ya. It's easy! In most cases a copy-and-paste of an interactive
+console session works fine -- just make sure the leading whitespace is
+rigidly consistent (you can mix tabs and spaces if you're too lazy to do it
+right, but doctest is not in the business of guessing what you think a tab
+means).
+
+ >>> # comments are ignored
+ >>> x = 12
+ >>> x
+ 12
+ >>> if x == 13:
+ ... print "yes"
+ ... else:
+ ... print "no"
+ ... print "NO"
+ ... print "NO!!!"
+ ...
+ no
+ NO
+ NO!!!
+ >>>
+
+Any expected output must immediately follow the final ">>>" or "..." line
+containing the code, and the expected output (if any) extends to the next
+">>>" or all-whitespace line. That's it.
+
+Bummers:
+
++ Expected output cannot contain an all-whitespace line, since such a line
+ is taken to signal the end of expected output.
+
++ Output to stdout is captured, but not output to stderr (exception
+ tracebacks are captured via a different means).
+
++ If you continue a line via backslashing in an interactive session, or for
+ any other reason use a backslash, you need to double the backslash in the
+ docstring version. This is simply because you're in a string, and so the
+ backslash must be escaped for it to survive intact. Like:
+
+>>> if "yes" == \\
+... "y" + \\
+... "es": # in the source code you'll see the doubled backslashes
+... print 'yes'
+yes
+
+The starting column doesn't matter:
+
+>>> assert "Easy!"
+ >>> import math
+ >>> math.floor(1.9)
+ 1.0
+
+and as many leading whitespace characters are stripped from the expected
+output as appeared in the initial ">>>" line that triggered it.
+
+If you execute this very file, the examples above will be found and
+executed, leading to this output in verbose mode:
+
+Running doctest.__doc__
+Trying: [1, 2, 3].remove(42)
+Expecting:
+Traceback (most recent call last):
+ File "<stdin>", line 1, in ?
+ValueError: list.remove(x): x not in list
+ok
+Trying: x = 12
+Expecting: nothing
+ok
+Trying: x
+Expecting: 12
+ok
+Trying:
+if x == 13:
+ print "yes"
+else:
+ print "no"
+ print "NO"
+ print "NO!!!"
+Expecting:
+no
+NO
+NO!!!
+ok
+... and a bunch more like that, with this summary at the end:
+
+5 items had no tests:
+ doctest.Tester.__init__
+ doctest.Tester.run__test__
+ doctest.Tester.summarize
+ doctest.run_docstring_examples
+ doctest.testmod
+12 items passed all tests:
+ 8 tests in doctest
+ 6 tests in doctest.Tester
+ 10 tests in doctest.Tester.merge
+ 7 tests in doctest.Tester.rundict
+ 3 tests in doctest.Tester.rundoc
+ 3 tests in doctest.Tester.runstring
+ 2 tests in doctest.__test__._TestClass
+ 2 tests in doctest.__test__._TestClass.__init__
+ 2 tests in doctest.__test__._TestClass.get
+ 1 tests in doctest.__test__._TestClass.square
+ 2 tests in doctest.__test__.string
+ 7 tests in doctest.is_private
+53 tests in 17 items.
+53 passed and 0 failed.
+Test passed.
+"""
+
+# 0,0,1 06-Mar-1999
+# initial version posted
+# 0,0,2 06-Mar-1999
+# loosened parsing:
+# cater to stinkin' tabs
+# don't insist on a blank after PS2 prefix
+# so trailing "... " line from a compound stmt no longer
+# breaks if the file gets whitespace-trimmed
+# better error msgs for inconsistent leading whitespace
+# 0,9,1 08-Mar-1999
+# exposed the Tester class and added client methods
+# plus docstring examples of their use (eww - head-twisting!)
+# fixed logic error in reporting total # of tests & failures
+# added __test__ support to testmod (a pale reflection of Christian
+# Tismer's vision ...)
+# removed the "deep" argument; fiddle __test__ instead
+# simplified endcase logic for extracting tests, and running them.
+# before, if no output was expected but some was produced
+# anyway via an eval'ed result, the discrepancy wasn't caught
+# made TestClass private and used __test__ to get at it
+# many doc updates
+# speed _SpoofOut for long expected outputs
+# 0,9,2 09-Mar-1999
+# throw out comments from examples, enabling use of the much simpler
+# exec compile(... "single") ...
+# for simulating the runtime; that barfs on comment-only lines
+# used the traceback module to do a much better job of reporting
+# exceptions
+# run __doc__ values thru str(), "just in case"
+# privateness of names now determined by an overridable "isprivate"
+# function
+# by default a name now considered to be private iff it begins with
+# an underscore but doesn't both begin & end with two of 'em; so
+# e.g. Class.__init__ etc are searched now -- as they always
+# should have been
+# 0,9,3 18-Mar-1999
+# added .flush stub to _SpoofOut (JPython buglet diagnosed by
+# Hugh Emberson)
+# repaired ridiculous docs about backslashes in examples
+# minor internal changes
+# changed source to Unix line-end conventions
+# moved __test__ logic into new Tester.run__test__ method
+# 0,9,4 27-Mar-1999
+# report item name and line # in failing examples
+# 0,9,5 29-Jun-1999
+# allow straightforward exceptions in examples - thanks to Mark Hammond!
+# 0,9,6 16-Jan-2001
+# fiddling for changes in Python 2.0: some of the embedded docstring
+# examples no longer worked *exactly* as advertised, due to minor
+# language changes, and running doctest on itself pointed that out.
+# Hard to think of a better example of why this is useful <wink>.
+# 0,9,7 9-Feb-2001
+# string method conversion
+
+__version__ = 0, 9, 7
+
+import types
+_FunctionType = types.FunctionType
+_ClassType = types.ClassType
+_ModuleType = types.ModuleType
+_StringType = types.StringType
+del types
+
+import re
+PS1 = ">>>"
+PS2 = "..."
+_isPS1 = re.compile(r"(\s*)" + re.escape(PS1)).match
+_isPS2 = re.compile(r"(\s*)" + re.escape(PS2)).match
+_isEmpty = re.compile(r"\s*$").match
+_isComment = re.compile(r"\s*#").match
+del re
+
+__all__ = []
+
+# Extract interactive examples from a string. Return a list of triples,
+# (source, outcome, lineno). "source" is the source code, and ends
+# with a newline iff the source spans more than one line. "outcome" is
+# the expected output if any, else an empty string. When not empty,
+# outcome always ends with a newline. "lineno" is the line number,
+# 0-based wrt the start of the string, of the first source line.
+
+def _extract_examples(s):
+ isPS1, isPS2 = _isPS1, _isPS2
+ isEmpty, isComment = _isEmpty, _isComment
+ examples = []
+ lines = s.split("\n")
+ i, n = 0, len(lines)
+ while i < n:
+ line = lines[i]
+ i = i + 1
+ m = isPS1(line)
+ if m is None:
+ continue
+ j = m.end(0) # beyond the prompt
+ if isEmpty(line, j) or isComment(line, j):
+ # a bare prompt or comment -- not interesting
+ continue
+ lineno = i - 1
+ if line[j] != " ":
+ raise ValueError("line " + `lineno` + " of docstring lacks "
+ "blank after " + PS1 + ": " + line)
+ j = j + 1
+ blanks = m.group(1)
+ nblanks = len(blanks)
+ # suck up this and following PS2 lines
+ source = []
+ while 1:
+ source.append(line[j:])
+ line = lines[i]
+ m = isPS2(line)
+ if m:
+ if m.group(1) != blanks:
+ raise ValueError("inconsistent leading whitespace "
+ "in line " + `i` + " of docstring: " + line)
+ i = i + 1
+ else:
+ break
+ if len(source) == 1:
+ source = source[0]
+ else:
+ # get rid of useless null line from trailing empty "..."
+ if source[-1] == "":
+ del source[-1]
+ source = "\n".join(source) + "\n"
+ # suck up response
+ if isPS1(line) or isEmpty(line):
+ expect = ""
+ else:
+ expect = []
+ while 1:
+ if line[:nblanks] != blanks:
+ raise ValueError("inconsistent leading whitespace "
+ "in line " + `i` + " of docstring: " + line)
+ expect.append(line[nblanks:])
+ i = i + 1
+ line = lines[i]
+ if isPS1(line) or isEmpty(line):
+ break
+ expect = "\n".join(expect) + "\n"
+ examples.append( (source, expect, lineno) )
+ return examples
+
+# Capture stdout when running examples.
+
+class _SpoofOut:
+ def __init__(self):
+ self.clear()
+ def write(self, s):
+ self.buf.append(s)
+ def get(self):
+ guts = "".join(self.buf)
+ # If anything at all was written, make sure there's a trailing
+ # newline. There's no way for the expected output to indicate
+ # that a trailing newline is missing.
+ if guts and not guts.endswith("\n"):
+ guts = guts + "\n"
+ return guts
+ def clear(self):
+ self.buf = []
+ def flush(self):
+ # JPython calls flush
+ pass
+
+# Display some tag-and-msg pairs nicely, keeping the tag and its msg
+# on the same line when that makes sense.
+
+def _tag_out(printer, *tag_msg_pairs):
+ for tag, msg in tag_msg_pairs:
+ printer(tag + ":")
+ msg_has_nl = msg[-1:] == "\n"
+ msg_has_two_nl = msg_has_nl and \
+ msg.find("\n") < len(msg) - 1
+ if len(tag) + len(msg) < 76 and not msg_has_two_nl:
+ printer(" ")
+ else:
+ printer("\n")
+ printer(msg)
+ if not msg_has_nl:
+ printer("\n")
+
+# Run list of examples, in context globs. "out" can be used to display
+# stuff to "the real" stdout, and fakeout is an instance of _SpoofOut
+# that captures the examples' std output. Return (#failures, #tries).
+
+def _run_examples_inner(out, fakeout, examples, globs, verbose, name):
+ import sys, traceback
+ OK, BOOM, FAIL = range(3)
+ NADA = "nothing"
+ stderr = _SpoofOut()
+ failures = 0
+ for source, want, lineno in examples:
+ if verbose:
+ _tag_out(out, ("Trying", source),
+ ("Expecting", want or NADA))
+ fakeout.clear()
+ try:
+ exec compile(source, "<string>", "single") in globs
+ got = fakeout.get()
+ state = OK
+ except:
+ # See whether the exception was expected.
+ if want.find("Traceback (innermost last):\n") == 0 or \
+ want.find("Traceback (most recent call last):\n") == 0:
+ # Only compare exception type and value - the rest of
+ # the traceback isn't necessary.
+ want = want.split('\n')[-2] + '\n'
+ exc_type, exc_val = sys.exc_info()[:2]
+ got = traceback.format_exception_only(exc_type, exc_val)[0]
+ state = OK
+ else:
+ # unexpected exception
+ stderr.clear()
+ traceback.print_exc(file=stderr)
+ state = BOOM
+
+ if state == OK:
+ if got == want:
+ if verbose:
+ out("ok\n")
+ continue
+ state = FAIL
+
+ assert state in (FAIL, BOOM)
+ failures = failures + 1
+ out("*" * 65 + "\n")
+ _tag_out(out, ("Failure in example", source))
+ out("from line #" + `lineno` + " of " + name + "\n")
+ if state == FAIL:
+ _tag_out(out, ("Expected", want or NADA), ("Got", got))
+ else:
+ assert state == BOOM
+ _tag_out(out, ("Exception raised", stderr.get()))
+
+ return failures, len(examples)
+
+# Run list of examples, in context globs. Return (#failures, #tries).
+
+def _run_examples(examples, globs, verbose, name):
+ import sys
+ saveout = sys.stdout
+ try:
+ sys.stdout = fakeout = _SpoofOut()
+ x = _run_examples_inner(saveout.write, fakeout, examples,
+ globs, verbose, name)
+ finally:
+ sys.stdout = saveout
+ return x
+
+def run_docstring_examples(f, globs, verbose=0, name="NoName"):
+ """f, globs, verbose=0, name="NoName" -> run examples from f.__doc__.
+
+ Use dict globs as the globals for execution.
+ Return (#failures, #tries).
+
+ If optional arg verbose is true, print stuff even if there are no
+ failures.
+ Use string name in failure msgs.
+ """
+
+ try:
+ doc = f.__doc__
+ if not doc:
+ # docstring empty or None
+ return 0, 0
+ # just in case CT invents a doc object that has to be forced
+ # to look like a string <0.9 wink>
+ doc = str(doc)
+ except:
+ return 0, 0
+
+ e = _extract_examples(doc)
+ if not e:
+ return 0, 0
+ return _run_examples(e, globs, verbose, name)
+
+def is_private(prefix, base):
+ """prefix, base -> true iff name prefix + "." + base is "private".
+
+ Prefix may be an empty string, and base does not contain a period.
+ Prefix is ignored (although functions you write conforming to this
+ protocol may make use of it).
+ Return true iff base begins with an (at least one) underscore, but
+ does not both begin and end with (at least) two underscores.
+
+ >>> is_private("a.b", "my_func")
+ 0
+ >>> is_private("____", "_my_func")
+ 1
+ >>> is_private("someclass", "__init__")
+ 0
+ >>> is_private("sometypo", "__init_")
+ 1
+ >>> is_private("x.y.z", "_")
+ 1
+ >>> is_private("_x.y.z", "__")
+ 0
+ >>> is_private("", "") # senseless but consistent
+ 0
+ """
+
+ return base[:1] == "_" and not base[:2] == "__" == base[-2:]
+
+class Tester:
+ """Class Tester -- runs docstring examples and accumulates stats.
+
+In normal use, function doctest.testmod() hides all this from you,
+so use that if you can. Create your own instances of Tester to do
+fancier things.
+
+Methods:
+ runstring(s, name)
+ Search string s for examples to run; use name for logging.
+ Return (#failures, #tries).
+
+ rundoc(object, name=None)
+ Search object.__doc__ for examples to run; use name (or
+ object.__name__) for logging. Return (#failures, #tries).
+
+ rundict(d, name)
+ Search for examples in docstrings in all of d.values(); use name
+ for logging. Return (#failures, #tries).
+
+ run__test__(d, name)
+ Treat dict d like module.__test__. Return (#failures, #tries).
+
+ summarize(verbose=None)
+ Display summary of testing results, to stdout. Return
+ (#failures, #tries).
+
+ merge(other)
+ Merge in the test results from Tester instance "other".
+
+>>> from doctest import Tester
+>>> t = Tester(globs={'x': 42}, verbose=0)
+>>> t.runstring(r'''
+... >>> x = x * 2
+... >>> print x
+... 42
+... ''', 'XYZ')
+*****************************************************************
+Failure in example: print x
+from line #2 of XYZ
+Expected: 42
+Got: 84
+(1, 2)
+>>> t.runstring(">>> x = x * 2\\n>>> print x\\n84\\n", 'example2')
+(0, 2)
+>>> t.summarize()
+*****************************************************************
+1 items had failures:
+ 1 of 2 in XYZ
+***Test Failed*** 1 failures.
+(1, 4)
+>>> t.summarize(verbose=1)
+1 items passed all tests:
+ 2 tests in example2
+*****************************************************************
+1 items had failures:
+ 1 of 2 in XYZ
+4 tests in 2 items.
+3 passed and 1 failed.
+***Test Failed*** 1 failures.
+(1, 4)
+>>>
+"""
+
+ def __init__(self, mod=None, globs=None, verbose=None,
+ isprivate=None):
+ """mod=None, globs=None, verbose=None, isprivate=None
+
+See doctest.__doc__ for an overview.
+
+Optional keyword arg "mod" is a module, whose globals are used for
+executing examples. If not specified, globs must be specified.
+
+Optional keyword arg "globs" gives a dict to be used as the globals
+when executing examples; if not specified, use the globals from
+module mod.
+
+In either case, a copy of the dict is used for each docstring
+examined.
+
+Optional keyword arg "verbose" prints lots of stuff if true, only
+failures if false; by default, it's true iff "-v" is in sys.argv.
+
+Optional keyword arg "isprivate" specifies a function used to determine
+whether a name is private. The default function is doctest.is_private;
+see its docs for details.
+"""
+
+ if mod is None and globs is None:
+ raise TypeError("Tester.__init__: must specify mod or globs")
+ if mod is not None and type(mod) is not _ModuleType:
+ raise TypeError("Tester.__init__: mod must be a module; " +
+ `mod`)
+ if globs is None:
+ globs = mod.__dict__
+ self.globs = globs
+
+ if verbose is None:
+ import sys
+ verbose = "-v" in sys.argv
+ self.verbose = verbose
+
+ if isprivate is None:
+ isprivate = is_private
+ self.isprivate = isprivate
+
+ self.name2ft = {} # map name to (#failures, #trials) pair
+
+ def runstring(self, s, name):
+ """
+ s, name -> search string s for examples to run, logging as name.
+
+ Use string name as the key for logging the outcome.
+ Return (#failures, #examples).
+
+ >>> t = Tester(globs={}, verbose=1)
+ >>> test = r'''
+ ... # just an example
+ ... >>> x = 1 + 2
+ ... >>> x
+ ... 3
+ ... '''
+ >>> t.runstring(test, "Example")
+ Running string Example
+ Trying: x = 1 + 2
+ Expecting: nothing
+ ok
+ Trying: x
+ Expecting: 3
+ ok
+ 0 of 2 examples failed in string Example
+ (0, 2)
+ """
+
+ if self.verbose:
+ print "Running string", name
+ f = t = 0
+ e = _extract_examples(s)
+ if e:
+ f, t = _run_examples(e, self.globs.copy(), self.verbose, name)
+ if self.verbose:
+ print f, "of", t, "examples failed in string", name
+ self.__record_outcome(name, f, t)
+ return f, t
+
+ def rundoc(self, object, name=None):
+ """
+ object, name=None -> search object.__doc__ for examples to run.
+
+ Use optional string name as the key for logging the outcome;
+ by default use object.__name__.
+ Return (#failures, #examples).
+ If object is a class object, search recursively for method
+ docstrings too.
+ object.__doc__ is examined regardless of name, but if object is
+ a class, whether private names reached from object are searched
+ depends on the constructor's "isprivate" argument.
+
+ >>> t = Tester(globs={}, verbose=0)
+ >>> def _f():
+ ... '''Trivial docstring example.
+ ... >>> assert 2 == 2
+ ... '''
+ ... return 32
+ ...
+ >>> t.rundoc(_f) # expect 0 failures in 1 example
+ (0, 1)
+ """
+
+ if name is None:
+ try:
+ name = object.__name__
+ except AttributeError:
+ raise ValueError("Tester.rundoc: name must be given "
+ "when object.__name__ doesn't exist; " + `object`)
+ if self.verbose:
+ print "Running", name + ".__doc__"
+ f, t = run_docstring_examples(object, self.globs.copy(),
+ self.verbose, name)
+ if self.verbose:
+ print f, "of", t, "examples failed in", name + ".__doc__"
+ self.__record_outcome(name, f, t)
+ if type(object) is _ClassType:
+ f2, t2 = self.rundict(object.__dict__, name)
+ f = f + f2
+ t = t + t2
+ return f, t
+
+ def rundict(self, d, name):
+ """
+ d. name -> search for docstring examples in all of d.values().
+
+ For k, v in d.items() such that v is a function or class,
+ do self.rundoc(v, name + "." + k). Whether this includes
+ objects with private names depends on the constructor's
+ "isprivate" argument.
+ Return aggregate (#failures, #examples).
+
+ >>> def _f():
+ ... '''>>> assert 1 == 1
+ ... '''
+ >>> def g():
+ ... '''>>> assert 2 != 1
+ ... '''
+ >>> d = {"_f": _f, "g": g}
+ >>> t = Tester(globs={}, verbose=0)
+ >>> t.rundict(d, "rundict_test") # _f is skipped
+ (0, 1)
+ >>> t = Tester(globs={}, verbose=0, isprivate=lambda x,y: 0)
+ >>> t.rundict(d, "rundict_test_pvt") # both are searched
+ (0, 2)
+ """
+
+ if not hasattr(d, "items"):
+ raise TypeError("Tester.rundict: d must support .items(); " +
+ `d`)
+ f = t = 0
+ # Run the tests by alpha order of names, for consistency in
+ # verbose-mode output.
+ names = d.keys()
+ names.sort()
+ for thisname in names:
+ value = d[thisname]
+ if type(value) in (_FunctionType, _ClassType):
+ f2, t2 = self.__runone(value, name + "." + thisname)
+ f = f + f2
+ t = t + t2
+ return f, t
+
+ def run__test__(self, d, name):
+ """d, name -> Treat dict d like module.__test__.
+
+ Return (#failures, #tries).
+ See testmod.__doc__ for details.
+ """
+
+ failures = tries = 0
+ prefix = name + "."
+ savepvt = self.isprivate
+ try:
+ self.isprivate = lambda *args: 0
+ # Run the tests by alpha order of names, for consistency in
+ # verbose-mode output.
+ keys = d.keys()
+ keys.sort()
+ for k in keys:
+ v = d[k]
+ thisname = prefix + k
+ if type(v) is _StringType:
+ f, t = self.runstring(v, thisname)
+ elif type(v) in (_FunctionType, _ClassType):
+ f, t = self.rundoc(v, thisname)
+ else:
+ raise TypeError("Tester.run__test__: values in "
+ "dict must be strings, functions "
+ "or classes; " + `v`)
+ failures = failures + f
+ tries = tries + t
+ finally:
+ self.isprivate = savepvt
+ return failures, tries
+
+ def summarize(self, verbose=None):
+ """
+ verbose=None -> summarize results, return (#failures, #tests).
+
+ Print summary of test results to stdout.
+ Optional arg 'verbose' controls how wordy this is. By
+ default, use the verbose setting established by the
+ constructor.
+ """
+
+ if verbose is None:
+ verbose = self.verbose
+ notests = []
+ passed = []
+ failed = []
+ totalt = totalf = 0
+ for x in self.name2ft.items():
+ name, (f, t) = x
+ assert f <= t
+ totalt = totalt + t
+ totalf = totalf + f
+ if t == 0:
+ notests.append(name)
+ elif f == 0:
+ passed.append( (name, t) )
+ else:
+ failed.append(x)
+ if verbose:
+ if notests:
+ print len(notests), "items had no tests:"
+ notests.sort()
+ for thing in notests:
+ print " ", thing
+ if passed:
+ print len(passed), "items passed all tests:"
+ passed.sort()
+ for thing, count in passed:
+ print " %3d tests in %s" % (count, thing)
+ if failed:
+ print "*" * 65
+ print len(failed), "items had failures:"
+ failed.sort()
+ for thing, (f, t) in failed:
+ print " %3d of %3d in %s" % (f, t, thing)
+ if verbose:
+ print totalt, "tests in", len(self.name2ft), "items."
+ print totalt - totalf, "passed and", totalf, "failed."
+ if totalf:
+ print "***Test Failed***", totalf, "failures."
+ elif verbose:
+ print "Test passed."
+ return totalf, totalt
+
+ def merge(self, other):
+ """
+ other -> merge in test results from the other Tester instance.
+
+ If self and other both have a test result for something
+ with the same name, the (#failures, #tests) results are
+ summed, and a warning is printed to stdout.
+
+ >>> from doctest import Tester
+ >>> t1 = Tester(globs={}, verbose=0)
+ >>> t1.runstring('''
+ ... >>> x = 12
+ ... >>> print x
+ ... 12
+ ... ''', "t1example")
+ (0, 2)
+ >>>
+ >>> t2 = Tester(globs={}, verbose=0)
+ >>> t2.runstring('''
+ ... >>> x = 13
+ ... >>> print x
+ ... 13
+ ... ''', "t2example")
+ (0, 2)
+ >>> common = ">>> assert 1 + 2 == 3\\n"
+ >>> t1.runstring(common, "common")
+ (0, 1)
+ >>> t2.runstring(common, "common")
+ (0, 1)
+ >>> t1.merge(t2)
+ *** Tester.merge: 'common' in both testers; summing outcomes.
+ >>> t1.summarize(1)
+ 3 items passed all tests:
+ 2 tests in common
+ 2 tests in t1example
+ 2 tests in t2example
+ 6 tests in 3 items.
+ 6 passed and 0 failed.
+ Test passed.
+ (0, 6)
+ >>>
+ """
+
+ d = self.name2ft
+ for name, (f, t) in other.name2ft.items():
+ if d.has_key(name):
+ print "*** Tester.merge: '" + name + "' in both" \
+ " testers; summing outcomes."
+ f2, t2 = d[name]
+ f = f + f2
+ t = t + t2
+ d[name] = f, t
+
+ def __record_outcome(self, name, f, t):
+ if self.name2ft.has_key(name):
+ print "*** Warning: '" + name + "' was tested before;", \
+ "summing outcomes."
+ f2, t2 = self.name2ft[name]
+ f = f + f2
+ t = t + t2
+ self.name2ft[name] = f, t
+
+ def __runone(self, target, name):
+ if "." in name:
+ i = name.rindex(".")
+ prefix, base = name[:i], name[i+1:]
+ else:
+ prefix, base = "", base
+ if self.isprivate(prefix, base):
+ return 0, 0
+ return self.rundoc(target, name)
+
+master = None
+
+def testmod(m, name=None, globs=None, verbose=None, isprivate=None,
+ report=1):
+ """m, name=None, globs=None, verbose=None, isprivate=None, report=1
+
+ Test examples in docstrings in functions and classes reachable from
+ module m, starting with m.__doc__. Private names are skipped.
+
+ Also test examples reachable from dict m.__test__ if it exists and is
+ not None. m.__dict__ maps names to functions, classes and strings;
+ function and class docstrings are tested even if the name is private;
+ strings are tested directly, as if they were docstrings.
+
+ Return (#failures, #tests).
+
+ See doctest.__doc__ for an overview.
+
+ Optional keyword arg "name" gives the name of the module; by default
+ use m.__name__.
+
+ Optional keyword arg "globs" gives a dict to be used as the globals
+ when executing examples; by default, use m.__dict__. A copy of this
+ dict is actually used for each docstring, so that each docstring's
+ examples start with a clean slate.
+
+ Optional keyword arg "verbose" prints lots of stuff if true, prints
+ only failures if false; by default, it's true iff "-v" is in sys.argv.
+
+ Optional keyword arg "isprivate" specifies a function used to
+ determine whether a name is private. The default function is
+ doctest.is_private; see its docs for details.
+
+ Optional keyword arg "report" prints a summary at the end when true,
+ else prints nothing at the end. In verbose mode, the summary is
+ detailed, else very brief (in fact, empty if all tests passed).
+
+ Advanced tomfoolery: testmod runs methods of a local instance of
+ class doctest.Tester, then merges the results into (or creates)
+ global Tester instance doctest.master. Methods of doctest.master
+ can be called directly too, if you want to do something unusual.
+ Passing report=0 to testmod is especially useful then, to delay
+ displaying a summary. Invoke doctest.master.summarize(verbose)
+ when you're done fiddling.
+ """
+
+ global master
+
+ if type(m) is not _ModuleType:
+ raise TypeError("testmod: module required; " + `m`)
+ if name is None:
+ name = m.__name__
+ tester = Tester(m, globs=globs, verbose=verbose, isprivate=isprivate)
+ failures, tries = tester.rundoc(m, name)
+ f, t = tester.rundict(m.__dict__, name)
+ failures = failures + f
+ tries = tries + t
+ if hasattr(m, "__test__"):
+ testdict = m.__test__
+ if testdict:
+ if not hasattr(testdict, "items"):
+ raise TypeError("testmod: module.__test__ must support "
+ ".items(); " + `testdict`)
+ f, t = tester.run__test__(testdict, name + ".__test__")
+ failures = failures + f
+ tries = tries + t
+ if report:
+ tester.summarize()
+ if master is None:
+ master = tester
+ else:
+ master.merge(tester)
+ return failures, tries
+
+class _TestClass:
+ """
+ A pointless class, for sanity-checking of docstring testing.
+
+ Methods:
+ square()
+ get()
+
+ >>> _TestClass(13).get() + _TestClass(-12).get()
+ 1
+ >>> hex(_TestClass(13).square().get())
+ '0xa9'
+ """
+
+ def __init__(self, val):
+ """val -> _TestClass object with associated value val.
+
+ >>> t = _TestClass(123)
+ >>> print t.get()
+ 123
+ """
+
+ self.val = val
+
+ def square(self):
+ """square() -> square TestClass's associated value
+
+ >>> _TestClass(13).square().get()
+ 169
+ """
+
+ self.val = self.val ** 2
+ return self
+
+ def get(self):
+ """get() -> return TestClass's associated value.
+
+ >>> x = _TestClass(-42)
+ >>> print x.get()
+ -42
+ """
+
+ return self.val
+
+__test__ = {"_TestClass": _TestClass,
+ "string": r"""
+ Example of a string object, searched as-is.
+ >>> x = 1; y = 2
+ >>> x + y, x * y
+ (3, 2)
+ """
+ }
+
+def _test():
+ import doctest
+ return doctest.testmod(doctest)
+
+if __name__ == "__main__":
+ _test()
diff --git a/lib/jython/Lib/dospath.py b/lib/jython/Lib/dospath.py new file mode 100644 index 000000000..a9fb45046 --- /dev/null +++ b/lib/jython/Lib/dospath.py @@ -0,0 +1,332 @@ +"""Common operations on DOS pathnames."""
+
+import os
+import stat
+
+__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
+ "basename","dirname","commonprefix","getsize","getmtime",
+ "getatime","islink","exists","isdir","isfile","ismount",
+ "walk","expanduser","expandvars","normpath","abspath"]
+
+def normcase(s):
+ """Normalize the case of a pathname.
+ On MS-DOS it maps the pathname to lowercase, turns slashes into
+ backslashes.
+ Other normalizations (such as optimizing '../' away) are not allowed
+ (this is done by normpath).
+ Previously, this version mapped invalid consecutive characters to a
+ single '_', but this has been removed. This functionality should
+ possibly be added as a new function."""
+
+ return s.replace("/", "\\").lower()
+
+
+def isabs(s):
+ """Return whether a path is absolute.
+ Trivial in Posix, harder on the Mac or MS-DOS.
+ For DOS it is absolute if it starts with a slash or backslash (current
+ volume), or if a pathname after the volume letter and colon starts with
+ a slash or backslash."""
+
+ s = splitdrive(s)[1]
+ return s != '' and s[:1] in '/\\'
+
+
+def join(a, *p):
+ """Join two (or more) paths."""
+
+ path = a
+ for b in p:
+ if isabs(b):
+ path = b
+ elif path == '' or path[-1:] in '/\\:':
+ path = path + b
+ else:
+ path = path + "\\" + b
+ return path
+
+
+def splitdrive(p):
+ """Split a path into a drive specification (a drive letter followed
+ by a colon) and path specification.
+ It is always true that drivespec + pathspec == p."""
+
+ if p[1:2] == ':':
+ return p[0:2], p[2:]
+ return '', p
+
+
+def split(p):
+ """Split a path into head (everything up to the last '/') and tail
+ (the rest). After the trailing '/' is stripped, the invariant
+ join(head, tail) == p holds.
+ The resulting head won't end in '/' unless it is the root."""
+
+ d, p = splitdrive(p)
+ # set i to index beyond p's last slash
+ i = len(p)
+ while i and p[i-1] not in '/\\':
+ i = i - 1
+ head, tail = p[:i], p[i:] # now tail has no slashes
+ # remove trailing slashes from head, unless it's all slashes
+ head2 = head
+ while head2 and head2[-1] in '/\\':
+ head2 = head2[:-1]
+ head = head2 or head
+ return d + head, tail
+
+
+def splitext(p):
+ """Split a path into 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."""
+
+ root, ext = '', ''
+ for c in p:
+ if c in '/\\':
+ root, ext = root + ext + c, ''
+ elif c == '.' or ext:
+ ext = ext + c
+ else:
+ root = root + c
+ return root, ext
+
+
+def basename(p):
+ """Return the tail (basename) part of a path."""
+
+ return split(p)[1]
+
+
+def dirname(p):
+ """Return the head (dirname) part of a path."""
+
+ return split(p)[0]
+
+
+def commonprefix(m):
+ """Return the longest prefix of all list elements."""
+
+ 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
+
+
+# Get size, mtime, atime of files.
+
+def getsize(filename):
+ """Return the size of a file, reported by os.stat()."""
+ st = os.stat(filename)
+ return st[stat.ST_SIZE]
+
+def getmtime(filename):
+ """Return the last modification time of a file, reported by os.stat()."""
+ st = os.stat(filename)
+ return st[stat.ST_MTIME]
+
+def getatime(filename):
+ """Return the last access time of a file, reported by os.stat()."""
+ st = os.stat(filename)
+ return st[stat.ST_ATIME]
+
+
+def islink(path):
+ """Is a path a symbolic link?
+ This will always return false on systems where posix.lstat doesn't exist."""
+
+ return 0
+
+
+def exists(path):
+ """Does a path exist?
+ This is false for dangling symbolic links."""
+
+ try:
+ st = os.stat(path)
+ except os.error:
+ return 0
+ return 1
+
+
+def isdir(path):
+ """Is a path a dos directory?"""
+
+ try:
+ st = os.stat(path)
+ except os.error:
+ return 0
+ return stat.S_ISDIR(st[stat.ST_MODE])
+
+
+def isfile(path):
+ """Is a path a regular file?"""
+
+ try:
+ st = os.stat(path)
+ except os.error:
+ return 0
+ return stat.S_ISREG(st[stat.ST_MODE])
+
+
+def ismount(path):
+ """Is a path a mount point?"""
+ # XXX This degenerates in: 'is this the root?' on DOS
+
+ return isabs(splitdrive(path)[1])
+
+
+def walk(top, func, arg):
+ """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."""
+
+ try:
+ names = os.listdir(top)
+ except os.error:
+ return
+ func(arg, top, names)
+ exceptions = ('.', '..')
+ for name in names:
+ if name not in exceptions:
+ name = join(top, name)
+ if isdir(name):
+ walk(name, func, arg)
+
+
+def expanduser(path):
+ """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.)"""
+
+ if path[:1] != '~':
+ return path
+ i, n = 1, len(path)
+ while i < n and path[i] not in '/\\':
+ i = i+1
+ if i == 1:
+ if not os.environ.has_key('HOME'):
+ return path
+ userhome = os.environ['HOME']
+ else:
+ return path
+ return userhome + path[i:]
+
+
+def expandvars(path):
+ """Expand paths containing shell variable substitutions.
+ The following rules apply:
+ - no expansion within single quotes
+ - no escape character, except for '$$' which is translated into '$'
+ - ${varname} is accepted.
+ - varnames can be made out of letters, digits and the character '_'"""
+ # XXX With COMMAND.COM you can use any characters in a variable name,
+ # XXX except '^|<>='.
+
+ if '$' not in path:
+ return path
+ import string
+ varchars = string.letters + string.digits + '_-'
+ res = ''
+ index = 0
+ pathlen = len(path)
+ while index < pathlen:
+ c = path[index]
+ if c == '\'': # no expansion within single quotes
+ path = path[index + 1:]
+ pathlen = len(path)
+ try:
+ index = path.index('\'')
+ res = res + '\'' + path[:index + 1]
+ except ValueError:
+ res = res + path
+ index = pathlen -1
+ elif c == '$': # variable or '$$'
+ if path[index + 1:index + 2] == '$':
+ res = res + c
+ index = index + 1
+ elif path[index + 1:index + 2] == '{':
+ path = path[index+2:]
+ pathlen = len(path)
+ try:
+ index = path.index('}')
+ var = path[:index]
+ if os.environ.has_key(var):
+ res = res + os.environ[var]
+ except ValueError:
+ res = res + path
+ index = pathlen - 1
+ else:
+ var = ''
+ index = index + 1
+ c = path[index:index + 1]
+ while c != '' and c in varchars:
+ var = var + c
+ index = index + 1
+ c = path[index:index + 1]
+ if os.environ.has_key(var):
+ res = res + os.environ[var]
+ if c != '':
+ res = res + c
+ else:
+ res = res + c
+ index = index + 1
+ return res
+
+
+def normpath(path):
+ """Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
+ Also, components of the path are silently truncated to 8+3 notation."""
+
+ path = path.replace("/", "\\")
+ prefix, path = splitdrive(path)
+ while path[:1] == "\\":
+ prefix = prefix + "\\"
+ path = path[1:]
+ comps = path.split("\\")
+ 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]
+ elif '.' in comps[i]:
+ comp = comps[i].split('.')
+ comps[i] = comp[0][:8] + '.' + comp[1][:3]
+ i = i + 1
+ elif len(comps[i]) > 8:
+ comps[i] = comps[i][:8]
+ i = i + 1
+ else:
+ i = i + 1
+ # If the path is now empty, substitute '.'
+ if not prefix and not comps:
+ comps.append('.')
+ return prefix + "\\".join(comps)
+
+
+
+def abspath(path):
+ """Return an absolute path."""
+ if not isabs(path):
+ path = join(os.getcwd(), path)
+ return normpath(path)
diff --git a/lib/jython/Lib/dumbdbm.py b/lib/jython/Lib/dumbdbm.py new file mode 100644 index 000000000..addb0e4da --- /dev/null +++ b/lib/jython/Lib/dumbdbm.py @@ -0,0 +1,148 @@ +"""A dumb and slow but simple dbm clone.
+
+For database spam, spam.dir contains the index (a text file),
+spam.bak *may* contain a backup of the index (also a text file),
+while spam.dat contains the data (a binary file).
+
+XXX TO DO:
+
+- seems to contain a bug when updating...
+
+- reclaim free space (currently, space once occupied by deleted or expanded
+items is never reused)
+
+- support concurrent access (currently, if two processes take turns making
+updates, they can mess up the index)
+
+- support efficient access to large databases (currently, the whole index
+is read when the database is opened, and some updates rewrite the whole index)
+
+- support opening for read-only (flag = 'm')
+
+"""
+
+_os = __import__('os')
+import __builtin__
+
+_open = __builtin__.open
+
+_BLOCKSIZE = 512
+
+error = IOError # For anydbm
+
+class _Database:
+
+ def __init__(self, file):
+ if _os.sep == '.':
+ endsep = '/'
+ else:
+ endsep = '.'
+ self._dirfile = file + endsep + 'dir'
+ self._datfile = file + endsep + 'dat'
+ self._bakfile = file + endsep + 'bak'
+ # Mod by Jack: create data file if needed
+ try:
+ f = _open(self._datfile, 'r')
+ except IOError:
+ f = _open(self._datfile, 'w')
+ f.close()
+ self._update()
+
+ def _update(self):
+ self._index = {}
+ try:
+ f = _open(self._dirfile)
+ except IOError:
+ pass
+ else:
+ while 1:
+ line = f.readline().rstrip()
+ if not line: break
+ key, (pos, siz) = eval(line)
+ self._index[key] = (pos, siz)
+ f.close()
+
+ def _commit(self):
+ try: _os.unlink(self._bakfile)
+ except _os.error: pass
+ try: _os.rename(self._dirfile, self._bakfile)
+ except _os.error: pass
+ f = _open(self._dirfile, 'w')
+ for key, (pos, siz) in self._index.items():
+ f.write("%s, (%s, %s)\n" % (`key`, `pos`, `siz`))
+ f.close()
+
+ def __getitem__(self, key):
+ pos, siz = self._index[key] # may raise KeyError
+ f = _open(self._datfile, 'rb')
+ f.seek(pos)
+ dat = f.read(siz)
+ f.close()
+ return dat
+
+ def _addval(self, val):
+ f = _open(self._datfile, 'rb+')
+ f.seek(0, 2)
+ pos = int(f.tell())
+## Does not work under MW compiler
+## pos = ((pos + _BLOCKSIZE - 1) / _BLOCKSIZE) * _BLOCKSIZE
+## f.seek(pos)
+ npos = ((pos + _BLOCKSIZE - 1) / _BLOCKSIZE) * _BLOCKSIZE
+ f.write('\0'*(npos-pos))
+ pos = npos
+
+ f.write(val)
+ f.close()
+ return (pos, len(val))
+
+ def _setval(self, pos, val):
+ f = _open(self._datfile, 'rb+')
+ f.seek(pos)
+ f.write(val)
+ f.close()
+ return (pos, len(val))
+
+ def _addkey(self, key, (pos, siz)):
+ self._index[key] = (pos, siz)
+ f = _open(self._dirfile, 'a')
+ f.write("%s, (%s, %s)\n" % (`key`, `pos`, `siz`))
+ f.close()
+
+ def __setitem__(self, key, val):
+ if not type(key) == type('') == type(val):
+ raise TypeError, "keys and values must be strings"
+ if not self._index.has_key(key):
+ (pos, siz) = self._addval(val)
+ self._addkey(key, (pos, siz))
+ else:
+ pos, siz = self._index[key]
+ oldblocks = (siz + _BLOCKSIZE - 1) / _BLOCKSIZE
+ newblocks = (len(val) + _BLOCKSIZE - 1) / _BLOCKSIZE
+ if newblocks <= oldblocks:
+ pos, siz = self._setval(pos, val)
+ self._index[key] = pos, siz
+ else:
+ pos, siz = self._addval(val)
+ self._index[key] = pos, siz
+
+ def __delitem__(self, key):
+ del self._index[key]
+ self._commit()
+
+ def keys(self):
+ return self._index.keys()
+
+ def has_key(self, key):
+ return self._index.has_key(key)
+
+ def __len__(self):
+ return len(self._index)
+
+ def close(self):
+ self._index = None
+ self._datfile = self._dirfile = self._bakfile = None
+
+
+def open(file, flag = None, mode = None):
+ # flag, mode arguments are currently ignored
+ return _Database(file)
diff --git a/lib/jython/Lib/encodings/__init__.py b/lib/jython/Lib/encodings/__init__.py new file mode 100644 index 000000000..12dcf6099 --- /dev/null +++ b/lib/jython/Lib/encodings/__init__.py @@ -0,0 +1,86 @@ +""" Standard "encodings" Package
+
+ Standard Python encoding modules are stored in this package
+ directory.
+
+ Codec modules must have names corresponding to standard lower-case
+ encoding names with hyphens mapped to underscores, e.g. 'utf-8' is
+ implemented by the module 'utf_8.py'.
+
+ Each codec module must export the following interface:
+
+ * getregentry() -> (encoder, decoder, stream_reader, stream_writer)
+ The getregentry() API must return callable objects which adhere to
+ the Python Codec Interface Standard.
+
+ In addition, a module may optionally also define the following
+ APIs which are then used by the package's codec search function:
+
+ * getaliases() -> sequence of encoding name strings to use as aliases
+
+ Alias names returned by getaliases() must be standard encoding
+ names as defined above (lower-case, hyphens converted to
+ underscores).
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+
+"""#"
+
+import codecs,aliases
+
+_cache = {}
+_unknown = '--unknown--'
+
+def search_function(encoding):
+
+ # Cache lookup
+ entry = _cache.get(encoding,_unknown)
+ if entry is not _unknown:
+ return entry
+
+ # Import the module
+ modname = encoding.replace('-', '_')
+ modname = aliases.aliases.get(modname,modname)
+ try:
+ mod = __import__(modname,globals(),locals(),'*')
+ except ImportError,why:
+ # cache misses
+ _cache[encoding] = None
+ return None
+
+ # Now ask the module for the registry entry
+ try:
+ entry = tuple(mod.getregentry())
+ except AttributeError:
+ entry = ()
+ if len(entry) != 4:
+ raise SystemError,\
+ 'module "%s.%s" failed to register' % \
+ (__name__,modname)
+ for obj in entry:
+ if not callable(obj):
+ raise SystemError,\
+ 'incompatible codecs in module "%s.%s"' % \
+ (__name__,modname)
+
+ # Cache the codec registry entry
+ _cache[encoding] = entry
+
+ # Register its aliases (without overwriting previously registered
+ # aliases)
+ try:
+ codecaliases = mod.getaliases()
+ except AttributeError:
+ pass
+ else:
+ for alias in codecaliases:
+ if not aliases.aliases.has_key(alias):
+ aliases.aliases[alias] = modname
+
+ # Return the registry entry
+ return entry
+
+# Register the search_function in the Python codec registry
+codecs.register(search_function)
diff --git a/lib/jython/Lib/encodings/aliases.py b/lib/jython/Lib/encodings/aliases.py new file mode 100644 index 000000000..db931b0fa --- /dev/null +++ b/lib/jython/Lib/encodings/aliases.py @@ -0,0 +1,82 @@ +""" Encoding Aliases Support
+
+ This module is used by the encodings package search function to
+ map encodings names to module names.
+
+ Note that the search function converts the encoding names to lower
+ case and replaces hyphens with underscores *before* performing the
+ lookup.
+
+"""
+aliases = {
+
+ # Latin-1
+ 'latin': 'latin_1',
+ 'latin1': 'latin_1',
+
+ # UTF-8
+ 'utf': 'utf_8',
+ 'utf8': 'utf_8',
+ 'u8': 'utf_8',
+ 'utf8@ucs2': 'utf_8',
+ 'utf8@ucs4': 'utf_8',
+
+ # UTF-16
+ 'utf16': 'utf_16',
+ 'u16': 'utf_16',
+ 'utf_16be': 'utf_16_be',
+ 'utf_16le': 'utf_16_le',
+ 'unicodebigunmarked': 'utf_16_be',
+ 'unicodelittleunmarked': 'utf_16_le',
+
+ # ASCII
+ 'us_ascii': 'ascii',
+
+ # ISO
+ '8859': 'latin_1',
+ 'iso8859': 'latin_1',
+ 'iso8859_1': 'latin_1',
+ 'iso_8859_1': 'latin_1',
+ 'iso_8859_10': 'iso8859_10',
+ 'iso_8859_13': 'iso8859_13',
+ 'iso_8859_14': 'iso8859_14',
+ 'iso_8859_15': 'iso8859_15',
+ 'iso_8859_2': 'iso8859_2',
+ 'iso_8859_3': 'iso8859_3',
+ 'iso_8859_4': 'iso8859_4',
+ 'iso_8859_5': 'iso8859_5',
+ 'iso_8859_6': 'iso8859_6',
+ 'iso_8859_7': 'iso8859_7',
+ 'iso_8859_8': 'iso8859_8',
+ 'iso_8859_9': 'iso8859_9',
+
+ # Mac
+ 'maclatin2': 'mac_latin2',
+ 'maccentraleurope': 'mac_latin2',
+ 'maccyrillic': 'mac_cyrillic',
+ 'macgreek': 'mac_greek',
+ 'maciceland': 'mac_iceland',
+ 'macroman': 'mac_roman',
+ 'macturkish': 'mac_turkish',
+
+ # MBCS
+ 'dbcs': 'mbcs',
+
+ # Code pages
+ '437': 'cp437',
+
+ # CJK
+ #
+ # The codecs for these encodings are not distributed with the
+ # Python core, but are included here for reference, since the
+ # locale module relies on having these aliases available.
+ #
+ 'jis_7': 'jis_7',
+ 'iso_2022_jp': 'jis_7',
+ 'ujis': 'euc_jp',
+ 'ajec': 'euc_jp',
+ 'eucjp': 'euc_jp',
+ 'tis260': 'tactis',
+ 'sjis': 'shift_jis',
+
+}
diff --git a/lib/jython/Lib/encodings/ascii.py b/lib/jython/Lib/encodings/ascii.py new file mode 100644 index 000000000..3f68e2832 --- /dev/null +++ b/lib/jython/Lib/encodings/ascii.py @@ -0,0 +1,35 @@ +""" Python 'ascii' Codec
+
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+
+"""
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ # Note: Binding these as C functions will result in the class not
+ # converting them to methods. This is intended.
+ encode = codecs.ascii_encode
+ decode = codecs.ascii_decode
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+class StreamConverter(StreamWriter,StreamReader):
+
+ encode = codecs.ascii_decode
+ decode = codecs.ascii_encode
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec.encode,Codec.decode,StreamReader,StreamWriter)
diff --git a/lib/jython/Lib/encodings/charmap.py b/lib/jython/Lib/encodings/charmap.py new file mode 100644 index 000000000..ec65b1ab0 --- /dev/null +++ b/lib/jython/Lib/encodings/charmap.py @@ -0,0 +1,51 @@ +""" Generic Python Character Mapping Codec.
+
+ Use this codec directly rather than through the automatic
+ conversion mechanisms supplied by unicode() and .encode().
+
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ # Note: Binding these as C functions will result in the class not
+ # converting them to methods. This is intended.
+ encode = codecs.charmap_encode
+ decode = codecs.charmap_decode
+
+class StreamWriter(Codec,codecs.StreamWriter):
+
+ def __init__(self,stream,errors='strict',mapping=None):
+
+ codecs.StreamWriter.__init__(self,strict,errors)
+ self.mapping = mapping
+
+ def encode(self,input,errors='strict'):
+
+ return Codec.encode(input,errors,self.mapping)
+
+class StreamReader(Codec,codecs.StreamReader):
+
+ def __init__(self,stream,errors='strict',mapping=None):
+
+ codecs.StreamReader.__init__(self,strict,errors)
+ self.mapping = mapping
+
+ def decode(self,input,errors='strict'):
+
+ return Codec.decode(input,errors,self.mapping)
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec.encode,Codec.decode,StreamReader,StreamWriter)
+
diff --git a/lib/jython/Lib/encodings/cp037.py b/lib/jython/Lib/encodings/cp037.py new file mode 100644 index 000000000..f4509b169 --- /dev/null +++ b/lib/jython/Lib/encodings/cp037.py @@ -0,0 +1,282 @@ +""" Python Character Mapping Codec generated from 'CP037.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0004: 0x009c, # CONTROL
+ 0x0005: 0x0009, # HORIZONTAL TABULATION
+ 0x0006: 0x0086, # CONTROL
+ 0x0007: 0x007f, # DELETE
+ 0x0008: 0x0097, # CONTROL
+ 0x0009: 0x008d, # CONTROL
+ 0x000a: 0x008e, # CONTROL
+ 0x0014: 0x009d, # CONTROL
+ 0x0015: 0x0085, # CONTROL
+ 0x0016: 0x0008, # BACKSPACE
+ 0x0017: 0x0087, # CONTROL
+ 0x001a: 0x0092, # CONTROL
+ 0x001b: 0x008f, # CONTROL
+ 0x0020: 0x0080, # CONTROL
+ 0x0021: 0x0081, # CONTROL
+ 0x0022: 0x0082, # CONTROL
+ 0x0023: 0x0083, # CONTROL
+ 0x0024: 0x0084, # CONTROL
+ 0x0025: 0x000a, # LINE FEED
+ 0x0026: 0x0017, # END OF TRANSMISSION BLOCK
+ 0x0027: 0x001b, # ESCAPE
+ 0x0028: 0x0088, # CONTROL
+ 0x0029: 0x0089, # CONTROL
+ 0x002a: 0x008a, # CONTROL
+ 0x002b: 0x008b, # CONTROL
+ 0x002c: 0x008c, # CONTROL
+ 0x002d: 0x0005, # ENQUIRY
+ 0x002e: 0x0006, # ACKNOWLEDGE
+ 0x002f: 0x0007, # BELL
+ 0x0030: 0x0090, # CONTROL
+ 0x0031: 0x0091, # CONTROL
+ 0x0032: 0x0016, # SYNCHRONOUS IDLE
+ 0x0033: 0x0093, # CONTROL
+ 0x0034: 0x0094, # CONTROL
+ 0x0035: 0x0095, # CONTROL
+ 0x0036: 0x0096, # CONTROL
+ 0x0037: 0x0004, # END OF TRANSMISSION
+ 0x0038: 0x0098, # CONTROL
+ 0x0039: 0x0099, # CONTROL
+ 0x003a: 0x009a, # CONTROL
+ 0x003b: 0x009b, # CONTROL
+ 0x003c: 0x0014, # DEVICE CONTROL FOUR
+ 0x003d: 0x0015, # NEGATIVE ACKNOWLEDGE
+ 0x003e: 0x009e, # CONTROL
+ 0x003f: 0x001a, # SUBSTITUTE
+ 0x0040: 0x0020, # SPACE
+ 0x0041: 0x00a0, # NO-BREAK SPACE
+ 0x0042: 0x00e2, # LATIN SMALL LETTER A WITH CIRCUMFLEX
+ 0x0043: 0x00e4, # LATIN SMALL LETTER A WITH DIAERESIS
+ 0x0044: 0x00e0, # LATIN SMALL LETTER A WITH GRAVE
+ 0x0045: 0x00e1, # LATIN SMALL LETTER A WITH ACUTE
+ 0x0046: 0x00e3, # LATIN SMALL LETTER A WITH TILDE
+ 0x0047: 0x00e5, # LATIN SMALL LETTER A WITH RING ABOVE
+ 0x0048: 0x00e7, # LATIN SMALL LETTER C WITH CEDILLA
+ 0x0049: 0x00f1, # LATIN SMALL LETTER N WITH TILDE
+ 0x004a: 0x00a2, # CENT SIGN
+ 0x004b: 0x002e, # FULL STOP
+ 0x004c: 0x003c, # LESS-THAN SIGN
+ 0x004d: 0x0028, # LEFT PARENTHESIS
+ 0x004e: 0x002b, # PLUS SIGN
+ 0x004f: 0x007c, # VERTICAL LINE
+ 0x0050: 0x0026, # AMPERSAND
+ 0x0051: 0x00e9, # LATIN SMALL LETTER E WITH ACUTE
+ 0x0052: 0x00ea, # LATIN SMALL LETTER E WITH CIRCUMFLEX
+ 0x0053: 0x00eb, # LATIN SMALL LETTER E WITH DIAERESIS
+ 0x0054: 0x00e8, # LATIN SMALL LETTER E WITH GRAVE
+ 0x0055: 0x00ed, # LATIN SMALL LETTER I WITH ACUTE
+ 0x0056: 0x00ee, # LATIN SMALL LETTER I WITH CIRCUMFLEX
+ 0x0057: 0x00ef, # LATIN SMALL LETTER I WITH DIAERESIS
+ 0x0058: 0x00ec, # LATIN SMALL LETTER I WITH GRAVE
+ 0x0059: 0x00df, # LATIN SMALL LETTER SHARP S (GERMAN)
+ 0x005a: 0x0021, # EXCLAMATION MARK
+ 0x005b: 0x0024, # DOLLAR SIGN
+ 0x005c: 0x002a, # ASTERISK
+ 0x005d: 0x0029, # RIGHT PARENTHESIS
+ 0x005e: 0x003b, # SEMICOLON
+ 0x005f: 0x00ac, # NOT SIGN
+ 0x0060: 0x002d, # HYPHEN-MINUS
+ 0x0061: 0x002f, # SOLIDUS
+ 0x0062: 0x00c2, # LATIN CAPITAL LETTER A WITH CIRCUMFLEX
+ 0x0063: 0x00c4, # LATIN CAPITAL LETTER A WITH DIAERESIS
+ 0x0064: 0x00c0, # LATIN CAPITAL LETTER A WITH GRAVE
+ 0x0065: 0x00c1, # LATIN CAPITAL LETTER A WITH ACUTE
+ 0x0066: 0x00c3, # LATIN CAPITAL LETTER A WITH TILDE
+ 0x0067: 0x00c5, # LATIN CAPITAL LETTER A WITH RING ABOVE
+ 0x0068: 0x00c7, # LATIN CAPITAL LETTER C WITH CEDILLA
+ 0x0069: 0x00d1, # LATIN CAPITAL LETTER N WITH TILDE
+ 0x006a: 0x00a6, # BROKEN BAR
+ 0x006b: 0x002c, # COMMA
+ 0x006c: 0x0025, # PERCENT SIGN
+ 0x006d: 0x005f, # LOW LINE
+ 0x006e: 0x003e, # GREATER-THAN SIGN
+ 0x006f: 0x003f, # QUESTION MARK
+ 0x0070: 0x00f8, # LATIN SMALL LETTER O WITH STROKE
+ 0x0071: 0x00c9, # LATIN CAPITAL LETTER E WITH ACUTE
+ 0x0072: 0x00ca, # LATIN CAPITAL LETTER E WITH CIRCUMFLEX
+ 0x0073: 0x00cb, # LATIN CAPITAL LETTER E WITH DIAERESIS
+ 0x0074: 0x00c8, # LATIN CAPITAL LETTER E WITH GRAVE
+ 0x0075: 0x00cd, # LATIN CAPITAL LETTER I WITH ACUTE
+ 0x0076: 0x00ce, # LATIN CAPITAL LETTER I WITH CIRCUMFLEX
+ 0x0077: 0x00cf, # LATIN CAPITAL LETTER I WITH DIAERESIS
+ 0x0078: 0x00cc, # LATIN CAPITAL LETTER I WITH GRAVE
+ 0x0079: 0x0060, # GRAVE ACCENT
+ 0x007a: 0x003a, # COLON
+ 0x007b: 0x0023, # NUMBER SIGN
+ 0x007c: 0x0040, # COMMERCIAL AT
+ 0x007d: 0x0027, # APOSTROPHE
+ 0x007e: 0x003d, # EQUALS SIGN
+ 0x007f: 0x0022, # QUOTATION MARK
+ 0x0080: 0x00d8, # LATIN CAPITAL LETTER O WITH STROKE
+ 0x0081: 0x0061, # LATIN SMALL LETTER A
+ 0x0082: 0x0062, # LATIN SMALL LETTER B
+ 0x0083: 0x0063, # LATIN SMALL LETTER C
+ 0x0084: 0x0064, # LATIN SMALL LETTER D
+ 0x0085: 0x0065, # LATIN SMALL LETTER E
+ 0x0086: 0x0066, # LATIN SMALL LETTER F
+ 0x0087: 0x0067, # LATIN SMALL LETTER G
+ 0x0088: 0x0068, # LATIN SMALL LETTER H
+ 0x0089: 0x0069, # LATIN SMALL LETTER I
+ 0x008a: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x008b: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x008c: 0x00f0, # LATIN SMALL LETTER ETH (ICELANDIC)
+ 0x008d: 0x00fd, # LATIN SMALL LETTER Y WITH ACUTE
+ 0x008e: 0x00fe, # LATIN SMALL LETTER THORN (ICELANDIC)
+ 0x008f: 0x00b1, # PLUS-MINUS SIGN
+ 0x0090: 0x00b0, # DEGREE SIGN
+ 0x0091: 0x006a, # LATIN SMALL LETTER J
+ 0x0092: 0x006b, # LATIN SMALL LETTER K
+ 0x0093: 0x006c, # LATIN SMALL LETTER L
+ 0x0094: 0x006d, # LATIN SMALL LETTER M
+ 0x0095: 0x006e, # LATIN SMALL LETTER N
+ 0x0096: 0x006f, # LATIN SMALL LETTER O
+ 0x0097: 0x0070, # LATIN SMALL LETTER P
+ 0x0098: 0x0071, # LATIN SMALL LETTER Q
+ 0x0099: 0x0072, # LATIN SMALL LETTER R
+ 0x009a: 0x00aa, # FEMININE ORDINAL INDICATOR
+ 0x009b: 0x00ba, # MASCULINE ORDINAL INDICATOR
+ 0x009c: 0x00e6, # LATIN SMALL LIGATURE AE
+ 0x009d: 0x00b8, # CEDILLA
+ 0x009e: 0x00c6, # LATIN CAPITAL LIGATURE AE
+ 0x009f: 0x00a4, # CURRENCY SIGN
+ 0x00a0: 0x00b5, # MICRO SIGN
+ 0x00a1: 0x007e, # TILDE
+ 0x00a2: 0x0073, # LATIN SMALL LETTER S
+ 0x00a3: 0x0074, # LATIN SMALL LETTER T
+ 0x00a4: 0x0075, # LATIN SMALL LETTER U
+ 0x00a5: 0x0076, # LATIN SMALL LETTER V
+ 0x00a6: 0x0077, # LATIN SMALL LETTER W
+ 0x00a7: 0x0078, # LATIN SMALL LETTER X
+ 0x00a8: 0x0079, # LATIN SMALL LETTER Y
+ 0x00a9: 0x007a, # LATIN SMALL LETTER Z
+ 0x00aa: 0x00a1, # INVERTED EXCLAMATION MARK
+ 0x00ab: 0x00bf, # INVERTED QUESTION MARK
+ 0x00ac: 0x00d0, # LATIN CAPITAL LETTER ETH (ICELANDIC)
+ 0x00ad: 0x00dd, # LATIN CAPITAL LETTER Y WITH ACUTE
+ 0x00ae: 0x00de, # LATIN CAPITAL LETTER THORN (ICELANDIC)
+ 0x00af: 0x00ae, # REGISTERED SIGN
+ 0x00b0: 0x005e, # CIRCUMFLEX ACCENT
+ 0x00b1: 0x00a3, # POUND SIGN
+ 0x00b2: 0x00a5, # YEN SIGN
+ 0x00b3: 0x00b7, # MIDDLE DOT
+ 0x00b4: 0x00a9, # COPYRIGHT SIGN
+ 0x00b5: 0x00a7, # SECTION SIGN
+ 0x00b7: 0x00bc, # VULGAR FRACTION ONE QUARTER
+ 0x00b8: 0x00bd, # VULGAR FRACTION ONE HALF
+ 0x00b9: 0x00be, # VULGAR FRACTION THREE QUARTERS
+ 0x00ba: 0x005b, # LEFT SQUARE BRACKET
+ 0x00bb: 0x005d, # RIGHT SQUARE BRACKET
+ 0x00bc: 0x00af, # MACRON
+ 0x00bd: 0x00a8, # DIAERESIS
+ 0x00be: 0x00b4, # ACUTE ACCENT
+ 0x00bf: 0x00d7, # MULTIPLICATION SIGN
+ 0x00c0: 0x007b, # LEFT CURLY BRACKET
+ 0x00c1: 0x0041, # LATIN CAPITAL LETTER A
+ 0x00c2: 0x0042, # LATIN CAPITAL LETTER B
+ 0x00c3: 0x0043, # LATIN CAPITAL LETTER C
+ 0x00c4: 0x0044, # LATIN CAPITAL LETTER D
+ 0x00c5: 0x0045, # LATIN CAPITAL LETTER E
+ 0x00c6: 0x0046, # LATIN CAPITAL LETTER F
+ 0x00c7: 0x0047, # LATIN CAPITAL LETTER G
+ 0x00c8: 0x0048, # LATIN CAPITAL LETTER H
+ 0x00c9: 0x0049, # LATIN CAPITAL LETTER I
+ 0x00ca: 0x00ad, # SOFT HYPHEN
+ 0x00cb: 0x00f4, # LATIN SMALL LETTER O WITH CIRCUMFLEX
+ 0x00cc: 0x00f6, # LATIN SMALL LETTER O WITH DIAERESIS
+ 0x00cd: 0x00f2, # LATIN SMALL LETTER O WITH GRAVE
+ 0x00ce: 0x00f3, # LATIN SMALL LETTER O WITH ACUTE
+ 0x00cf: 0x00f5, # LATIN SMALL LETTER O WITH TILDE
+ 0x00d0: 0x007d, # RIGHT CURLY BRACKET
+ 0x00d1: 0x004a, # LATIN CAPITAL LETTER J
+ 0x00d2: 0x004b, # LATIN CAPITAL LETTER K
+ 0x00d3: 0x004c, # LATIN CAPITAL LETTER L
+ 0x00d4: 0x004d, # LATIN CAPITAL LETTER M
+ 0x00d5: 0x004e, # LATIN CAPITAL LETTER N
+ 0x00d6: 0x004f, # LATIN CAPITAL LETTER O
+ 0x00d7: 0x0050, # LATIN CAPITAL LETTER P
+ 0x00d8: 0x0051, # LATIN CAPITAL LETTER Q
+ 0x00d9: 0x0052, # LATIN CAPITAL LETTER R
+ 0x00da: 0x00b9, # SUPERSCRIPT ONE
+ 0x00db: 0x00fb, # LATIN SMALL LETTER U WITH CIRCUMFLEX
+ 0x00dc: 0x00fc, # LATIN SMALL LETTER U WITH DIAERESIS
+ 0x00dd: 0x00f9, # LATIN SMALL LETTER U WITH GRAVE
+ 0x00de: 0x00fa, # LATIN SMALL LETTER U WITH ACUTE
+ 0x00df: 0x00ff, # LATIN SMALL LETTER Y WITH DIAERESIS
+ 0x00e0: 0x005c, # REVERSE SOLIDUS
+ 0x00e1: 0x00f7, # DIVISION SIGN
+ 0x00e2: 0x0053, # LATIN CAPITAL LETTER S
+ 0x00e3: 0x0054, # LATIN CAPITAL LETTER T
+ 0x00e4: 0x0055, # LATIN CAPITAL LETTER U
+ 0x00e5: 0x0056, # LATIN CAPITAL LETTER V
+ 0x00e6: 0x0057, # LATIN CAPITAL LETTER W
+ 0x00e7: 0x0058, # LATIN CAPITAL LETTER X
+ 0x00e8: 0x0059, # LATIN CAPITAL LETTER Y
+ 0x00e9: 0x005a, # LATIN CAPITAL LETTER Z
+ 0x00ea: 0x00b2, # SUPERSCRIPT TWO
+ 0x00eb: 0x00d4, # LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+ 0x00ec: 0x00d6, # LATIN CAPITAL LETTER O WITH DIAERESIS
+ 0x00ed: 0x00d2, # LATIN CAPITAL LETTER O WITH GRAVE
+ 0x00ee: 0x00d3, # LATIN CAPITAL LETTER O WITH ACUTE
+ 0x00ef: 0x00d5, # LATIN CAPITAL LETTER O WITH TILDE
+ 0x00f0: 0x0030, # DIGIT ZERO
+ 0x00f1: 0x0031, # DIGIT ONE
+ 0x00f2: 0x0032, # DIGIT TWO
+ 0x00f3: 0x0033, # DIGIT THREE
+ 0x00f4: 0x0034, # DIGIT FOUR
+ 0x00f5: 0x0035, # DIGIT FIVE
+ 0x00f6: 0x0036, # DIGIT SIX
+ 0x00f7: 0x0037, # DIGIT SEVEN
+ 0x00f8: 0x0038, # DIGIT EIGHT
+ 0x00f9: 0x0039, # DIGIT NINE
+ 0x00fa: 0x00b3, # SUPERSCRIPT THREE
+ 0x00fb: 0x00db, # LATIN CAPITAL LETTER U WITH CIRCUMFLEX
+ 0x00fc: 0x00dc, # LATIN CAPITAL LETTER U WITH DIAERESIS
+ 0x00fd: 0x00d9, # LATIN CAPITAL LETTER U WITH GRAVE
+ 0x00fe: 0x00da, # LATIN CAPITAL LETTER U WITH ACUTE
+ 0x00ff: 0x009f, # CONTROL
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp1006.py b/lib/jython/Lib/encodings/cp1006.py new file mode 100644 index 000000000..d63c3cc8d --- /dev/null +++ b/lib/jython/Lib/encodings/cp1006.py @@ -0,0 +1,140 @@ +""" Python Character Mapping Codec generated from 'CP1006.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x00a1: 0x06f0, # EXTENDED ARABIC-INDIC DIGIT ZERO
+ 0x00a2: 0x06f1, # EXTENDED ARABIC-INDIC DIGIT ONE
+ 0x00a3: 0x06f2, # EXTENDED ARABIC-INDIC DIGIT TWO
+ 0x00a4: 0x06f3, # EXTENDED ARABIC-INDIC DIGIT THREE
+ 0x00a5: 0x06f4, # EXTENDED ARABIC-INDIC DIGIT FOUR
+ 0x00a6: 0x06f5, # EXTENDED ARABIC-INDIC DIGIT FIVE
+ 0x00a7: 0x06f6, # EXTENDED ARABIC-INDIC DIGIT SIX
+ 0x00a8: 0x06f7, # EXTENDED ARABIC-INDIC DIGIT SEVEN
+ 0x00a9: 0x06f8, # EXTENDED ARABIC-INDIC DIGIT EIGHT
+ 0x00aa: 0x06f9, # EXTENDED ARABIC-INDIC DIGIT NINE
+ 0x00ab: 0x060c, # ARABIC COMMA
+ 0x00ac: 0x061b, # ARABIC SEMICOLON
+ 0x00ae: 0x061f, # ARABIC QUESTION MARK
+ 0x00af: 0xfe81, # ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM
+ 0x00b0: 0xfe8d, # ARABIC LETTER ALEF ISOLATED FORM
+ 0x00b1: 0xfe8e, # ARABIC LETTER ALEF FINAL FORM
+ 0x00b2: 0xfe8e, # ARABIC LETTER ALEF FINAL FORM
+ 0x00b3: 0xfe8f, # ARABIC LETTER BEH ISOLATED FORM
+ 0x00b4: 0xfe91, # ARABIC LETTER BEH INITIAL FORM
+ 0x00b5: 0xfb56, # ARABIC LETTER PEH ISOLATED FORM
+ 0x00b6: 0xfb58, # ARABIC LETTER PEH INITIAL FORM
+ 0x00b7: 0xfe93, # ARABIC LETTER TEH MARBUTA ISOLATED FORM
+ 0x00b8: 0xfe95, # ARABIC LETTER TEH ISOLATED FORM
+ 0x00b9: 0xfe97, # ARABIC LETTER TEH INITIAL FORM
+ 0x00ba: 0xfb66, # ARABIC LETTER TTEH ISOLATED FORM
+ 0x00bb: 0xfb68, # ARABIC LETTER TTEH INITIAL FORM
+ 0x00bc: 0xfe99, # ARABIC LETTER THEH ISOLATED FORM
+ 0x00bd: 0xfe9b, # ARABIC LETTER THEH INITIAL FORM
+ 0x00be: 0xfe9d, # ARABIC LETTER JEEM ISOLATED FORM
+ 0x00bf: 0xfe9f, # ARABIC LETTER JEEM INITIAL FORM
+ 0x00c0: 0xfb7a, # ARABIC LETTER TCHEH ISOLATED FORM
+ 0x00c1: 0xfb7c, # ARABIC LETTER TCHEH INITIAL FORM
+ 0x00c2: 0xfea1, # ARABIC LETTER HAH ISOLATED FORM
+ 0x00c3: 0xfea3, # ARABIC LETTER HAH INITIAL FORM
+ 0x00c4: 0xfea5, # ARABIC LETTER KHAH ISOLATED FORM
+ 0x00c5: 0xfea7, # ARABIC LETTER KHAH INITIAL FORM
+ 0x00c6: 0xfea9, # ARABIC LETTER DAL ISOLATED FORM
+ 0x00c7: 0xfb84, # ARABIC LETTER DAHAL ISOLATED FORMN
+ 0x00c8: 0xfeab, # ARABIC LETTER THAL ISOLATED FORM
+ 0x00c9: 0xfead, # ARABIC LETTER REH ISOLATED FORM
+ 0x00ca: 0xfb8c, # ARABIC LETTER RREH ISOLATED FORM
+ 0x00cb: 0xfeaf, # ARABIC LETTER ZAIN ISOLATED FORM
+ 0x00cc: 0xfb8a, # ARABIC LETTER JEH ISOLATED FORM
+ 0x00cd: 0xfeb1, # ARABIC LETTER SEEN ISOLATED FORM
+ 0x00ce: 0xfeb3, # ARABIC LETTER SEEN INITIAL FORM
+ 0x00cf: 0xfeb5, # ARABIC LETTER SHEEN ISOLATED FORM
+ 0x00d0: 0xfeb7, # ARABIC LETTER SHEEN INITIAL FORM
+ 0x00d1: 0xfeb9, # ARABIC LETTER SAD ISOLATED FORM
+ 0x00d2: 0xfebb, # ARABIC LETTER SAD INITIAL FORM
+ 0x00d3: 0xfebd, # ARABIC LETTER DAD ISOLATED FORM
+ 0x00d4: 0xfebf, # ARABIC LETTER DAD INITIAL FORM
+ 0x00d5: 0xfec1, # ARABIC LETTER TAH ISOLATED FORM
+ 0x00d6: 0xfec5, # ARABIC LETTER ZAH ISOLATED FORM
+ 0x00d7: 0xfec9, # ARABIC LETTER AIN ISOLATED FORM
+ 0x00d8: 0xfeca, # ARABIC LETTER AIN FINAL FORM
+ 0x00d9: 0xfecb, # ARABIC LETTER AIN INITIAL FORM
+ 0x00da: 0xfecc, # ARABIC LETTER AIN MEDIAL FORM
+ 0x00db: 0xfecd, # ARABIC LETTER GHAIN ISOLATED FORM
+ 0x00dc: 0xfece, # ARABIC LETTER GHAIN FINAL FORM
+ 0x00dd: 0xfecf, # ARABIC LETTER GHAIN INITIAL FORM
+ 0x00de: 0xfed0, # ARABIC LETTER GHAIN MEDIAL FORM
+ 0x00df: 0xfed1, # ARABIC LETTER FEH ISOLATED FORM
+ 0x00e0: 0xfed3, # ARABIC LETTER FEH INITIAL FORM
+ 0x00e1: 0xfed5, # ARABIC LETTER QAF ISOLATED FORM
+ 0x00e2: 0xfed7, # ARABIC LETTER QAF INITIAL FORM
+ 0x00e3: 0xfed9, # ARABIC LETTER KAF ISOLATED FORM
+ 0x00e4: 0xfedb, # ARABIC LETTER KAF INITIAL FORM
+ 0x00e5: 0xfb92, # ARABIC LETTER GAF ISOLATED FORM
+ 0x00e6: 0xfb94, # ARABIC LETTER GAF INITIAL FORM
+ 0x00e7: 0xfedd, # ARABIC LETTER LAM ISOLATED FORM
+ 0x00e8: 0xfedf, # ARABIC LETTER LAM INITIAL FORM
+ 0x00e9: 0xfee0, # ARABIC LETTER LAM MEDIAL FORM
+ 0x00ea: 0xfee1, # ARABIC LETTER MEEM ISOLATED FORM
+ 0x00eb: 0xfee3, # ARABIC LETTER MEEM INITIAL FORM
+ 0x00ec: 0xfb9e, # ARABIC LETTER NOON GHUNNA ISOLATED FORM
+ 0x00ed: 0xfee5, # ARABIC LETTER NOON ISOLATED FORM
+ 0x00ee: 0xfee7, # ARABIC LETTER NOON INITIAL FORM
+ 0x00ef: 0xfe85, # ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM
+ 0x00f0: 0xfeed, # ARABIC LETTER WAW ISOLATED FORM
+ 0x00f1: 0xfba6, # ARABIC LETTER HEH GOAL ISOLATED FORM
+ 0x00f2: 0xfba8, # ARABIC LETTER HEH GOAL INITIAL FORM
+ 0x00f3: 0xfba9, # ARABIC LETTER HEH GOAL MEDIAL FORM
+ 0x00f4: 0xfbaa, # ARABIC LETTER HEH DOACHASHMEE ISOLATED FORM
+ 0x00f5: 0xfe80, # ARABIC LETTER HAMZA ISOLATED FORM
+ 0x00f6: 0xfe89, # ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM
+ 0x00f7: 0xfe8a, # ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM
+ 0x00f8: 0xfe8b, # ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM
+ 0x00f9: 0xfef1, # ARABIC LETTER YEH ISOLATED FORM
+ 0x00fa: 0xfef2, # ARABIC LETTER YEH FINAL FORM
+ 0x00fb: 0xfef3, # ARABIC LETTER YEH INITIAL FORM
+ 0x00fc: 0xfbb0, # ARABIC LETTER YEH BARREE WITH HAMZA ABOVE ISOLATED FORM
+ 0x00fd: 0xfbae, # ARABIC LETTER YEH BARREE ISOLATED FORM
+ 0x00fe: 0xfe7c, # ARABIC SHADDA ISOLATED FORM
+ 0x00ff: 0xfe7d, # ARABIC SHADDA MEDIAL FORM
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp1026.py b/lib/jython/Lib/encodings/cp1026.py new file mode 100644 index 000000000..79c5bc003 --- /dev/null +++ b/lib/jython/Lib/encodings/cp1026.py @@ -0,0 +1,282 @@ +""" Python Character Mapping Codec generated from 'CP1026.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0004: 0x009c, # CONTROL
+ 0x0005: 0x0009, # HORIZONTAL TABULATION
+ 0x0006: 0x0086, # CONTROL
+ 0x0007: 0x007f, # DELETE
+ 0x0008: 0x0097, # CONTROL
+ 0x0009: 0x008d, # CONTROL
+ 0x000a: 0x008e, # CONTROL
+ 0x0014: 0x009d, # CONTROL
+ 0x0015: 0x0085, # CONTROL
+ 0x0016: 0x0008, # BACKSPACE
+ 0x0017: 0x0087, # CONTROL
+ 0x001a: 0x0092, # CONTROL
+ 0x001b: 0x008f, # CONTROL
+ 0x0020: 0x0080, # CONTROL
+ 0x0021: 0x0081, # CONTROL
+ 0x0022: 0x0082, # CONTROL
+ 0x0023: 0x0083, # CONTROL
+ 0x0024: 0x0084, # CONTROL
+ 0x0025: 0x000a, # LINE FEED
+ 0x0026: 0x0017, # END OF TRANSMISSION BLOCK
+ 0x0027: 0x001b, # ESCAPE
+ 0x0028: 0x0088, # CONTROL
+ 0x0029: 0x0089, # CONTROL
+ 0x002a: 0x008a, # CONTROL
+ 0x002b: 0x008b, # CONTROL
+ 0x002c: 0x008c, # CONTROL
+ 0x002d: 0x0005, # ENQUIRY
+ 0x002e: 0x0006, # ACKNOWLEDGE
+ 0x002f: 0x0007, # BELL
+ 0x0030: 0x0090, # CONTROL
+ 0x0031: 0x0091, # CONTROL
+ 0x0032: 0x0016, # SYNCHRONOUS IDLE
+ 0x0033: 0x0093, # CONTROL
+ 0x0034: 0x0094, # CONTROL
+ 0x0035: 0x0095, # CONTROL
+ 0x0036: 0x0096, # CONTROL
+ 0x0037: 0x0004, # END OF TRANSMISSION
+ 0x0038: 0x0098, # CONTROL
+ 0x0039: 0x0099, # CONTROL
+ 0x003a: 0x009a, # CONTROL
+ 0x003b: 0x009b, # CONTROL
+ 0x003c: 0x0014, # DEVICE CONTROL FOUR
+ 0x003d: 0x0015, # NEGATIVE ACKNOWLEDGE
+ 0x003e: 0x009e, # CONTROL
+ 0x003f: 0x001a, # SUBSTITUTE
+ 0x0040: 0x0020, # SPACE
+ 0x0041: 0x00a0, # NO-BREAK SPACE
+ 0x0042: 0x00e2, # LATIN SMALL LETTER A WITH CIRCUMFLEX
+ 0x0043: 0x00e4, # LATIN SMALL LETTER A WITH DIAERESIS
+ 0x0044: 0x00e0, # LATIN SMALL LETTER A WITH GRAVE
+ 0x0045: 0x00e1, # LATIN SMALL LETTER A WITH ACUTE
+ 0x0046: 0x00e3, # LATIN SMALL LETTER A WITH TILDE
+ 0x0047: 0x00e5, # LATIN SMALL LETTER A WITH RING ABOVE
+ 0x0048: 0x007b, # LEFT CURLY BRACKET
+ 0x0049: 0x00f1, # LATIN SMALL LETTER N WITH TILDE
+ 0x004a: 0x00c7, # LATIN CAPITAL LETTER C WITH CEDILLA
+ 0x004b: 0x002e, # FULL STOP
+ 0x004c: 0x003c, # LESS-THAN SIGN
+ 0x004d: 0x0028, # LEFT PARENTHESIS
+ 0x004e: 0x002b, # PLUS SIGN
+ 0x004f: 0x0021, # EXCLAMATION MARK
+ 0x0050: 0x0026, # AMPERSAND
+ 0x0051: 0x00e9, # LATIN SMALL LETTER E WITH ACUTE
+ 0x0052: 0x00ea, # LATIN SMALL LETTER E WITH CIRCUMFLEX
+ 0x0053: 0x00eb, # LATIN SMALL LETTER E WITH DIAERESIS
+ 0x0054: 0x00e8, # LATIN SMALL LETTER E WITH GRAVE
+ 0x0055: 0x00ed, # LATIN SMALL LETTER I WITH ACUTE
+ 0x0056: 0x00ee, # LATIN SMALL LETTER I WITH CIRCUMFLEX
+ 0x0057: 0x00ef, # LATIN SMALL LETTER I WITH DIAERESIS
+ 0x0058: 0x00ec, # LATIN SMALL LETTER I WITH GRAVE
+ 0x0059: 0x00df, # LATIN SMALL LETTER SHARP S (GERMAN)
+ 0x005a: 0x011e, # LATIN CAPITAL LETTER G WITH BREVE
+ 0x005b: 0x0130, # LATIN CAPITAL LETTER I WITH DOT ABOVE
+ 0x005c: 0x002a, # ASTERISK
+ 0x005d: 0x0029, # RIGHT PARENTHESIS
+ 0x005e: 0x003b, # SEMICOLON
+ 0x005f: 0x005e, # CIRCUMFLEX ACCENT
+ 0x0060: 0x002d, # HYPHEN-MINUS
+ 0x0061: 0x002f, # SOLIDUS
+ 0x0062: 0x00c2, # LATIN CAPITAL LETTER A WITH CIRCUMFLEX
+ 0x0063: 0x00c4, # LATIN CAPITAL LETTER A WITH DIAERESIS
+ 0x0064: 0x00c0, # LATIN CAPITAL LETTER A WITH GRAVE
+ 0x0065: 0x00c1, # LATIN CAPITAL LETTER A WITH ACUTE
+ 0x0066: 0x00c3, # LATIN CAPITAL LETTER A WITH TILDE
+ 0x0067: 0x00c5, # LATIN CAPITAL LETTER A WITH RING ABOVE
+ 0x0068: 0x005b, # LEFT SQUARE BRACKET
+ 0x0069: 0x00d1, # LATIN CAPITAL LETTER N WITH TILDE
+ 0x006a: 0x015f, # LATIN SMALL LETTER S WITH CEDILLA
+ 0x006b: 0x002c, # COMMA
+ 0x006c: 0x0025, # PERCENT SIGN
+ 0x006d: 0x005f, # LOW LINE
+ 0x006e: 0x003e, # GREATER-THAN SIGN
+ 0x006f: 0x003f, # QUESTION MARK
+ 0x0070: 0x00f8, # LATIN SMALL LETTER O WITH STROKE
+ 0x0071: 0x00c9, # LATIN CAPITAL LETTER E WITH ACUTE
+ 0x0072: 0x00ca, # LATIN CAPITAL LETTER E WITH CIRCUMFLEX
+ 0x0073: 0x00cb, # LATIN CAPITAL LETTER E WITH DIAERESIS
+ 0x0074: 0x00c8, # LATIN CAPITAL LETTER E WITH GRAVE
+ 0x0075: 0x00cd, # LATIN CAPITAL LETTER I WITH ACUTE
+ 0x0076: 0x00ce, # LATIN CAPITAL LETTER I WITH CIRCUMFLEX
+ 0x0077: 0x00cf, # LATIN CAPITAL LETTER I WITH DIAERESIS
+ 0x0078: 0x00cc, # LATIN CAPITAL LETTER I WITH GRAVE
+ 0x0079: 0x0131, # LATIN SMALL LETTER DOTLESS I
+ 0x007a: 0x003a, # COLON
+ 0x007b: 0x00d6, # LATIN CAPITAL LETTER O WITH DIAERESIS
+ 0x007c: 0x015e, # LATIN CAPITAL LETTER S WITH CEDILLA
+ 0x007d: 0x0027, # APOSTROPHE
+ 0x007e: 0x003d, # EQUALS SIGN
+ 0x007f: 0x00dc, # LATIN CAPITAL LETTER U WITH DIAERESIS
+ 0x0080: 0x00d8, # LATIN CAPITAL LETTER O WITH STROKE
+ 0x0081: 0x0061, # LATIN SMALL LETTER A
+ 0x0082: 0x0062, # LATIN SMALL LETTER B
+ 0x0083: 0x0063, # LATIN SMALL LETTER C
+ 0x0084: 0x0064, # LATIN SMALL LETTER D
+ 0x0085: 0x0065, # LATIN SMALL LETTER E
+ 0x0086: 0x0066, # LATIN SMALL LETTER F
+ 0x0087: 0x0067, # LATIN SMALL LETTER G
+ 0x0088: 0x0068, # LATIN SMALL LETTER H
+ 0x0089: 0x0069, # LATIN SMALL LETTER I
+ 0x008a: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x008b: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x008c: 0x007d, # RIGHT CURLY BRACKET
+ 0x008d: 0x0060, # GRAVE ACCENT
+ 0x008e: 0x00a6, # BROKEN BAR
+ 0x008f: 0x00b1, # PLUS-MINUS SIGN
+ 0x0090: 0x00b0, # DEGREE SIGN
+ 0x0091: 0x006a, # LATIN SMALL LETTER J
+ 0x0092: 0x006b, # LATIN SMALL LETTER K
+ 0x0093: 0x006c, # LATIN SMALL LETTER L
+ 0x0094: 0x006d, # LATIN SMALL LETTER M
+ 0x0095: 0x006e, # LATIN SMALL LETTER N
+ 0x0096: 0x006f, # LATIN SMALL LETTER O
+ 0x0097: 0x0070, # LATIN SMALL LETTER P
+ 0x0098: 0x0071, # LATIN SMALL LETTER Q
+ 0x0099: 0x0072, # LATIN SMALL LETTER R
+ 0x009a: 0x00aa, # FEMININE ORDINAL INDICATOR
+ 0x009b: 0x00ba, # MASCULINE ORDINAL INDICATOR
+ 0x009c: 0x00e6, # LATIN SMALL LIGATURE AE
+ 0x009d: 0x00b8, # CEDILLA
+ 0x009e: 0x00c6, # LATIN CAPITAL LIGATURE AE
+ 0x009f: 0x00a4, # CURRENCY SIGN
+ 0x00a0: 0x00b5, # MICRO SIGN
+ 0x00a1: 0x00f6, # LATIN SMALL LETTER O WITH DIAERESIS
+ 0x00a2: 0x0073, # LATIN SMALL LETTER S
+ 0x00a3: 0x0074, # LATIN SMALL LETTER T
+ 0x00a4: 0x0075, # LATIN SMALL LETTER U
+ 0x00a5: 0x0076, # LATIN SMALL LETTER V
+ 0x00a6: 0x0077, # LATIN SMALL LETTER W
+ 0x00a7: 0x0078, # LATIN SMALL LETTER X
+ 0x00a8: 0x0079, # LATIN SMALL LETTER Y
+ 0x00a9: 0x007a, # LATIN SMALL LETTER Z
+ 0x00aa: 0x00a1, # INVERTED EXCLAMATION MARK
+ 0x00ab: 0x00bf, # INVERTED QUESTION MARK
+ 0x00ac: 0x005d, # RIGHT SQUARE BRACKET
+ 0x00ad: 0x0024, # DOLLAR SIGN
+ 0x00ae: 0x0040, # COMMERCIAL AT
+ 0x00af: 0x00ae, # REGISTERED SIGN
+ 0x00b0: 0x00a2, # CENT SIGN
+ 0x00b1: 0x00a3, # POUND SIGN
+ 0x00b2: 0x00a5, # YEN SIGN
+ 0x00b3: 0x00b7, # MIDDLE DOT
+ 0x00b4: 0x00a9, # COPYRIGHT SIGN
+ 0x00b5: 0x00a7, # SECTION SIGN
+ 0x00b7: 0x00bc, # VULGAR FRACTION ONE QUARTER
+ 0x00b8: 0x00bd, # VULGAR FRACTION ONE HALF
+ 0x00b9: 0x00be, # VULGAR FRACTION THREE QUARTERS
+ 0x00ba: 0x00ac, # NOT SIGN
+ 0x00bb: 0x007c, # VERTICAL LINE
+ 0x00bc: 0x00af, # MACRON
+ 0x00bd: 0x00a8, # DIAERESIS
+ 0x00be: 0x00b4, # ACUTE ACCENT
+ 0x00bf: 0x00d7, # MULTIPLICATION SIGN
+ 0x00c0: 0x00e7, # LATIN SMALL LETTER C WITH CEDILLA
+ 0x00c1: 0x0041, # LATIN CAPITAL LETTER A
+ 0x00c2: 0x0042, # LATIN CAPITAL LETTER B
+ 0x00c3: 0x0043, # LATIN CAPITAL LETTER C
+ 0x00c4: 0x0044, # LATIN CAPITAL LETTER D
+ 0x00c5: 0x0045, # LATIN CAPITAL LETTER E
+ 0x00c6: 0x0046, # LATIN CAPITAL LETTER F
+ 0x00c7: 0x0047, # LATIN CAPITAL LETTER G
+ 0x00c8: 0x0048, # LATIN CAPITAL LETTER H
+ 0x00c9: 0x0049, # LATIN CAPITAL LETTER I
+ 0x00ca: 0x00ad, # SOFT HYPHEN
+ 0x00cb: 0x00f4, # LATIN SMALL LETTER O WITH CIRCUMFLEX
+ 0x00cc: 0x007e, # TILDE
+ 0x00cd: 0x00f2, # LATIN SMALL LETTER O WITH GRAVE
+ 0x00ce: 0x00f3, # LATIN SMALL LETTER O WITH ACUTE
+ 0x00cf: 0x00f5, # LATIN SMALL LETTER O WITH TILDE
+ 0x00d0: 0x011f, # LATIN SMALL LETTER G WITH BREVE
+ 0x00d1: 0x004a, # LATIN CAPITAL LETTER J
+ 0x00d2: 0x004b, # LATIN CAPITAL LETTER K
+ 0x00d3: 0x004c, # LATIN CAPITAL LETTER L
+ 0x00d4: 0x004d, # LATIN CAPITAL LETTER M
+ 0x00d5: 0x004e, # LATIN CAPITAL LETTER N
+ 0x00d6: 0x004f, # LATIN CAPITAL LETTER O
+ 0x00d7: 0x0050, # LATIN CAPITAL LETTER P
+ 0x00d8: 0x0051, # LATIN CAPITAL LETTER Q
+ 0x00d9: 0x0052, # LATIN CAPITAL LETTER R
+ 0x00da: 0x00b9, # SUPERSCRIPT ONE
+ 0x00db: 0x00fb, # LATIN SMALL LETTER U WITH CIRCUMFLEX
+ 0x00dc: 0x005c, # REVERSE SOLIDUS
+ 0x00dd: 0x00f9, # LATIN SMALL LETTER U WITH GRAVE
+ 0x00de: 0x00fa, # LATIN SMALL LETTER U WITH ACUTE
+ 0x00df: 0x00ff, # LATIN SMALL LETTER Y WITH DIAERESIS
+ 0x00e0: 0x00fc, # LATIN SMALL LETTER U WITH DIAERESIS
+ 0x00e1: 0x00f7, # DIVISION SIGN
+ 0x00e2: 0x0053, # LATIN CAPITAL LETTER S
+ 0x00e3: 0x0054, # LATIN CAPITAL LETTER T
+ 0x00e4: 0x0055, # LATIN CAPITAL LETTER U
+ 0x00e5: 0x0056, # LATIN CAPITAL LETTER V
+ 0x00e6: 0x0057, # LATIN CAPITAL LETTER W
+ 0x00e7: 0x0058, # LATIN CAPITAL LETTER X
+ 0x00e8: 0x0059, # LATIN CAPITAL LETTER Y
+ 0x00e9: 0x005a, # LATIN CAPITAL LETTER Z
+ 0x00ea: 0x00b2, # SUPERSCRIPT TWO
+ 0x00eb: 0x00d4, # LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+ 0x00ec: 0x0023, # NUMBER SIGN
+ 0x00ed: 0x00d2, # LATIN CAPITAL LETTER O WITH GRAVE
+ 0x00ee: 0x00d3, # LATIN CAPITAL LETTER O WITH ACUTE
+ 0x00ef: 0x00d5, # LATIN CAPITAL LETTER O WITH TILDE
+ 0x00f0: 0x0030, # DIGIT ZERO
+ 0x00f1: 0x0031, # DIGIT ONE
+ 0x00f2: 0x0032, # DIGIT TWO
+ 0x00f3: 0x0033, # DIGIT THREE
+ 0x00f4: 0x0034, # DIGIT FOUR
+ 0x00f5: 0x0035, # DIGIT FIVE
+ 0x00f6: 0x0036, # DIGIT SIX
+ 0x00f7: 0x0037, # DIGIT SEVEN
+ 0x00f8: 0x0038, # DIGIT EIGHT
+ 0x00f9: 0x0039, # DIGIT NINE
+ 0x00fa: 0x00b3, # SUPERSCRIPT THREE
+ 0x00fb: 0x00db, # LATIN CAPITAL LETTER U WITH CIRCUMFLEX
+ 0x00fc: 0x0022, # QUOTATION MARK
+ 0x00fd: 0x00d9, # LATIN CAPITAL LETTER U WITH GRAVE
+ 0x00fe: 0x00da, # LATIN CAPITAL LETTER U WITH ACUTE
+ 0x00ff: 0x009f, # CONTROL
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp1250.py b/lib/jython/Lib/encodings/cp1250.py new file mode 100644 index 000000000..2a728905a --- /dev/null +++ b/lib/jython/Lib/encodings/cp1250.py @@ -0,0 +1,125 @@ +""" Python Character Mapping Codec generated from 'CP1250.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x20ac, # EURO SIGN
+ 0x0081: None, # UNDEFINED
+ 0x0082: 0x201a, # SINGLE LOW-9 QUOTATION MARK
+ 0x0083: None, # UNDEFINED
+ 0x0084: 0x201e, # DOUBLE LOW-9 QUOTATION MARK
+ 0x0085: 0x2026, # HORIZONTAL ELLIPSIS
+ 0x0086: 0x2020, # DAGGER
+ 0x0087: 0x2021, # DOUBLE DAGGER
+ 0x0088: None, # UNDEFINED
+ 0x0089: 0x2030, # PER MILLE SIGN
+ 0x008a: 0x0160, # LATIN CAPITAL LETTER S WITH CARON
+ 0x008b: 0x2039, # SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ 0x008c: 0x015a, # LATIN CAPITAL LETTER S WITH ACUTE
+ 0x008d: 0x0164, # LATIN CAPITAL LETTER T WITH CARON
+ 0x008e: 0x017d, # LATIN CAPITAL LETTER Z WITH CARON
+ 0x008f: 0x0179, # LATIN CAPITAL LETTER Z WITH ACUTE
+ 0x0090: None, # UNDEFINED
+ 0x0091: 0x2018, # LEFT SINGLE QUOTATION MARK
+ 0x0092: 0x2019, # RIGHT SINGLE QUOTATION MARK
+ 0x0093: 0x201c, # LEFT DOUBLE QUOTATION MARK
+ 0x0094: 0x201d, # RIGHT DOUBLE QUOTATION MARK
+ 0x0095: 0x2022, # BULLET
+ 0x0096: 0x2013, # EN DASH
+ 0x0097: 0x2014, # EM DASH
+ 0x0098: None, # UNDEFINED
+ 0x0099: 0x2122, # TRADE MARK SIGN
+ 0x009a: 0x0161, # LATIN SMALL LETTER S WITH CARON
+ 0x009b: 0x203a, # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ 0x009c: 0x015b, # LATIN SMALL LETTER S WITH ACUTE
+ 0x009d: 0x0165, # LATIN SMALL LETTER T WITH CARON
+ 0x009e: 0x017e, # LATIN SMALL LETTER Z WITH CARON
+ 0x009f: 0x017a, # LATIN SMALL LETTER Z WITH ACUTE
+ 0x00a1: 0x02c7, # CARON
+ 0x00a2: 0x02d8, # BREVE
+ 0x00a3: 0x0141, # LATIN CAPITAL LETTER L WITH STROKE
+ 0x00a5: 0x0104, # LATIN CAPITAL LETTER A WITH OGONEK
+ 0x00aa: 0x015e, # LATIN CAPITAL LETTER S WITH CEDILLA
+ 0x00af: 0x017b, # LATIN CAPITAL LETTER Z WITH DOT ABOVE
+ 0x00b2: 0x02db, # OGONEK
+ 0x00b3: 0x0142, # LATIN SMALL LETTER L WITH STROKE
+ 0x00b9: 0x0105, # LATIN SMALL LETTER A WITH OGONEK
+ 0x00ba: 0x015f, # LATIN SMALL LETTER S WITH CEDILLA
+ 0x00bc: 0x013d, # LATIN CAPITAL LETTER L WITH CARON
+ 0x00bd: 0x02dd, # DOUBLE ACUTE ACCENT
+ 0x00be: 0x013e, # LATIN SMALL LETTER L WITH CARON
+ 0x00bf: 0x017c, # LATIN SMALL LETTER Z WITH DOT ABOVE
+ 0x00c0: 0x0154, # LATIN CAPITAL LETTER R WITH ACUTE
+ 0x00c3: 0x0102, # LATIN CAPITAL LETTER A WITH BREVE
+ 0x00c5: 0x0139, # LATIN CAPITAL LETTER L WITH ACUTE
+ 0x00c6: 0x0106, # LATIN CAPITAL LETTER C WITH ACUTE
+ 0x00c8: 0x010c, # LATIN CAPITAL LETTER C WITH CARON
+ 0x00ca: 0x0118, # LATIN CAPITAL LETTER E WITH OGONEK
+ 0x00cc: 0x011a, # LATIN CAPITAL LETTER E WITH CARON
+ 0x00cf: 0x010e, # LATIN CAPITAL LETTER D WITH CARON
+ 0x00d0: 0x0110, # LATIN CAPITAL LETTER D WITH STROKE
+ 0x00d1: 0x0143, # LATIN CAPITAL LETTER N WITH ACUTE
+ 0x00d2: 0x0147, # LATIN CAPITAL LETTER N WITH CARON
+ 0x00d5: 0x0150, # LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
+ 0x00d8: 0x0158, # LATIN CAPITAL LETTER R WITH CARON
+ 0x00d9: 0x016e, # LATIN CAPITAL LETTER U WITH RING ABOVE
+ 0x00db: 0x0170, # LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
+ 0x00de: 0x0162, # LATIN CAPITAL LETTER T WITH CEDILLA
+ 0x00e0: 0x0155, # LATIN SMALL LETTER R WITH ACUTE
+ 0x00e3: 0x0103, # LATIN SMALL LETTER A WITH BREVE
+ 0x00e5: 0x013a, # LATIN SMALL LETTER L WITH ACUTE
+ 0x00e6: 0x0107, # LATIN SMALL LETTER C WITH ACUTE
+ 0x00e8: 0x010d, # LATIN SMALL LETTER C WITH CARON
+ 0x00ea: 0x0119, # LATIN SMALL LETTER E WITH OGONEK
+ 0x00ec: 0x011b, # LATIN SMALL LETTER E WITH CARON
+ 0x00ef: 0x010f, # LATIN SMALL LETTER D WITH CARON
+ 0x00f0: 0x0111, # LATIN SMALL LETTER D WITH STROKE
+ 0x00f1: 0x0144, # LATIN SMALL LETTER N WITH ACUTE
+ 0x00f2: 0x0148, # LATIN SMALL LETTER N WITH CARON
+ 0x00f5: 0x0151, # LATIN SMALL LETTER O WITH DOUBLE ACUTE
+ 0x00f8: 0x0159, # LATIN SMALL LETTER R WITH CARON
+ 0x00f9: 0x016f, # LATIN SMALL LETTER U WITH RING ABOVE
+ 0x00fb: 0x0171, # LATIN SMALL LETTER U WITH DOUBLE ACUTE
+ 0x00fe: 0x0163, # LATIN SMALL LETTER T WITH CEDILLA
+ 0x00ff: 0x02d9, # DOT ABOVE
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp1251.py b/lib/jython/Lib/encodings/cp1251.py new file mode 100644 index 000000000..45119dfec --- /dev/null +++ b/lib/jython/Lib/encodings/cp1251.py @@ -0,0 +1,159 @@ +""" Python Character Mapping Codec generated from 'CP1251.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x0402, # CYRILLIC CAPITAL LETTER DJE
+ 0x0081: 0x0403, # CYRILLIC CAPITAL LETTER GJE
+ 0x0082: 0x201a, # SINGLE LOW-9 QUOTATION MARK
+ 0x0083: 0x0453, # CYRILLIC SMALL LETTER GJE
+ 0x0084: 0x201e, # DOUBLE LOW-9 QUOTATION MARK
+ 0x0085: 0x2026, # HORIZONTAL ELLIPSIS
+ 0x0086: 0x2020, # DAGGER
+ 0x0087: 0x2021, # DOUBLE DAGGER
+ 0x0088: 0x20ac, # EURO SIGN
+ 0x0089: 0x2030, # PER MILLE SIGN
+ 0x008a: 0x0409, # CYRILLIC CAPITAL LETTER LJE
+ 0x008b: 0x2039, # SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ 0x008c: 0x040a, # CYRILLIC CAPITAL LETTER NJE
+ 0x008d: 0x040c, # CYRILLIC CAPITAL LETTER KJE
+ 0x008e: 0x040b, # CYRILLIC CAPITAL LETTER TSHE
+ 0x008f: 0x040f, # CYRILLIC CAPITAL LETTER DZHE
+ 0x0090: 0x0452, # CYRILLIC SMALL LETTER DJE
+ 0x0091: 0x2018, # LEFT SINGLE QUOTATION MARK
+ 0x0092: 0x2019, # RIGHT SINGLE QUOTATION MARK
+ 0x0093: 0x201c, # LEFT DOUBLE QUOTATION MARK
+ 0x0094: 0x201d, # RIGHT DOUBLE QUOTATION MARK
+ 0x0095: 0x2022, # BULLET
+ 0x0096: 0x2013, # EN DASH
+ 0x0097: 0x2014, # EM DASH
+ 0x0098: None, # UNDEFINED
+ 0x0099: 0x2122, # TRADE MARK SIGN
+ 0x009a: 0x0459, # CYRILLIC SMALL LETTER LJE
+ 0x009b: 0x203a, # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ 0x009c: 0x045a, # CYRILLIC SMALL LETTER NJE
+ 0x009d: 0x045c, # CYRILLIC SMALL LETTER KJE
+ 0x009e: 0x045b, # CYRILLIC SMALL LETTER TSHE
+ 0x009f: 0x045f, # CYRILLIC SMALL LETTER DZHE
+ 0x00a1: 0x040e, # CYRILLIC CAPITAL LETTER SHORT U
+ 0x00a2: 0x045e, # CYRILLIC SMALL LETTER SHORT U
+ 0x00a3: 0x0408, # CYRILLIC CAPITAL LETTER JE
+ 0x00a5: 0x0490, # CYRILLIC CAPITAL LETTER GHE WITH UPTURN
+ 0x00a8: 0x0401, # CYRILLIC CAPITAL LETTER IO
+ 0x00aa: 0x0404, # CYRILLIC CAPITAL LETTER UKRAINIAN IE
+ 0x00af: 0x0407, # CYRILLIC CAPITAL LETTER YI
+ 0x00b2: 0x0406, # CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
+ 0x00b3: 0x0456, # CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
+ 0x00b4: 0x0491, # CYRILLIC SMALL LETTER GHE WITH UPTURN
+ 0x00b8: 0x0451, # CYRILLIC SMALL LETTER IO
+ 0x00b9: 0x2116, # NUMERO SIGN
+ 0x00ba: 0x0454, # CYRILLIC SMALL LETTER UKRAINIAN IE
+ 0x00bc: 0x0458, # CYRILLIC SMALL LETTER JE
+ 0x00bd: 0x0405, # CYRILLIC CAPITAL LETTER DZE
+ 0x00be: 0x0455, # CYRILLIC SMALL LETTER DZE
+ 0x00bf: 0x0457, # CYRILLIC SMALL LETTER YI
+ 0x00c0: 0x0410, # CYRILLIC CAPITAL LETTER A
+ 0x00c1: 0x0411, # CYRILLIC CAPITAL LETTER BE
+ 0x00c2: 0x0412, # CYRILLIC CAPITAL LETTER VE
+ 0x00c3: 0x0413, # CYRILLIC CAPITAL LETTER GHE
+ 0x00c4: 0x0414, # CYRILLIC CAPITAL LETTER DE
+ 0x00c5: 0x0415, # CYRILLIC CAPITAL LETTER IE
+ 0x00c6: 0x0416, # CYRILLIC CAPITAL LETTER ZHE
+ 0x00c7: 0x0417, # CYRILLIC CAPITAL LETTER ZE
+ 0x00c8: 0x0418, # CYRILLIC CAPITAL LETTER I
+ 0x00c9: 0x0419, # CYRILLIC CAPITAL LETTER SHORT I
+ 0x00ca: 0x041a, # CYRILLIC CAPITAL LETTER KA
+ 0x00cb: 0x041b, # CYRILLIC CAPITAL LETTER EL
+ 0x00cc: 0x041c, # CYRILLIC CAPITAL LETTER EM
+ 0x00cd: 0x041d, # CYRILLIC CAPITAL LETTER EN
+ 0x00ce: 0x041e, # CYRILLIC CAPITAL LETTER O
+ 0x00cf: 0x041f, # CYRILLIC CAPITAL LETTER PE
+ 0x00d0: 0x0420, # CYRILLIC CAPITAL LETTER ER
+ 0x00d1: 0x0421, # CYRILLIC CAPITAL LETTER ES
+ 0x00d2: 0x0422, # CYRILLIC CAPITAL LETTER TE
+ 0x00d3: 0x0423, # CYRILLIC CAPITAL LETTER U
+ 0x00d4: 0x0424, # CYRILLIC CAPITAL LETTER EF
+ 0x00d5: 0x0425, # CYRILLIC CAPITAL LETTER HA
+ 0x00d6: 0x0426, # CYRILLIC CAPITAL LETTER TSE
+ 0x00d7: 0x0427, # CYRILLIC CAPITAL LETTER CHE
+ 0x00d8: 0x0428, # CYRILLIC CAPITAL LETTER SHA
+ 0x00d9: 0x0429, # CYRILLIC CAPITAL LETTER SHCHA
+ 0x00da: 0x042a, # CYRILLIC CAPITAL LETTER HARD SIGN
+ 0x00db: 0x042b, # CYRILLIC CAPITAL LETTER YERU
+ 0x00dc: 0x042c, # CYRILLIC CAPITAL LETTER SOFT SIGN
+ 0x00dd: 0x042d, # CYRILLIC CAPITAL LETTER E
+ 0x00de: 0x042e, # CYRILLIC CAPITAL LETTER YU
+ 0x00df: 0x042f, # CYRILLIC CAPITAL LETTER YA
+ 0x00e0: 0x0430, # CYRILLIC SMALL LETTER A
+ 0x00e1: 0x0431, # CYRILLIC SMALL LETTER BE
+ 0x00e2: 0x0432, # CYRILLIC SMALL LETTER VE
+ 0x00e3: 0x0433, # CYRILLIC SMALL LETTER GHE
+ 0x00e4: 0x0434, # CYRILLIC SMALL LETTER DE
+ 0x00e5: 0x0435, # CYRILLIC SMALL LETTER IE
+ 0x00e6: 0x0436, # CYRILLIC SMALL LETTER ZHE
+ 0x00e7: 0x0437, # CYRILLIC SMALL LETTER ZE
+ 0x00e8: 0x0438, # CYRILLIC SMALL LETTER I
+ 0x00e9: 0x0439, # CYRILLIC SMALL LETTER SHORT I
+ 0x00ea: 0x043a, # CYRILLIC SMALL LETTER KA
+ 0x00eb: 0x043b, # CYRILLIC SMALL LETTER EL
+ 0x00ec: 0x043c, # CYRILLIC SMALL LETTER EM
+ 0x00ed: 0x043d, # CYRILLIC SMALL LETTER EN
+ 0x00ee: 0x043e, # CYRILLIC SMALL LETTER O
+ 0x00ef: 0x043f, # CYRILLIC SMALL LETTER PE
+ 0x00f0: 0x0440, # CYRILLIC SMALL LETTER ER
+ 0x00f1: 0x0441, # CYRILLIC SMALL LETTER ES
+ 0x00f2: 0x0442, # CYRILLIC SMALL LETTER TE
+ 0x00f3: 0x0443, # CYRILLIC SMALL LETTER U
+ 0x00f4: 0x0444, # CYRILLIC SMALL LETTER EF
+ 0x00f5: 0x0445, # CYRILLIC SMALL LETTER HA
+ 0x00f6: 0x0446, # CYRILLIC SMALL LETTER TSE
+ 0x00f7: 0x0447, # CYRILLIC SMALL LETTER CHE
+ 0x00f8: 0x0448, # CYRILLIC SMALL LETTER SHA
+ 0x00f9: 0x0449, # CYRILLIC SMALL LETTER SHCHA
+ 0x00fa: 0x044a, # CYRILLIC SMALL LETTER HARD SIGN
+ 0x00fb: 0x044b, # CYRILLIC SMALL LETTER YERU
+ 0x00fc: 0x044c, # CYRILLIC SMALL LETTER SOFT SIGN
+ 0x00fd: 0x044d, # CYRILLIC SMALL LETTER E
+ 0x00fe: 0x044e, # CYRILLIC SMALL LETTER YU
+ 0x00ff: 0x044f, # CYRILLIC SMALL LETTER YA
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp1252.py b/lib/jython/Lib/encodings/cp1252.py new file mode 100644 index 000000000..5a8bc1833 --- /dev/null +++ b/lib/jython/Lib/encodings/cp1252.py @@ -0,0 +1,78 @@ +""" Python Character Mapping Codec generated from 'CP1252.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x20ac, # EURO SIGN
+ 0x0081: None, # UNDEFINED
+ 0x0082: 0x201a, # SINGLE LOW-9 QUOTATION MARK
+ 0x0083: 0x0192, # LATIN SMALL LETTER F WITH HOOK
+ 0x0084: 0x201e, # DOUBLE LOW-9 QUOTATION MARK
+ 0x0085: 0x2026, # HORIZONTAL ELLIPSIS
+ 0x0086: 0x2020, # DAGGER
+ 0x0087: 0x2021, # DOUBLE DAGGER
+ 0x0088: 0x02c6, # MODIFIER LETTER CIRCUMFLEX ACCENT
+ 0x0089: 0x2030, # PER MILLE SIGN
+ 0x008a: 0x0160, # LATIN CAPITAL LETTER S WITH CARON
+ 0x008b: 0x2039, # SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ 0x008c: 0x0152, # LATIN CAPITAL LIGATURE OE
+ 0x008d: None, # UNDEFINED
+ 0x008e: 0x017d, # LATIN CAPITAL LETTER Z WITH CARON
+ 0x008f: None, # UNDEFINED
+ 0x0090: None, # UNDEFINED
+ 0x0091: 0x2018, # LEFT SINGLE QUOTATION MARK
+ 0x0092: 0x2019, # RIGHT SINGLE QUOTATION MARK
+ 0x0093: 0x201c, # LEFT DOUBLE QUOTATION MARK
+ 0x0094: 0x201d, # RIGHT DOUBLE QUOTATION MARK
+ 0x0095: 0x2022, # BULLET
+ 0x0096: 0x2013, # EN DASH
+ 0x0097: 0x2014, # EM DASH
+ 0x0098: 0x02dc, # SMALL TILDE
+ 0x0099: 0x2122, # TRADE MARK SIGN
+ 0x009a: 0x0161, # LATIN SMALL LETTER S WITH CARON
+ 0x009b: 0x203a, # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ 0x009c: 0x0153, # LATIN SMALL LIGATURE OE
+ 0x009d: None, # UNDEFINED
+ 0x009e: 0x017e, # LATIN SMALL LETTER Z WITH CARON
+ 0x009f: 0x0178, # LATIN CAPITAL LETTER Y WITH DIAERESIS
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp1253.py b/lib/jython/Lib/encodings/cp1253.py new file mode 100644 index 000000000..94940c3de --- /dev/null +++ b/lib/jython/Lib/encodings/cp1253.py @@ -0,0 +1,153 @@ +""" Python Character Mapping Codec generated from 'CP1253.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x20ac, # EURO SIGN
+ 0x0081: None, # UNDEFINED
+ 0x0082: 0x201a, # SINGLE LOW-9 QUOTATION MARK
+ 0x0083: 0x0192, # LATIN SMALL LETTER F WITH HOOK
+ 0x0084: 0x201e, # DOUBLE LOW-9 QUOTATION MARK
+ 0x0085: 0x2026, # HORIZONTAL ELLIPSIS
+ 0x0086: 0x2020, # DAGGER
+ 0x0087: 0x2021, # DOUBLE DAGGER
+ 0x0088: None, # UNDEFINED
+ 0x0089: 0x2030, # PER MILLE SIGN
+ 0x008a: None, # UNDEFINED
+ 0x008b: 0x2039, # SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ 0x008c: None, # UNDEFINED
+ 0x008d: None, # UNDEFINED
+ 0x008e: None, # UNDEFINED
+ 0x008f: None, # UNDEFINED
+ 0x0090: None, # UNDEFINED
+ 0x0091: 0x2018, # LEFT SINGLE QUOTATION MARK
+ 0x0092: 0x2019, # RIGHT SINGLE QUOTATION MARK
+ 0x0093: 0x201c, # LEFT DOUBLE QUOTATION MARK
+ 0x0094: 0x201d, # RIGHT DOUBLE QUOTATION MARK
+ 0x0095: 0x2022, # BULLET
+ 0x0096: 0x2013, # EN DASH
+ 0x0097: 0x2014, # EM DASH
+ 0x0098: None, # UNDEFINED
+ 0x0099: 0x2122, # TRADE MARK SIGN
+ 0x009a: None, # UNDEFINED
+ 0x009b: 0x203a, # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ 0x009c: None, # UNDEFINED
+ 0x009d: None, # UNDEFINED
+ 0x009e: None, # UNDEFINED
+ 0x009f: None, # UNDEFINED
+ 0x00a1: 0x0385, # GREEK DIALYTIKA TONOS
+ 0x00a2: 0x0386, # GREEK CAPITAL LETTER ALPHA WITH TONOS
+ 0x00aa: None, # UNDEFINED
+ 0x00af: 0x2015, # HORIZONTAL BAR
+ 0x00b4: 0x0384, # GREEK TONOS
+ 0x00b8: 0x0388, # GREEK CAPITAL LETTER EPSILON WITH TONOS
+ 0x00b9: 0x0389, # GREEK CAPITAL LETTER ETA WITH TONOS
+ 0x00ba: 0x038a, # GREEK CAPITAL LETTER IOTA WITH TONOS
+ 0x00bc: 0x038c, # GREEK CAPITAL LETTER OMICRON WITH TONOS
+ 0x00be: 0x038e, # GREEK CAPITAL LETTER UPSILON WITH TONOS
+ 0x00bf: 0x038f, # GREEK CAPITAL LETTER OMEGA WITH TONOS
+ 0x00c0: 0x0390, # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
+ 0x00c1: 0x0391, # GREEK CAPITAL LETTER ALPHA
+ 0x00c2: 0x0392, # GREEK CAPITAL LETTER BETA
+ 0x00c3: 0x0393, # GREEK CAPITAL LETTER GAMMA
+ 0x00c4: 0x0394, # GREEK CAPITAL LETTER DELTA
+ 0x00c5: 0x0395, # GREEK CAPITAL LETTER EPSILON
+ 0x00c6: 0x0396, # GREEK CAPITAL LETTER ZETA
+ 0x00c7: 0x0397, # GREEK CAPITAL LETTER ETA
+ 0x00c8: 0x0398, # GREEK CAPITAL LETTER THETA
+ 0x00c9: 0x0399, # GREEK CAPITAL LETTER IOTA
+ 0x00ca: 0x039a, # GREEK CAPITAL LETTER KAPPA
+ 0x00cb: 0x039b, # GREEK CAPITAL LETTER LAMDA
+ 0x00cc: 0x039c, # GREEK CAPITAL LETTER MU
+ 0x00cd: 0x039d, # GREEK CAPITAL LETTER NU
+ 0x00ce: 0x039e, # GREEK CAPITAL LETTER XI
+ 0x00cf: 0x039f, # GREEK CAPITAL LETTER OMICRON
+ 0x00d0: 0x03a0, # GREEK CAPITAL LETTER PI
+ 0x00d1: 0x03a1, # GREEK CAPITAL LETTER RHO
+ 0x00d2: None, # UNDEFINED
+ 0x00d3: 0x03a3, # GREEK CAPITAL LETTER SIGMA
+ 0x00d4: 0x03a4, # GREEK CAPITAL LETTER TAU
+ 0x00d5: 0x03a5, # GREEK CAPITAL LETTER UPSILON
+ 0x00d6: 0x03a6, # GREEK CAPITAL LETTER PHI
+ 0x00d7: 0x03a7, # GREEK CAPITAL LETTER CHI
+ 0x00d8: 0x03a8, # GREEK CAPITAL LETTER PSI
+ 0x00d9: 0x03a9, # GREEK CAPITAL LETTER OMEGA
+ 0x00da: 0x03aa, # GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
+ 0x00db: 0x03ab, # GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
+ 0x00dc: 0x03ac, # GREEK SMALL LETTER ALPHA WITH TONOS
+ 0x00dd: 0x03ad, # GREEK SMALL LETTER EPSILON WITH TONOS
+ 0x00de: 0x03ae, # GREEK SMALL LETTER ETA WITH TONOS
+ 0x00df: 0x03af, # GREEK SMALL LETTER IOTA WITH TONOS
+ 0x00e0: 0x03b0, # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
+ 0x00e1: 0x03b1, # GREEK SMALL LETTER ALPHA
+ 0x00e2: 0x03b2, # GREEK SMALL LETTER BETA
+ 0x00e3: 0x03b3, # GREEK SMALL LETTER GAMMA
+ 0x00e4: 0x03b4, # GREEK SMALL LETTER DELTA
+ 0x00e5: 0x03b5, # GREEK SMALL LETTER EPSILON
+ 0x00e6: 0x03b6, # GREEK SMALL LETTER ZETA
+ 0x00e7: 0x03b7, # GREEK SMALL LETTER ETA
+ 0x00e8: 0x03b8, # GREEK SMALL LETTER THETA
+ 0x00e9: 0x03b9, # GREEK SMALL LETTER IOTA
+ 0x00ea: 0x03ba, # GREEK SMALL LETTER KAPPA
+ 0x00eb: 0x03bb, # GREEK SMALL LETTER LAMDA
+ 0x00ec: 0x03bc, # GREEK SMALL LETTER MU
+ 0x00ed: 0x03bd, # GREEK SMALL LETTER NU
+ 0x00ee: 0x03be, # GREEK SMALL LETTER XI
+ 0x00ef: 0x03bf, # GREEK SMALL LETTER OMICRON
+ 0x00f0: 0x03c0, # GREEK SMALL LETTER PI
+ 0x00f1: 0x03c1, # GREEK SMALL LETTER RHO
+ 0x00f2: 0x03c2, # GREEK SMALL LETTER FINAL SIGMA
+ 0x00f3: 0x03c3, # GREEK SMALL LETTER SIGMA
+ 0x00f4: 0x03c4, # GREEK SMALL LETTER TAU
+ 0x00f5: 0x03c5, # GREEK SMALL LETTER UPSILON
+ 0x00f6: 0x03c6, # GREEK SMALL LETTER PHI
+ 0x00f7: 0x03c7, # GREEK SMALL LETTER CHI
+ 0x00f8: 0x03c8, # GREEK SMALL LETTER PSI
+ 0x00f9: 0x03c9, # GREEK SMALL LETTER OMEGA
+ 0x00fa: 0x03ca, # GREEK SMALL LETTER IOTA WITH DIALYTIKA
+ 0x00fb: 0x03cb, # GREEK SMALL LETTER UPSILON WITH DIALYTIKA
+ 0x00fc: 0x03cc, # GREEK SMALL LETTER OMICRON WITH TONOS
+ 0x00fd: 0x03cd, # GREEK SMALL LETTER UPSILON WITH TONOS
+ 0x00fe: 0x03ce, # GREEK SMALL LETTER OMEGA WITH TONOS
+ 0x00ff: None, # UNDEFINED
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp1254.py b/lib/jython/Lib/encodings/cp1254.py new file mode 100644 index 000000000..819f7a966 --- /dev/null +++ b/lib/jython/Lib/encodings/cp1254.py @@ -0,0 +1,84 @@ +""" Python Character Mapping Codec generated from 'CP1254.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x20ac, # EURO SIGN
+ 0x0081: None, # UNDEFINED
+ 0x0082: 0x201a, # SINGLE LOW-9 QUOTATION MARK
+ 0x0083: 0x0192, # LATIN SMALL LETTER F WITH HOOK
+ 0x0084: 0x201e, # DOUBLE LOW-9 QUOTATION MARK
+ 0x0085: 0x2026, # HORIZONTAL ELLIPSIS
+ 0x0086: 0x2020, # DAGGER
+ 0x0087: 0x2021, # DOUBLE DAGGER
+ 0x0088: 0x02c6, # MODIFIER LETTER CIRCUMFLEX ACCENT
+ 0x0089: 0x2030, # PER MILLE SIGN
+ 0x008a: 0x0160, # LATIN CAPITAL LETTER S WITH CARON
+ 0x008b: 0x2039, # SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ 0x008c: 0x0152, # LATIN CAPITAL LIGATURE OE
+ 0x008d: None, # UNDEFINED
+ 0x008e: None, # UNDEFINED
+ 0x008f: None, # UNDEFINED
+ 0x0090: None, # UNDEFINED
+ 0x0091: 0x2018, # LEFT SINGLE QUOTATION MARK
+ 0x0092: 0x2019, # RIGHT SINGLE QUOTATION MARK
+ 0x0093: 0x201c, # LEFT DOUBLE QUOTATION MARK
+ 0x0094: 0x201d, # RIGHT DOUBLE QUOTATION MARK
+ 0x0095: 0x2022, # BULLET
+ 0x0096: 0x2013, # EN DASH
+ 0x0097: 0x2014, # EM DASH
+ 0x0098: 0x02dc, # SMALL TILDE
+ 0x0099: 0x2122, # TRADE MARK SIGN
+ 0x009a: 0x0161, # LATIN SMALL LETTER S WITH CARON
+ 0x009b: 0x203a, # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ 0x009c: 0x0153, # LATIN SMALL LIGATURE OE
+ 0x009d: None, # UNDEFINED
+ 0x009e: None, # UNDEFINED
+ 0x009f: 0x0178, # LATIN CAPITAL LETTER Y WITH DIAERESIS
+ 0x00d0: 0x011e, # LATIN CAPITAL LETTER G WITH BREVE
+ 0x00dd: 0x0130, # LATIN CAPITAL LETTER I WITH DOT ABOVE
+ 0x00de: 0x015e, # LATIN CAPITAL LETTER S WITH CEDILLA
+ 0x00f0: 0x011f, # LATIN SMALL LETTER G WITH BREVE
+ 0x00fd: 0x0131, # LATIN SMALL LETTER DOTLESS I
+ 0x00fe: 0x015f, # LATIN SMALL LETTER S WITH CEDILLA
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp1255.py b/lib/jython/Lib/encodings/cp1255.py new file mode 100644 index 000000000..e07a84c81 --- /dev/null +++ b/lib/jython/Lib/encodings/cp1255.py @@ -0,0 +1,145 @@ +""" Python Character Mapping Codec generated from 'CP1255.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x20ac, # EURO SIGN
+ 0x0081: None, # UNDEFINED
+ 0x0082: 0x201a, # SINGLE LOW-9 QUOTATION MARK
+ 0x0083: 0x0192, # LATIN SMALL LETTER F WITH HOOK
+ 0x0084: 0x201e, # DOUBLE LOW-9 QUOTATION MARK
+ 0x0085: 0x2026, # HORIZONTAL ELLIPSIS
+ 0x0086: 0x2020, # DAGGER
+ 0x0087: 0x2021, # DOUBLE DAGGER
+ 0x0088: 0x02c6, # MODIFIER LETTER CIRCUMFLEX ACCENT
+ 0x0089: 0x2030, # PER MILLE SIGN
+ 0x008a: None, # UNDEFINED
+ 0x008b: 0x2039, # SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ 0x008c: None, # UNDEFINED
+ 0x008d: None, # UNDEFINED
+ 0x008e: None, # UNDEFINED
+ 0x008f: None, # UNDEFINED
+ 0x0090: None, # UNDEFINED
+ 0x0091: 0x2018, # LEFT SINGLE QUOTATION MARK
+ 0x0092: 0x2019, # RIGHT SINGLE QUOTATION MARK
+ 0x0093: 0x201c, # LEFT DOUBLE QUOTATION MARK
+ 0x0094: 0x201d, # RIGHT DOUBLE QUOTATION MARK
+ 0x0095: 0x2022, # BULLET
+ 0x0096: 0x2013, # EN DASH
+ 0x0097: 0x2014, # EM DASH
+ 0x0098: 0x02dc, # SMALL TILDE
+ 0x0099: 0x2122, # TRADE MARK SIGN
+ 0x009a: None, # UNDEFINED
+ 0x009b: 0x203a, # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ 0x009c: None, # UNDEFINED
+ 0x009d: None, # UNDEFINED
+ 0x009e: None, # UNDEFINED
+ 0x009f: None, # UNDEFINED
+ 0x00a4: 0x20aa, # NEW SHEQEL SIGN
+ 0x00aa: 0x00d7, # MULTIPLICATION SIGN
+ 0x00ba: 0x00f7, # DIVISION SIGN
+ 0x00c0: 0x05b0, # HEBREW POINT SHEVA
+ 0x00c1: 0x05b1, # HEBREW POINT HATAF SEGOL
+ 0x00c2: 0x05b2, # HEBREW POINT HATAF PATAH
+ 0x00c3: 0x05b3, # HEBREW POINT HATAF QAMATS
+ 0x00c4: 0x05b4, # HEBREW POINT HIRIQ
+ 0x00c5: 0x05b5, # HEBREW POINT TSERE
+ 0x00c6: 0x05b6, # HEBREW POINT SEGOL
+ 0x00c7: 0x05b7, # HEBREW POINT PATAH
+ 0x00c8: 0x05b8, # HEBREW POINT QAMATS
+ 0x00c9: 0x05b9, # HEBREW POINT HOLAM
+ 0x00ca: None, # UNDEFINED
+ 0x00cb: 0x05bb, # HEBREW POINT QUBUTS
+ 0x00cc: 0x05bc, # HEBREW POINT DAGESH OR MAPIQ
+ 0x00cd: 0x05bd, # HEBREW POINT METEG
+ 0x00ce: 0x05be, # HEBREW PUNCTUATION MAQAF
+ 0x00cf: 0x05bf, # HEBREW POINT RAFE
+ 0x00d0: 0x05c0, # HEBREW PUNCTUATION PASEQ
+ 0x00d1: 0x05c1, # HEBREW POINT SHIN DOT
+ 0x00d2: 0x05c2, # HEBREW POINT SIN DOT
+ 0x00d3: 0x05c3, # HEBREW PUNCTUATION SOF PASUQ
+ 0x00d4: 0x05f0, # HEBREW LIGATURE YIDDISH DOUBLE VAV
+ 0x00d5: 0x05f1, # HEBREW LIGATURE YIDDISH VAV YOD
+ 0x00d6: 0x05f2, # HEBREW LIGATURE YIDDISH DOUBLE YOD
+ 0x00d7: 0x05f3, # HEBREW PUNCTUATION GERESH
+ 0x00d8: 0x05f4, # HEBREW PUNCTUATION GERSHAYIM
+ 0x00d9: None, # UNDEFINED
+ 0x00da: None, # UNDEFINED
+ 0x00db: None, # UNDEFINED
+ 0x00dc: None, # UNDEFINED
+ 0x00dd: None, # UNDEFINED
+ 0x00de: None, # UNDEFINED
+ 0x00df: None, # UNDEFINED
+ 0x00e0: 0x05d0, # HEBREW LETTER ALEF
+ 0x00e1: 0x05d1, # HEBREW LETTER BET
+ 0x00e2: 0x05d2, # HEBREW LETTER GIMEL
+ 0x00e3: 0x05d3, # HEBREW LETTER DALET
+ 0x00e4: 0x05d4, # HEBREW LETTER HE
+ 0x00e5: 0x05d5, # HEBREW LETTER VAV
+ 0x00e6: 0x05d6, # HEBREW LETTER ZAYIN
+ 0x00e7: 0x05d7, # HEBREW LETTER HET
+ 0x00e8: 0x05d8, # HEBREW LETTER TET
+ 0x00e9: 0x05d9, # HEBREW LETTER YOD
+ 0x00ea: 0x05da, # HEBREW LETTER FINAL KAF
+ 0x00eb: 0x05db, # HEBREW LETTER KAF
+ 0x00ec: 0x05dc, # HEBREW LETTER LAMED
+ 0x00ed: 0x05dd, # HEBREW LETTER FINAL MEM
+ 0x00ee: 0x05de, # HEBREW LETTER MEM
+ 0x00ef: 0x05df, # HEBREW LETTER FINAL NUN
+ 0x00f0: 0x05e0, # HEBREW LETTER NUN
+ 0x00f1: 0x05e1, # HEBREW LETTER SAMEKH
+ 0x00f2: 0x05e2, # HEBREW LETTER AYIN
+ 0x00f3: 0x05e3, # HEBREW LETTER FINAL PE
+ 0x00f4: 0x05e4, # HEBREW LETTER PE
+ 0x00f5: 0x05e5, # HEBREW LETTER FINAL TSADI
+ 0x00f6: 0x05e6, # HEBREW LETTER TSADI
+ 0x00f7: 0x05e7, # HEBREW LETTER QOF
+ 0x00f8: 0x05e8, # HEBREW LETTER RESH
+ 0x00f9: 0x05e9, # HEBREW LETTER SHIN
+ 0x00fa: 0x05ea, # HEBREW LETTER TAV
+ 0x00fb: None, # UNDEFINED
+ 0x00fc: None, # UNDEFINED
+ 0x00fd: 0x200e, # LEFT-TO-RIGHT MARK
+ 0x00fe: 0x200f, # RIGHT-TO-LEFT MARK
+ 0x00ff: None, # UNDEFINED
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp1256.py b/lib/jython/Lib/encodings/cp1256.py new file mode 100644 index 000000000..9bda9e091 --- /dev/null +++ b/lib/jython/Lib/encodings/cp1256.py @@ -0,0 +1,131 @@ +""" Python Character Mapping Codec generated from 'CP1256.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x20ac, # EURO SIGN
+ 0x0081: 0x067e, # ARABIC LETTER PEH
+ 0x0082: 0x201a, # SINGLE LOW-9 QUOTATION MARK
+ 0x0083: 0x0192, # LATIN SMALL LETTER F WITH HOOK
+ 0x0084: 0x201e, # DOUBLE LOW-9 QUOTATION MARK
+ 0x0085: 0x2026, # HORIZONTAL ELLIPSIS
+ 0x0086: 0x2020, # DAGGER
+ 0x0087: 0x2021, # DOUBLE DAGGER
+ 0x0088: 0x02c6, # MODIFIER LETTER CIRCUMFLEX ACCENT
+ 0x0089: 0x2030, # PER MILLE SIGN
+ 0x008a: 0x0679, # ARABIC LETTER TTEH
+ 0x008b: 0x2039, # SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ 0x008c: 0x0152, # LATIN CAPITAL LIGATURE OE
+ 0x008d: 0x0686, # ARABIC LETTER TCHEH
+ 0x008e: 0x0698, # ARABIC LETTER JEH
+ 0x008f: 0x0688, # ARABIC LETTER DDAL
+ 0x0090: 0x06af, # ARABIC LETTER GAF
+ 0x0091: 0x2018, # LEFT SINGLE QUOTATION MARK
+ 0x0092: 0x2019, # RIGHT SINGLE QUOTATION MARK
+ 0x0093: 0x201c, # LEFT DOUBLE QUOTATION MARK
+ 0x0094: 0x201d, # RIGHT DOUBLE QUOTATION MARK
+ 0x0095: 0x2022, # BULLET
+ 0x0096: 0x2013, # EN DASH
+ 0x0097: 0x2014, # EM DASH
+ 0x0098: 0x06a9, # ARABIC LETTER KEHEH
+ 0x0099: 0x2122, # TRADE MARK SIGN
+ 0x009a: 0x0691, # ARABIC LETTER RREH
+ 0x009b: 0x203a, # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ 0x009c: 0x0153, # LATIN SMALL LIGATURE OE
+ 0x009d: 0x200c, # ZERO WIDTH NON-JOINER
+ 0x009e: 0x200d, # ZERO WIDTH JOINER
+ 0x009f: 0x06ba, # ARABIC LETTER NOON GHUNNA
+ 0x00a1: 0x060c, # ARABIC COMMA
+ 0x00aa: 0x06be, # ARABIC LETTER HEH DOACHASHMEE
+ 0x00ba: 0x061b, # ARABIC SEMICOLON
+ 0x00bf: 0x061f, # ARABIC QUESTION MARK
+ 0x00c0: 0x06c1, # ARABIC LETTER HEH GOAL
+ 0x00c1: 0x0621, # ARABIC LETTER HAMZA
+ 0x00c2: 0x0622, # ARABIC LETTER ALEF WITH MADDA ABOVE
+ 0x00c3: 0x0623, # ARABIC LETTER ALEF WITH HAMZA ABOVE
+ 0x00c4: 0x0624, # ARABIC LETTER WAW WITH HAMZA ABOVE
+ 0x00c5: 0x0625, # ARABIC LETTER ALEF WITH HAMZA BELOW
+ 0x00c6: 0x0626, # ARABIC LETTER YEH WITH HAMZA ABOVE
+ 0x00c7: 0x0627, # ARABIC LETTER ALEF
+ 0x00c8: 0x0628, # ARABIC LETTER BEH
+ 0x00c9: 0x0629, # ARABIC LETTER TEH MARBUTA
+ 0x00ca: 0x062a, # ARABIC LETTER TEH
+ 0x00cb: 0x062b, # ARABIC LETTER THEH
+ 0x00cc: 0x062c, # ARABIC LETTER JEEM
+ 0x00cd: 0x062d, # ARABIC LETTER HAH
+ 0x00ce: 0x062e, # ARABIC LETTER KHAH
+ 0x00cf: 0x062f, # ARABIC LETTER DAL
+ 0x00d0: 0x0630, # ARABIC LETTER THAL
+ 0x00d1: 0x0631, # ARABIC LETTER REH
+ 0x00d2: 0x0632, # ARABIC LETTER ZAIN
+ 0x00d3: 0x0633, # ARABIC LETTER SEEN
+ 0x00d4: 0x0634, # ARABIC LETTER SHEEN
+ 0x00d5: 0x0635, # ARABIC LETTER SAD
+ 0x00d6: 0x0636, # ARABIC LETTER DAD
+ 0x00d8: 0x0637, # ARABIC LETTER TAH
+ 0x00d9: 0x0638, # ARABIC LETTER ZAH
+ 0x00da: 0x0639, # ARABIC LETTER AIN
+ 0x00db: 0x063a, # ARABIC LETTER GHAIN
+ 0x00dc: 0x0640, # ARABIC TATWEEL
+ 0x00dd: 0x0641, # ARABIC LETTER FEH
+ 0x00de: 0x0642, # ARABIC LETTER QAF
+ 0x00df: 0x0643, # ARABIC LETTER KAF
+ 0x00e1: 0x0644, # ARABIC LETTER LAM
+ 0x00e3: 0x0645, # ARABIC LETTER MEEM
+ 0x00e4: 0x0646, # ARABIC LETTER NOON
+ 0x00e5: 0x0647, # ARABIC LETTER HEH
+ 0x00e6: 0x0648, # ARABIC LETTER WAW
+ 0x00ec: 0x0649, # ARABIC LETTER ALEF MAKSURA
+ 0x00ed: 0x064a, # ARABIC LETTER YEH
+ 0x00f0: 0x064b, # ARABIC FATHATAN
+ 0x00f1: 0x064c, # ARABIC DAMMATAN
+ 0x00f2: 0x064d, # ARABIC KASRATAN
+ 0x00f3: 0x064e, # ARABIC FATHA
+ 0x00f5: 0x064f, # ARABIC DAMMA
+ 0x00f6: 0x0650, # ARABIC KASRA
+ 0x00f8: 0x0651, # ARABIC SHADDA
+ 0x00fa: 0x0652, # ARABIC SUKUN
+ 0x00fd: 0x200e, # LEFT-TO-RIGHT MARK
+ 0x00fe: 0x200f, # RIGHT-TO-LEFT MARK
+ 0x00ff: 0x06d2, # ARABIC LETTER YEH BARREE
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp1257.py b/lib/jython/Lib/encodings/cp1257.py new file mode 100644 index 000000000..776ab6858 --- /dev/null +++ b/lib/jython/Lib/encodings/cp1257.py @@ -0,0 +1,133 @@ +""" Python Character Mapping Codec generated from 'CP1257.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x20ac, # EURO SIGN
+ 0x0081: None, # UNDEFINED
+ 0x0082: 0x201a, # SINGLE LOW-9 QUOTATION MARK
+ 0x0083: None, # UNDEFINED
+ 0x0084: 0x201e, # DOUBLE LOW-9 QUOTATION MARK
+ 0x0085: 0x2026, # HORIZONTAL ELLIPSIS
+ 0x0086: 0x2020, # DAGGER
+ 0x0087: 0x2021, # DOUBLE DAGGER
+ 0x0088: None, # UNDEFINED
+ 0x0089: 0x2030, # PER MILLE SIGN
+ 0x008a: None, # UNDEFINED
+ 0x008b: 0x2039, # SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ 0x008c: None, # UNDEFINED
+ 0x008d: 0x00a8, # DIAERESIS
+ 0x008e: 0x02c7, # CARON
+ 0x008f: 0x00b8, # CEDILLA
+ 0x0090: None, # UNDEFINED
+ 0x0091: 0x2018, # LEFT SINGLE QUOTATION MARK
+ 0x0092: 0x2019, # RIGHT SINGLE QUOTATION MARK
+ 0x0093: 0x201c, # LEFT DOUBLE QUOTATION MARK
+ 0x0094: 0x201d, # RIGHT DOUBLE QUOTATION MARK
+ 0x0095: 0x2022, # BULLET
+ 0x0096: 0x2013, # EN DASH
+ 0x0097: 0x2014, # EM DASH
+ 0x0098: None, # UNDEFINED
+ 0x0099: 0x2122, # TRADE MARK SIGN
+ 0x009a: None, # UNDEFINED
+ 0x009b: 0x203a, # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ 0x009c: None, # UNDEFINED
+ 0x009d: 0x00af, # MACRON
+ 0x009e: 0x02db, # OGONEK
+ 0x009f: None, # UNDEFINED
+ 0x00a1: None, # UNDEFINED
+ 0x00a5: None, # UNDEFINED
+ 0x00a8: 0x00d8, # LATIN CAPITAL LETTER O WITH STROKE
+ 0x00aa: 0x0156, # LATIN CAPITAL LETTER R WITH CEDILLA
+ 0x00af: 0x00c6, # LATIN CAPITAL LETTER AE
+ 0x00b8: 0x00f8, # LATIN SMALL LETTER O WITH STROKE
+ 0x00ba: 0x0157, # LATIN SMALL LETTER R WITH CEDILLA
+ 0x00bf: 0x00e6, # LATIN SMALL LETTER AE
+ 0x00c0: 0x0104, # LATIN CAPITAL LETTER A WITH OGONEK
+ 0x00c1: 0x012e, # LATIN CAPITAL LETTER I WITH OGONEK
+ 0x00c2: 0x0100, # LATIN CAPITAL LETTER A WITH MACRON
+ 0x00c3: 0x0106, # LATIN CAPITAL LETTER C WITH ACUTE
+ 0x00c6: 0x0118, # LATIN CAPITAL LETTER E WITH OGONEK
+ 0x00c7: 0x0112, # LATIN CAPITAL LETTER E WITH MACRON
+ 0x00c8: 0x010c, # LATIN CAPITAL LETTER C WITH CARON
+ 0x00ca: 0x0179, # LATIN CAPITAL LETTER Z WITH ACUTE
+ 0x00cb: 0x0116, # LATIN CAPITAL LETTER E WITH DOT ABOVE
+ 0x00cc: 0x0122, # LATIN CAPITAL LETTER G WITH CEDILLA
+ 0x00cd: 0x0136, # LATIN CAPITAL LETTER K WITH CEDILLA
+ 0x00ce: 0x012a, # LATIN CAPITAL LETTER I WITH MACRON
+ 0x00cf: 0x013b, # LATIN CAPITAL LETTER L WITH CEDILLA
+ 0x00d0: 0x0160, # LATIN CAPITAL LETTER S WITH CARON
+ 0x00d1: 0x0143, # LATIN CAPITAL LETTER N WITH ACUTE
+ 0x00d2: 0x0145, # LATIN CAPITAL LETTER N WITH CEDILLA
+ 0x00d4: 0x014c, # LATIN CAPITAL LETTER O WITH MACRON
+ 0x00d8: 0x0172, # LATIN CAPITAL LETTER U WITH OGONEK
+ 0x00d9: 0x0141, # LATIN CAPITAL LETTER L WITH STROKE
+ 0x00da: 0x015a, # LATIN CAPITAL LETTER S WITH ACUTE
+ 0x00db: 0x016a, # LATIN CAPITAL LETTER U WITH MACRON
+ 0x00dd: 0x017b, # LATIN CAPITAL LETTER Z WITH DOT ABOVE
+ 0x00de: 0x017d, # LATIN CAPITAL LETTER Z WITH CARON
+ 0x00e0: 0x0105, # LATIN SMALL LETTER A WITH OGONEK
+ 0x00e1: 0x012f, # LATIN SMALL LETTER I WITH OGONEK
+ 0x00e2: 0x0101, # LATIN SMALL LETTER A WITH MACRON
+ 0x00e3: 0x0107, # LATIN SMALL LETTER C WITH ACUTE
+ 0x00e6: 0x0119, # LATIN SMALL LETTER E WITH OGONEK
+ 0x00e7: 0x0113, # LATIN SMALL LETTER E WITH MACRON
+ 0x00e8: 0x010d, # LATIN SMALL LETTER C WITH CARON
+ 0x00ea: 0x017a, # LATIN SMALL LETTER Z WITH ACUTE
+ 0x00eb: 0x0117, # LATIN SMALL LETTER E WITH DOT ABOVE
+ 0x00ec: 0x0123, # LATIN SMALL LETTER G WITH CEDILLA
+ 0x00ed: 0x0137, # LATIN SMALL LETTER K WITH CEDILLA
+ 0x00ee: 0x012b, # LATIN SMALL LETTER I WITH MACRON
+ 0x00ef: 0x013c, # LATIN SMALL LETTER L WITH CEDILLA
+ 0x00f0: 0x0161, # LATIN SMALL LETTER S WITH CARON
+ 0x00f1: 0x0144, # LATIN SMALL LETTER N WITH ACUTE
+ 0x00f2: 0x0146, # LATIN SMALL LETTER N WITH CEDILLA
+ 0x00f4: 0x014d, # LATIN SMALL LETTER O WITH MACRON
+ 0x00f8: 0x0173, # LATIN SMALL LETTER U WITH OGONEK
+ 0x00f9: 0x0142, # LATIN SMALL LETTER L WITH STROKE
+ 0x00fa: 0x015b, # LATIN SMALL LETTER S WITH ACUTE
+ 0x00fb: 0x016b, # LATIN SMALL LETTER U WITH MACRON
+ 0x00fd: 0x017c, # LATIN SMALL LETTER Z WITH DOT ABOVE
+ 0x00fe: 0x017e, # LATIN SMALL LETTER Z WITH CARON
+ 0x00ff: 0x02d9, # DOT ABOVE
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp1258.py b/lib/jython/Lib/encodings/cp1258.py new file mode 100644 index 000000000..9547488f7 --- /dev/null +++ b/lib/jython/Lib/encodings/cp1258.py @@ -0,0 +1,92 @@ +""" Python Character Mapping Codec generated from 'CP1258.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x20ac, # EURO SIGN
+ 0x0081: None, # UNDEFINED
+ 0x0082: 0x201a, # SINGLE LOW-9 QUOTATION MARK
+ 0x0083: 0x0192, # LATIN SMALL LETTER F WITH HOOK
+ 0x0084: 0x201e, # DOUBLE LOW-9 QUOTATION MARK
+ 0x0085: 0x2026, # HORIZONTAL ELLIPSIS
+ 0x0086: 0x2020, # DAGGER
+ 0x0087: 0x2021, # DOUBLE DAGGER
+ 0x0088: 0x02c6, # MODIFIER LETTER CIRCUMFLEX ACCENT
+ 0x0089: 0x2030, # PER MILLE SIGN
+ 0x008a: None, # UNDEFINED
+ 0x008b: 0x2039, # SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ 0x008c: 0x0152, # LATIN CAPITAL LIGATURE OE
+ 0x008d: None, # UNDEFINED
+ 0x008e: None, # UNDEFINED
+ 0x008f: None, # UNDEFINED
+ 0x0090: None, # UNDEFINED
+ 0x0091: 0x2018, # LEFT SINGLE QUOTATION MARK
+ 0x0092: 0x2019, # RIGHT SINGLE QUOTATION MARK
+ 0x0093: 0x201c, # LEFT DOUBLE QUOTATION MARK
+ 0x0094: 0x201d, # RIGHT DOUBLE QUOTATION MARK
+ 0x0095: 0x2022, # BULLET
+ 0x0096: 0x2013, # EN DASH
+ 0x0097: 0x2014, # EM DASH
+ 0x0098: 0x02dc, # SMALL TILDE
+ 0x0099: 0x2122, # TRADE MARK SIGN
+ 0x009a: None, # UNDEFINED
+ 0x009b: 0x203a, # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ 0x009c: 0x0153, # LATIN SMALL LIGATURE OE
+ 0x009d: None, # UNDEFINED
+ 0x009e: None, # UNDEFINED
+ 0x009f: 0x0178, # LATIN CAPITAL LETTER Y WITH DIAERESIS
+ 0x00c3: 0x0102, # LATIN CAPITAL LETTER A WITH BREVE
+ 0x00cc: 0x0300, # COMBINING GRAVE ACCENT
+ 0x00d0: 0x0110, # LATIN CAPITAL LETTER D WITH STROKE
+ 0x00d2: 0x0309, # COMBINING HOOK ABOVE
+ 0x00d5: 0x01a0, # LATIN CAPITAL LETTER O WITH HORN
+ 0x00dd: 0x01af, # LATIN CAPITAL LETTER U WITH HORN
+ 0x00de: 0x0303, # COMBINING TILDE
+ 0x00e3: 0x0103, # LATIN SMALL LETTER A WITH BREVE
+ 0x00ec: 0x0301, # COMBINING ACUTE ACCENT
+ 0x00f0: 0x0111, # LATIN SMALL LETTER D WITH STROKE
+ 0x00f2: 0x0323, # COMBINING DOT BELOW
+ 0x00f5: 0x01a1, # LATIN SMALL LETTER O WITH HORN
+ 0x00fd: 0x01b0, # LATIN SMALL LETTER U WITH HORN
+ 0x00fe: 0x20ab, # DONG SIGN
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp424.py b/lib/jython/Lib/encodings/cp424.py new file mode 100644 index 000000000..7f9b80986 --- /dev/null +++ b/lib/jython/Lib/encodings/cp424.py @@ -0,0 +1,282 @@ +""" Python Character Mapping Codec generated from 'CP424.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0004: 0x009c, # SELECT
+ 0x0005: 0x0009, # HORIZONTAL TABULATION
+ 0x0006: 0x0086, # REQUIRED NEW LINE
+ 0x0007: 0x007f, # DELETE
+ 0x0008: 0x0097, # GRAPHIC ESCAPE
+ 0x0009: 0x008d, # SUPERSCRIPT
+ 0x000a: 0x008e, # REPEAT
+ 0x0014: 0x009d, # RESTORE/ENABLE PRESENTATION
+ 0x0015: 0x0085, # NEW LINE
+ 0x0016: 0x0008, # BACKSPACE
+ 0x0017: 0x0087, # PROGRAM OPERATOR COMMUNICATION
+ 0x001a: 0x0092, # UNIT BACK SPACE
+ 0x001b: 0x008f, # CUSTOMER USE ONE
+ 0x0020: 0x0080, # DIGIT SELECT
+ 0x0021: 0x0081, # START OF SIGNIFICANCE
+ 0x0022: 0x0082, # FIELD SEPARATOR
+ 0x0023: 0x0083, # WORD UNDERSCORE
+ 0x0024: 0x0084, # BYPASS OR INHIBIT PRESENTATION
+ 0x0025: 0x000a, # LINE FEED
+ 0x0026: 0x0017, # END OF TRANSMISSION BLOCK
+ 0x0027: 0x001b, # ESCAPE
+ 0x0028: 0x0088, # SET ATTRIBUTE
+ 0x0029: 0x0089, # START FIELD EXTENDED
+ 0x002a: 0x008a, # SET MODE OR SWITCH
+ 0x002b: 0x008b, # CONTROL SEQUENCE PREFIX
+ 0x002c: 0x008c, # MODIFY FIELD ATTRIBUTE
+ 0x002d: 0x0005, # ENQUIRY
+ 0x002e: 0x0006, # ACKNOWLEDGE
+ 0x002f: 0x0007, # BELL
+ 0x0030: 0x0090, # <reserved>
+ 0x0031: 0x0091, # <reserved>
+ 0x0032: 0x0016, # SYNCHRONOUS IDLE
+ 0x0033: 0x0093, # INDEX RETURN
+ 0x0034: 0x0094, # PRESENTATION POSITION
+ 0x0035: 0x0095, # TRANSPARENT
+ 0x0036: 0x0096, # NUMERIC BACKSPACE
+ 0x0037: 0x0004, # END OF TRANSMISSION
+ 0x0038: 0x0098, # SUBSCRIPT
+ 0x0039: 0x0099, # INDENT TABULATION
+ 0x003a: 0x009a, # REVERSE FORM FEED
+ 0x003b: 0x009b, # CUSTOMER USE THREE
+ 0x003c: 0x0014, # DEVICE CONTROL FOUR
+ 0x003d: 0x0015, # NEGATIVE ACKNOWLEDGE
+ 0x003e: 0x009e, # <reserved>
+ 0x003f: 0x001a, # SUBSTITUTE
+ 0x0040: 0x0020, # SPACE
+ 0x0041: 0x05d0, # HEBREW LETTER ALEF
+ 0x0042: 0x05d1, # HEBREW LETTER BET
+ 0x0043: 0x05d2, # HEBREW LETTER GIMEL
+ 0x0044: 0x05d3, # HEBREW LETTER DALET
+ 0x0045: 0x05d4, # HEBREW LETTER HE
+ 0x0046: 0x05d5, # HEBREW LETTER VAV
+ 0x0047: 0x05d6, # HEBREW LETTER ZAYIN
+ 0x0048: 0x05d7, # HEBREW LETTER HET
+ 0x0049: 0x05d8, # HEBREW LETTER TET
+ 0x004a: 0x00a2, # CENT SIGN
+ 0x004b: 0x002e, # FULL STOP
+ 0x004c: 0x003c, # LESS-THAN SIGN
+ 0x004d: 0x0028, # LEFT PARENTHESIS
+ 0x004e: 0x002b, # PLUS SIGN
+ 0x004f: 0x007c, # VERTICAL LINE
+ 0x0050: 0x0026, # AMPERSAND
+ 0x0051: 0x05d9, # HEBREW LETTER YOD
+ 0x0052: 0x05da, # HEBREW LETTER FINAL KAF
+ 0x0053: 0x05db, # HEBREW LETTER KAF
+ 0x0054: 0x05dc, # HEBREW LETTER LAMED
+ 0x0055: 0x05dd, # HEBREW LETTER FINAL MEM
+ 0x0056: 0x05de, # HEBREW LETTER MEM
+ 0x0057: 0x05df, # HEBREW LETTER FINAL NUN
+ 0x0058: 0x05e0, # HEBREW LETTER NUN
+ 0x0059: 0x05e1, # HEBREW LETTER SAMEKH
+ 0x005a: 0x0021, # EXCLAMATION MARK
+ 0x005b: 0x0024, # DOLLAR SIGN
+ 0x005c: 0x002a, # ASTERISK
+ 0x005d: 0x0029, # RIGHT PARENTHESIS
+ 0x005e: 0x003b, # SEMICOLON
+ 0x005f: 0x00ac, # NOT SIGN
+ 0x0060: 0x002d, # HYPHEN-MINUS
+ 0x0061: 0x002f, # SOLIDUS
+ 0x0062: 0x05e2, # HEBREW LETTER AYIN
+ 0x0063: 0x05e3, # HEBREW LETTER FINAL PE
+ 0x0064: 0x05e4, # HEBREW LETTER PE
+ 0x0065: 0x05e5, # HEBREW LETTER FINAL TSADI
+ 0x0066: 0x05e6, # HEBREW LETTER TSADI
+ 0x0067: 0x05e7, # HEBREW LETTER QOF
+ 0x0068: 0x05e8, # HEBREW LETTER RESH
+ 0x0069: 0x05e9, # HEBREW LETTER SHIN
+ 0x006a: 0x00a6, # BROKEN BAR
+ 0x006b: 0x002c, # COMMA
+ 0x006c: 0x0025, # PERCENT SIGN
+ 0x006d: 0x005f, # LOW LINE
+ 0x006e: 0x003e, # GREATER-THAN SIGN
+ 0x006f: 0x003f, # QUESTION MARK
+ 0x0070: None, # UNDEFINED
+ 0x0071: 0x05ea, # HEBREW LETTER TAV
+ 0x0072: None, # UNDEFINED
+ 0x0073: None, # UNDEFINED
+ 0x0074: 0x00a0, # NO-BREAK SPACE
+ 0x0075: None, # UNDEFINED
+ 0x0076: None, # UNDEFINED
+ 0x0077: None, # UNDEFINED
+ 0x0078: 0x2017, # DOUBLE LOW LINE
+ 0x0079: 0x0060, # GRAVE ACCENT
+ 0x007a: 0x003a, # COLON
+ 0x007b: 0x0023, # NUMBER SIGN
+ 0x007c: 0x0040, # COMMERCIAL AT
+ 0x007d: 0x0027, # APOSTROPHE
+ 0x007e: 0x003d, # EQUALS SIGN
+ 0x007f: 0x0022, # QUOTATION MARK
+ 0x0080: None, # UNDEFINED
+ 0x0081: 0x0061, # LATIN SMALL LETTER A
+ 0x0082: 0x0062, # LATIN SMALL LETTER B
+ 0x0083: 0x0063, # LATIN SMALL LETTER C
+ 0x0084: 0x0064, # LATIN SMALL LETTER D
+ 0x0085: 0x0065, # LATIN SMALL LETTER E
+ 0x0086: 0x0066, # LATIN SMALL LETTER F
+ 0x0087: 0x0067, # LATIN SMALL LETTER G
+ 0x0088: 0x0068, # LATIN SMALL LETTER H
+ 0x0089: 0x0069, # LATIN SMALL LETTER I
+ 0x008a: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x008b: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x008c: None, # UNDEFINED
+ 0x008d: None, # UNDEFINED
+ 0x008e: None, # UNDEFINED
+ 0x008f: 0x00b1, # PLUS-MINUS SIGN
+ 0x0090: 0x00b0, # DEGREE SIGN
+ 0x0091: 0x006a, # LATIN SMALL LETTER J
+ 0x0092: 0x006b, # LATIN SMALL LETTER K
+ 0x0093: 0x006c, # LATIN SMALL LETTER L
+ 0x0094: 0x006d, # LATIN SMALL LETTER M
+ 0x0095: 0x006e, # LATIN SMALL LETTER N
+ 0x0096: 0x006f, # LATIN SMALL LETTER O
+ 0x0097: 0x0070, # LATIN SMALL LETTER P
+ 0x0098: 0x0071, # LATIN SMALL LETTER Q
+ 0x0099: 0x0072, # LATIN SMALL LETTER R
+ 0x009a: None, # UNDEFINED
+ 0x009b: None, # UNDEFINED
+ 0x009c: None, # UNDEFINED
+ 0x009d: 0x00b8, # CEDILLA
+ 0x009e: None, # UNDEFINED
+ 0x009f: 0x00a4, # CURRENCY SIGN
+ 0x00a0: 0x00b5, # MICRO SIGN
+ 0x00a1: 0x007e, # TILDE
+ 0x00a2: 0x0073, # LATIN SMALL LETTER S
+ 0x00a3: 0x0074, # LATIN SMALL LETTER T
+ 0x00a4: 0x0075, # LATIN SMALL LETTER U
+ 0x00a5: 0x0076, # LATIN SMALL LETTER V
+ 0x00a6: 0x0077, # LATIN SMALL LETTER W
+ 0x00a7: 0x0078, # LATIN SMALL LETTER X
+ 0x00a8: 0x0079, # LATIN SMALL LETTER Y
+ 0x00a9: 0x007a, # LATIN SMALL LETTER Z
+ 0x00aa: None, # UNDEFINED
+ 0x00ab: None, # UNDEFINED
+ 0x00ac: None, # UNDEFINED
+ 0x00ad: None, # UNDEFINED
+ 0x00ae: None, # UNDEFINED
+ 0x00af: 0x00ae, # REGISTERED SIGN
+ 0x00b0: 0x005e, # CIRCUMFLEX ACCENT
+ 0x00b1: 0x00a3, # POUND SIGN
+ 0x00b2: 0x00a5, # YEN SIGN
+ 0x00b3: 0x00b7, # MIDDLE DOT
+ 0x00b4: 0x00a9, # COPYRIGHT SIGN
+ 0x00b5: 0x00a7, # SECTION SIGN
+ 0x00b7: 0x00bc, # VULGAR FRACTION ONE QUARTER
+ 0x00b8: 0x00bd, # VULGAR FRACTION ONE HALF
+ 0x00b9: 0x00be, # VULGAR FRACTION THREE QUARTERS
+ 0x00ba: 0x005b, # LEFT SQUARE BRACKET
+ 0x00bb: 0x005d, # RIGHT SQUARE BRACKET
+ 0x00bc: 0x00af, # MACRON
+ 0x00bd: 0x00a8, # DIAERESIS
+ 0x00be: 0x00b4, # ACUTE ACCENT
+ 0x00bf: 0x00d7, # MULTIPLICATION SIGN
+ 0x00c0: 0x007b, # LEFT CURLY BRACKET
+ 0x00c1: 0x0041, # LATIN CAPITAL LETTER A
+ 0x00c2: 0x0042, # LATIN CAPITAL LETTER B
+ 0x00c3: 0x0043, # LATIN CAPITAL LETTER C
+ 0x00c4: 0x0044, # LATIN CAPITAL LETTER D
+ 0x00c5: 0x0045, # LATIN CAPITAL LETTER E
+ 0x00c6: 0x0046, # LATIN CAPITAL LETTER F
+ 0x00c7: 0x0047, # LATIN CAPITAL LETTER G
+ 0x00c8: 0x0048, # LATIN CAPITAL LETTER H
+ 0x00c9: 0x0049, # LATIN CAPITAL LETTER I
+ 0x00ca: 0x00ad, # SOFT HYPHEN
+ 0x00cb: None, # UNDEFINED
+ 0x00cc: None, # UNDEFINED
+ 0x00cd: None, # UNDEFINED
+ 0x00ce: None, # UNDEFINED
+ 0x00cf: None, # UNDEFINED
+ 0x00d0: 0x007d, # RIGHT CURLY BRACKET
+ 0x00d1: 0x004a, # LATIN CAPITAL LETTER J
+ 0x00d2: 0x004b, # LATIN CAPITAL LETTER K
+ 0x00d3: 0x004c, # LATIN CAPITAL LETTER L
+ 0x00d4: 0x004d, # LATIN CAPITAL LETTER M
+ 0x00d5: 0x004e, # LATIN CAPITAL LETTER N
+ 0x00d6: 0x004f, # LATIN CAPITAL LETTER O
+ 0x00d7: 0x0050, # LATIN CAPITAL LETTER P
+ 0x00d8: 0x0051, # LATIN CAPITAL LETTER Q
+ 0x00d9: 0x0052, # LATIN CAPITAL LETTER R
+ 0x00da: 0x00b9, # SUPERSCRIPT ONE
+ 0x00db: None, # UNDEFINED
+ 0x00dc: None, # UNDEFINED
+ 0x00dd: None, # UNDEFINED
+ 0x00de: None, # UNDEFINED
+ 0x00df: None, # UNDEFINED
+ 0x00e0: 0x005c, # REVERSE SOLIDUS
+ 0x00e1: 0x00f7, # DIVISION SIGN
+ 0x00e2: 0x0053, # LATIN CAPITAL LETTER S
+ 0x00e3: 0x0054, # LATIN CAPITAL LETTER T
+ 0x00e4: 0x0055, # LATIN CAPITAL LETTER U
+ 0x00e5: 0x0056, # LATIN CAPITAL LETTER V
+ 0x00e6: 0x0057, # LATIN CAPITAL LETTER W
+ 0x00e7: 0x0058, # LATIN CAPITAL LETTER X
+ 0x00e8: 0x0059, # LATIN CAPITAL LETTER Y
+ 0x00e9: 0x005a, # LATIN CAPITAL LETTER Z
+ 0x00ea: 0x00b2, # SUPERSCRIPT TWO
+ 0x00eb: None, # UNDEFINED
+ 0x00ec: None, # UNDEFINED
+ 0x00ed: None, # UNDEFINED
+ 0x00ee: None, # UNDEFINED
+ 0x00ef: None, # UNDEFINED
+ 0x00f0: 0x0030, # DIGIT ZERO
+ 0x00f1: 0x0031, # DIGIT ONE
+ 0x00f2: 0x0032, # DIGIT TWO
+ 0x00f3: 0x0033, # DIGIT THREE
+ 0x00f4: 0x0034, # DIGIT FOUR
+ 0x00f5: 0x0035, # DIGIT FIVE
+ 0x00f6: 0x0036, # DIGIT SIX
+ 0x00f7: 0x0037, # DIGIT SEVEN
+ 0x00f8: 0x0038, # DIGIT EIGHT
+ 0x00f9: 0x0039, # DIGIT NINE
+ 0x00fa: 0x00b3, # SUPERSCRIPT THREE
+ 0x00fb: None, # UNDEFINED
+ 0x00fc: None, # UNDEFINED
+ 0x00fd: None, # UNDEFINED
+ 0x00fe: None, # UNDEFINED
+ 0x00ff: 0x009f, # EIGHT ONES
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp437.py b/lib/jython/Lib/encodings/cp437.py new file mode 100644 index 000000000..6a728300f --- /dev/null +++ b/lib/jython/Lib/encodings/cp437.py @@ -0,0 +1,174 @@ +""" Python Character Mapping Codec generated from 'CP437.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x00c7, # LATIN CAPITAL LETTER C WITH CEDILLA
+ 0x0081: 0x00fc, # LATIN SMALL LETTER U WITH DIAERESIS
+ 0x0082: 0x00e9, # LATIN SMALL LETTER E WITH ACUTE
+ 0x0083: 0x00e2, # LATIN SMALL LETTER A WITH CIRCUMFLEX
+ 0x0084: 0x00e4, # LATIN SMALL LETTER A WITH DIAERESIS
+ 0x0085: 0x00e0, # LATIN SMALL LETTER A WITH GRAVE
+ 0x0086: 0x00e5, # LATIN SMALL LETTER A WITH RING ABOVE
+ 0x0087: 0x00e7, # LATIN SMALL LETTER C WITH CEDILLA
+ 0x0088: 0x00ea, # LATIN SMALL LETTER E WITH CIRCUMFLEX
+ 0x0089: 0x00eb, # LATIN SMALL LETTER E WITH DIAERESIS
+ 0x008a: 0x00e8, # LATIN SMALL LETTER E WITH GRAVE
+ 0x008b: 0x00ef, # LATIN SMALL LETTER I WITH DIAERESIS
+ 0x008c: 0x00ee, # LATIN SMALL LETTER I WITH CIRCUMFLEX
+ 0x008d: 0x00ec, # LATIN SMALL LETTER I WITH GRAVE
+ 0x008e: 0x00c4, # LATIN CAPITAL LETTER A WITH DIAERESIS
+ 0x008f: 0x00c5, # LATIN CAPITAL LETTER A WITH RING ABOVE
+ 0x0090: 0x00c9, # LATIN CAPITAL LETTER E WITH ACUTE
+ 0x0091: 0x00e6, # LATIN SMALL LIGATURE AE
+ 0x0092: 0x00c6, # LATIN CAPITAL LIGATURE AE
+ 0x0093: 0x00f4, # LATIN SMALL LETTER O WITH CIRCUMFLEX
+ 0x0094: 0x00f6, # LATIN SMALL LETTER O WITH DIAERESIS
+ 0x0095: 0x00f2, # LATIN SMALL LETTER O WITH GRAVE
+ 0x0096: 0x00fb, # LATIN SMALL LETTER U WITH CIRCUMFLEX
+ 0x0097: 0x00f9, # LATIN SMALL LETTER U WITH GRAVE
+ 0x0098: 0x00ff, # LATIN SMALL LETTER Y WITH DIAERESIS
+ 0x0099: 0x00d6, # LATIN CAPITAL LETTER O WITH DIAERESIS
+ 0x009a: 0x00dc, # LATIN CAPITAL LETTER U WITH DIAERESIS
+ 0x009b: 0x00a2, # CENT SIGN
+ 0x009c: 0x00a3, # POUND SIGN
+ 0x009d: 0x00a5, # YEN SIGN
+ 0x009e: 0x20a7, # PESETA SIGN
+ 0x009f: 0x0192, # LATIN SMALL LETTER F WITH HOOK
+ 0x00a0: 0x00e1, # LATIN SMALL LETTER A WITH ACUTE
+ 0x00a1: 0x00ed, # LATIN SMALL LETTER I WITH ACUTE
+ 0x00a2: 0x00f3, # LATIN SMALL LETTER O WITH ACUTE
+ 0x00a3: 0x00fa, # LATIN SMALL LETTER U WITH ACUTE
+ 0x00a4: 0x00f1, # LATIN SMALL LETTER N WITH TILDE
+ 0x00a5: 0x00d1, # LATIN CAPITAL LETTER N WITH TILDE
+ 0x00a6: 0x00aa, # FEMININE ORDINAL INDICATOR
+ 0x00a7: 0x00ba, # MASCULINE ORDINAL INDICATOR
+ 0x00a8: 0x00bf, # INVERTED QUESTION MARK
+ 0x00a9: 0x2310, # REVERSED NOT SIGN
+ 0x00aa: 0x00ac, # NOT SIGN
+ 0x00ab: 0x00bd, # VULGAR FRACTION ONE HALF
+ 0x00ac: 0x00bc, # VULGAR FRACTION ONE QUARTER
+ 0x00ad: 0x00a1, # INVERTED EXCLAMATION MARK
+ 0x00ae: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00af: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00b0: 0x2591, # LIGHT SHADE
+ 0x00b1: 0x2592, # MEDIUM SHADE
+ 0x00b2: 0x2593, # DARK SHADE
+ 0x00b3: 0x2502, # BOX DRAWINGS LIGHT VERTICAL
+ 0x00b4: 0x2524, # BOX DRAWINGS LIGHT VERTICAL AND LEFT
+ 0x00b5: 0x2561, # BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
+ 0x00b6: 0x2562, # BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
+ 0x00b7: 0x2556, # BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
+ 0x00b8: 0x2555, # BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
+ 0x00b9: 0x2563, # BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+ 0x00ba: 0x2551, # BOX DRAWINGS DOUBLE VERTICAL
+ 0x00bb: 0x2557, # BOX DRAWINGS DOUBLE DOWN AND LEFT
+ 0x00bc: 0x255d, # BOX DRAWINGS DOUBLE UP AND LEFT
+ 0x00bd: 0x255c, # BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
+ 0x00be: 0x255b, # BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
+ 0x00bf: 0x2510, # BOX DRAWINGS LIGHT DOWN AND LEFT
+ 0x00c0: 0x2514, # BOX DRAWINGS LIGHT UP AND RIGHT
+ 0x00c1: 0x2534, # BOX DRAWINGS LIGHT UP AND HORIZONTAL
+ 0x00c2: 0x252c, # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+ 0x00c3: 0x251c, # BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+ 0x00c4: 0x2500, # BOX DRAWINGS LIGHT HORIZONTAL
+ 0x00c5: 0x253c, # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+ 0x00c6: 0x255e, # BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
+ 0x00c7: 0x255f, # BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
+ 0x00c8: 0x255a, # BOX DRAWINGS DOUBLE UP AND RIGHT
+ 0x00c9: 0x2554, # BOX DRAWINGS DOUBLE DOWN AND RIGHT
+ 0x00ca: 0x2569, # BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+ 0x00cb: 0x2566, # BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+ 0x00cc: 0x2560, # BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+ 0x00cd: 0x2550, # BOX DRAWINGS DOUBLE HORIZONTAL
+ 0x00ce: 0x256c, # BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+ 0x00cf: 0x2567, # BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
+ 0x00d0: 0x2568, # BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
+ 0x00d1: 0x2564, # BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
+ 0x00d2: 0x2565, # BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
+ 0x00d3: 0x2559, # BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
+ 0x00d4: 0x2558, # BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
+ 0x00d5: 0x2552, # BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
+ 0x00d6: 0x2553, # BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
+ 0x00d7: 0x256b, # BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
+ 0x00d8: 0x256a, # BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
+ 0x00d9: 0x2518, # BOX DRAWINGS LIGHT UP AND LEFT
+ 0x00da: 0x250c, # BOX DRAWINGS LIGHT DOWN AND RIGHT
+ 0x00db: 0x2588, # FULL BLOCK
+ 0x00dc: 0x2584, # LOWER HALF BLOCK
+ 0x00dd: 0x258c, # LEFT HALF BLOCK
+ 0x00de: 0x2590, # RIGHT HALF BLOCK
+ 0x00df: 0x2580, # UPPER HALF BLOCK
+ 0x00e0: 0x03b1, # GREEK SMALL LETTER ALPHA
+ 0x00e1: 0x00df, # LATIN SMALL LETTER SHARP S
+ 0x00e2: 0x0393, # GREEK CAPITAL LETTER GAMMA
+ 0x00e3: 0x03c0, # GREEK SMALL LETTER PI
+ 0x00e4: 0x03a3, # GREEK CAPITAL LETTER SIGMA
+ 0x00e5: 0x03c3, # GREEK SMALL LETTER SIGMA
+ 0x00e6: 0x00b5, # MICRO SIGN
+ 0x00e7: 0x03c4, # GREEK SMALL LETTER TAU
+ 0x00e8: 0x03a6, # GREEK CAPITAL LETTER PHI
+ 0x00e9: 0x0398, # GREEK CAPITAL LETTER THETA
+ 0x00ea: 0x03a9, # GREEK CAPITAL LETTER OMEGA
+ 0x00eb: 0x03b4, # GREEK SMALL LETTER DELTA
+ 0x00ec: 0x221e, # INFINITY
+ 0x00ed: 0x03c6, # GREEK SMALL LETTER PHI
+ 0x00ee: 0x03b5, # GREEK SMALL LETTER EPSILON
+ 0x00ef: 0x2229, # INTERSECTION
+ 0x00f0: 0x2261, # IDENTICAL TO
+ 0x00f1: 0x00b1, # PLUS-MINUS SIGN
+ 0x00f2: 0x2265, # GREATER-THAN OR EQUAL TO
+ 0x00f3: 0x2264, # LESS-THAN OR EQUAL TO
+ 0x00f4: 0x2320, # TOP HALF INTEGRAL
+ 0x00f5: 0x2321, # BOTTOM HALF INTEGRAL
+ 0x00f6: 0x00f7, # DIVISION SIGN
+ 0x00f7: 0x2248, # ALMOST EQUAL TO
+ 0x00f8: 0x00b0, # DEGREE SIGN
+ 0x00f9: 0x2219, # BULLET OPERATOR
+ 0x00fa: 0x00b7, # MIDDLE DOT
+ 0x00fb: 0x221a, # SQUARE ROOT
+ 0x00fc: 0x207f, # SUPERSCRIPT LATIN SMALL LETTER N
+ 0x00fd: 0x00b2, # SUPERSCRIPT TWO
+ 0x00fe: 0x25a0, # BLACK SQUARE
+ 0x00ff: 0x00a0, # NO-BREAK SPACE
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp500.py b/lib/jython/Lib/encodings/cp500.py new file mode 100644 index 000000000..fc4a9b013 --- /dev/null +++ b/lib/jython/Lib/encodings/cp500.py @@ -0,0 +1,282 @@ +""" Python Character Mapping Codec generated from 'CP500.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0004: 0x009c, # CONTROL
+ 0x0005: 0x0009, # HORIZONTAL TABULATION
+ 0x0006: 0x0086, # CONTROL
+ 0x0007: 0x007f, # DELETE
+ 0x0008: 0x0097, # CONTROL
+ 0x0009: 0x008d, # CONTROL
+ 0x000a: 0x008e, # CONTROL
+ 0x0014: 0x009d, # CONTROL
+ 0x0015: 0x0085, # CONTROL
+ 0x0016: 0x0008, # BACKSPACE
+ 0x0017: 0x0087, # CONTROL
+ 0x001a: 0x0092, # CONTROL
+ 0x001b: 0x008f, # CONTROL
+ 0x0020: 0x0080, # CONTROL
+ 0x0021: 0x0081, # CONTROL
+ 0x0022: 0x0082, # CONTROL
+ 0x0023: 0x0083, # CONTROL
+ 0x0024: 0x0084, # CONTROL
+ 0x0025: 0x000a, # LINE FEED
+ 0x0026: 0x0017, # END OF TRANSMISSION BLOCK
+ 0x0027: 0x001b, # ESCAPE
+ 0x0028: 0x0088, # CONTROL
+ 0x0029: 0x0089, # CONTROL
+ 0x002a: 0x008a, # CONTROL
+ 0x002b: 0x008b, # CONTROL
+ 0x002c: 0x008c, # CONTROL
+ 0x002d: 0x0005, # ENQUIRY
+ 0x002e: 0x0006, # ACKNOWLEDGE
+ 0x002f: 0x0007, # BELL
+ 0x0030: 0x0090, # CONTROL
+ 0x0031: 0x0091, # CONTROL
+ 0x0032: 0x0016, # SYNCHRONOUS IDLE
+ 0x0033: 0x0093, # CONTROL
+ 0x0034: 0x0094, # CONTROL
+ 0x0035: 0x0095, # CONTROL
+ 0x0036: 0x0096, # CONTROL
+ 0x0037: 0x0004, # END OF TRANSMISSION
+ 0x0038: 0x0098, # CONTROL
+ 0x0039: 0x0099, # CONTROL
+ 0x003a: 0x009a, # CONTROL
+ 0x003b: 0x009b, # CONTROL
+ 0x003c: 0x0014, # DEVICE CONTROL FOUR
+ 0x003d: 0x0015, # NEGATIVE ACKNOWLEDGE
+ 0x003e: 0x009e, # CONTROL
+ 0x003f: 0x001a, # SUBSTITUTE
+ 0x0040: 0x0020, # SPACE
+ 0x0041: 0x00a0, # NO-BREAK SPACE
+ 0x0042: 0x00e2, # LATIN SMALL LETTER A WITH CIRCUMFLEX
+ 0x0043: 0x00e4, # LATIN SMALL LETTER A WITH DIAERESIS
+ 0x0044: 0x00e0, # LATIN SMALL LETTER A WITH GRAVE
+ 0x0045: 0x00e1, # LATIN SMALL LETTER A WITH ACUTE
+ 0x0046: 0x00e3, # LATIN SMALL LETTER A WITH TILDE
+ 0x0047: 0x00e5, # LATIN SMALL LETTER A WITH RING ABOVE
+ 0x0048: 0x00e7, # LATIN SMALL LETTER C WITH CEDILLA
+ 0x0049: 0x00f1, # LATIN SMALL LETTER N WITH TILDE
+ 0x004a: 0x005b, # LEFT SQUARE BRACKET
+ 0x004b: 0x002e, # FULL STOP
+ 0x004c: 0x003c, # LESS-THAN SIGN
+ 0x004d: 0x0028, # LEFT PARENTHESIS
+ 0x004e: 0x002b, # PLUS SIGN
+ 0x004f: 0x0021, # EXCLAMATION MARK
+ 0x0050: 0x0026, # AMPERSAND
+ 0x0051: 0x00e9, # LATIN SMALL LETTER E WITH ACUTE
+ 0x0052: 0x00ea, # LATIN SMALL LETTER E WITH CIRCUMFLEX
+ 0x0053: 0x00eb, # LATIN SMALL LETTER E WITH DIAERESIS
+ 0x0054: 0x00e8, # LATIN SMALL LETTER E WITH GRAVE
+ 0x0055: 0x00ed, # LATIN SMALL LETTER I WITH ACUTE
+ 0x0056: 0x00ee, # LATIN SMALL LETTER I WITH CIRCUMFLEX
+ 0x0057: 0x00ef, # LATIN SMALL LETTER I WITH DIAERESIS
+ 0x0058: 0x00ec, # LATIN SMALL LETTER I WITH GRAVE
+ 0x0059: 0x00df, # LATIN SMALL LETTER SHARP S (GERMAN)
+ 0x005a: 0x005d, # RIGHT SQUARE BRACKET
+ 0x005b: 0x0024, # DOLLAR SIGN
+ 0x005c: 0x002a, # ASTERISK
+ 0x005d: 0x0029, # RIGHT PARENTHESIS
+ 0x005e: 0x003b, # SEMICOLON
+ 0x005f: 0x005e, # CIRCUMFLEX ACCENT
+ 0x0060: 0x002d, # HYPHEN-MINUS
+ 0x0061: 0x002f, # SOLIDUS
+ 0x0062: 0x00c2, # LATIN CAPITAL LETTER A WITH CIRCUMFLEX
+ 0x0063: 0x00c4, # LATIN CAPITAL LETTER A WITH DIAERESIS
+ 0x0064: 0x00c0, # LATIN CAPITAL LETTER A WITH GRAVE
+ 0x0065: 0x00c1, # LATIN CAPITAL LETTER A WITH ACUTE
+ 0x0066: 0x00c3, # LATIN CAPITAL LETTER A WITH TILDE
+ 0x0067: 0x00c5, # LATIN CAPITAL LETTER A WITH RING ABOVE
+ 0x0068: 0x00c7, # LATIN CAPITAL LETTER C WITH CEDILLA
+ 0x0069: 0x00d1, # LATIN CAPITAL LETTER N WITH TILDE
+ 0x006a: 0x00a6, # BROKEN BAR
+ 0x006b: 0x002c, # COMMA
+ 0x006c: 0x0025, # PERCENT SIGN
+ 0x006d: 0x005f, # LOW LINE
+ 0x006e: 0x003e, # GREATER-THAN SIGN
+ 0x006f: 0x003f, # QUESTION MARK
+ 0x0070: 0x00f8, # LATIN SMALL LETTER O WITH STROKE
+ 0x0071: 0x00c9, # LATIN CAPITAL LETTER E WITH ACUTE
+ 0x0072: 0x00ca, # LATIN CAPITAL LETTER E WITH CIRCUMFLEX
+ 0x0073: 0x00cb, # LATIN CAPITAL LETTER E WITH DIAERESIS
+ 0x0074: 0x00c8, # LATIN CAPITAL LETTER E WITH GRAVE
+ 0x0075: 0x00cd, # LATIN CAPITAL LETTER I WITH ACUTE
+ 0x0076: 0x00ce, # LATIN CAPITAL LETTER I WITH CIRCUMFLEX
+ 0x0077: 0x00cf, # LATIN CAPITAL LETTER I WITH DIAERESIS
+ 0x0078: 0x00cc, # LATIN CAPITAL LETTER I WITH GRAVE
+ 0x0079: 0x0060, # GRAVE ACCENT
+ 0x007a: 0x003a, # COLON
+ 0x007b: 0x0023, # NUMBER SIGN
+ 0x007c: 0x0040, # COMMERCIAL AT
+ 0x007d: 0x0027, # APOSTROPHE
+ 0x007e: 0x003d, # EQUALS SIGN
+ 0x007f: 0x0022, # QUOTATION MARK
+ 0x0080: 0x00d8, # LATIN CAPITAL LETTER O WITH STROKE
+ 0x0081: 0x0061, # LATIN SMALL LETTER A
+ 0x0082: 0x0062, # LATIN SMALL LETTER B
+ 0x0083: 0x0063, # LATIN SMALL LETTER C
+ 0x0084: 0x0064, # LATIN SMALL LETTER D
+ 0x0085: 0x0065, # LATIN SMALL LETTER E
+ 0x0086: 0x0066, # LATIN SMALL LETTER F
+ 0x0087: 0x0067, # LATIN SMALL LETTER G
+ 0x0088: 0x0068, # LATIN SMALL LETTER H
+ 0x0089: 0x0069, # LATIN SMALL LETTER I
+ 0x008a: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x008b: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x008c: 0x00f0, # LATIN SMALL LETTER ETH (ICELANDIC)
+ 0x008d: 0x00fd, # LATIN SMALL LETTER Y WITH ACUTE
+ 0x008e: 0x00fe, # LATIN SMALL LETTER THORN (ICELANDIC)
+ 0x008f: 0x00b1, # PLUS-MINUS SIGN
+ 0x0090: 0x00b0, # DEGREE SIGN
+ 0x0091: 0x006a, # LATIN SMALL LETTER J
+ 0x0092: 0x006b, # LATIN SMALL LETTER K
+ 0x0093: 0x006c, # LATIN SMALL LETTER L
+ 0x0094: 0x006d, # LATIN SMALL LETTER M
+ 0x0095: 0x006e, # LATIN SMALL LETTER N
+ 0x0096: 0x006f, # LATIN SMALL LETTER O
+ 0x0097: 0x0070, # LATIN SMALL LETTER P
+ 0x0098: 0x0071, # LATIN SMALL LETTER Q
+ 0x0099: 0x0072, # LATIN SMALL LETTER R
+ 0x009a: 0x00aa, # FEMININE ORDINAL INDICATOR
+ 0x009b: 0x00ba, # MASCULINE ORDINAL INDICATOR
+ 0x009c: 0x00e6, # LATIN SMALL LIGATURE AE
+ 0x009d: 0x00b8, # CEDILLA
+ 0x009e: 0x00c6, # LATIN CAPITAL LIGATURE AE
+ 0x009f: 0x00a4, # CURRENCY SIGN
+ 0x00a0: 0x00b5, # MICRO SIGN
+ 0x00a1: 0x007e, # TILDE
+ 0x00a2: 0x0073, # LATIN SMALL LETTER S
+ 0x00a3: 0x0074, # LATIN SMALL LETTER T
+ 0x00a4: 0x0075, # LATIN SMALL LETTER U
+ 0x00a5: 0x0076, # LATIN SMALL LETTER V
+ 0x00a6: 0x0077, # LATIN SMALL LETTER W
+ 0x00a7: 0x0078, # LATIN SMALL LETTER X
+ 0x00a8: 0x0079, # LATIN SMALL LETTER Y
+ 0x00a9: 0x007a, # LATIN SMALL LETTER Z
+ 0x00aa: 0x00a1, # INVERTED EXCLAMATION MARK
+ 0x00ab: 0x00bf, # INVERTED QUESTION MARK
+ 0x00ac: 0x00d0, # LATIN CAPITAL LETTER ETH (ICELANDIC)
+ 0x00ad: 0x00dd, # LATIN CAPITAL LETTER Y WITH ACUTE
+ 0x00ae: 0x00de, # LATIN CAPITAL LETTER THORN (ICELANDIC)
+ 0x00af: 0x00ae, # REGISTERED SIGN
+ 0x00b0: 0x00a2, # CENT SIGN
+ 0x00b1: 0x00a3, # POUND SIGN
+ 0x00b2: 0x00a5, # YEN SIGN
+ 0x00b3: 0x00b7, # MIDDLE DOT
+ 0x00b4: 0x00a9, # COPYRIGHT SIGN
+ 0x00b5: 0x00a7, # SECTION SIGN
+ 0x00b7: 0x00bc, # VULGAR FRACTION ONE QUARTER
+ 0x00b8: 0x00bd, # VULGAR FRACTION ONE HALF
+ 0x00b9: 0x00be, # VULGAR FRACTION THREE QUARTERS
+ 0x00ba: 0x00ac, # NOT SIGN
+ 0x00bb: 0x007c, # VERTICAL LINE
+ 0x00bc: 0x00af, # MACRON
+ 0x00bd: 0x00a8, # DIAERESIS
+ 0x00be: 0x00b4, # ACUTE ACCENT
+ 0x00bf: 0x00d7, # MULTIPLICATION SIGN
+ 0x00c0: 0x007b, # LEFT CURLY BRACKET
+ 0x00c1: 0x0041, # LATIN CAPITAL LETTER A
+ 0x00c2: 0x0042, # LATIN CAPITAL LETTER B
+ 0x00c3: 0x0043, # LATIN CAPITAL LETTER C
+ 0x00c4: 0x0044, # LATIN CAPITAL LETTER D
+ 0x00c5: 0x0045, # LATIN CAPITAL LETTER E
+ 0x00c6: 0x0046, # LATIN CAPITAL LETTER F
+ 0x00c7: 0x0047, # LATIN CAPITAL LETTER G
+ 0x00c8: 0x0048, # LATIN CAPITAL LETTER H
+ 0x00c9: 0x0049, # LATIN CAPITAL LETTER I
+ 0x00ca: 0x00ad, # SOFT HYPHEN
+ 0x00cb: 0x00f4, # LATIN SMALL LETTER O WITH CIRCUMFLEX
+ 0x00cc: 0x00f6, # LATIN SMALL LETTER O WITH DIAERESIS
+ 0x00cd: 0x00f2, # LATIN SMALL LETTER O WITH GRAVE
+ 0x00ce: 0x00f3, # LATIN SMALL LETTER O WITH ACUTE
+ 0x00cf: 0x00f5, # LATIN SMALL LETTER O WITH TILDE
+ 0x00d0: 0x007d, # RIGHT CURLY BRACKET
+ 0x00d1: 0x004a, # LATIN CAPITAL LETTER J
+ 0x00d2: 0x004b, # LATIN CAPITAL LETTER K
+ 0x00d3: 0x004c, # LATIN CAPITAL LETTER L
+ 0x00d4: 0x004d, # LATIN CAPITAL LETTER M
+ 0x00d5: 0x004e, # LATIN CAPITAL LETTER N
+ 0x00d6: 0x004f, # LATIN CAPITAL LETTER O
+ 0x00d7: 0x0050, # LATIN CAPITAL LETTER P
+ 0x00d8: 0x0051, # LATIN CAPITAL LETTER Q
+ 0x00d9: 0x0052, # LATIN CAPITAL LETTER R
+ 0x00da: 0x00b9, # SUPERSCRIPT ONE
+ 0x00db: 0x00fb, # LATIN SMALL LETTER U WITH CIRCUMFLEX
+ 0x00dc: 0x00fc, # LATIN SMALL LETTER U WITH DIAERESIS
+ 0x00dd: 0x00f9, # LATIN SMALL LETTER U WITH GRAVE
+ 0x00de: 0x00fa, # LATIN SMALL LETTER U WITH ACUTE
+ 0x00df: 0x00ff, # LATIN SMALL LETTER Y WITH DIAERESIS
+ 0x00e0: 0x005c, # REVERSE SOLIDUS
+ 0x00e1: 0x00f7, # DIVISION SIGN
+ 0x00e2: 0x0053, # LATIN CAPITAL LETTER S
+ 0x00e3: 0x0054, # LATIN CAPITAL LETTER T
+ 0x00e4: 0x0055, # LATIN CAPITAL LETTER U
+ 0x00e5: 0x0056, # LATIN CAPITAL LETTER V
+ 0x00e6: 0x0057, # LATIN CAPITAL LETTER W
+ 0x00e7: 0x0058, # LATIN CAPITAL LETTER X
+ 0x00e8: 0x0059, # LATIN CAPITAL LETTER Y
+ 0x00e9: 0x005a, # LATIN CAPITAL LETTER Z
+ 0x00ea: 0x00b2, # SUPERSCRIPT TWO
+ 0x00eb: 0x00d4, # LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+ 0x00ec: 0x00d6, # LATIN CAPITAL LETTER O WITH DIAERESIS
+ 0x00ed: 0x00d2, # LATIN CAPITAL LETTER O WITH GRAVE
+ 0x00ee: 0x00d3, # LATIN CAPITAL LETTER O WITH ACUTE
+ 0x00ef: 0x00d5, # LATIN CAPITAL LETTER O WITH TILDE
+ 0x00f0: 0x0030, # DIGIT ZERO
+ 0x00f1: 0x0031, # DIGIT ONE
+ 0x00f2: 0x0032, # DIGIT TWO
+ 0x00f3: 0x0033, # DIGIT THREE
+ 0x00f4: 0x0034, # DIGIT FOUR
+ 0x00f5: 0x0035, # DIGIT FIVE
+ 0x00f6: 0x0036, # DIGIT SIX
+ 0x00f7: 0x0037, # DIGIT SEVEN
+ 0x00f8: 0x0038, # DIGIT EIGHT
+ 0x00f9: 0x0039, # DIGIT NINE
+ 0x00fa: 0x00b3, # SUPERSCRIPT THREE
+ 0x00fb: 0x00db, # LATIN CAPITAL LETTER U WITH CIRCUMFLEX
+ 0x00fc: 0x00dc, # LATIN CAPITAL LETTER U WITH DIAERESIS
+ 0x00fd: 0x00d9, # LATIN CAPITAL LETTER U WITH GRAVE
+ 0x00fe: 0x00da, # LATIN CAPITAL LETTER U WITH ACUTE
+ 0x00ff: 0x009f, # CONTROL
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp737.py b/lib/jython/Lib/encodings/cp737.py new file mode 100644 index 000000000..02e2fb2c5 --- /dev/null +++ b/lib/jython/Lib/encodings/cp737.py @@ -0,0 +1,174 @@ +""" Python Character Mapping Codec generated from 'CP737.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x0391, # GREEK CAPITAL LETTER ALPHA
+ 0x0081: 0x0392, # GREEK CAPITAL LETTER BETA
+ 0x0082: 0x0393, # GREEK CAPITAL LETTER GAMMA
+ 0x0083: 0x0394, # GREEK CAPITAL LETTER DELTA
+ 0x0084: 0x0395, # GREEK CAPITAL LETTER EPSILON
+ 0x0085: 0x0396, # GREEK CAPITAL LETTER ZETA
+ 0x0086: 0x0397, # GREEK CAPITAL LETTER ETA
+ 0x0087: 0x0398, # GREEK CAPITAL LETTER THETA
+ 0x0088: 0x0399, # GREEK CAPITAL LETTER IOTA
+ 0x0089: 0x039a, # GREEK CAPITAL LETTER KAPPA
+ 0x008a: 0x039b, # GREEK CAPITAL LETTER LAMDA
+ 0x008b: 0x039c, # GREEK CAPITAL LETTER MU
+ 0x008c: 0x039d, # GREEK CAPITAL LETTER NU
+ 0x008d: 0x039e, # GREEK CAPITAL LETTER XI
+ 0x008e: 0x039f, # GREEK CAPITAL LETTER OMICRON
+ 0x008f: 0x03a0, # GREEK CAPITAL LETTER PI
+ 0x0090: 0x03a1, # GREEK CAPITAL LETTER RHO
+ 0x0091: 0x03a3, # GREEK CAPITAL LETTER SIGMA
+ 0x0092: 0x03a4, # GREEK CAPITAL LETTER TAU
+ 0x0093: 0x03a5, # GREEK CAPITAL LETTER UPSILON
+ 0x0094: 0x03a6, # GREEK CAPITAL LETTER PHI
+ 0x0095: 0x03a7, # GREEK CAPITAL LETTER CHI
+ 0x0096: 0x03a8, # GREEK CAPITAL LETTER PSI
+ 0x0097: 0x03a9, # GREEK CAPITAL LETTER OMEGA
+ 0x0098: 0x03b1, # GREEK SMALL LETTER ALPHA
+ 0x0099: 0x03b2, # GREEK SMALL LETTER BETA
+ 0x009a: 0x03b3, # GREEK SMALL LETTER GAMMA
+ 0x009b: 0x03b4, # GREEK SMALL LETTER DELTA
+ 0x009c: 0x03b5, # GREEK SMALL LETTER EPSILON
+ 0x009d: 0x03b6, # GREEK SMALL LETTER ZETA
+ 0x009e: 0x03b7, # GREEK SMALL LETTER ETA
+ 0x009f: 0x03b8, # GREEK SMALL LETTER THETA
+ 0x00a0: 0x03b9, # GREEK SMALL LETTER IOTA
+ 0x00a1: 0x03ba, # GREEK SMALL LETTER KAPPA
+ 0x00a2: 0x03bb, # GREEK SMALL LETTER LAMDA
+ 0x00a3: 0x03bc, # GREEK SMALL LETTER MU
+ 0x00a4: 0x03bd, # GREEK SMALL LETTER NU
+ 0x00a5: 0x03be, # GREEK SMALL LETTER XI
+ 0x00a6: 0x03bf, # GREEK SMALL LETTER OMICRON
+ 0x00a7: 0x03c0, # GREEK SMALL LETTER PI
+ 0x00a8: 0x03c1, # GREEK SMALL LETTER RHO
+ 0x00a9: 0x03c3, # GREEK SMALL LETTER SIGMA
+ 0x00aa: 0x03c2, # GREEK SMALL LETTER FINAL SIGMA
+ 0x00ab: 0x03c4, # GREEK SMALL LETTER TAU
+ 0x00ac: 0x03c5, # GREEK SMALL LETTER UPSILON
+ 0x00ad: 0x03c6, # GREEK SMALL LETTER PHI
+ 0x00ae: 0x03c7, # GREEK SMALL LETTER CHI
+ 0x00af: 0x03c8, # GREEK SMALL LETTER PSI
+ 0x00b0: 0x2591, # LIGHT SHADE
+ 0x00b1: 0x2592, # MEDIUM SHADE
+ 0x00b2: 0x2593, # DARK SHADE
+ 0x00b3: 0x2502, # BOX DRAWINGS LIGHT VERTICAL
+ 0x00b4: 0x2524, # BOX DRAWINGS LIGHT VERTICAL AND LEFT
+ 0x00b5: 0x2561, # BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
+ 0x00b6: 0x2562, # BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
+ 0x00b7: 0x2556, # BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
+ 0x00b8: 0x2555, # BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
+ 0x00b9: 0x2563, # BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+ 0x00ba: 0x2551, # BOX DRAWINGS DOUBLE VERTICAL
+ 0x00bb: 0x2557, # BOX DRAWINGS DOUBLE DOWN AND LEFT
+ 0x00bc: 0x255d, # BOX DRAWINGS DOUBLE UP AND LEFT
+ 0x00bd: 0x255c, # BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
+ 0x00be: 0x255b, # BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
+ 0x00bf: 0x2510, # BOX DRAWINGS LIGHT DOWN AND LEFT
+ 0x00c0: 0x2514, # BOX DRAWINGS LIGHT UP AND RIGHT
+ 0x00c1: 0x2534, # BOX DRAWINGS LIGHT UP AND HORIZONTAL
+ 0x00c2: 0x252c, # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+ 0x00c3: 0x251c, # BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+ 0x00c4: 0x2500, # BOX DRAWINGS LIGHT HORIZONTAL
+ 0x00c5: 0x253c, # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+ 0x00c6: 0x255e, # BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
+ 0x00c7: 0x255f, # BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
+ 0x00c8: 0x255a, # BOX DRAWINGS DOUBLE UP AND RIGHT
+ 0x00c9: 0x2554, # BOX DRAWINGS DOUBLE DOWN AND RIGHT
+ 0x00ca: 0x2569, # BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+ 0x00cb: 0x2566, # BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+ 0x00cc: 0x2560, # BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+ 0x00cd: 0x2550, # BOX DRAWINGS DOUBLE HORIZONTAL
+ 0x00ce: 0x256c, # BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+ 0x00cf: 0x2567, # BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
+ 0x00d0: 0x2568, # BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
+ 0x00d1: 0x2564, # BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
+ 0x00d2: 0x2565, # BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
+ 0x00d3: 0x2559, # BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
+ 0x00d4: 0x2558, # BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
+ 0x00d5: 0x2552, # BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
+ 0x00d6: 0x2553, # BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
+ 0x00d7: 0x256b, # BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
+ 0x00d8: 0x256a, # BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
+ 0x00d9: 0x2518, # BOX DRAWINGS LIGHT UP AND LEFT
+ 0x00da: 0x250c, # BOX DRAWINGS LIGHT DOWN AND RIGHT
+ 0x00db: 0x2588, # FULL BLOCK
+ 0x00dc: 0x2584, # LOWER HALF BLOCK
+ 0x00dd: 0x258c, # LEFT HALF BLOCK
+ 0x00de: 0x2590, # RIGHT HALF BLOCK
+ 0x00df: 0x2580, # UPPER HALF BLOCK
+ 0x00e0: 0x03c9, # GREEK SMALL LETTER OMEGA
+ 0x00e1: 0x03ac, # GREEK SMALL LETTER ALPHA WITH TONOS
+ 0x00e2: 0x03ad, # GREEK SMALL LETTER EPSILON WITH TONOS
+ 0x00e3: 0x03ae, # GREEK SMALL LETTER ETA WITH TONOS
+ 0x00e4: 0x03ca, # GREEK SMALL LETTER IOTA WITH DIALYTIKA
+ 0x00e5: 0x03af, # GREEK SMALL LETTER IOTA WITH TONOS
+ 0x00e6: 0x03cc, # GREEK SMALL LETTER OMICRON WITH TONOS
+ 0x00e7: 0x03cd, # GREEK SMALL LETTER UPSILON WITH TONOS
+ 0x00e8: 0x03cb, # GREEK SMALL LETTER UPSILON WITH DIALYTIKA
+ 0x00e9: 0x03ce, # GREEK SMALL LETTER OMEGA WITH TONOS
+ 0x00ea: 0x0386, # GREEK CAPITAL LETTER ALPHA WITH TONOS
+ 0x00eb: 0x0388, # GREEK CAPITAL LETTER EPSILON WITH TONOS
+ 0x00ec: 0x0389, # GREEK CAPITAL LETTER ETA WITH TONOS
+ 0x00ed: 0x038a, # GREEK CAPITAL LETTER IOTA WITH TONOS
+ 0x00ee: 0x038c, # GREEK CAPITAL LETTER OMICRON WITH TONOS
+ 0x00ef: 0x038e, # GREEK CAPITAL LETTER UPSILON WITH TONOS
+ 0x00f0: 0x038f, # GREEK CAPITAL LETTER OMEGA WITH TONOS
+ 0x00f1: 0x00b1, # PLUS-MINUS SIGN
+ 0x00f2: 0x2265, # GREATER-THAN OR EQUAL TO
+ 0x00f3: 0x2264, # LESS-THAN OR EQUAL TO
+ 0x00f4: 0x03aa, # GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
+ 0x00f5: 0x03ab, # GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
+ 0x00f6: 0x00f7, # DIVISION SIGN
+ 0x00f7: 0x2248, # ALMOST EQUAL TO
+ 0x00f8: 0x00b0, # DEGREE SIGN
+ 0x00f9: 0x2219, # BULLET OPERATOR
+ 0x00fa: 0x00b7, # MIDDLE DOT
+ 0x00fb: 0x221a, # SQUARE ROOT
+ 0x00fc: 0x207f, # SUPERSCRIPT LATIN SMALL LETTER N
+ 0x00fd: 0x00b2, # SUPERSCRIPT TWO
+ 0x00fe: 0x25a0, # BLACK SQUARE
+ 0x00ff: 0x00a0, # NO-BREAK SPACE
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp775.py b/lib/jython/Lib/encodings/cp775.py new file mode 100644 index 000000000..97f9b049b --- /dev/null +++ b/lib/jython/Lib/encodings/cp775.py @@ -0,0 +1,174 @@ +""" Python Character Mapping Codec generated from 'CP775.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x0106, # LATIN CAPITAL LETTER C WITH ACUTE
+ 0x0081: 0x00fc, # LATIN SMALL LETTER U WITH DIAERESIS
+ 0x0082: 0x00e9, # LATIN SMALL LETTER E WITH ACUTE
+ 0x0083: 0x0101, # LATIN SMALL LETTER A WITH MACRON
+ 0x0084: 0x00e4, # LATIN SMALL LETTER A WITH DIAERESIS
+ 0x0085: 0x0123, # LATIN SMALL LETTER G WITH CEDILLA
+ 0x0086: 0x00e5, # LATIN SMALL LETTER A WITH RING ABOVE
+ 0x0087: 0x0107, # LATIN SMALL LETTER C WITH ACUTE
+ 0x0088: 0x0142, # LATIN SMALL LETTER L WITH STROKE
+ 0x0089: 0x0113, # LATIN SMALL LETTER E WITH MACRON
+ 0x008a: 0x0156, # LATIN CAPITAL LETTER R WITH CEDILLA
+ 0x008b: 0x0157, # LATIN SMALL LETTER R WITH CEDILLA
+ 0x008c: 0x012b, # LATIN SMALL LETTER I WITH MACRON
+ 0x008d: 0x0179, # LATIN CAPITAL LETTER Z WITH ACUTE
+ 0x008e: 0x00c4, # LATIN CAPITAL LETTER A WITH DIAERESIS
+ 0x008f: 0x00c5, # LATIN CAPITAL LETTER A WITH RING ABOVE
+ 0x0090: 0x00c9, # LATIN CAPITAL LETTER E WITH ACUTE
+ 0x0091: 0x00e6, # LATIN SMALL LIGATURE AE
+ 0x0092: 0x00c6, # LATIN CAPITAL LIGATURE AE
+ 0x0093: 0x014d, # LATIN SMALL LETTER O WITH MACRON
+ 0x0094: 0x00f6, # LATIN SMALL LETTER O WITH DIAERESIS
+ 0x0095: 0x0122, # LATIN CAPITAL LETTER G WITH CEDILLA
+ 0x0096: 0x00a2, # CENT SIGN
+ 0x0097: 0x015a, # LATIN CAPITAL LETTER S WITH ACUTE
+ 0x0098: 0x015b, # LATIN SMALL LETTER S WITH ACUTE
+ 0x0099: 0x00d6, # LATIN CAPITAL LETTER O WITH DIAERESIS
+ 0x009a: 0x00dc, # LATIN CAPITAL LETTER U WITH DIAERESIS
+ 0x009b: 0x00f8, # LATIN SMALL LETTER O WITH STROKE
+ 0x009c: 0x00a3, # POUND SIGN
+ 0x009d: 0x00d8, # LATIN CAPITAL LETTER O WITH STROKE
+ 0x009e: 0x00d7, # MULTIPLICATION SIGN
+ 0x009f: 0x00a4, # CURRENCY SIGN
+ 0x00a0: 0x0100, # LATIN CAPITAL LETTER A WITH MACRON
+ 0x00a1: 0x012a, # LATIN CAPITAL LETTER I WITH MACRON
+ 0x00a2: 0x00f3, # LATIN SMALL LETTER O WITH ACUTE
+ 0x00a3: 0x017b, # LATIN CAPITAL LETTER Z WITH DOT ABOVE
+ 0x00a4: 0x017c, # LATIN SMALL LETTER Z WITH DOT ABOVE
+ 0x00a5: 0x017a, # LATIN SMALL LETTER Z WITH ACUTE
+ 0x00a6: 0x201d, # RIGHT DOUBLE QUOTATION MARK
+ 0x00a7: 0x00a6, # BROKEN BAR
+ 0x00a8: 0x00a9, # COPYRIGHT SIGN
+ 0x00a9: 0x00ae, # REGISTERED SIGN
+ 0x00aa: 0x00ac, # NOT SIGN
+ 0x00ab: 0x00bd, # VULGAR FRACTION ONE HALF
+ 0x00ac: 0x00bc, # VULGAR FRACTION ONE QUARTER
+ 0x00ad: 0x0141, # LATIN CAPITAL LETTER L WITH STROKE
+ 0x00ae: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00af: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00b0: 0x2591, # LIGHT SHADE
+ 0x00b1: 0x2592, # MEDIUM SHADE
+ 0x00b2: 0x2593, # DARK SHADE
+ 0x00b3: 0x2502, # BOX DRAWINGS LIGHT VERTICAL
+ 0x00b4: 0x2524, # BOX DRAWINGS LIGHT VERTICAL AND LEFT
+ 0x00b5: 0x0104, # LATIN CAPITAL LETTER A WITH OGONEK
+ 0x00b6: 0x010c, # LATIN CAPITAL LETTER C WITH CARON
+ 0x00b7: 0x0118, # LATIN CAPITAL LETTER E WITH OGONEK
+ 0x00b8: 0x0116, # LATIN CAPITAL LETTER E WITH DOT ABOVE
+ 0x00b9: 0x2563, # BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+ 0x00ba: 0x2551, # BOX DRAWINGS DOUBLE VERTICAL
+ 0x00bb: 0x2557, # BOX DRAWINGS DOUBLE DOWN AND LEFT
+ 0x00bc: 0x255d, # BOX DRAWINGS DOUBLE UP AND LEFT
+ 0x00bd: 0x012e, # LATIN CAPITAL LETTER I WITH OGONEK
+ 0x00be: 0x0160, # LATIN CAPITAL LETTER S WITH CARON
+ 0x00bf: 0x2510, # BOX DRAWINGS LIGHT DOWN AND LEFT
+ 0x00c0: 0x2514, # BOX DRAWINGS LIGHT UP AND RIGHT
+ 0x00c1: 0x2534, # BOX DRAWINGS LIGHT UP AND HORIZONTAL
+ 0x00c2: 0x252c, # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+ 0x00c3: 0x251c, # BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+ 0x00c4: 0x2500, # BOX DRAWINGS LIGHT HORIZONTAL
+ 0x00c5: 0x253c, # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+ 0x00c6: 0x0172, # LATIN CAPITAL LETTER U WITH OGONEK
+ 0x00c7: 0x016a, # LATIN CAPITAL LETTER U WITH MACRON
+ 0x00c8: 0x255a, # BOX DRAWINGS DOUBLE UP AND RIGHT
+ 0x00c9: 0x2554, # BOX DRAWINGS DOUBLE DOWN AND RIGHT
+ 0x00ca: 0x2569, # BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+ 0x00cb: 0x2566, # BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+ 0x00cc: 0x2560, # BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+ 0x00cd: 0x2550, # BOX DRAWINGS DOUBLE HORIZONTAL
+ 0x00ce: 0x256c, # BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+ 0x00cf: 0x017d, # LATIN CAPITAL LETTER Z WITH CARON
+ 0x00d0: 0x0105, # LATIN SMALL LETTER A WITH OGONEK
+ 0x00d1: 0x010d, # LATIN SMALL LETTER C WITH CARON
+ 0x00d2: 0x0119, # LATIN SMALL LETTER E WITH OGONEK
+ 0x00d3: 0x0117, # LATIN SMALL LETTER E WITH DOT ABOVE
+ 0x00d4: 0x012f, # LATIN SMALL LETTER I WITH OGONEK
+ 0x00d5: 0x0161, # LATIN SMALL LETTER S WITH CARON
+ 0x00d6: 0x0173, # LATIN SMALL LETTER U WITH OGONEK
+ 0x00d7: 0x016b, # LATIN SMALL LETTER U WITH MACRON
+ 0x00d8: 0x017e, # LATIN SMALL LETTER Z WITH CARON
+ 0x00d9: 0x2518, # BOX DRAWINGS LIGHT UP AND LEFT
+ 0x00da: 0x250c, # BOX DRAWINGS LIGHT DOWN AND RIGHT
+ 0x00db: 0x2588, # FULL BLOCK
+ 0x00dc: 0x2584, # LOWER HALF BLOCK
+ 0x00dd: 0x258c, # LEFT HALF BLOCK
+ 0x00de: 0x2590, # RIGHT HALF BLOCK
+ 0x00df: 0x2580, # UPPER HALF BLOCK
+ 0x00e0: 0x00d3, # LATIN CAPITAL LETTER O WITH ACUTE
+ 0x00e1: 0x00df, # LATIN SMALL LETTER SHARP S (GERMAN)
+ 0x00e2: 0x014c, # LATIN CAPITAL LETTER O WITH MACRON
+ 0x00e3: 0x0143, # LATIN CAPITAL LETTER N WITH ACUTE
+ 0x00e4: 0x00f5, # LATIN SMALL LETTER O WITH TILDE
+ 0x00e5: 0x00d5, # LATIN CAPITAL LETTER O WITH TILDE
+ 0x00e6: 0x00b5, # MICRO SIGN
+ 0x00e7: 0x0144, # LATIN SMALL LETTER N WITH ACUTE
+ 0x00e8: 0x0136, # LATIN CAPITAL LETTER K WITH CEDILLA
+ 0x00e9: 0x0137, # LATIN SMALL LETTER K WITH CEDILLA
+ 0x00ea: 0x013b, # LATIN CAPITAL LETTER L WITH CEDILLA
+ 0x00eb: 0x013c, # LATIN SMALL LETTER L WITH CEDILLA
+ 0x00ec: 0x0146, # LATIN SMALL LETTER N WITH CEDILLA
+ 0x00ed: 0x0112, # LATIN CAPITAL LETTER E WITH MACRON
+ 0x00ee: 0x0145, # LATIN CAPITAL LETTER N WITH CEDILLA
+ 0x00ef: 0x2019, # RIGHT SINGLE QUOTATION MARK
+ 0x00f0: 0x00ad, # SOFT HYPHEN
+ 0x00f1: 0x00b1, # PLUS-MINUS SIGN
+ 0x00f2: 0x201c, # LEFT DOUBLE QUOTATION MARK
+ 0x00f3: 0x00be, # VULGAR FRACTION THREE QUARTERS
+ 0x00f4: 0x00b6, # PILCROW SIGN
+ 0x00f5: 0x00a7, # SECTION SIGN
+ 0x00f6: 0x00f7, # DIVISION SIGN
+ 0x00f7: 0x201e, # DOUBLE LOW-9 QUOTATION MARK
+ 0x00f8: 0x00b0, # DEGREE SIGN
+ 0x00f9: 0x2219, # BULLET OPERATOR
+ 0x00fa: 0x00b7, # MIDDLE DOT
+ 0x00fb: 0x00b9, # SUPERSCRIPT ONE
+ 0x00fc: 0x00b3, # SUPERSCRIPT THREE
+ 0x00fd: 0x00b2, # SUPERSCRIPT TWO
+ 0x00fe: 0x25a0, # BLACK SQUARE
+ 0x00ff: 0x00a0, # NO-BREAK SPACE
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp850.py b/lib/jython/Lib/encodings/cp850.py new file mode 100644 index 000000000..bd673db9b --- /dev/null +++ b/lib/jython/Lib/encodings/cp850.py @@ -0,0 +1,174 @@ +""" Python Character Mapping Codec generated from 'CP850.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x00c7, # LATIN CAPITAL LETTER C WITH CEDILLA
+ 0x0081: 0x00fc, # LATIN SMALL LETTER U WITH DIAERESIS
+ 0x0082: 0x00e9, # LATIN SMALL LETTER E WITH ACUTE
+ 0x0083: 0x00e2, # LATIN SMALL LETTER A WITH CIRCUMFLEX
+ 0x0084: 0x00e4, # LATIN SMALL LETTER A WITH DIAERESIS
+ 0x0085: 0x00e0, # LATIN SMALL LETTER A WITH GRAVE
+ 0x0086: 0x00e5, # LATIN SMALL LETTER A WITH RING ABOVE
+ 0x0087: 0x00e7, # LATIN SMALL LETTER C WITH CEDILLA
+ 0x0088: 0x00ea, # LATIN SMALL LETTER E WITH CIRCUMFLEX
+ 0x0089: 0x00eb, # LATIN SMALL LETTER E WITH DIAERESIS
+ 0x008a: 0x00e8, # LATIN SMALL LETTER E WITH GRAVE
+ 0x008b: 0x00ef, # LATIN SMALL LETTER I WITH DIAERESIS
+ 0x008c: 0x00ee, # LATIN SMALL LETTER I WITH CIRCUMFLEX
+ 0x008d: 0x00ec, # LATIN SMALL LETTER I WITH GRAVE
+ 0x008e: 0x00c4, # LATIN CAPITAL LETTER A WITH DIAERESIS
+ 0x008f: 0x00c5, # LATIN CAPITAL LETTER A WITH RING ABOVE
+ 0x0090: 0x00c9, # LATIN CAPITAL LETTER E WITH ACUTE
+ 0x0091: 0x00e6, # LATIN SMALL LIGATURE AE
+ 0x0092: 0x00c6, # LATIN CAPITAL LIGATURE AE
+ 0x0093: 0x00f4, # LATIN SMALL LETTER O WITH CIRCUMFLEX
+ 0x0094: 0x00f6, # LATIN SMALL LETTER O WITH DIAERESIS
+ 0x0095: 0x00f2, # LATIN SMALL LETTER O WITH GRAVE
+ 0x0096: 0x00fb, # LATIN SMALL LETTER U WITH CIRCUMFLEX
+ 0x0097: 0x00f9, # LATIN SMALL LETTER U WITH GRAVE
+ 0x0098: 0x00ff, # LATIN SMALL LETTER Y WITH DIAERESIS
+ 0x0099: 0x00d6, # LATIN CAPITAL LETTER O WITH DIAERESIS
+ 0x009a: 0x00dc, # LATIN CAPITAL LETTER U WITH DIAERESIS
+ 0x009b: 0x00f8, # LATIN SMALL LETTER O WITH STROKE
+ 0x009c: 0x00a3, # POUND SIGN
+ 0x009d: 0x00d8, # LATIN CAPITAL LETTER O WITH STROKE
+ 0x009e: 0x00d7, # MULTIPLICATION SIGN
+ 0x009f: 0x0192, # LATIN SMALL LETTER F WITH HOOK
+ 0x00a0: 0x00e1, # LATIN SMALL LETTER A WITH ACUTE
+ 0x00a1: 0x00ed, # LATIN SMALL LETTER I WITH ACUTE
+ 0x00a2: 0x00f3, # LATIN SMALL LETTER O WITH ACUTE
+ 0x00a3: 0x00fa, # LATIN SMALL LETTER U WITH ACUTE
+ 0x00a4: 0x00f1, # LATIN SMALL LETTER N WITH TILDE
+ 0x00a5: 0x00d1, # LATIN CAPITAL LETTER N WITH TILDE
+ 0x00a6: 0x00aa, # FEMININE ORDINAL INDICATOR
+ 0x00a7: 0x00ba, # MASCULINE ORDINAL INDICATOR
+ 0x00a8: 0x00bf, # INVERTED QUESTION MARK
+ 0x00a9: 0x00ae, # REGISTERED SIGN
+ 0x00aa: 0x00ac, # NOT SIGN
+ 0x00ab: 0x00bd, # VULGAR FRACTION ONE HALF
+ 0x00ac: 0x00bc, # VULGAR FRACTION ONE QUARTER
+ 0x00ad: 0x00a1, # INVERTED EXCLAMATION MARK
+ 0x00ae: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00af: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00b0: 0x2591, # LIGHT SHADE
+ 0x00b1: 0x2592, # MEDIUM SHADE
+ 0x00b2: 0x2593, # DARK SHADE
+ 0x00b3: 0x2502, # BOX DRAWINGS LIGHT VERTICAL
+ 0x00b4: 0x2524, # BOX DRAWINGS LIGHT VERTICAL AND LEFT
+ 0x00b5: 0x00c1, # LATIN CAPITAL LETTER A WITH ACUTE
+ 0x00b6: 0x00c2, # LATIN CAPITAL LETTER A WITH CIRCUMFLEX
+ 0x00b7: 0x00c0, # LATIN CAPITAL LETTER A WITH GRAVE
+ 0x00b8: 0x00a9, # COPYRIGHT SIGN
+ 0x00b9: 0x2563, # BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+ 0x00ba: 0x2551, # BOX DRAWINGS DOUBLE VERTICAL
+ 0x00bb: 0x2557, # BOX DRAWINGS DOUBLE DOWN AND LEFT
+ 0x00bc: 0x255d, # BOX DRAWINGS DOUBLE UP AND LEFT
+ 0x00bd: 0x00a2, # CENT SIGN
+ 0x00be: 0x00a5, # YEN SIGN
+ 0x00bf: 0x2510, # BOX DRAWINGS LIGHT DOWN AND LEFT
+ 0x00c0: 0x2514, # BOX DRAWINGS LIGHT UP AND RIGHT
+ 0x00c1: 0x2534, # BOX DRAWINGS LIGHT UP AND HORIZONTAL
+ 0x00c2: 0x252c, # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+ 0x00c3: 0x251c, # BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+ 0x00c4: 0x2500, # BOX DRAWINGS LIGHT HORIZONTAL
+ 0x00c5: 0x253c, # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+ 0x00c6: 0x00e3, # LATIN SMALL LETTER A WITH TILDE
+ 0x00c7: 0x00c3, # LATIN CAPITAL LETTER A WITH TILDE
+ 0x00c8: 0x255a, # BOX DRAWINGS DOUBLE UP AND RIGHT
+ 0x00c9: 0x2554, # BOX DRAWINGS DOUBLE DOWN AND RIGHT
+ 0x00ca: 0x2569, # BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+ 0x00cb: 0x2566, # BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+ 0x00cc: 0x2560, # BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+ 0x00cd: 0x2550, # BOX DRAWINGS DOUBLE HORIZONTAL
+ 0x00ce: 0x256c, # BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+ 0x00cf: 0x00a4, # CURRENCY SIGN
+ 0x00d0: 0x00f0, # LATIN SMALL LETTER ETH
+ 0x00d1: 0x00d0, # LATIN CAPITAL LETTER ETH
+ 0x00d2: 0x00ca, # LATIN CAPITAL LETTER E WITH CIRCUMFLEX
+ 0x00d3: 0x00cb, # LATIN CAPITAL LETTER E WITH DIAERESIS
+ 0x00d4: 0x00c8, # LATIN CAPITAL LETTER E WITH GRAVE
+ 0x00d5: 0x0131, # LATIN SMALL LETTER DOTLESS I
+ 0x00d6: 0x00cd, # LATIN CAPITAL LETTER I WITH ACUTE
+ 0x00d7: 0x00ce, # LATIN CAPITAL LETTER I WITH CIRCUMFLEX
+ 0x00d8: 0x00cf, # LATIN CAPITAL LETTER I WITH DIAERESIS
+ 0x00d9: 0x2518, # BOX DRAWINGS LIGHT UP AND LEFT
+ 0x00da: 0x250c, # BOX DRAWINGS LIGHT DOWN AND RIGHT
+ 0x00db: 0x2588, # FULL BLOCK
+ 0x00dc: 0x2584, # LOWER HALF BLOCK
+ 0x00dd: 0x00a6, # BROKEN BAR
+ 0x00de: 0x00cc, # LATIN CAPITAL LETTER I WITH GRAVE
+ 0x00df: 0x2580, # UPPER HALF BLOCK
+ 0x00e0: 0x00d3, # LATIN CAPITAL LETTER O WITH ACUTE
+ 0x00e1: 0x00df, # LATIN SMALL LETTER SHARP S
+ 0x00e2: 0x00d4, # LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+ 0x00e3: 0x00d2, # LATIN CAPITAL LETTER O WITH GRAVE
+ 0x00e4: 0x00f5, # LATIN SMALL LETTER O WITH TILDE
+ 0x00e5: 0x00d5, # LATIN CAPITAL LETTER O WITH TILDE
+ 0x00e6: 0x00b5, # MICRO SIGN
+ 0x00e7: 0x00fe, # LATIN SMALL LETTER THORN
+ 0x00e8: 0x00de, # LATIN CAPITAL LETTER THORN
+ 0x00e9: 0x00da, # LATIN CAPITAL LETTER U WITH ACUTE
+ 0x00ea: 0x00db, # LATIN CAPITAL LETTER U WITH CIRCUMFLEX
+ 0x00eb: 0x00d9, # LATIN CAPITAL LETTER U WITH GRAVE
+ 0x00ec: 0x00fd, # LATIN SMALL LETTER Y WITH ACUTE
+ 0x00ed: 0x00dd, # LATIN CAPITAL LETTER Y WITH ACUTE
+ 0x00ee: 0x00af, # MACRON
+ 0x00ef: 0x00b4, # ACUTE ACCENT
+ 0x00f0: 0x00ad, # SOFT HYPHEN
+ 0x00f1: 0x00b1, # PLUS-MINUS SIGN
+ 0x00f2: 0x2017, # DOUBLE LOW LINE
+ 0x00f3: 0x00be, # VULGAR FRACTION THREE QUARTERS
+ 0x00f4: 0x00b6, # PILCROW SIGN
+ 0x00f5: 0x00a7, # SECTION SIGN
+ 0x00f6: 0x00f7, # DIVISION SIGN
+ 0x00f7: 0x00b8, # CEDILLA
+ 0x00f8: 0x00b0, # DEGREE SIGN
+ 0x00f9: 0x00a8, # DIAERESIS
+ 0x00fa: 0x00b7, # MIDDLE DOT
+ 0x00fb: 0x00b9, # SUPERSCRIPT ONE
+ 0x00fc: 0x00b3, # SUPERSCRIPT THREE
+ 0x00fd: 0x00b2, # SUPERSCRIPT TWO
+ 0x00fe: 0x25a0, # BLACK SQUARE
+ 0x00ff: 0x00a0, # NO-BREAK SPACE
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp852.py b/lib/jython/Lib/encodings/cp852.py new file mode 100644 index 000000000..2db7fa35f --- /dev/null +++ b/lib/jython/Lib/encodings/cp852.py @@ -0,0 +1,174 @@ +""" Python Character Mapping Codec generated from 'CP852.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x00c7, # LATIN CAPITAL LETTER C WITH CEDILLA
+ 0x0081: 0x00fc, # LATIN SMALL LETTER U WITH DIAERESIS
+ 0x0082: 0x00e9, # LATIN SMALL LETTER E WITH ACUTE
+ 0x0083: 0x00e2, # LATIN SMALL LETTER A WITH CIRCUMFLEX
+ 0x0084: 0x00e4, # LATIN SMALL LETTER A WITH DIAERESIS
+ 0x0085: 0x016f, # LATIN SMALL LETTER U WITH RING ABOVE
+ 0x0086: 0x0107, # LATIN SMALL LETTER C WITH ACUTE
+ 0x0087: 0x00e7, # LATIN SMALL LETTER C WITH CEDILLA
+ 0x0088: 0x0142, # LATIN SMALL LETTER L WITH STROKE
+ 0x0089: 0x00eb, # LATIN SMALL LETTER E WITH DIAERESIS
+ 0x008a: 0x0150, # LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
+ 0x008b: 0x0151, # LATIN SMALL LETTER O WITH DOUBLE ACUTE
+ 0x008c: 0x00ee, # LATIN SMALL LETTER I WITH CIRCUMFLEX
+ 0x008d: 0x0179, # LATIN CAPITAL LETTER Z WITH ACUTE
+ 0x008e: 0x00c4, # LATIN CAPITAL LETTER A WITH DIAERESIS
+ 0x008f: 0x0106, # LATIN CAPITAL LETTER C WITH ACUTE
+ 0x0090: 0x00c9, # LATIN CAPITAL LETTER E WITH ACUTE
+ 0x0091: 0x0139, # LATIN CAPITAL LETTER L WITH ACUTE
+ 0x0092: 0x013a, # LATIN SMALL LETTER L WITH ACUTE
+ 0x0093: 0x00f4, # LATIN SMALL LETTER O WITH CIRCUMFLEX
+ 0x0094: 0x00f6, # LATIN SMALL LETTER O WITH DIAERESIS
+ 0x0095: 0x013d, # LATIN CAPITAL LETTER L WITH CARON
+ 0x0096: 0x013e, # LATIN SMALL LETTER L WITH CARON
+ 0x0097: 0x015a, # LATIN CAPITAL LETTER S WITH ACUTE
+ 0x0098: 0x015b, # LATIN SMALL LETTER S WITH ACUTE
+ 0x0099: 0x00d6, # LATIN CAPITAL LETTER O WITH DIAERESIS
+ 0x009a: 0x00dc, # LATIN CAPITAL LETTER U WITH DIAERESIS
+ 0x009b: 0x0164, # LATIN CAPITAL LETTER T WITH CARON
+ 0x009c: 0x0165, # LATIN SMALL LETTER T WITH CARON
+ 0x009d: 0x0141, # LATIN CAPITAL LETTER L WITH STROKE
+ 0x009e: 0x00d7, # MULTIPLICATION SIGN
+ 0x009f: 0x010d, # LATIN SMALL LETTER C WITH CARON
+ 0x00a0: 0x00e1, # LATIN SMALL LETTER A WITH ACUTE
+ 0x00a1: 0x00ed, # LATIN SMALL LETTER I WITH ACUTE
+ 0x00a2: 0x00f3, # LATIN SMALL LETTER O WITH ACUTE
+ 0x00a3: 0x00fa, # LATIN SMALL LETTER U WITH ACUTE
+ 0x00a4: 0x0104, # LATIN CAPITAL LETTER A WITH OGONEK
+ 0x00a5: 0x0105, # LATIN SMALL LETTER A WITH OGONEK
+ 0x00a6: 0x017d, # LATIN CAPITAL LETTER Z WITH CARON
+ 0x00a7: 0x017e, # LATIN SMALL LETTER Z WITH CARON
+ 0x00a8: 0x0118, # LATIN CAPITAL LETTER E WITH OGONEK
+ 0x00a9: 0x0119, # LATIN SMALL LETTER E WITH OGONEK
+ 0x00aa: 0x00ac, # NOT SIGN
+ 0x00ab: 0x017a, # LATIN SMALL LETTER Z WITH ACUTE
+ 0x00ac: 0x010c, # LATIN CAPITAL LETTER C WITH CARON
+ 0x00ad: 0x015f, # LATIN SMALL LETTER S WITH CEDILLA
+ 0x00ae: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00af: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00b0: 0x2591, # LIGHT SHADE
+ 0x00b1: 0x2592, # MEDIUM SHADE
+ 0x00b2: 0x2593, # DARK SHADE
+ 0x00b3: 0x2502, # BOX DRAWINGS LIGHT VERTICAL
+ 0x00b4: 0x2524, # BOX DRAWINGS LIGHT VERTICAL AND LEFT
+ 0x00b5: 0x00c1, # LATIN CAPITAL LETTER A WITH ACUTE
+ 0x00b6: 0x00c2, # LATIN CAPITAL LETTER A WITH CIRCUMFLEX
+ 0x00b7: 0x011a, # LATIN CAPITAL LETTER E WITH CARON
+ 0x00b8: 0x015e, # LATIN CAPITAL LETTER S WITH CEDILLA
+ 0x00b9: 0x2563, # BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+ 0x00ba: 0x2551, # BOX DRAWINGS DOUBLE VERTICAL
+ 0x00bb: 0x2557, # BOX DRAWINGS DOUBLE DOWN AND LEFT
+ 0x00bc: 0x255d, # BOX DRAWINGS DOUBLE UP AND LEFT
+ 0x00bd: 0x017b, # LATIN CAPITAL LETTER Z WITH DOT ABOVE
+ 0x00be: 0x017c, # LATIN SMALL LETTER Z WITH DOT ABOVE
+ 0x00bf: 0x2510, # BOX DRAWINGS LIGHT DOWN AND LEFT
+ 0x00c0: 0x2514, # BOX DRAWINGS LIGHT UP AND RIGHT
+ 0x00c1: 0x2534, # BOX DRAWINGS LIGHT UP AND HORIZONTAL
+ 0x00c2: 0x252c, # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+ 0x00c3: 0x251c, # BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+ 0x00c4: 0x2500, # BOX DRAWINGS LIGHT HORIZONTAL
+ 0x00c5: 0x253c, # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+ 0x00c6: 0x0102, # LATIN CAPITAL LETTER A WITH BREVE
+ 0x00c7: 0x0103, # LATIN SMALL LETTER A WITH BREVE
+ 0x00c8: 0x255a, # BOX DRAWINGS DOUBLE UP AND RIGHT
+ 0x00c9: 0x2554, # BOX DRAWINGS DOUBLE DOWN AND RIGHT
+ 0x00ca: 0x2569, # BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+ 0x00cb: 0x2566, # BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+ 0x00cc: 0x2560, # BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+ 0x00cd: 0x2550, # BOX DRAWINGS DOUBLE HORIZONTAL
+ 0x00ce: 0x256c, # BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+ 0x00cf: 0x00a4, # CURRENCY SIGN
+ 0x00d0: 0x0111, # LATIN SMALL LETTER D WITH STROKE
+ 0x00d1: 0x0110, # LATIN CAPITAL LETTER D WITH STROKE
+ 0x00d2: 0x010e, # LATIN CAPITAL LETTER D WITH CARON
+ 0x00d3: 0x00cb, # LATIN CAPITAL LETTER E WITH DIAERESIS
+ 0x00d4: 0x010f, # LATIN SMALL LETTER D WITH CARON
+ 0x00d5: 0x0147, # LATIN CAPITAL LETTER N WITH CARON
+ 0x00d6: 0x00cd, # LATIN CAPITAL LETTER I WITH ACUTE
+ 0x00d7: 0x00ce, # LATIN CAPITAL LETTER I WITH CIRCUMFLEX
+ 0x00d8: 0x011b, # LATIN SMALL LETTER E WITH CARON
+ 0x00d9: 0x2518, # BOX DRAWINGS LIGHT UP AND LEFT
+ 0x00da: 0x250c, # BOX DRAWINGS LIGHT DOWN AND RIGHT
+ 0x00db: 0x2588, # FULL BLOCK
+ 0x00dc: 0x2584, # LOWER HALF BLOCK
+ 0x00dd: 0x0162, # LATIN CAPITAL LETTER T WITH CEDILLA
+ 0x00de: 0x016e, # LATIN CAPITAL LETTER U WITH RING ABOVE
+ 0x00df: 0x2580, # UPPER HALF BLOCK
+ 0x00e0: 0x00d3, # LATIN CAPITAL LETTER O WITH ACUTE
+ 0x00e1: 0x00df, # LATIN SMALL LETTER SHARP S
+ 0x00e2: 0x00d4, # LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+ 0x00e3: 0x0143, # LATIN CAPITAL LETTER N WITH ACUTE
+ 0x00e4: 0x0144, # LATIN SMALL LETTER N WITH ACUTE
+ 0x00e5: 0x0148, # LATIN SMALL LETTER N WITH CARON
+ 0x00e6: 0x0160, # LATIN CAPITAL LETTER S WITH CARON
+ 0x00e7: 0x0161, # LATIN SMALL LETTER S WITH CARON
+ 0x00e8: 0x0154, # LATIN CAPITAL LETTER R WITH ACUTE
+ 0x00e9: 0x00da, # LATIN CAPITAL LETTER U WITH ACUTE
+ 0x00ea: 0x0155, # LATIN SMALL LETTER R WITH ACUTE
+ 0x00eb: 0x0170, # LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
+ 0x00ec: 0x00fd, # LATIN SMALL LETTER Y WITH ACUTE
+ 0x00ed: 0x00dd, # LATIN CAPITAL LETTER Y WITH ACUTE
+ 0x00ee: 0x0163, # LATIN SMALL LETTER T WITH CEDILLA
+ 0x00ef: 0x00b4, # ACUTE ACCENT
+ 0x00f0: 0x00ad, # SOFT HYPHEN
+ 0x00f1: 0x02dd, # DOUBLE ACUTE ACCENT
+ 0x00f2: 0x02db, # OGONEK
+ 0x00f3: 0x02c7, # CARON
+ 0x00f4: 0x02d8, # BREVE
+ 0x00f5: 0x00a7, # SECTION SIGN
+ 0x00f6: 0x00f7, # DIVISION SIGN
+ 0x00f7: 0x00b8, # CEDILLA
+ 0x00f8: 0x00b0, # DEGREE SIGN
+ 0x00f9: 0x00a8, # DIAERESIS
+ 0x00fa: 0x02d9, # DOT ABOVE
+ 0x00fb: 0x0171, # LATIN SMALL LETTER U WITH DOUBLE ACUTE
+ 0x00fc: 0x0158, # LATIN CAPITAL LETTER R WITH CARON
+ 0x00fd: 0x0159, # LATIN SMALL LETTER R WITH CARON
+ 0x00fe: 0x25a0, # BLACK SQUARE
+ 0x00ff: 0x00a0, # NO-BREAK SPACE
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp855.py b/lib/jython/Lib/encodings/cp855.py new file mode 100644 index 000000000..3d119fd10 --- /dev/null +++ b/lib/jython/Lib/encodings/cp855.py @@ -0,0 +1,174 @@ +""" Python Character Mapping Codec generated from 'CP855.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x0452, # CYRILLIC SMALL LETTER DJE
+ 0x0081: 0x0402, # CYRILLIC CAPITAL LETTER DJE
+ 0x0082: 0x0453, # CYRILLIC SMALL LETTER GJE
+ 0x0083: 0x0403, # CYRILLIC CAPITAL LETTER GJE
+ 0x0084: 0x0451, # CYRILLIC SMALL LETTER IO
+ 0x0085: 0x0401, # CYRILLIC CAPITAL LETTER IO
+ 0x0086: 0x0454, # CYRILLIC SMALL LETTER UKRAINIAN IE
+ 0x0087: 0x0404, # CYRILLIC CAPITAL LETTER UKRAINIAN IE
+ 0x0088: 0x0455, # CYRILLIC SMALL LETTER DZE
+ 0x0089: 0x0405, # CYRILLIC CAPITAL LETTER DZE
+ 0x008a: 0x0456, # CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
+ 0x008b: 0x0406, # CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
+ 0x008c: 0x0457, # CYRILLIC SMALL LETTER YI
+ 0x008d: 0x0407, # CYRILLIC CAPITAL LETTER YI
+ 0x008e: 0x0458, # CYRILLIC SMALL LETTER JE
+ 0x008f: 0x0408, # CYRILLIC CAPITAL LETTER JE
+ 0x0090: 0x0459, # CYRILLIC SMALL LETTER LJE
+ 0x0091: 0x0409, # CYRILLIC CAPITAL LETTER LJE
+ 0x0092: 0x045a, # CYRILLIC SMALL LETTER NJE
+ 0x0093: 0x040a, # CYRILLIC CAPITAL LETTER NJE
+ 0x0094: 0x045b, # CYRILLIC SMALL LETTER TSHE
+ 0x0095: 0x040b, # CYRILLIC CAPITAL LETTER TSHE
+ 0x0096: 0x045c, # CYRILLIC SMALL LETTER KJE
+ 0x0097: 0x040c, # CYRILLIC CAPITAL LETTER KJE
+ 0x0098: 0x045e, # CYRILLIC SMALL LETTER SHORT U
+ 0x0099: 0x040e, # CYRILLIC CAPITAL LETTER SHORT U
+ 0x009a: 0x045f, # CYRILLIC SMALL LETTER DZHE
+ 0x009b: 0x040f, # CYRILLIC CAPITAL LETTER DZHE
+ 0x009c: 0x044e, # CYRILLIC SMALL LETTER YU
+ 0x009d: 0x042e, # CYRILLIC CAPITAL LETTER YU
+ 0x009e: 0x044a, # CYRILLIC SMALL LETTER HARD SIGN
+ 0x009f: 0x042a, # CYRILLIC CAPITAL LETTER HARD SIGN
+ 0x00a0: 0x0430, # CYRILLIC SMALL LETTER A
+ 0x00a1: 0x0410, # CYRILLIC CAPITAL LETTER A
+ 0x00a2: 0x0431, # CYRILLIC SMALL LETTER BE
+ 0x00a3: 0x0411, # CYRILLIC CAPITAL LETTER BE
+ 0x00a4: 0x0446, # CYRILLIC SMALL LETTER TSE
+ 0x00a5: 0x0426, # CYRILLIC CAPITAL LETTER TSE
+ 0x00a6: 0x0434, # CYRILLIC SMALL LETTER DE
+ 0x00a7: 0x0414, # CYRILLIC CAPITAL LETTER DE
+ 0x00a8: 0x0435, # CYRILLIC SMALL LETTER IE
+ 0x00a9: 0x0415, # CYRILLIC CAPITAL LETTER IE
+ 0x00aa: 0x0444, # CYRILLIC SMALL LETTER EF
+ 0x00ab: 0x0424, # CYRILLIC CAPITAL LETTER EF
+ 0x00ac: 0x0433, # CYRILLIC SMALL LETTER GHE
+ 0x00ad: 0x0413, # CYRILLIC CAPITAL LETTER GHE
+ 0x00ae: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00af: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00b0: 0x2591, # LIGHT SHADE
+ 0x00b1: 0x2592, # MEDIUM SHADE
+ 0x00b2: 0x2593, # DARK SHADE
+ 0x00b3: 0x2502, # BOX DRAWINGS LIGHT VERTICAL
+ 0x00b4: 0x2524, # BOX DRAWINGS LIGHT VERTICAL AND LEFT
+ 0x00b5: 0x0445, # CYRILLIC SMALL LETTER HA
+ 0x00b6: 0x0425, # CYRILLIC CAPITAL LETTER HA
+ 0x00b7: 0x0438, # CYRILLIC SMALL LETTER I
+ 0x00b8: 0x0418, # CYRILLIC CAPITAL LETTER I
+ 0x00b9: 0x2563, # BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+ 0x00ba: 0x2551, # BOX DRAWINGS DOUBLE VERTICAL
+ 0x00bb: 0x2557, # BOX DRAWINGS DOUBLE DOWN AND LEFT
+ 0x00bc: 0x255d, # BOX DRAWINGS DOUBLE UP AND LEFT
+ 0x00bd: 0x0439, # CYRILLIC SMALL LETTER SHORT I
+ 0x00be: 0x0419, # CYRILLIC CAPITAL LETTER SHORT I
+ 0x00bf: 0x2510, # BOX DRAWINGS LIGHT DOWN AND LEFT
+ 0x00c0: 0x2514, # BOX DRAWINGS LIGHT UP AND RIGHT
+ 0x00c1: 0x2534, # BOX DRAWINGS LIGHT UP AND HORIZONTAL
+ 0x00c2: 0x252c, # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+ 0x00c3: 0x251c, # BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+ 0x00c4: 0x2500, # BOX DRAWINGS LIGHT HORIZONTAL
+ 0x00c5: 0x253c, # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+ 0x00c6: 0x043a, # CYRILLIC SMALL LETTER KA
+ 0x00c7: 0x041a, # CYRILLIC CAPITAL LETTER KA
+ 0x00c8: 0x255a, # BOX DRAWINGS DOUBLE UP AND RIGHT
+ 0x00c9: 0x2554, # BOX DRAWINGS DOUBLE DOWN AND RIGHT
+ 0x00ca: 0x2569, # BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+ 0x00cb: 0x2566, # BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+ 0x00cc: 0x2560, # BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+ 0x00cd: 0x2550, # BOX DRAWINGS DOUBLE HORIZONTAL
+ 0x00ce: 0x256c, # BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+ 0x00cf: 0x00a4, # CURRENCY SIGN
+ 0x00d0: 0x043b, # CYRILLIC SMALL LETTER EL
+ 0x00d1: 0x041b, # CYRILLIC CAPITAL LETTER EL
+ 0x00d2: 0x043c, # CYRILLIC SMALL LETTER EM
+ 0x00d3: 0x041c, # CYRILLIC CAPITAL LETTER EM
+ 0x00d4: 0x043d, # CYRILLIC SMALL LETTER EN
+ 0x00d5: 0x041d, # CYRILLIC CAPITAL LETTER EN
+ 0x00d6: 0x043e, # CYRILLIC SMALL LETTER O
+ 0x00d7: 0x041e, # CYRILLIC CAPITAL LETTER O
+ 0x00d8: 0x043f, # CYRILLIC SMALL LETTER PE
+ 0x00d9: 0x2518, # BOX DRAWINGS LIGHT UP AND LEFT
+ 0x00da: 0x250c, # BOX DRAWINGS LIGHT DOWN AND RIGHT
+ 0x00db: 0x2588, # FULL BLOCK
+ 0x00dc: 0x2584, # LOWER HALF BLOCK
+ 0x00dd: 0x041f, # CYRILLIC CAPITAL LETTER PE
+ 0x00de: 0x044f, # CYRILLIC SMALL LETTER YA
+ 0x00df: 0x2580, # UPPER HALF BLOCK
+ 0x00e0: 0x042f, # CYRILLIC CAPITAL LETTER YA
+ 0x00e1: 0x0440, # CYRILLIC SMALL LETTER ER
+ 0x00e2: 0x0420, # CYRILLIC CAPITAL LETTER ER
+ 0x00e3: 0x0441, # CYRILLIC SMALL LETTER ES
+ 0x00e4: 0x0421, # CYRILLIC CAPITAL LETTER ES
+ 0x00e5: 0x0442, # CYRILLIC SMALL LETTER TE
+ 0x00e6: 0x0422, # CYRILLIC CAPITAL LETTER TE
+ 0x00e7: 0x0443, # CYRILLIC SMALL LETTER U
+ 0x00e8: 0x0423, # CYRILLIC CAPITAL LETTER U
+ 0x00e9: 0x0436, # CYRILLIC SMALL LETTER ZHE
+ 0x00ea: 0x0416, # CYRILLIC CAPITAL LETTER ZHE
+ 0x00eb: 0x0432, # CYRILLIC SMALL LETTER VE
+ 0x00ec: 0x0412, # CYRILLIC CAPITAL LETTER VE
+ 0x00ed: 0x044c, # CYRILLIC SMALL LETTER SOFT SIGN
+ 0x00ee: 0x042c, # CYRILLIC CAPITAL LETTER SOFT SIGN
+ 0x00ef: 0x2116, # NUMERO SIGN
+ 0x00f0: 0x00ad, # SOFT HYPHEN
+ 0x00f1: 0x044b, # CYRILLIC SMALL LETTER YERU
+ 0x00f2: 0x042b, # CYRILLIC CAPITAL LETTER YERU
+ 0x00f3: 0x0437, # CYRILLIC SMALL LETTER ZE
+ 0x00f4: 0x0417, # CYRILLIC CAPITAL LETTER ZE
+ 0x00f5: 0x0448, # CYRILLIC SMALL LETTER SHA
+ 0x00f6: 0x0428, # CYRILLIC CAPITAL LETTER SHA
+ 0x00f7: 0x044d, # CYRILLIC SMALL LETTER E
+ 0x00f8: 0x042d, # CYRILLIC CAPITAL LETTER E
+ 0x00f9: 0x0449, # CYRILLIC SMALL LETTER SHCHA
+ 0x00fa: 0x0429, # CYRILLIC CAPITAL LETTER SHCHA
+ 0x00fb: 0x0447, # CYRILLIC SMALL LETTER CHE
+ 0x00fc: 0x0427, # CYRILLIC CAPITAL LETTER CHE
+ 0x00fd: 0x00a7, # SECTION SIGN
+ 0x00fe: 0x25a0, # BLACK SQUARE
+ 0x00ff: 0x00a0, # NO-BREAK SPACE
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp856.py b/lib/jython/Lib/encodings/cp856.py new file mode 100644 index 000000000..1cd28c260 --- /dev/null +++ b/lib/jython/Lib/encodings/cp856.py @@ -0,0 +1,174 @@ +""" Python Character Mapping Codec generated from 'CP856.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x05d0, # HEBREW LETTER ALEF
+ 0x0081: 0x05d1, # HEBREW LETTER BET
+ 0x0082: 0x05d2, # HEBREW LETTER GIMEL
+ 0x0083: 0x05d3, # HEBREW LETTER DALET
+ 0x0084: 0x05d4, # HEBREW LETTER HE
+ 0x0085: 0x05d5, # HEBREW LETTER VAV
+ 0x0086: 0x05d6, # HEBREW LETTER ZAYIN
+ 0x0087: 0x05d7, # HEBREW LETTER HET
+ 0x0088: 0x05d8, # HEBREW LETTER TET
+ 0x0089: 0x05d9, # HEBREW LETTER YOD
+ 0x008a: 0x05da, # HEBREW LETTER FINAL KAF
+ 0x008b: 0x05db, # HEBREW LETTER KAF
+ 0x008c: 0x05dc, # HEBREW LETTER LAMED
+ 0x008d: 0x05dd, # HEBREW LETTER FINAL MEM
+ 0x008e: 0x05de, # HEBREW LETTER MEM
+ 0x008f: 0x05df, # HEBREW LETTER FINAL NUN
+ 0x0090: 0x05e0, # HEBREW LETTER NUN
+ 0x0091: 0x05e1, # HEBREW LETTER SAMEKH
+ 0x0092: 0x05e2, # HEBREW LETTER AYIN
+ 0x0093: 0x05e3, # HEBREW LETTER FINAL PE
+ 0x0094: 0x05e4, # HEBREW LETTER PE
+ 0x0095: 0x05e5, # HEBREW LETTER FINAL TSADI
+ 0x0096: 0x05e6, # HEBREW LETTER TSADI
+ 0x0097: 0x05e7, # HEBREW LETTER QOF
+ 0x0098: 0x05e8, # HEBREW LETTER RESH
+ 0x0099: 0x05e9, # HEBREW LETTER SHIN
+ 0x009a: 0x05ea, # HEBREW LETTER TAV
+ 0x009b: None, # UNDEFINED
+ 0x009c: 0x00a3, # POUND SIGN
+ 0x009d: None, # UNDEFINED
+ 0x009e: 0x00d7, # MULTIPLICATION SIGN
+ 0x009f: None, # UNDEFINED
+ 0x00a0: None, # UNDEFINED
+ 0x00a1: None, # UNDEFINED
+ 0x00a2: None, # UNDEFINED
+ 0x00a3: None, # UNDEFINED
+ 0x00a4: None, # UNDEFINED
+ 0x00a5: None, # UNDEFINED
+ 0x00a6: None, # UNDEFINED
+ 0x00a7: None, # UNDEFINED
+ 0x00a8: None, # UNDEFINED
+ 0x00a9: 0x00ae, # REGISTERED SIGN
+ 0x00aa: 0x00ac, # NOT SIGN
+ 0x00ab: 0x00bd, # VULGAR FRACTION ONE HALF
+ 0x00ac: 0x00bc, # VULGAR FRACTION ONE QUARTER
+ 0x00ad: None, # UNDEFINED
+ 0x00ae: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00af: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00b0: 0x2591, # LIGHT SHADE
+ 0x00b1: 0x2592, # MEDIUM SHADE
+ 0x00b2: 0x2593, # DARK SHADE
+ 0x00b3: 0x2502, # BOX DRAWINGS LIGHT VERTICAL
+ 0x00b4: 0x2524, # BOX DRAWINGS LIGHT VERTICAL AND LEFT
+ 0x00b5: None, # UNDEFINED
+ 0x00b6: None, # UNDEFINED
+ 0x00b7: None, # UNDEFINED
+ 0x00b8: 0x00a9, # COPYRIGHT SIGN
+ 0x00b9: 0x2563, # BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+ 0x00ba: 0x2551, # BOX DRAWINGS DOUBLE VERTICAL
+ 0x00bb: 0x2557, # BOX DRAWINGS DOUBLE DOWN AND LEFT
+ 0x00bc: 0x255d, # BOX DRAWINGS DOUBLE UP AND LEFT
+ 0x00bd: 0x00a2, # CENT SIGN
+ 0x00be: 0x00a5, # YEN SIGN
+ 0x00bf: 0x2510, # BOX DRAWINGS LIGHT DOWN AND LEFT
+ 0x00c0: 0x2514, # BOX DRAWINGS LIGHT UP AND RIGHT
+ 0x00c1: 0x2534, # BOX DRAWINGS LIGHT UP AND HORIZONTAL
+ 0x00c2: 0x252c, # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+ 0x00c3: 0x251c, # BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+ 0x00c4: 0x2500, # BOX DRAWINGS LIGHT HORIZONTAL
+ 0x00c5: 0x253c, # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+ 0x00c6: None, # UNDEFINED
+ 0x00c7: None, # UNDEFINED
+ 0x00c8: 0x255a, # BOX DRAWINGS DOUBLE UP AND RIGHT
+ 0x00c9: 0x2554, # BOX DRAWINGS DOUBLE DOWN AND RIGHT
+ 0x00ca: 0x2569, # BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+ 0x00cb: 0x2566, # BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+ 0x00cc: 0x2560, # BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+ 0x00cd: 0x2550, # BOX DRAWINGS DOUBLE HORIZONTAL
+ 0x00ce: 0x256c, # BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+ 0x00cf: 0x00a4, # CURRENCY SIGN
+ 0x00d0: None, # UNDEFINED
+ 0x00d1: None, # UNDEFINED
+ 0x00d2: None, # UNDEFINED
+ 0x00d3: None, # UNDEFINEDS
+ 0x00d4: None, # UNDEFINED
+ 0x00d5: None, # UNDEFINED
+ 0x00d6: None, # UNDEFINEDE
+ 0x00d7: None, # UNDEFINED
+ 0x00d8: None, # UNDEFINED
+ 0x00d9: 0x2518, # BOX DRAWINGS LIGHT UP AND LEFT
+ 0x00da: 0x250c, # BOX DRAWINGS LIGHT DOWN AND RIGHT
+ 0x00db: 0x2588, # FULL BLOCK
+ 0x00dc: 0x2584, # LOWER HALF BLOCK
+ 0x00dd: 0x00a6, # BROKEN BAR
+ 0x00de: None, # UNDEFINED
+ 0x00df: 0x2580, # UPPER HALF BLOCK
+ 0x00e0: None, # UNDEFINED
+ 0x00e1: None, # UNDEFINED
+ 0x00e2: None, # UNDEFINED
+ 0x00e3: None, # UNDEFINED
+ 0x00e4: None, # UNDEFINED
+ 0x00e5: None, # UNDEFINED
+ 0x00e6: 0x00b5, # MICRO SIGN
+ 0x00e7: None, # UNDEFINED
+ 0x00e8: None, # UNDEFINED
+ 0x00e9: None, # UNDEFINED
+ 0x00ea: None, # UNDEFINED
+ 0x00eb: None, # UNDEFINED
+ 0x00ec: None, # UNDEFINED
+ 0x00ed: None, # UNDEFINED
+ 0x00ee: 0x00af, # MACRON
+ 0x00ef: 0x00b4, # ACUTE ACCENT
+ 0x00f0: 0x00ad, # SOFT HYPHEN
+ 0x00f1: 0x00b1, # PLUS-MINUS SIGN
+ 0x00f2: 0x2017, # DOUBLE LOW LINE
+ 0x00f3: 0x00be, # VULGAR FRACTION THREE QUARTERS
+ 0x00f4: 0x00b6, # PILCROW SIGN
+ 0x00f5: 0x00a7, # SECTION SIGN
+ 0x00f6: 0x00f7, # DIVISION SIGN
+ 0x00f7: 0x00b8, # CEDILLA
+ 0x00f8: 0x00b0, # DEGREE SIGN
+ 0x00f9: 0x00a8, # DIAERESIS
+ 0x00fa: 0x00b7, # MIDDLE DOT
+ 0x00fb: 0x00b9, # SUPERSCRIPT ONE
+ 0x00fc: 0x00b3, # SUPERSCRIPT THREE
+ 0x00fd: 0x00b2, # SUPERSCRIPT TWO
+ 0x00fe: 0x25a0, # BLACK SQUARE
+ 0x00ff: 0x00a0, # NO-BREAK SPACE
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp857.py b/lib/jython/Lib/encodings/cp857.py new file mode 100644 index 000000000..d8addc1f6 --- /dev/null +++ b/lib/jython/Lib/encodings/cp857.py @@ -0,0 +1,173 @@ +""" Python Character Mapping Codec generated from 'CP857.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x00c7, # LATIN CAPITAL LETTER C WITH CEDILLA
+ 0x0081: 0x00fc, # LATIN SMALL LETTER U WITH DIAERESIS
+ 0x0082: 0x00e9, # LATIN SMALL LETTER E WITH ACUTE
+ 0x0083: 0x00e2, # LATIN SMALL LETTER A WITH CIRCUMFLEX
+ 0x0084: 0x00e4, # LATIN SMALL LETTER A WITH DIAERESIS
+ 0x0085: 0x00e0, # LATIN SMALL LETTER A WITH GRAVE
+ 0x0086: 0x00e5, # LATIN SMALL LETTER A WITH RING ABOVE
+ 0x0087: 0x00e7, # LATIN SMALL LETTER C WITH CEDILLA
+ 0x0088: 0x00ea, # LATIN SMALL LETTER E WITH CIRCUMFLEX
+ 0x0089: 0x00eb, # LATIN SMALL LETTER E WITH DIAERESIS
+ 0x008a: 0x00e8, # LATIN SMALL LETTER E WITH GRAVE
+ 0x008b: 0x00ef, # LATIN SMALL LETTER I WITH DIAERESIS
+ 0x008c: 0x00ee, # LATIN SMALL LETTER I WITH CIRCUMFLEX
+ 0x008d: 0x0131, # LATIN SMALL LETTER DOTLESS I
+ 0x008e: 0x00c4, # LATIN CAPITAL LETTER A WITH DIAERESIS
+ 0x008f: 0x00c5, # LATIN CAPITAL LETTER A WITH RING ABOVE
+ 0x0090: 0x00c9, # LATIN CAPITAL LETTER E WITH ACUTE
+ 0x0091: 0x00e6, # LATIN SMALL LIGATURE AE
+ 0x0092: 0x00c6, # LATIN CAPITAL LIGATURE AE
+ 0x0093: 0x00f4, # LATIN SMALL LETTER O WITH CIRCUMFLEX
+ 0x0094: 0x00f6, # LATIN SMALL LETTER O WITH DIAERESIS
+ 0x0095: 0x00f2, # LATIN SMALL LETTER O WITH GRAVE
+ 0x0096: 0x00fb, # LATIN SMALL LETTER U WITH CIRCUMFLEX
+ 0x0097: 0x00f9, # LATIN SMALL LETTER U WITH GRAVE
+ 0x0098: 0x0130, # LATIN CAPITAL LETTER I WITH DOT ABOVE
+ 0x0099: 0x00d6, # LATIN CAPITAL LETTER O WITH DIAERESIS
+ 0x009a: 0x00dc, # LATIN CAPITAL LETTER U WITH DIAERESIS
+ 0x009b: 0x00f8, # LATIN SMALL LETTER O WITH STROKE
+ 0x009c: 0x00a3, # POUND SIGN
+ 0x009d: 0x00d8, # LATIN CAPITAL LETTER O WITH STROKE
+ 0x009e: 0x015e, # LATIN CAPITAL LETTER S WITH CEDILLA
+ 0x009f: 0x015f, # LATIN SMALL LETTER S WITH CEDILLA
+ 0x00a0: 0x00e1, # LATIN SMALL LETTER A WITH ACUTE
+ 0x00a1: 0x00ed, # LATIN SMALL LETTER I WITH ACUTE
+ 0x00a2: 0x00f3, # LATIN SMALL LETTER O WITH ACUTE
+ 0x00a3: 0x00fa, # LATIN SMALL LETTER U WITH ACUTE
+ 0x00a4: 0x00f1, # LATIN SMALL LETTER N WITH TILDE
+ 0x00a5: 0x00d1, # LATIN CAPITAL LETTER N WITH TILDE
+ 0x00a6: 0x011e, # LATIN CAPITAL LETTER G WITH BREVE
+ 0x00a7: 0x011f, # LATIN SMALL LETTER G WITH BREVE
+ 0x00a8: 0x00bf, # INVERTED QUESTION MARK
+ 0x00a9: 0x00ae, # REGISTERED SIGN
+ 0x00aa: 0x00ac, # NOT SIGN
+ 0x00ab: 0x00bd, # VULGAR FRACTION ONE HALF
+ 0x00ac: 0x00bc, # VULGAR FRACTION ONE QUARTER
+ 0x00ad: 0x00a1, # INVERTED EXCLAMATION MARK
+ 0x00ae: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00af: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00b0: 0x2591, # LIGHT SHADE
+ 0x00b1: 0x2592, # MEDIUM SHADE
+ 0x00b2: 0x2593, # DARK SHADE
+ 0x00b3: 0x2502, # BOX DRAWINGS LIGHT VERTICAL
+ 0x00b4: 0x2524, # BOX DRAWINGS LIGHT VERTICAL AND LEFT
+ 0x00b5: 0x00c1, # LATIN CAPITAL LETTER A WITH ACUTE
+ 0x00b6: 0x00c2, # LATIN CAPITAL LETTER A WITH CIRCUMFLEX
+ 0x00b7: 0x00c0, # LATIN CAPITAL LETTER A WITH GRAVE
+ 0x00b8: 0x00a9, # COPYRIGHT SIGN
+ 0x00b9: 0x2563, # BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+ 0x00ba: 0x2551, # BOX DRAWINGS DOUBLE VERTICAL
+ 0x00bb: 0x2557, # BOX DRAWINGS DOUBLE DOWN AND LEFT
+ 0x00bc: 0x255d, # BOX DRAWINGS DOUBLE UP AND LEFT
+ 0x00bd: 0x00a2, # CENT SIGN
+ 0x00be: 0x00a5, # YEN SIGN
+ 0x00bf: 0x2510, # BOX DRAWINGS LIGHT DOWN AND LEFT
+ 0x00c0: 0x2514, # BOX DRAWINGS LIGHT UP AND RIGHT
+ 0x00c1: 0x2534, # BOX DRAWINGS LIGHT UP AND HORIZONTAL
+ 0x00c2: 0x252c, # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+ 0x00c3: 0x251c, # BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+ 0x00c4: 0x2500, # BOX DRAWINGS LIGHT HORIZONTAL
+ 0x00c5: 0x253c, # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+ 0x00c6: 0x00e3, # LATIN SMALL LETTER A WITH TILDE
+ 0x00c7: 0x00c3, # LATIN CAPITAL LETTER A WITH TILDE
+ 0x00c8: 0x255a, # BOX DRAWINGS DOUBLE UP AND RIGHT
+ 0x00c9: 0x2554, # BOX DRAWINGS DOUBLE DOWN AND RIGHT
+ 0x00ca: 0x2569, # BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+ 0x00cb: 0x2566, # BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+ 0x00cc: 0x2560, # BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+ 0x00cd: 0x2550, # BOX DRAWINGS DOUBLE HORIZONTAL
+ 0x00ce: 0x256c, # BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+ 0x00cf: 0x00a4, # CURRENCY SIGN
+ 0x00d0: 0x00ba, # MASCULINE ORDINAL INDICATOR
+ 0x00d1: 0x00aa, # FEMININE ORDINAL INDICATOR
+ 0x00d2: 0x00ca, # LATIN CAPITAL LETTER E WITH CIRCUMFLEX
+ 0x00d3: 0x00cb, # LATIN CAPITAL LETTER E WITH DIAERESIS
+ 0x00d4: 0x00c8, # LATIN CAPITAL LETTER E WITH GRAVE
+ 0x00d5: None, # UNDEFINED
+ 0x00d6: 0x00cd, # LATIN CAPITAL LETTER I WITH ACUTE
+ 0x00d7: 0x00ce, # LATIN CAPITAL LETTER I WITH CIRCUMFLEX
+ 0x00d8: 0x00cf, # LATIN CAPITAL LETTER I WITH DIAERESIS
+ 0x00d9: 0x2518, # BOX DRAWINGS LIGHT UP AND LEFT
+ 0x00da: 0x250c, # BOX DRAWINGS LIGHT DOWN AND RIGHT
+ 0x00db: 0x2588, # FULL BLOCK
+ 0x00dc: 0x2584, # LOWER HALF BLOCK
+ 0x00dd: 0x00a6, # BROKEN BAR
+ 0x00de: 0x00cc, # LATIN CAPITAL LETTER I WITH GRAVE
+ 0x00df: 0x2580, # UPPER HALF BLOCK
+ 0x00e0: 0x00d3, # LATIN CAPITAL LETTER O WITH ACUTE
+ 0x00e1: 0x00df, # LATIN SMALL LETTER SHARP S
+ 0x00e2: 0x00d4, # LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+ 0x00e3: 0x00d2, # LATIN CAPITAL LETTER O WITH GRAVE
+ 0x00e4: 0x00f5, # LATIN SMALL LETTER O WITH TILDE
+ 0x00e5: 0x00d5, # LATIN CAPITAL LETTER O WITH TILDE
+ 0x00e6: 0x00b5, # MICRO SIGN
+ 0x00e7: None, # UNDEFINED
+ 0x00e8: 0x00d7, # MULTIPLICATION SIGN
+ 0x00e9: 0x00da, # LATIN CAPITAL LETTER U WITH ACUTE
+ 0x00ea: 0x00db, # LATIN CAPITAL LETTER U WITH CIRCUMFLEX
+ 0x00eb: 0x00d9, # LATIN CAPITAL LETTER U WITH GRAVE
+ 0x00ed: 0x00ff, # LATIN SMALL LETTER Y WITH DIAERESIS
+ 0x00ee: 0x00af, # MACRON
+ 0x00ef: 0x00b4, # ACUTE ACCENT
+ 0x00f0: 0x00ad, # SOFT HYPHEN
+ 0x00f1: 0x00b1, # PLUS-MINUS SIGN
+ 0x00f2: None, # UNDEFINED
+ 0x00f3: 0x00be, # VULGAR FRACTION THREE QUARTERS
+ 0x00f4: 0x00b6, # PILCROW SIGN
+ 0x00f5: 0x00a7, # SECTION SIGN
+ 0x00f6: 0x00f7, # DIVISION SIGN
+ 0x00f7: 0x00b8, # CEDILLA
+ 0x00f8: 0x00b0, # DEGREE SIGN
+ 0x00f9: 0x00a8, # DIAERESIS
+ 0x00fa: 0x00b7, # MIDDLE DOT
+ 0x00fb: 0x00b9, # SUPERSCRIPT ONE
+ 0x00fc: 0x00b3, # SUPERSCRIPT THREE
+ 0x00fd: 0x00b2, # SUPERSCRIPT TWO
+ 0x00fe: 0x25a0, # BLACK SQUARE
+ 0x00ff: 0x00a0, # NO-BREAK SPACE
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp860.py b/lib/jython/Lib/encodings/cp860.py new file mode 100644 index 000000000..8d7876497 --- /dev/null +++ b/lib/jython/Lib/encodings/cp860.py @@ -0,0 +1,174 @@ +""" Python Character Mapping Codec generated from 'CP860.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x00c7, # LATIN CAPITAL LETTER C WITH CEDILLA
+ 0x0081: 0x00fc, # LATIN SMALL LETTER U WITH DIAERESIS
+ 0x0082: 0x00e9, # LATIN SMALL LETTER E WITH ACUTE
+ 0x0083: 0x00e2, # LATIN SMALL LETTER A WITH CIRCUMFLEX
+ 0x0084: 0x00e3, # LATIN SMALL LETTER A WITH TILDE
+ 0x0085: 0x00e0, # LATIN SMALL LETTER A WITH GRAVE
+ 0x0086: 0x00c1, # LATIN CAPITAL LETTER A WITH ACUTE
+ 0x0087: 0x00e7, # LATIN SMALL LETTER C WITH CEDILLA
+ 0x0088: 0x00ea, # LATIN SMALL LETTER E WITH CIRCUMFLEX
+ 0x0089: 0x00ca, # LATIN CAPITAL LETTER E WITH CIRCUMFLEX
+ 0x008a: 0x00e8, # LATIN SMALL LETTER E WITH GRAVE
+ 0x008b: 0x00cd, # LATIN CAPITAL LETTER I WITH ACUTE
+ 0x008c: 0x00d4, # LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+ 0x008d: 0x00ec, # LATIN SMALL LETTER I WITH GRAVE
+ 0x008e: 0x00c3, # LATIN CAPITAL LETTER A WITH TILDE
+ 0x008f: 0x00c2, # LATIN CAPITAL LETTER A WITH CIRCUMFLEX
+ 0x0090: 0x00c9, # LATIN CAPITAL LETTER E WITH ACUTE
+ 0x0091: 0x00c0, # LATIN CAPITAL LETTER A WITH GRAVE
+ 0x0092: 0x00c8, # LATIN CAPITAL LETTER E WITH GRAVE
+ 0x0093: 0x00f4, # LATIN SMALL LETTER O WITH CIRCUMFLEX
+ 0x0094: 0x00f5, # LATIN SMALL LETTER O WITH TILDE
+ 0x0095: 0x00f2, # LATIN SMALL LETTER O WITH GRAVE
+ 0x0096: 0x00da, # LATIN CAPITAL LETTER U WITH ACUTE
+ 0x0097: 0x00f9, # LATIN SMALL LETTER U WITH GRAVE
+ 0x0098: 0x00cc, # LATIN CAPITAL LETTER I WITH GRAVE
+ 0x0099: 0x00d5, # LATIN CAPITAL LETTER O WITH TILDE
+ 0x009a: 0x00dc, # LATIN CAPITAL LETTER U WITH DIAERESIS
+ 0x009b: 0x00a2, # CENT SIGN
+ 0x009c: 0x00a3, # POUND SIGN
+ 0x009d: 0x00d9, # LATIN CAPITAL LETTER U WITH GRAVE
+ 0x009e: 0x20a7, # PESETA SIGN
+ 0x009f: 0x00d3, # LATIN CAPITAL LETTER O WITH ACUTE
+ 0x00a0: 0x00e1, # LATIN SMALL LETTER A WITH ACUTE
+ 0x00a1: 0x00ed, # LATIN SMALL LETTER I WITH ACUTE
+ 0x00a2: 0x00f3, # LATIN SMALL LETTER O WITH ACUTE
+ 0x00a3: 0x00fa, # LATIN SMALL LETTER U WITH ACUTE
+ 0x00a4: 0x00f1, # LATIN SMALL LETTER N WITH TILDE
+ 0x00a5: 0x00d1, # LATIN CAPITAL LETTER N WITH TILDE
+ 0x00a6: 0x00aa, # FEMININE ORDINAL INDICATOR
+ 0x00a7: 0x00ba, # MASCULINE ORDINAL INDICATOR
+ 0x00a8: 0x00bf, # INVERTED QUESTION MARK
+ 0x00a9: 0x00d2, # LATIN CAPITAL LETTER O WITH GRAVE
+ 0x00aa: 0x00ac, # NOT SIGN
+ 0x00ab: 0x00bd, # VULGAR FRACTION ONE HALF
+ 0x00ac: 0x00bc, # VULGAR FRACTION ONE QUARTER
+ 0x00ad: 0x00a1, # INVERTED EXCLAMATION MARK
+ 0x00ae: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00af: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00b0: 0x2591, # LIGHT SHADE
+ 0x00b1: 0x2592, # MEDIUM SHADE
+ 0x00b2: 0x2593, # DARK SHADE
+ 0x00b3: 0x2502, # BOX DRAWINGS LIGHT VERTICAL
+ 0x00b4: 0x2524, # BOX DRAWINGS LIGHT VERTICAL AND LEFT
+ 0x00b5: 0x2561, # BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
+ 0x00b6: 0x2562, # BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
+ 0x00b7: 0x2556, # BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
+ 0x00b8: 0x2555, # BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
+ 0x00b9: 0x2563, # BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+ 0x00ba: 0x2551, # BOX DRAWINGS DOUBLE VERTICAL
+ 0x00bb: 0x2557, # BOX DRAWINGS DOUBLE DOWN AND LEFT
+ 0x00bc: 0x255d, # BOX DRAWINGS DOUBLE UP AND LEFT
+ 0x00bd: 0x255c, # BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
+ 0x00be: 0x255b, # BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
+ 0x00bf: 0x2510, # BOX DRAWINGS LIGHT DOWN AND LEFT
+ 0x00c0: 0x2514, # BOX DRAWINGS LIGHT UP AND RIGHT
+ 0x00c1: 0x2534, # BOX DRAWINGS LIGHT UP AND HORIZONTAL
+ 0x00c2: 0x252c, # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+ 0x00c3: 0x251c, # BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+ 0x00c4: 0x2500, # BOX DRAWINGS LIGHT HORIZONTAL
+ 0x00c5: 0x253c, # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+ 0x00c6: 0x255e, # BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
+ 0x00c7: 0x255f, # BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
+ 0x00c8: 0x255a, # BOX DRAWINGS DOUBLE UP AND RIGHT
+ 0x00c9: 0x2554, # BOX DRAWINGS DOUBLE DOWN AND RIGHT
+ 0x00ca: 0x2569, # BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+ 0x00cb: 0x2566, # BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+ 0x00cc: 0x2560, # BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+ 0x00cd: 0x2550, # BOX DRAWINGS DOUBLE HORIZONTAL
+ 0x00ce: 0x256c, # BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+ 0x00cf: 0x2567, # BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
+ 0x00d0: 0x2568, # BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
+ 0x00d1: 0x2564, # BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
+ 0x00d2: 0x2565, # BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
+ 0x00d3: 0x2559, # BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
+ 0x00d4: 0x2558, # BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
+ 0x00d5: 0x2552, # BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
+ 0x00d6: 0x2553, # BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
+ 0x00d7: 0x256b, # BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
+ 0x00d8: 0x256a, # BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
+ 0x00d9: 0x2518, # BOX DRAWINGS LIGHT UP AND LEFT
+ 0x00da: 0x250c, # BOX DRAWINGS LIGHT DOWN AND RIGHT
+ 0x00db: 0x2588, # FULL BLOCK
+ 0x00dc: 0x2584, # LOWER HALF BLOCK
+ 0x00dd: 0x258c, # LEFT HALF BLOCK
+ 0x00de: 0x2590, # RIGHT HALF BLOCK
+ 0x00df: 0x2580, # UPPER HALF BLOCK
+ 0x00e0: 0x03b1, # GREEK SMALL LETTER ALPHA
+ 0x00e1: 0x00df, # LATIN SMALL LETTER SHARP S
+ 0x00e2: 0x0393, # GREEK CAPITAL LETTER GAMMA
+ 0x00e3: 0x03c0, # GREEK SMALL LETTER PI
+ 0x00e4: 0x03a3, # GREEK CAPITAL LETTER SIGMA
+ 0x00e5: 0x03c3, # GREEK SMALL LETTER SIGMA
+ 0x00e6: 0x00b5, # MICRO SIGN
+ 0x00e7: 0x03c4, # GREEK SMALL LETTER TAU
+ 0x00e8: 0x03a6, # GREEK CAPITAL LETTER PHI
+ 0x00e9: 0x0398, # GREEK CAPITAL LETTER THETA
+ 0x00ea: 0x03a9, # GREEK CAPITAL LETTER OMEGA
+ 0x00eb: 0x03b4, # GREEK SMALL LETTER DELTA
+ 0x00ec: 0x221e, # INFINITY
+ 0x00ed: 0x03c6, # GREEK SMALL LETTER PHI
+ 0x00ee: 0x03b5, # GREEK SMALL LETTER EPSILON
+ 0x00ef: 0x2229, # INTERSECTION
+ 0x00f0: 0x2261, # IDENTICAL TO
+ 0x00f1: 0x00b1, # PLUS-MINUS SIGN
+ 0x00f2: 0x2265, # GREATER-THAN OR EQUAL TO
+ 0x00f3: 0x2264, # LESS-THAN OR EQUAL TO
+ 0x00f4: 0x2320, # TOP HALF INTEGRAL
+ 0x00f5: 0x2321, # BOTTOM HALF INTEGRAL
+ 0x00f6: 0x00f7, # DIVISION SIGN
+ 0x00f7: 0x2248, # ALMOST EQUAL TO
+ 0x00f8: 0x00b0, # DEGREE SIGN
+ 0x00f9: 0x2219, # BULLET OPERATOR
+ 0x00fa: 0x00b7, # MIDDLE DOT
+ 0x00fb: 0x221a, # SQUARE ROOT
+ 0x00fc: 0x207f, # SUPERSCRIPT LATIN SMALL LETTER N
+ 0x00fd: 0x00b2, # SUPERSCRIPT TWO
+ 0x00fe: 0x25a0, # BLACK SQUARE
+ 0x00ff: 0x00a0, # NO-BREAK SPACE
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp861.py b/lib/jython/Lib/encodings/cp861.py new file mode 100644 index 000000000..0267781ec --- /dev/null +++ b/lib/jython/Lib/encodings/cp861.py @@ -0,0 +1,174 @@ +""" Python Character Mapping Codec generated from 'CP861.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x00c7, # LATIN CAPITAL LETTER C WITH CEDILLA
+ 0x0081: 0x00fc, # LATIN SMALL LETTER U WITH DIAERESIS
+ 0x0082: 0x00e9, # LATIN SMALL LETTER E WITH ACUTE
+ 0x0083: 0x00e2, # LATIN SMALL LETTER A WITH CIRCUMFLEX
+ 0x0084: 0x00e4, # LATIN SMALL LETTER A WITH DIAERESIS
+ 0x0085: 0x00e0, # LATIN SMALL LETTER A WITH GRAVE
+ 0x0086: 0x00e5, # LATIN SMALL LETTER A WITH RING ABOVE
+ 0x0087: 0x00e7, # LATIN SMALL LETTER C WITH CEDILLA
+ 0x0088: 0x00ea, # LATIN SMALL LETTER E WITH CIRCUMFLEX
+ 0x0089: 0x00eb, # LATIN SMALL LETTER E WITH DIAERESIS
+ 0x008a: 0x00e8, # LATIN SMALL LETTER E WITH GRAVE
+ 0x008b: 0x00d0, # LATIN CAPITAL LETTER ETH
+ 0x008c: 0x00f0, # LATIN SMALL LETTER ETH
+ 0x008d: 0x00de, # LATIN CAPITAL LETTER THORN
+ 0x008e: 0x00c4, # LATIN CAPITAL LETTER A WITH DIAERESIS
+ 0x008f: 0x00c5, # LATIN CAPITAL LETTER A WITH RING ABOVE
+ 0x0090: 0x00c9, # LATIN CAPITAL LETTER E WITH ACUTE
+ 0x0091: 0x00e6, # LATIN SMALL LIGATURE AE
+ 0x0092: 0x00c6, # LATIN CAPITAL LIGATURE AE
+ 0x0093: 0x00f4, # LATIN SMALL LETTER O WITH CIRCUMFLEX
+ 0x0094: 0x00f6, # LATIN SMALL LETTER O WITH DIAERESIS
+ 0x0095: 0x00fe, # LATIN SMALL LETTER THORN
+ 0x0096: 0x00fb, # LATIN SMALL LETTER U WITH CIRCUMFLEX
+ 0x0097: 0x00dd, # LATIN CAPITAL LETTER Y WITH ACUTE
+ 0x0098: 0x00fd, # LATIN SMALL LETTER Y WITH ACUTE
+ 0x0099: 0x00d6, # LATIN CAPITAL LETTER O WITH DIAERESIS
+ 0x009a: 0x00dc, # LATIN CAPITAL LETTER U WITH DIAERESIS
+ 0x009b: 0x00f8, # LATIN SMALL LETTER O WITH STROKE
+ 0x009c: 0x00a3, # POUND SIGN
+ 0x009d: 0x00d8, # LATIN CAPITAL LETTER O WITH STROKE
+ 0x009e: 0x20a7, # PESETA SIGN
+ 0x009f: 0x0192, # LATIN SMALL LETTER F WITH HOOK
+ 0x00a0: 0x00e1, # LATIN SMALL LETTER A WITH ACUTE
+ 0x00a1: 0x00ed, # LATIN SMALL LETTER I WITH ACUTE
+ 0x00a2: 0x00f3, # LATIN SMALL LETTER O WITH ACUTE
+ 0x00a3: 0x00fa, # LATIN SMALL LETTER U WITH ACUTE
+ 0x00a4: 0x00c1, # LATIN CAPITAL LETTER A WITH ACUTE
+ 0x00a5: 0x00cd, # LATIN CAPITAL LETTER I WITH ACUTE
+ 0x00a6: 0x00d3, # LATIN CAPITAL LETTER O WITH ACUTE
+ 0x00a7: 0x00da, # LATIN CAPITAL LETTER U WITH ACUTE
+ 0x00a8: 0x00bf, # INVERTED QUESTION MARK
+ 0x00a9: 0x2310, # REVERSED NOT SIGN
+ 0x00aa: 0x00ac, # NOT SIGN
+ 0x00ab: 0x00bd, # VULGAR FRACTION ONE HALF
+ 0x00ac: 0x00bc, # VULGAR FRACTION ONE QUARTER
+ 0x00ad: 0x00a1, # INVERTED EXCLAMATION MARK
+ 0x00ae: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00af: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00b0: 0x2591, # LIGHT SHADE
+ 0x00b1: 0x2592, # MEDIUM SHADE
+ 0x00b2: 0x2593, # DARK SHADE
+ 0x00b3: 0x2502, # BOX DRAWINGS LIGHT VERTICAL
+ 0x00b4: 0x2524, # BOX DRAWINGS LIGHT VERTICAL AND LEFT
+ 0x00b5: 0x2561, # BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
+ 0x00b6: 0x2562, # BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
+ 0x00b7: 0x2556, # BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
+ 0x00b8: 0x2555, # BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
+ 0x00b9: 0x2563, # BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+ 0x00ba: 0x2551, # BOX DRAWINGS DOUBLE VERTICAL
+ 0x00bb: 0x2557, # BOX DRAWINGS DOUBLE DOWN AND LEFT
+ 0x00bc: 0x255d, # BOX DRAWINGS DOUBLE UP AND LEFT
+ 0x00bd: 0x255c, # BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
+ 0x00be: 0x255b, # BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
+ 0x00bf: 0x2510, # BOX DRAWINGS LIGHT DOWN AND LEFT
+ 0x00c0: 0x2514, # BOX DRAWINGS LIGHT UP AND RIGHT
+ 0x00c1: 0x2534, # BOX DRAWINGS LIGHT UP AND HORIZONTAL
+ 0x00c2: 0x252c, # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+ 0x00c3: 0x251c, # BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+ 0x00c4: 0x2500, # BOX DRAWINGS LIGHT HORIZONTAL
+ 0x00c5: 0x253c, # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+ 0x00c6: 0x255e, # BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
+ 0x00c7: 0x255f, # BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
+ 0x00c8: 0x255a, # BOX DRAWINGS DOUBLE UP AND RIGHT
+ 0x00c9: 0x2554, # BOX DRAWINGS DOUBLE DOWN AND RIGHT
+ 0x00ca: 0x2569, # BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+ 0x00cb: 0x2566, # BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+ 0x00cc: 0x2560, # BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+ 0x00cd: 0x2550, # BOX DRAWINGS DOUBLE HORIZONTAL
+ 0x00ce: 0x256c, # BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+ 0x00cf: 0x2567, # BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
+ 0x00d0: 0x2568, # BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
+ 0x00d1: 0x2564, # BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
+ 0x00d2: 0x2565, # BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
+ 0x00d3: 0x2559, # BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
+ 0x00d4: 0x2558, # BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
+ 0x00d5: 0x2552, # BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
+ 0x00d6: 0x2553, # BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
+ 0x00d7: 0x256b, # BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
+ 0x00d8: 0x256a, # BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
+ 0x00d9: 0x2518, # BOX DRAWINGS LIGHT UP AND LEFT
+ 0x00da: 0x250c, # BOX DRAWINGS LIGHT DOWN AND RIGHT
+ 0x00db: 0x2588, # FULL BLOCK
+ 0x00dc: 0x2584, # LOWER HALF BLOCK
+ 0x00dd: 0x258c, # LEFT HALF BLOCK
+ 0x00de: 0x2590, # RIGHT HALF BLOCK
+ 0x00df: 0x2580, # UPPER HALF BLOCK
+ 0x00e0: 0x03b1, # GREEK SMALL LETTER ALPHA
+ 0x00e1: 0x00df, # LATIN SMALL LETTER SHARP S
+ 0x00e2: 0x0393, # GREEK CAPITAL LETTER GAMMA
+ 0x00e3: 0x03c0, # GREEK SMALL LETTER PI
+ 0x00e4: 0x03a3, # GREEK CAPITAL LETTER SIGMA
+ 0x00e5: 0x03c3, # GREEK SMALL LETTER SIGMA
+ 0x00e6: 0x00b5, # MICRO SIGN
+ 0x00e7: 0x03c4, # GREEK SMALL LETTER TAU
+ 0x00e8: 0x03a6, # GREEK CAPITAL LETTER PHI
+ 0x00e9: 0x0398, # GREEK CAPITAL LETTER THETA
+ 0x00ea: 0x03a9, # GREEK CAPITAL LETTER OMEGA
+ 0x00eb: 0x03b4, # GREEK SMALL LETTER DELTA
+ 0x00ec: 0x221e, # INFINITY
+ 0x00ed: 0x03c6, # GREEK SMALL LETTER PHI
+ 0x00ee: 0x03b5, # GREEK SMALL LETTER EPSILON
+ 0x00ef: 0x2229, # INTERSECTION
+ 0x00f0: 0x2261, # IDENTICAL TO
+ 0x00f1: 0x00b1, # PLUS-MINUS SIGN
+ 0x00f2: 0x2265, # GREATER-THAN OR EQUAL TO
+ 0x00f3: 0x2264, # LESS-THAN OR EQUAL TO
+ 0x00f4: 0x2320, # TOP HALF INTEGRAL
+ 0x00f5: 0x2321, # BOTTOM HALF INTEGRAL
+ 0x00f6: 0x00f7, # DIVISION SIGN
+ 0x00f7: 0x2248, # ALMOST EQUAL TO
+ 0x00f8: 0x00b0, # DEGREE SIGN
+ 0x00f9: 0x2219, # BULLET OPERATOR
+ 0x00fa: 0x00b7, # MIDDLE DOT
+ 0x00fb: 0x221a, # SQUARE ROOT
+ 0x00fc: 0x207f, # SUPERSCRIPT LATIN SMALL LETTER N
+ 0x00fd: 0x00b2, # SUPERSCRIPT TWO
+ 0x00fe: 0x25a0, # BLACK SQUARE
+ 0x00ff: 0x00a0, # NO-BREAK SPACE
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp862.py b/lib/jython/Lib/encodings/cp862.py new file mode 100644 index 000000000..0f1a6b8a5 --- /dev/null +++ b/lib/jython/Lib/encodings/cp862.py @@ -0,0 +1,174 @@ +""" Python Character Mapping Codec generated from 'CP862.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x05d0, # HEBREW LETTER ALEF
+ 0x0081: 0x05d1, # HEBREW LETTER BET
+ 0x0082: 0x05d2, # HEBREW LETTER GIMEL
+ 0x0083: 0x05d3, # HEBREW LETTER DALET
+ 0x0084: 0x05d4, # HEBREW LETTER HE
+ 0x0085: 0x05d5, # HEBREW LETTER VAV
+ 0x0086: 0x05d6, # HEBREW LETTER ZAYIN
+ 0x0087: 0x05d7, # HEBREW LETTER HET
+ 0x0088: 0x05d8, # HEBREW LETTER TET
+ 0x0089: 0x05d9, # HEBREW LETTER YOD
+ 0x008a: 0x05da, # HEBREW LETTER FINAL KAF
+ 0x008b: 0x05db, # HEBREW LETTER KAF
+ 0x008c: 0x05dc, # HEBREW LETTER LAMED
+ 0x008d: 0x05dd, # HEBREW LETTER FINAL MEM
+ 0x008e: 0x05de, # HEBREW LETTER MEM
+ 0x008f: 0x05df, # HEBREW LETTER FINAL NUN
+ 0x0090: 0x05e0, # HEBREW LETTER NUN
+ 0x0091: 0x05e1, # HEBREW LETTER SAMEKH
+ 0x0092: 0x05e2, # HEBREW LETTER AYIN
+ 0x0093: 0x05e3, # HEBREW LETTER FINAL PE
+ 0x0094: 0x05e4, # HEBREW LETTER PE
+ 0x0095: 0x05e5, # HEBREW LETTER FINAL TSADI
+ 0x0096: 0x05e6, # HEBREW LETTER TSADI
+ 0x0097: 0x05e7, # HEBREW LETTER QOF
+ 0x0098: 0x05e8, # HEBREW LETTER RESH
+ 0x0099: 0x05e9, # HEBREW LETTER SHIN
+ 0x009a: 0x05ea, # HEBREW LETTER TAV
+ 0x009b: 0x00a2, # CENT SIGN
+ 0x009c: 0x00a3, # POUND SIGN
+ 0x009d: 0x00a5, # YEN SIGN
+ 0x009e: 0x20a7, # PESETA SIGN
+ 0x009f: 0x0192, # LATIN SMALL LETTER F WITH HOOK
+ 0x00a0: 0x00e1, # LATIN SMALL LETTER A WITH ACUTE
+ 0x00a1: 0x00ed, # LATIN SMALL LETTER I WITH ACUTE
+ 0x00a2: 0x00f3, # LATIN SMALL LETTER O WITH ACUTE
+ 0x00a3: 0x00fa, # LATIN SMALL LETTER U WITH ACUTE
+ 0x00a4: 0x00f1, # LATIN SMALL LETTER N WITH TILDE
+ 0x00a5: 0x00d1, # LATIN CAPITAL LETTER N WITH TILDE
+ 0x00a6: 0x00aa, # FEMININE ORDINAL INDICATOR
+ 0x00a7: 0x00ba, # MASCULINE ORDINAL INDICATOR
+ 0x00a8: 0x00bf, # INVERTED QUESTION MARK
+ 0x00a9: 0x2310, # REVERSED NOT SIGN
+ 0x00aa: 0x00ac, # NOT SIGN
+ 0x00ab: 0x00bd, # VULGAR FRACTION ONE HALF
+ 0x00ac: 0x00bc, # VULGAR FRACTION ONE QUARTER
+ 0x00ad: 0x00a1, # INVERTED EXCLAMATION MARK
+ 0x00ae: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00af: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00b0: 0x2591, # LIGHT SHADE
+ 0x00b1: 0x2592, # MEDIUM SHADE
+ 0x00b2: 0x2593, # DARK SHADE
+ 0x00b3: 0x2502, # BOX DRAWINGS LIGHT VERTICAL
+ 0x00b4: 0x2524, # BOX DRAWINGS LIGHT VERTICAL AND LEFT
+ 0x00b5: 0x2561, # BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
+ 0x00b6: 0x2562, # BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
+ 0x00b7: 0x2556, # BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
+ 0x00b8: 0x2555, # BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
+ 0x00b9: 0x2563, # BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+ 0x00ba: 0x2551, # BOX DRAWINGS DOUBLE VERTICAL
+ 0x00bb: 0x2557, # BOX DRAWINGS DOUBLE DOWN AND LEFT
+ 0x00bc: 0x255d, # BOX DRAWINGS DOUBLE UP AND LEFT
+ 0x00bd: 0x255c, # BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
+ 0x00be: 0x255b, # BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
+ 0x00bf: 0x2510, # BOX DRAWINGS LIGHT DOWN AND LEFT
+ 0x00c0: 0x2514, # BOX DRAWINGS LIGHT UP AND RIGHT
+ 0x00c1: 0x2534, # BOX DRAWINGS LIGHT UP AND HORIZONTAL
+ 0x00c2: 0x252c, # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+ 0x00c3: 0x251c, # BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+ 0x00c4: 0x2500, # BOX DRAWINGS LIGHT HORIZONTAL
+ 0x00c5: 0x253c, # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+ 0x00c6: 0x255e, # BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
+ 0x00c7: 0x255f, # BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
+ 0x00c8: 0x255a, # BOX DRAWINGS DOUBLE UP AND RIGHT
+ 0x00c9: 0x2554, # BOX DRAWINGS DOUBLE DOWN AND RIGHT
+ 0x00ca: 0x2569, # BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+ 0x00cb: 0x2566, # BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+ 0x00cc: 0x2560, # BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+ 0x00cd: 0x2550, # BOX DRAWINGS DOUBLE HORIZONTAL
+ 0x00ce: 0x256c, # BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+ 0x00cf: 0x2567, # BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
+ 0x00d0: 0x2568, # BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
+ 0x00d1: 0x2564, # BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
+ 0x00d2: 0x2565, # BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
+ 0x00d3: 0x2559, # BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
+ 0x00d4: 0x2558, # BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
+ 0x00d5: 0x2552, # BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
+ 0x00d6: 0x2553, # BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
+ 0x00d7: 0x256b, # BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
+ 0x00d8: 0x256a, # BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
+ 0x00d9: 0x2518, # BOX DRAWINGS LIGHT UP AND LEFT
+ 0x00da: 0x250c, # BOX DRAWINGS LIGHT DOWN AND RIGHT
+ 0x00db: 0x2588, # FULL BLOCK
+ 0x00dc: 0x2584, # LOWER HALF BLOCK
+ 0x00dd: 0x258c, # LEFT HALF BLOCK
+ 0x00de: 0x2590, # RIGHT HALF BLOCK
+ 0x00df: 0x2580, # UPPER HALF BLOCK
+ 0x00e0: 0x03b1, # GREEK SMALL LETTER ALPHA
+ 0x00e1: 0x00df, # LATIN SMALL LETTER SHARP S (GERMAN)
+ 0x00e2: 0x0393, # GREEK CAPITAL LETTER GAMMA
+ 0x00e3: 0x03c0, # GREEK SMALL LETTER PI
+ 0x00e4: 0x03a3, # GREEK CAPITAL LETTER SIGMA
+ 0x00e5: 0x03c3, # GREEK SMALL LETTER SIGMA
+ 0x00e6: 0x00b5, # MICRO SIGN
+ 0x00e7: 0x03c4, # GREEK SMALL LETTER TAU
+ 0x00e8: 0x03a6, # GREEK CAPITAL LETTER PHI
+ 0x00e9: 0x0398, # GREEK CAPITAL LETTER THETA
+ 0x00ea: 0x03a9, # GREEK CAPITAL LETTER OMEGA
+ 0x00eb: 0x03b4, # GREEK SMALL LETTER DELTA
+ 0x00ec: 0x221e, # INFINITY
+ 0x00ed: 0x03c6, # GREEK SMALL LETTER PHI
+ 0x00ee: 0x03b5, # GREEK SMALL LETTER EPSILON
+ 0x00ef: 0x2229, # INTERSECTION
+ 0x00f0: 0x2261, # IDENTICAL TO
+ 0x00f1: 0x00b1, # PLUS-MINUS SIGN
+ 0x00f2: 0x2265, # GREATER-THAN OR EQUAL TO
+ 0x00f3: 0x2264, # LESS-THAN OR EQUAL TO
+ 0x00f4: 0x2320, # TOP HALF INTEGRAL
+ 0x00f5: 0x2321, # BOTTOM HALF INTEGRAL
+ 0x00f6: 0x00f7, # DIVISION SIGN
+ 0x00f7: 0x2248, # ALMOST EQUAL TO
+ 0x00f8: 0x00b0, # DEGREE SIGN
+ 0x00f9: 0x2219, # BULLET OPERATOR
+ 0x00fa: 0x00b7, # MIDDLE DOT
+ 0x00fb: 0x221a, # SQUARE ROOT
+ 0x00fc: 0x207f, # SUPERSCRIPT LATIN SMALL LETTER N
+ 0x00fd: 0x00b2, # SUPERSCRIPT TWO
+ 0x00fe: 0x25a0, # BLACK SQUARE
+ 0x00ff: 0x00a0, # NO-BREAK SPACE
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp863.py b/lib/jython/Lib/encodings/cp863.py new file mode 100644 index 000000000..206a9a10d --- /dev/null +++ b/lib/jython/Lib/encodings/cp863.py @@ -0,0 +1,174 @@ +""" Python Character Mapping Codec generated from 'CP863.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x00c7, # LATIN CAPITAL LETTER C WITH CEDILLA
+ 0x0081: 0x00fc, # LATIN SMALL LETTER U WITH DIAERESIS
+ 0x0082: 0x00e9, # LATIN SMALL LETTER E WITH ACUTE
+ 0x0083: 0x00e2, # LATIN SMALL LETTER A WITH CIRCUMFLEX
+ 0x0084: 0x00c2, # LATIN CAPITAL LETTER A WITH CIRCUMFLEX
+ 0x0085: 0x00e0, # LATIN SMALL LETTER A WITH GRAVE
+ 0x0086: 0x00b6, # PILCROW SIGN
+ 0x0087: 0x00e7, # LATIN SMALL LETTER C WITH CEDILLA
+ 0x0088: 0x00ea, # LATIN SMALL LETTER E WITH CIRCUMFLEX
+ 0x0089: 0x00eb, # LATIN SMALL LETTER E WITH DIAERESIS
+ 0x008a: 0x00e8, # LATIN SMALL LETTER E WITH GRAVE
+ 0x008b: 0x00ef, # LATIN SMALL LETTER I WITH DIAERESIS
+ 0x008c: 0x00ee, # LATIN SMALL LETTER I WITH CIRCUMFLEX
+ 0x008d: 0x2017, # DOUBLE LOW LINE
+ 0x008e: 0x00c0, # LATIN CAPITAL LETTER A WITH GRAVE
+ 0x008f: 0x00a7, # SECTION SIGN
+ 0x0090: 0x00c9, # LATIN CAPITAL LETTER E WITH ACUTE
+ 0x0091: 0x00c8, # LATIN CAPITAL LETTER E WITH GRAVE
+ 0x0092: 0x00ca, # LATIN CAPITAL LETTER E WITH CIRCUMFLEX
+ 0x0093: 0x00f4, # LATIN SMALL LETTER O WITH CIRCUMFLEX
+ 0x0094: 0x00cb, # LATIN CAPITAL LETTER E WITH DIAERESIS
+ 0x0095: 0x00cf, # LATIN CAPITAL LETTER I WITH DIAERESIS
+ 0x0096: 0x00fb, # LATIN SMALL LETTER U WITH CIRCUMFLEX
+ 0x0097: 0x00f9, # LATIN SMALL LETTER U WITH GRAVE
+ 0x0098: 0x00a4, # CURRENCY SIGN
+ 0x0099: 0x00d4, # LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+ 0x009a: 0x00dc, # LATIN CAPITAL LETTER U WITH DIAERESIS
+ 0x009b: 0x00a2, # CENT SIGN
+ 0x009c: 0x00a3, # POUND SIGN
+ 0x009d: 0x00d9, # LATIN CAPITAL LETTER U WITH GRAVE
+ 0x009e: 0x00db, # LATIN CAPITAL LETTER U WITH CIRCUMFLEX
+ 0x009f: 0x0192, # LATIN SMALL LETTER F WITH HOOK
+ 0x00a0: 0x00a6, # BROKEN BAR
+ 0x00a1: 0x00b4, # ACUTE ACCENT
+ 0x00a2: 0x00f3, # LATIN SMALL LETTER O WITH ACUTE
+ 0x00a3: 0x00fa, # LATIN SMALL LETTER U WITH ACUTE
+ 0x00a4: 0x00a8, # DIAERESIS
+ 0x00a5: 0x00b8, # CEDILLA
+ 0x00a6: 0x00b3, # SUPERSCRIPT THREE
+ 0x00a7: 0x00af, # MACRON
+ 0x00a8: 0x00ce, # LATIN CAPITAL LETTER I WITH CIRCUMFLEX
+ 0x00a9: 0x2310, # REVERSED NOT SIGN
+ 0x00aa: 0x00ac, # NOT SIGN
+ 0x00ab: 0x00bd, # VULGAR FRACTION ONE HALF
+ 0x00ac: 0x00bc, # VULGAR FRACTION ONE QUARTER
+ 0x00ad: 0x00be, # VULGAR FRACTION THREE QUARTERS
+ 0x00ae: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00af: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00b0: 0x2591, # LIGHT SHADE
+ 0x00b1: 0x2592, # MEDIUM SHADE
+ 0x00b2: 0x2593, # DARK SHADE
+ 0x00b3: 0x2502, # BOX DRAWINGS LIGHT VERTICAL
+ 0x00b4: 0x2524, # BOX DRAWINGS LIGHT VERTICAL AND LEFT
+ 0x00b5: 0x2561, # BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
+ 0x00b6: 0x2562, # BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
+ 0x00b7: 0x2556, # BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
+ 0x00b8: 0x2555, # BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
+ 0x00b9: 0x2563, # BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+ 0x00ba: 0x2551, # BOX DRAWINGS DOUBLE VERTICAL
+ 0x00bb: 0x2557, # BOX DRAWINGS DOUBLE DOWN AND LEFT
+ 0x00bc: 0x255d, # BOX DRAWINGS DOUBLE UP AND LEFT
+ 0x00bd: 0x255c, # BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
+ 0x00be: 0x255b, # BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
+ 0x00bf: 0x2510, # BOX DRAWINGS LIGHT DOWN AND LEFT
+ 0x00c0: 0x2514, # BOX DRAWINGS LIGHT UP AND RIGHT
+ 0x00c1: 0x2534, # BOX DRAWINGS LIGHT UP AND HORIZONTAL
+ 0x00c2: 0x252c, # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+ 0x00c3: 0x251c, # BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+ 0x00c4: 0x2500, # BOX DRAWINGS LIGHT HORIZONTAL
+ 0x00c5: 0x253c, # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+ 0x00c6: 0x255e, # BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
+ 0x00c7: 0x255f, # BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
+ 0x00c8: 0x255a, # BOX DRAWINGS DOUBLE UP AND RIGHT
+ 0x00c9: 0x2554, # BOX DRAWINGS DOUBLE DOWN AND RIGHT
+ 0x00ca: 0x2569, # BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+ 0x00cb: 0x2566, # BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+ 0x00cc: 0x2560, # BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+ 0x00cd: 0x2550, # BOX DRAWINGS DOUBLE HORIZONTAL
+ 0x00ce: 0x256c, # BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+ 0x00cf: 0x2567, # BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
+ 0x00d0: 0x2568, # BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
+ 0x00d1: 0x2564, # BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
+ 0x00d2: 0x2565, # BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
+ 0x00d3: 0x2559, # BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
+ 0x00d4: 0x2558, # BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
+ 0x00d5: 0x2552, # BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
+ 0x00d6: 0x2553, # BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
+ 0x00d7: 0x256b, # BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
+ 0x00d8: 0x256a, # BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
+ 0x00d9: 0x2518, # BOX DRAWINGS LIGHT UP AND LEFT
+ 0x00da: 0x250c, # BOX DRAWINGS LIGHT DOWN AND RIGHT
+ 0x00db: 0x2588, # FULL BLOCK
+ 0x00dc: 0x2584, # LOWER HALF BLOCK
+ 0x00dd: 0x258c, # LEFT HALF BLOCK
+ 0x00de: 0x2590, # RIGHT HALF BLOCK
+ 0x00df: 0x2580, # UPPER HALF BLOCK
+ 0x00e0: 0x03b1, # GREEK SMALL LETTER ALPHA
+ 0x00e1: 0x00df, # LATIN SMALL LETTER SHARP S
+ 0x00e2: 0x0393, # GREEK CAPITAL LETTER GAMMA
+ 0x00e3: 0x03c0, # GREEK SMALL LETTER PI
+ 0x00e4: 0x03a3, # GREEK CAPITAL LETTER SIGMA
+ 0x00e5: 0x03c3, # GREEK SMALL LETTER SIGMA
+ 0x00e6: 0x00b5, # MICRO SIGN
+ 0x00e7: 0x03c4, # GREEK SMALL LETTER TAU
+ 0x00e8: 0x03a6, # GREEK CAPITAL LETTER PHI
+ 0x00e9: 0x0398, # GREEK CAPITAL LETTER THETA
+ 0x00ea: 0x03a9, # GREEK CAPITAL LETTER OMEGA
+ 0x00eb: 0x03b4, # GREEK SMALL LETTER DELTA
+ 0x00ec: 0x221e, # INFINITY
+ 0x00ed: 0x03c6, # GREEK SMALL LETTER PHI
+ 0x00ee: 0x03b5, # GREEK SMALL LETTER EPSILON
+ 0x00ef: 0x2229, # INTERSECTION
+ 0x00f0: 0x2261, # IDENTICAL TO
+ 0x00f1: 0x00b1, # PLUS-MINUS SIGN
+ 0x00f2: 0x2265, # GREATER-THAN OR EQUAL TO
+ 0x00f3: 0x2264, # LESS-THAN OR EQUAL TO
+ 0x00f4: 0x2320, # TOP HALF INTEGRAL
+ 0x00f5: 0x2321, # BOTTOM HALF INTEGRAL
+ 0x00f6: 0x00f7, # DIVISION SIGN
+ 0x00f7: 0x2248, # ALMOST EQUAL TO
+ 0x00f8: 0x00b0, # DEGREE SIGN
+ 0x00f9: 0x2219, # BULLET OPERATOR
+ 0x00fa: 0x00b7, # MIDDLE DOT
+ 0x00fb: 0x221a, # SQUARE ROOT
+ 0x00fc: 0x207f, # SUPERSCRIPT LATIN SMALL LETTER N
+ 0x00fd: 0x00b2, # SUPERSCRIPT TWO
+ 0x00fe: 0x25a0, # BLACK SQUARE
+ 0x00ff: 0x00a0, # NO-BREAK SPACE
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp864.py b/lib/jython/Lib/encodings/cp864.py new file mode 100644 index 000000000..241b1bc54 --- /dev/null +++ b/lib/jython/Lib/encodings/cp864.py @@ -0,0 +1,172 @@ +""" Python Character Mapping Codec generated from 'CP864.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0025: 0x066a, # ARABIC PERCENT SIGN
+ 0x0080: 0x00b0, # DEGREE SIGN
+ 0x0081: 0x00b7, # MIDDLE DOT
+ 0x0082: 0x2219, # BULLET OPERATOR
+ 0x0083: 0x221a, # SQUARE ROOT
+ 0x0084: 0x2592, # MEDIUM SHADE
+ 0x0085: 0x2500, # FORMS LIGHT HORIZONTAL
+ 0x0086: 0x2502, # FORMS LIGHT VERTICAL
+ 0x0087: 0x253c, # FORMS LIGHT VERTICAL AND HORIZONTAL
+ 0x0088: 0x2524, # FORMS LIGHT VERTICAL AND LEFT
+ 0x0089: 0x252c, # FORMS LIGHT DOWN AND HORIZONTAL
+ 0x008a: 0x251c, # FORMS LIGHT VERTICAL AND RIGHT
+ 0x008b: 0x2534, # FORMS LIGHT UP AND HORIZONTAL
+ 0x008c: 0x2510, # FORMS LIGHT DOWN AND LEFT
+ 0x008d: 0x250c, # FORMS LIGHT DOWN AND RIGHT
+ 0x008e: 0x2514, # FORMS LIGHT UP AND RIGHT
+ 0x008f: 0x2518, # FORMS LIGHT UP AND LEFT
+ 0x0090: 0x03b2, # GREEK SMALL BETA
+ 0x0091: 0x221e, # INFINITY
+ 0x0092: 0x03c6, # GREEK SMALL PHI
+ 0x0093: 0x00b1, # PLUS-OR-MINUS SIGN
+ 0x0094: 0x00bd, # FRACTION 1/2
+ 0x0095: 0x00bc, # FRACTION 1/4
+ 0x0096: 0x2248, # ALMOST EQUAL TO
+ 0x0097: 0x00ab, # LEFT POINTING GUILLEMET
+ 0x0098: 0x00bb, # RIGHT POINTING GUILLEMET
+ 0x0099: 0xfef7, # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM
+ 0x009a: 0xfef8, # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM
+ 0x009b: None, # UNDEFINED
+ 0x009c: None, # UNDEFINED
+ 0x009d: 0xfefb, # ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM
+ 0x009e: 0xfefc, # ARABIC LIGATURE LAM WITH ALEF FINAL FORM
+ 0x009f: None, # UNDEFINED
+ 0x00a1: 0x00ad, # SOFT HYPHEN
+ 0x00a2: 0xfe82, # ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM
+ 0x00a5: 0xfe84, # ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM
+ 0x00a6: None, # UNDEFINED
+ 0x00a7: None, # UNDEFINED
+ 0x00a8: 0xfe8e, # ARABIC LETTER ALEF FINAL FORM
+ 0x00a9: 0xfe8f, # ARABIC LETTER BEH ISOLATED FORM
+ 0x00aa: 0xfe95, # ARABIC LETTER TEH ISOLATED FORM
+ 0x00ab: 0xfe99, # ARABIC LETTER THEH ISOLATED FORM
+ 0x00ac: 0x060c, # ARABIC COMMA
+ 0x00ad: 0xfe9d, # ARABIC LETTER JEEM ISOLATED FORM
+ 0x00ae: 0xfea1, # ARABIC LETTER HAH ISOLATED FORM
+ 0x00af: 0xfea5, # ARABIC LETTER KHAH ISOLATED FORM
+ 0x00b0: 0x0660, # ARABIC-INDIC DIGIT ZERO
+ 0x00b1: 0x0661, # ARABIC-INDIC DIGIT ONE
+ 0x00b2: 0x0662, # ARABIC-INDIC DIGIT TWO
+ 0x00b3: 0x0663, # ARABIC-INDIC DIGIT THREE
+ 0x00b4: 0x0664, # ARABIC-INDIC DIGIT FOUR
+ 0x00b5: 0x0665, # ARABIC-INDIC DIGIT FIVE
+ 0x00b6: 0x0666, # ARABIC-INDIC DIGIT SIX
+ 0x00b7: 0x0667, # ARABIC-INDIC DIGIT SEVEN
+ 0x00b8: 0x0668, # ARABIC-INDIC DIGIT EIGHT
+ 0x00b9: 0x0669, # ARABIC-INDIC DIGIT NINE
+ 0x00ba: 0xfed1, # ARABIC LETTER FEH ISOLATED FORM
+ 0x00bb: 0x061b, # ARABIC SEMICOLON
+ 0x00bc: 0xfeb1, # ARABIC LETTER SEEN ISOLATED FORM
+ 0x00bd: 0xfeb5, # ARABIC LETTER SHEEN ISOLATED FORM
+ 0x00be: 0xfeb9, # ARABIC LETTER SAD ISOLATED FORM
+ 0x00bf: 0x061f, # ARABIC QUESTION MARK
+ 0x00c0: 0x00a2, # CENT SIGN
+ 0x00c1: 0xfe80, # ARABIC LETTER HAMZA ISOLATED FORM
+ 0x00c2: 0xfe81, # ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM
+ 0x00c3: 0xfe83, # ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM
+ 0x00c4: 0xfe85, # ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM
+ 0x00c5: 0xfeca, # ARABIC LETTER AIN FINAL FORM
+ 0x00c6: 0xfe8b, # ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM
+ 0x00c7: 0xfe8d, # ARABIC LETTER ALEF ISOLATED FORM
+ 0x00c8: 0xfe91, # ARABIC LETTER BEH INITIAL FORM
+ 0x00c9: 0xfe93, # ARABIC LETTER TEH MARBUTA ISOLATED FORM
+ 0x00ca: 0xfe97, # ARABIC LETTER TEH INITIAL FORM
+ 0x00cb: 0xfe9b, # ARABIC LETTER THEH INITIAL FORM
+ 0x00cc: 0xfe9f, # ARABIC LETTER JEEM INITIAL FORM
+ 0x00cd: 0xfea3, # ARABIC LETTER HAH INITIAL FORM
+ 0x00ce: 0xfea7, # ARABIC LETTER KHAH INITIAL FORM
+ 0x00cf: 0xfea9, # ARABIC LETTER DAL ISOLATED FORM
+ 0x00d0: 0xfeab, # ARABIC LETTER THAL ISOLATED FORM
+ 0x00d1: 0xfead, # ARABIC LETTER REH ISOLATED FORM
+ 0x00d2: 0xfeaf, # ARABIC LETTER ZAIN ISOLATED FORM
+ 0x00d3: 0xfeb3, # ARABIC LETTER SEEN INITIAL FORM
+ 0x00d4: 0xfeb7, # ARABIC LETTER SHEEN INITIAL FORM
+ 0x00d5: 0xfebb, # ARABIC LETTER SAD INITIAL FORM
+ 0x00d6: 0xfebf, # ARABIC LETTER DAD INITIAL FORM
+ 0x00d7: 0xfec1, # ARABIC LETTER TAH ISOLATED FORM
+ 0x00d8: 0xfec5, # ARABIC LETTER ZAH ISOLATED FORM
+ 0x00d9: 0xfecb, # ARABIC LETTER AIN INITIAL FORM
+ 0x00da: 0xfecf, # ARABIC LETTER GHAIN INITIAL FORM
+ 0x00db: 0x00a6, # BROKEN VERTICAL BAR
+ 0x00dc: 0x00ac, # NOT SIGN
+ 0x00dd: 0x00f7, # DIVISION SIGN
+ 0x00de: 0x00d7, # MULTIPLICATION SIGN
+ 0x00df: 0xfec9, # ARABIC LETTER AIN ISOLATED FORM
+ 0x00e0: 0x0640, # ARABIC TATWEEL
+ 0x00e1: 0xfed3, # ARABIC LETTER FEH INITIAL FORM
+ 0x00e2: 0xfed7, # ARABIC LETTER QAF INITIAL FORM
+ 0x00e3: 0xfedb, # ARABIC LETTER KAF INITIAL FORM
+ 0x00e4: 0xfedf, # ARABIC LETTER LAM INITIAL FORM
+ 0x00e5: 0xfee3, # ARABIC LETTER MEEM INITIAL FORM
+ 0x00e6: 0xfee7, # ARABIC LETTER NOON INITIAL FORM
+ 0x00e7: 0xfeeb, # ARABIC LETTER HEH INITIAL FORM
+ 0x00e8: 0xfeed, # ARABIC LETTER WAW ISOLATED FORM
+ 0x00e9: 0xfeef, # ARABIC LETTER ALEF MAKSURA ISOLATED FORM
+ 0x00ea: 0xfef3, # ARABIC LETTER YEH INITIAL FORM
+ 0x00eb: 0xfebd, # ARABIC LETTER DAD ISOLATED FORM
+ 0x00ec: 0xfecc, # ARABIC LETTER AIN MEDIAL FORM
+ 0x00ed: 0xfece, # ARABIC LETTER GHAIN FINAL FORM
+ 0x00ee: 0xfecd, # ARABIC LETTER GHAIN ISOLATED FORM
+ 0x00ef: 0xfee1, # ARABIC LETTER MEEM ISOLATED FORM
+ 0x00f0: 0xfe7d, # ARABIC SHADDA MEDIAL FORM
+ 0x00f1: 0x0651, # ARABIC SHADDAH
+ 0x00f2: 0xfee5, # ARABIC LETTER NOON ISOLATED FORM
+ 0x00f3: 0xfee9, # ARABIC LETTER HEH ISOLATED FORM
+ 0x00f4: 0xfeec, # ARABIC LETTER HEH MEDIAL FORM
+ 0x00f5: 0xfef0, # ARABIC LETTER ALEF MAKSURA FINAL FORM
+ 0x00f6: 0xfef2, # ARABIC LETTER YEH FINAL FORM
+ 0x00f7: 0xfed0, # ARABIC LETTER GHAIN MEDIAL FORM
+ 0x00f8: 0xfed5, # ARABIC LETTER QAF ISOLATED FORM
+ 0x00f9: 0xfef5, # ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM
+ 0x00fa: 0xfef6, # ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM
+ 0x00fb: 0xfedd, # ARABIC LETTER LAM ISOLATED FORM
+ 0x00fc: 0xfed9, # ARABIC LETTER KAF ISOLATED FORM
+ 0x00fd: 0xfef1, # ARABIC LETTER YEH ISOLATED FORM
+ 0x00fe: 0x25a0, # BLACK SQUARE
+ 0x00ff: None, # UNDEFINED
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp865.py b/lib/jython/Lib/encodings/cp865.py new file mode 100644 index 000000000..04393da1f --- /dev/null +++ b/lib/jython/Lib/encodings/cp865.py @@ -0,0 +1,174 @@ +""" Python Character Mapping Codec generated from 'CP865.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x00c7, # LATIN CAPITAL LETTER C WITH CEDILLA
+ 0x0081: 0x00fc, # LATIN SMALL LETTER U WITH DIAERESIS
+ 0x0082: 0x00e9, # LATIN SMALL LETTER E WITH ACUTE
+ 0x0083: 0x00e2, # LATIN SMALL LETTER A WITH CIRCUMFLEX
+ 0x0084: 0x00e4, # LATIN SMALL LETTER A WITH DIAERESIS
+ 0x0085: 0x00e0, # LATIN SMALL LETTER A WITH GRAVE
+ 0x0086: 0x00e5, # LATIN SMALL LETTER A WITH RING ABOVE
+ 0x0087: 0x00e7, # LATIN SMALL LETTER C WITH CEDILLA
+ 0x0088: 0x00ea, # LATIN SMALL LETTER E WITH CIRCUMFLEX
+ 0x0089: 0x00eb, # LATIN SMALL LETTER E WITH DIAERESIS
+ 0x008a: 0x00e8, # LATIN SMALL LETTER E WITH GRAVE
+ 0x008b: 0x00ef, # LATIN SMALL LETTER I WITH DIAERESIS
+ 0x008c: 0x00ee, # LATIN SMALL LETTER I WITH CIRCUMFLEX
+ 0x008d: 0x00ec, # LATIN SMALL LETTER I WITH GRAVE
+ 0x008e: 0x00c4, # LATIN CAPITAL LETTER A WITH DIAERESIS
+ 0x008f: 0x00c5, # LATIN CAPITAL LETTER A WITH RING ABOVE
+ 0x0090: 0x00c9, # LATIN CAPITAL LETTER E WITH ACUTE
+ 0x0091: 0x00e6, # LATIN SMALL LIGATURE AE
+ 0x0092: 0x00c6, # LATIN CAPITAL LIGATURE AE
+ 0x0093: 0x00f4, # LATIN SMALL LETTER O WITH CIRCUMFLEX
+ 0x0094: 0x00f6, # LATIN SMALL LETTER O WITH DIAERESIS
+ 0x0095: 0x00f2, # LATIN SMALL LETTER O WITH GRAVE
+ 0x0096: 0x00fb, # LATIN SMALL LETTER U WITH CIRCUMFLEX
+ 0x0097: 0x00f9, # LATIN SMALL LETTER U WITH GRAVE
+ 0x0098: 0x00ff, # LATIN SMALL LETTER Y WITH DIAERESIS
+ 0x0099: 0x00d6, # LATIN CAPITAL LETTER O WITH DIAERESIS
+ 0x009a: 0x00dc, # LATIN CAPITAL LETTER U WITH DIAERESIS
+ 0x009b: 0x00f8, # LATIN SMALL LETTER O WITH STROKE
+ 0x009c: 0x00a3, # POUND SIGN
+ 0x009d: 0x00d8, # LATIN CAPITAL LETTER O WITH STROKE
+ 0x009e: 0x20a7, # PESETA SIGN
+ 0x009f: 0x0192, # LATIN SMALL LETTER F WITH HOOK
+ 0x00a0: 0x00e1, # LATIN SMALL LETTER A WITH ACUTE
+ 0x00a1: 0x00ed, # LATIN SMALL LETTER I WITH ACUTE
+ 0x00a2: 0x00f3, # LATIN SMALL LETTER O WITH ACUTE
+ 0x00a3: 0x00fa, # LATIN SMALL LETTER U WITH ACUTE
+ 0x00a4: 0x00f1, # LATIN SMALL LETTER N WITH TILDE
+ 0x00a5: 0x00d1, # LATIN CAPITAL LETTER N WITH TILDE
+ 0x00a6: 0x00aa, # FEMININE ORDINAL INDICATOR
+ 0x00a7: 0x00ba, # MASCULINE ORDINAL INDICATOR
+ 0x00a8: 0x00bf, # INVERTED QUESTION MARK
+ 0x00a9: 0x2310, # REVERSED NOT SIGN
+ 0x00aa: 0x00ac, # NOT SIGN
+ 0x00ab: 0x00bd, # VULGAR FRACTION ONE HALF
+ 0x00ac: 0x00bc, # VULGAR FRACTION ONE QUARTER
+ 0x00ad: 0x00a1, # INVERTED EXCLAMATION MARK
+ 0x00ae: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00af: 0x00a4, # CURRENCY SIGN
+ 0x00b0: 0x2591, # LIGHT SHADE
+ 0x00b1: 0x2592, # MEDIUM SHADE
+ 0x00b2: 0x2593, # DARK SHADE
+ 0x00b3: 0x2502, # BOX DRAWINGS LIGHT VERTICAL
+ 0x00b4: 0x2524, # BOX DRAWINGS LIGHT VERTICAL AND LEFT
+ 0x00b5: 0x2561, # BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
+ 0x00b6: 0x2562, # BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
+ 0x00b7: 0x2556, # BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
+ 0x00b8: 0x2555, # BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
+ 0x00b9: 0x2563, # BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+ 0x00ba: 0x2551, # BOX DRAWINGS DOUBLE VERTICAL
+ 0x00bb: 0x2557, # BOX DRAWINGS DOUBLE DOWN AND LEFT
+ 0x00bc: 0x255d, # BOX DRAWINGS DOUBLE UP AND LEFT
+ 0x00bd: 0x255c, # BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
+ 0x00be: 0x255b, # BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
+ 0x00bf: 0x2510, # BOX DRAWINGS LIGHT DOWN AND LEFT
+ 0x00c0: 0x2514, # BOX DRAWINGS LIGHT UP AND RIGHT
+ 0x00c1: 0x2534, # BOX DRAWINGS LIGHT UP AND HORIZONTAL
+ 0x00c2: 0x252c, # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+ 0x00c3: 0x251c, # BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+ 0x00c4: 0x2500, # BOX DRAWINGS LIGHT HORIZONTAL
+ 0x00c5: 0x253c, # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+ 0x00c6: 0x255e, # BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
+ 0x00c7: 0x255f, # BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
+ 0x00c8: 0x255a, # BOX DRAWINGS DOUBLE UP AND RIGHT
+ 0x00c9: 0x2554, # BOX DRAWINGS DOUBLE DOWN AND RIGHT
+ 0x00ca: 0x2569, # BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+ 0x00cb: 0x2566, # BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+ 0x00cc: 0x2560, # BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+ 0x00cd: 0x2550, # BOX DRAWINGS DOUBLE HORIZONTAL
+ 0x00ce: 0x256c, # BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+ 0x00cf: 0x2567, # BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
+ 0x00d0: 0x2568, # BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
+ 0x00d1: 0x2564, # BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
+ 0x00d2: 0x2565, # BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
+ 0x00d3: 0x2559, # BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
+ 0x00d4: 0x2558, # BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
+ 0x00d5: 0x2552, # BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
+ 0x00d6: 0x2553, # BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
+ 0x00d7: 0x256b, # BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
+ 0x00d8: 0x256a, # BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
+ 0x00d9: 0x2518, # BOX DRAWINGS LIGHT UP AND LEFT
+ 0x00da: 0x250c, # BOX DRAWINGS LIGHT DOWN AND RIGHT
+ 0x00db: 0x2588, # FULL BLOCK
+ 0x00dc: 0x2584, # LOWER HALF BLOCK
+ 0x00dd: 0x258c, # LEFT HALF BLOCK
+ 0x00de: 0x2590, # RIGHT HALF BLOCK
+ 0x00df: 0x2580, # UPPER HALF BLOCK
+ 0x00e0: 0x03b1, # GREEK SMALL LETTER ALPHA
+ 0x00e1: 0x00df, # LATIN SMALL LETTER SHARP S
+ 0x00e2: 0x0393, # GREEK CAPITAL LETTER GAMMA
+ 0x00e3: 0x03c0, # GREEK SMALL LETTER PI
+ 0x00e4: 0x03a3, # GREEK CAPITAL LETTER SIGMA
+ 0x00e5: 0x03c3, # GREEK SMALL LETTER SIGMA
+ 0x00e6: 0x00b5, # MICRO SIGN
+ 0x00e7: 0x03c4, # GREEK SMALL LETTER TAU
+ 0x00e8: 0x03a6, # GREEK CAPITAL LETTER PHI
+ 0x00e9: 0x0398, # GREEK CAPITAL LETTER THETA
+ 0x00ea: 0x03a9, # GREEK CAPITAL LETTER OMEGA
+ 0x00eb: 0x03b4, # GREEK SMALL LETTER DELTA
+ 0x00ec: 0x221e, # INFINITY
+ 0x00ed: 0x03c6, # GREEK SMALL LETTER PHI
+ 0x00ee: 0x03b5, # GREEK SMALL LETTER EPSILON
+ 0x00ef: 0x2229, # INTERSECTION
+ 0x00f0: 0x2261, # IDENTICAL TO
+ 0x00f1: 0x00b1, # PLUS-MINUS SIGN
+ 0x00f2: 0x2265, # GREATER-THAN OR EQUAL TO
+ 0x00f3: 0x2264, # LESS-THAN OR EQUAL TO
+ 0x00f4: 0x2320, # TOP HALF INTEGRAL
+ 0x00f5: 0x2321, # BOTTOM HALF INTEGRAL
+ 0x00f6: 0x00f7, # DIVISION SIGN
+ 0x00f7: 0x2248, # ALMOST EQUAL TO
+ 0x00f8: 0x00b0, # DEGREE SIGN
+ 0x00f9: 0x2219, # BULLET OPERATOR
+ 0x00fa: 0x00b7, # MIDDLE DOT
+ 0x00fb: 0x221a, # SQUARE ROOT
+ 0x00fc: 0x207f, # SUPERSCRIPT LATIN SMALL LETTER N
+ 0x00fd: 0x00b2, # SUPERSCRIPT TWO
+ 0x00fe: 0x25a0, # BLACK SQUARE
+ 0x00ff: 0x00a0, # NO-BREAK SPACE
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp866.py b/lib/jython/Lib/encodings/cp866.py new file mode 100644 index 000000000..435c06876 --- /dev/null +++ b/lib/jython/Lib/encodings/cp866.py @@ -0,0 +1,174 @@ +""" Python Character Mapping Codec generated from 'CP866.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x0410, # CYRILLIC CAPITAL LETTER A
+ 0x0081: 0x0411, # CYRILLIC CAPITAL LETTER BE
+ 0x0082: 0x0412, # CYRILLIC CAPITAL LETTER VE
+ 0x0083: 0x0413, # CYRILLIC CAPITAL LETTER GHE
+ 0x0084: 0x0414, # CYRILLIC CAPITAL LETTER DE
+ 0x0085: 0x0415, # CYRILLIC CAPITAL LETTER IE
+ 0x0086: 0x0416, # CYRILLIC CAPITAL LETTER ZHE
+ 0x0087: 0x0417, # CYRILLIC CAPITAL LETTER ZE
+ 0x0088: 0x0418, # CYRILLIC CAPITAL LETTER I
+ 0x0089: 0x0419, # CYRILLIC CAPITAL LETTER SHORT I
+ 0x008a: 0x041a, # CYRILLIC CAPITAL LETTER KA
+ 0x008b: 0x041b, # CYRILLIC CAPITAL LETTER EL
+ 0x008c: 0x041c, # CYRILLIC CAPITAL LETTER EM
+ 0x008d: 0x041d, # CYRILLIC CAPITAL LETTER EN
+ 0x008e: 0x041e, # CYRILLIC CAPITAL LETTER O
+ 0x008f: 0x041f, # CYRILLIC CAPITAL LETTER PE
+ 0x0090: 0x0420, # CYRILLIC CAPITAL LETTER ER
+ 0x0091: 0x0421, # CYRILLIC CAPITAL LETTER ES
+ 0x0092: 0x0422, # CYRILLIC CAPITAL LETTER TE
+ 0x0093: 0x0423, # CYRILLIC CAPITAL LETTER U
+ 0x0094: 0x0424, # CYRILLIC CAPITAL LETTER EF
+ 0x0095: 0x0425, # CYRILLIC CAPITAL LETTER HA
+ 0x0096: 0x0426, # CYRILLIC CAPITAL LETTER TSE
+ 0x0097: 0x0427, # CYRILLIC CAPITAL LETTER CHE
+ 0x0098: 0x0428, # CYRILLIC CAPITAL LETTER SHA
+ 0x0099: 0x0429, # CYRILLIC CAPITAL LETTER SHCHA
+ 0x009a: 0x042a, # CYRILLIC CAPITAL LETTER HARD SIGN
+ 0x009b: 0x042b, # CYRILLIC CAPITAL LETTER YERU
+ 0x009c: 0x042c, # CYRILLIC CAPITAL LETTER SOFT SIGN
+ 0x009d: 0x042d, # CYRILLIC CAPITAL LETTER E
+ 0x009e: 0x042e, # CYRILLIC CAPITAL LETTER YU
+ 0x009f: 0x042f, # CYRILLIC CAPITAL LETTER YA
+ 0x00a0: 0x0430, # CYRILLIC SMALL LETTER A
+ 0x00a1: 0x0431, # CYRILLIC SMALL LETTER BE
+ 0x00a2: 0x0432, # CYRILLIC SMALL LETTER VE
+ 0x00a3: 0x0433, # CYRILLIC SMALL LETTER GHE
+ 0x00a4: 0x0434, # CYRILLIC SMALL LETTER DE
+ 0x00a5: 0x0435, # CYRILLIC SMALL LETTER IE
+ 0x00a6: 0x0436, # CYRILLIC SMALL LETTER ZHE
+ 0x00a7: 0x0437, # CYRILLIC SMALL LETTER ZE
+ 0x00a8: 0x0438, # CYRILLIC SMALL LETTER I
+ 0x00a9: 0x0439, # CYRILLIC SMALL LETTER SHORT I
+ 0x00aa: 0x043a, # CYRILLIC SMALL LETTER KA
+ 0x00ab: 0x043b, # CYRILLIC SMALL LETTER EL
+ 0x00ac: 0x043c, # CYRILLIC SMALL LETTER EM
+ 0x00ad: 0x043d, # CYRILLIC SMALL LETTER EN
+ 0x00ae: 0x043e, # CYRILLIC SMALL LETTER O
+ 0x00af: 0x043f, # CYRILLIC SMALL LETTER PE
+ 0x00b0: 0x2591, # LIGHT SHADE
+ 0x00b1: 0x2592, # MEDIUM SHADE
+ 0x00b2: 0x2593, # DARK SHADE
+ 0x00b3: 0x2502, # BOX DRAWINGS LIGHT VERTICAL
+ 0x00b4: 0x2524, # BOX DRAWINGS LIGHT VERTICAL AND LEFT
+ 0x00b5: 0x2561, # BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
+ 0x00b6: 0x2562, # BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
+ 0x00b7: 0x2556, # BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
+ 0x00b8: 0x2555, # BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
+ 0x00b9: 0x2563, # BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+ 0x00ba: 0x2551, # BOX DRAWINGS DOUBLE VERTICAL
+ 0x00bb: 0x2557, # BOX DRAWINGS DOUBLE DOWN AND LEFT
+ 0x00bc: 0x255d, # BOX DRAWINGS DOUBLE UP AND LEFT
+ 0x00bd: 0x255c, # BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
+ 0x00be: 0x255b, # BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
+ 0x00bf: 0x2510, # BOX DRAWINGS LIGHT DOWN AND LEFT
+ 0x00c0: 0x2514, # BOX DRAWINGS LIGHT UP AND RIGHT
+ 0x00c1: 0x2534, # BOX DRAWINGS LIGHT UP AND HORIZONTAL
+ 0x00c2: 0x252c, # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+ 0x00c3: 0x251c, # BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+ 0x00c4: 0x2500, # BOX DRAWINGS LIGHT HORIZONTAL
+ 0x00c5: 0x253c, # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+ 0x00c6: 0x255e, # BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
+ 0x00c7: 0x255f, # BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
+ 0x00c8: 0x255a, # BOX DRAWINGS DOUBLE UP AND RIGHT
+ 0x00c9: 0x2554, # BOX DRAWINGS DOUBLE DOWN AND RIGHT
+ 0x00ca: 0x2569, # BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+ 0x00cb: 0x2566, # BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+ 0x00cc: 0x2560, # BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+ 0x00cd: 0x2550, # BOX DRAWINGS DOUBLE HORIZONTAL
+ 0x00ce: 0x256c, # BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+ 0x00cf: 0x2567, # BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
+ 0x00d0: 0x2568, # BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
+ 0x00d1: 0x2564, # BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
+ 0x00d2: 0x2565, # BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
+ 0x00d3: 0x2559, # BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
+ 0x00d4: 0x2558, # BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
+ 0x00d5: 0x2552, # BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
+ 0x00d6: 0x2553, # BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
+ 0x00d7: 0x256b, # BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
+ 0x00d8: 0x256a, # BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
+ 0x00d9: 0x2518, # BOX DRAWINGS LIGHT UP AND LEFT
+ 0x00da: 0x250c, # BOX DRAWINGS LIGHT DOWN AND RIGHT
+ 0x00db: 0x2588, # FULL BLOCK
+ 0x00dc: 0x2584, # LOWER HALF BLOCK
+ 0x00dd: 0x258c, # LEFT HALF BLOCK
+ 0x00de: 0x2590, # RIGHT HALF BLOCK
+ 0x00df: 0x2580, # UPPER HALF BLOCK
+ 0x00e0: 0x0440, # CYRILLIC SMALL LETTER ER
+ 0x00e1: 0x0441, # CYRILLIC SMALL LETTER ES
+ 0x00e2: 0x0442, # CYRILLIC SMALL LETTER TE
+ 0x00e3: 0x0443, # CYRILLIC SMALL LETTER U
+ 0x00e4: 0x0444, # CYRILLIC SMALL LETTER EF
+ 0x00e5: 0x0445, # CYRILLIC SMALL LETTER HA
+ 0x00e6: 0x0446, # CYRILLIC SMALL LETTER TSE
+ 0x00e7: 0x0447, # CYRILLIC SMALL LETTER CHE
+ 0x00e8: 0x0448, # CYRILLIC SMALL LETTER SHA
+ 0x00e9: 0x0449, # CYRILLIC SMALL LETTER SHCHA
+ 0x00ea: 0x044a, # CYRILLIC SMALL LETTER HARD SIGN
+ 0x00eb: 0x044b, # CYRILLIC SMALL LETTER YERU
+ 0x00ec: 0x044c, # CYRILLIC SMALL LETTER SOFT SIGN
+ 0x00ed: 0x044d, # CYRILLIC SMALL LETTER E
+ 0x00ee: 0x044e, # CYRILLIC SMALL LETTER YU
+ 0x00ef: 0x044f, # CYRILLIC SMALL LETTER YA
+ 0x00f0: 0x0401, # CYRILLIC CAPITAL LETTER IO
+ 0x00f1: 0x0451, # CYRILLIC SMALL LETTER IO
+ 0x00f2: 0x0404, # CYRILLIC CAPITAL LETTER UKRAINIAN IE
+ 0x00f3: 0x0454, # CYRILLIC SMALL LETTER UKRAINIAN IE
+ 0x00f4: 0x0407, # CYRILLIC CAPITAL LETTER YI
+ 0x00f5: 0x0457, # CYRILLIC SMALL LETTER YI
+ 0x00f6: 0x040e, # CYRILLIC CAPITAL LETTER SHORT U
+ 0x00f7: 0x045e, # CYRILLIC SMALL LETTER SHORT U
+ 0x00f8: 0x00b0, # DEGREE SIGN
+ 0x00f9: 0x2219, # BULLET OPERATOR
+ 0x00fa: 0x00b7, # MIDDLE DOT
+ 0x00fb: 0x221a, # SQUARE ROOT
+ 0x00fc: 0x2116, # NUMERO SIGN
+ 0x00fd: 0x00a4, # CURRENCY SIGN
+ 0x00fe: 0x25a0, # BLACK SQUARE
+ 0x00ff: 0x00a0, # NO-BREAK SPACE
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp869.py b/lib/jython/Lib/encodings/cp869.py new file mode 100644 index 000000000..ff344de4a --- /dev/null +++ b/lib/jython/Lib/encodings/cp869.py @@ -0,0 +1,174 @@ +""" Python Character Mapping Codec generated from 'CP869.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: None, # UNDEFINED
+ 0x0081: None, # UNDEFINED
+ 0x0082: None, # UNDEFINED
+ 0x0083: None, # UNDEFINED
+ 0x0084: None, # UNDEFINED
+ 0x0085: None, # UNDEFINED
+ 0x0086: 0x0386, # GREEK CAPITAL LETTER ALPHA WITH TONOS
+ 0x0087: None, # UNDEFINED
+ 0x0088: 0x00b7, # MIDDLE DOT
+ 0x0089: 0x00ac, # NOT SIGN
+ 0x008a: 0x00a6, # BROKEN BAR
+ 0x008b: 0x2018, # LEFT SINGLE QUOTATION MARK
+ 0x008c: 0x2019, # RIGHT SINGLE QUOTATION MARK
+ 0x008d: 0x0388, # GREEK CAPITAL LETTER EPSILON WITH TONOS
+ 0x008e: 0x2015, # HORIZONTAL BAR
+ 0x008f: 0x0389, # GREEK CAPITAL LETTER ETA WITH TONOS
+ 0x0090: 0x038a, # GREEK CAPITAL LETTER IOTA WITH TONOS
+ 0x0091: 0x03aa, # GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
+ 0x0092: 0x038c, # GREEK CAPITAL LETTER OMICRON WITH TONOS
+ 0x0093: None, # UNDEFINED
+ 0x0094: None, # UNDEFINED
+ 0x0095: 0x038e, # GREEK CAPITAL LETTER UPSILON WITH TONOS
+ 0x0096: 0x03ab, # GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
+ 0x0097: 0x00a9, # COPYRIGHT SIGN
+ 0x0098: 0x038f, # GREEK CAPITAL LETTER OMEGA WITH TONOS
+ 0x0099: 0x00b2, # SUPERSCRIPT TWO
+ 0x009a: 0x00b3, # SUPERSCRIPT THREE
+ 0x009b: 0x03ac, # GREEK SMALL LETTER ALPHA WITH TONOS
+ 0x009c: 0x00a3, # POUND SIGN
+ 0x009d: 0x03ad, # GREEK SMALL LETTER EPSILON WITH TONOS
+ 0x009e: 0x03ae, # GREEK SMALL LETTER ETA WITH TONOS
+ 0x009f: 0x03af, # GREEK SMALL LETTER IOTA WITH TONOS
+ 0x00a0: 0x03ca, # GREEK SMALL LETTER IOTA WITH DIALYTIKA
+ 0x00a1: 0x0390, # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
+ 0x00a2: 0x03cc, # GREEK SMALL LETTER OMICRON WITH TONOS
+ 0x00a3: 0x03cd, # GREEK SMALL LETTER UPSILON WITH TONOS
+ 0x00a4: 0x0391, # GREEK CAPITAL LETTER ALPHA
+ 0x00a5: 0x0392, # GREEK CAPITAL LETTER BETA
+ 0x00a6: 0x0393, # GREEK CAPITAL LETTER GAMMA
+ 0x00a7: 0x0394, # GREEK CAPITAL LETTER DELTA
+ 0x00a8: 0x0395, # GREEK CAPITAL LETTER EPSILON
+ 0x00a9: 0x0396, # GREEK CAPITAL LETTER ZETA
+ 0x00aa: 0x0397, # GREEK CAPITAL LETTER ETA
+ 0x00ab: 0x00bd, # VULGAR FRACTION ONE HALF
+ 0x00ac: 0x0398, # GREEK CAPITAL LETTER THETA
+ 0x00ad: 0x0399, # GREEK CAPITAL LETTER IOTA
+ 0x00ae: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00af: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00b0: 0x2591, # LIGHT SHADE
+ 0x00b1: 0x2592, # MEDIUM SHADE
+ 0x00b2: 0x2593, # DARK SHADE
+ 0x00b3: 0x2502, # BOX DRAWINGS LIGHT VERTICAL
+ 0x00b4: 0x2524, # BOX DRAWINGS LIGHT VERTICAL AND LEFT
+ 0x00b5: 0x039a, # GREEK CAPITAL LETTER KAPPA
+ 0x00b6: 0x039b, # GREEK CAPITAL LETTER LAMDA
+ 0x00b7: 0x039c, # GREEK CAPITAL LETTER MU
+ 0x00b8: 0x039d, # GREEK CAPITAL LETTER NU
+ 0x00b9: 0x2563, # BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+ 0x00ba: 0x2551, # BOX DRAWINGS DOUBLE VERTICAL
+ 0x00bb: 0x2557, # BOX DRAWINGS DOUBLE DOWN AND LEFT
+ 0x00bc: 0x255d, # BOX DRAWINGS DOUBLE UP AND LEFT
+ 0x00bd: 0x039e, # GREEK CAPITAL LETTER XI
+ 0x00be: 0x039f, # GREEK CAPITAL LETTER OMICRON
+ 0x00bf: 0x2510, # BOX DRAWINGS LIGHT DOWN AND LEFT
+ 0x00c0: 0x2514, # BOX DRAWINGS LIGHT UP AND RIGHT
+ 0x00c1: 0x2534, # BOX DRAWINGS LIGHT UP AND HORIZONTAL
+ 0x00c2: 0x252c, # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+ 0x00c3: 0x251c, # BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+ 0x00c4: 0x2500, # BOX DRAWINGS LIGHT HORIZONTAL
+ 0x00c5: 0x253c, # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+ 0x00c6: 0x03a0, # GREEK CAPITAL LETTER PI
+ 0x00c7: 0x03a1, # GREEK CAPITAL LETTER RHO
+ 0x00c8: 0x255a, # BOX DRAWINGS DOUBLE UP AND RIGHT
+ 0x00c9: 0x2554, # BOX DRAWINGS DOUBLE DOWN AND RIGHT
+ 0x00ca: 0x2569, # BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+ 0x00cb: 0x2566, # BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+ 0x00cc: 0x2560, # BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+ 0x00cd: 0x2550, # BOX DRAWINGS DOUBLE HORIZONTAL
+ 0x00ce: 0x256c, # BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+ 0x00cf: 0x03a3, # GREEK CAPITAL LETTER SIGMA
+ 0x00d0: 0x03a4, # GREEK CAPITAL LETTER TAU
+ 0x00d1: 0x03a5, # GREEK CAPITAL LETTER UPSILON
+ 0x00d2: 0x03a6, # GREEK CAPITAL LETTER PHI
+ 0x00d3: 0x03a7, # GREEK CAPITAL LETTER CHI
+ 0x00d4: 0x03a8, # GREEK CAPITAL LETTER PSI
+ 0x00d5: 0x03a9, # GREEK CAPITAL LETTER OMEGA
+ 0x00d6: 0x03b1, # GREEK SMALL LETTER ALPHA
+ 0x00d7: 0x03b2, # GREEK SMALL LETTER BETA
+ 0x00d8: 0x03b3, # GREEK SMALL LETTER GAMMA
+ 0x00d9: 0x2518, # BOX DRAWINGS LIGHT UP AND LEFT
+ 0x00da: 0x250c, # BOX DRAWINGS LIGHT DOWN AND RIGHT
+ 0x00db: 0x2588, # FULL BLOCK
+ 0x00dc: 0x2584, # LOWER HALF BLOCK
+ 0x00dd: 0x03b4, # GREEK SMALL LETTER DELTA
+ 0x00de: 0x03b5, # GREEK SMALL LETTER EPSILON
+ 0x00df: 0x2580, # UPPER HALF BLOCK
+ 0x00e0: 0x03b6, # GREEK SMALL LETTER ZETA
+ 0x00e1: 0x03b7, # GREEK SMALL LETTER ETA
+ 0x00e2: 0x03b8, # GREEK SMALL LETTER THETA
+ 0x00e3: 0x03b9, # GREEK SMALL LETTER IOTA
+ 0x00e4: 0x03ba, # GREEK SMALL LETTER KAPPA
+ 0x00e5: 0x03bb, # GREEK SMALL LETTER LAMDA
+ 0x00e6: 0x03bc, # GREEK SMALL LETTER MU
+ 0x00e7: 0x03bd, # GREEK SMALL LETTER NU
+ 0x00e8: 0x03be, # GREEK SMALL LETTER XI
+ 0x00e9: 0x03bf, # GREEK SMALL LETTER OMICRON
+ 0x00ea: 0x03c0, # GREEK SMALL LETTER PI
+ 0x00eb: 0x03c1, # GREEK SMALL LETTER RHO
+ 0x00ec: 0x03c3, # GREEK SMALL LETTER SIGMA
+ 0x00ed: 0x03c2, # GREEK SMALL LETTER FINAL SIGMA
+ 0x00ee: 0x03c4, # GREEK SMALL LETTER TAU
+ 0x00ef: 0x0384, # GREEK TONOS
+ 0x00f0: 0x00ad, # SOFT HYPHEN
+ 0x00f1: 0x00b1, # PLUS-MINUS SIGN
+ 0x00f2: 0x03c5, # GREEK SMALL LETTER UPSILON
+ 0x00f3: 0x03c6, # GREEK SMALL LETTER PHI
+ 0x00f4: 0x03c7, # GREEK SMALL LETTER CHI
+ 0x00f5: 0x00a7, # SECTION SIGN
+ 0x00f6: 0x03c8, # GREEK SMALL LETTER PSI
+ 0x00f7: 0x0385, # GREEK DIALYTIKA TONOS
+ 0x00f8: 0x00b0, # DEGREE SIGN
+ 0x00f9: 0x00a8, # DIAERESIS
+ 0x00fa: 0x03c9, # GREEK SMALL LETTER OMEGA
+ 0x00fb: 0x03cb, # GREEK SMALL LETTER UPSILON WITH DIALYTIKA
+ 0x00fc: 0x03b0, # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
+ 0x00fd: 0x03ce, # GREEK SMALL LETTER OMEGA WITH TONOS
+ 0x00fe: 0x25a0, # BLACK SQUARE
+ 0x00ff: 0x00a0, # NO-BREAK SPACE
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp874.py b/lib/jython/Lib/encodings/cp874.py new file mode 100644 index 000000000..e7eac0f9d --- /dev/null +++ b/lib/jython/Lib/encodings/cp874.py @@ -0,0 +1,173 @@ +""" Python Character Mapping Codec generated from 'CP874.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x20ac, # EURO SIGN
+ 0x0081: None, # UNDEFINED
+ 0x0082: None, # UNDEFINED
+ 0x0083: None, # UNDEFINED
+ 0x0084: None, # UNDEFINED
+ 0x0085: 0x2026, # HORIZONTAL ELLIPSIS
+ 0x0086: None, # UNDEFINED
+ 0x0087: None, # UNDEFINED
+ 0x0088: None, # UNDEFINED
+ 0x0089: None, # UNDEFINED
+ 0x008a: None, # UNDEFINED
+ 0x008b: None, # UNDEFINED
+ 0x008c: None, # UNDEFINED
+ 0x008d: None, # UNDEFINED
+ 0x008e: None, # UNDEFINED
+ 0x008f: None, # UNDEFINED
+ 0x0090: None, # UNDEFINED
+ 0x0091: 0x2018, # LEFT SINGLE QUOTATION MARK
+ 0x0092: 0x2019, # RIGHT SINGLE QUOTATION MARK
+ 0x0093: 0x201c, # LEFT DOUBLE QUOTATION MARK
+ 0x0094: 0x201d, # RIGHT DOUBLE QUOTATION MARK
+ 0x0095: 0x2022, # BULLET
+ 0x0096: 0x2013, # EN DASH
+ 0x0097: 0x2014, # EM DASH
+ 0x0098: None, # UNDEFINED
+ 0x0099: None, # UNDEFINED
+ 0x009a: None, # UNDEFINED
+ 0x009b: None, # UNDEFINED
+ 0x009c: None, # UNDEFINED
+ 0x009d: None, # UNDEFINED
+ 0x009e: None, # UNDEFINED
+ 0x009f: None, # UNDEFINED
+ 0x00a1: 0x0e01, # THAI CHARACTER KO KAI
+ 0x00a2: 0x0e02, # THAI CHARACTER KHO KHAI
+ 0x00a3: 0x0e03, # THAI CHARACTER KHO KHUAT
+ 0x00a4: 0x0e04, # THAI CHARACTER KHO KHWAI
+ 0x00a5: 0x0e05, # THAI CHARACTER KHO KHON
+ 0x00a6: 0x0e06, # THAI CHARACTER KHO RAKHANG
+ 0x00a7: 0x0e07, # THAI CHARACTER NGO NGU
+ 0x00a8: 0x0e08, # THAI CHARACTER CHO CHAN
+ 0x00a9: 0x0e09, # THAI CHARACTER CHO CHING
+ 0x00aa: 0x0e0a, # THAI CHARACTER CHO CHANG
+ 0x00ab: 0x0e0b, # THAI CHARACTER SO SO
+ 0x00ac: 0x0e0c, # THAI CHARACTER CHO CHOE
+ 0x00ad: 0x0e0d, # THAI CHARACTER YO YING
+ 0x00ae: 0x0e0e, # THAI CHARACTER DO CHADA
+ 0x00af: 0x0e0f, # THAI CHARACTER TO PATAK
+ 0x00b0: 0x0e10, # THAI CHARACTER THO THAN
+ 0x00b1: 0x0e11, # THAI CHARACTER THO NANGMONTHO
+ 0x00b2: 0x0e12, # THAI CHARACTER THO PHUTHAO
+ 0x00b3: 0x0e13, # THAI CHARACTER NO NEN
+ 0x00b4: 0x0e14, # THAI CHARACTER DO DEK
+ 0x00b5: 0x0e15, # THAI CHARACTER TO TAO
+ 0x00b6: 0x0e16, # THAI CHARACTER THO THUNG
+ 0x00b7: 0x0e17, # THAI CHARACTER THO THAHAN
+ 0x00b8: 0x0e18, # THAI CHARACTER THO THONG
+ 0x00b9: 0x0e19, # THAI CHARACTER NO NU
+ 0x00ba: 0x0e1a, # THAI CHARACTER BO BAIMAI
+ 0x00bb: 0x0e1b, # THAI CHARACTER PO PLA
+ 0x00bc: 0x0e1c, # THAI CHARACTER PHO PHUNG
+ 0x00bd: 0x0e1d, # THAI CHARACTER FO FA
+ 0x00be: 0x0e1e, # THAI CHARACTER PHO PHAN
+ 0x00bf: 0x0e1f, # THAI CHARACTER FO FAN
+ 0x00c0: 0x0e20, # THAI CHARACTER PHO SAMPHAO
+ 0x00c1: 0x0e21, # THAI CHARACTER MO MA
+ 0x00c2: 0x0e22, # THAI CHARACTER YO YAK
+ 0x00c3: 0x0e23, # THAI CHARACTER RO RUA
+ 0x00c4: 0x0e24, # THAI CHARACTER RU
+ 0x00c5: 0x0e25, # THAI CHARACTER LO LING
+ 0x00c6: 0x0e26, # THAI CHARACTER LU
+ 0x00c7: 0x0e27, # THAI CHARACTER WO WAEN
+ 0x00c8: 0x0e28, # THAI CHARACTER SO SALA
+ 0x00c9: 0x0e29, # THAI CHARACTER SO RUSI
+ 0x00ca: 0x0e2a, # THAI CHARACTER SO SUA
+ 0x00cb: 0x0e2b, # THAI CHARACTER HO HIP
+ 0x00cc: 0x0e2c, # THAI CHARACTER LO CHULA
+ 0x00cd: 0x0e2d, # THAI CHARACTER O ANG
+ 0x00ce: 0x0e2e, # THAI CHARACTER HO NOKHUK
+ 0x00cf: 0x0e2f, # THAI CHARACTER PAIYANNOI
+ 0x00d0: 0x0e30, # THAI CHARACTER SARA A
+ 0x00d1: 0x0e31, # THAI CHARACTER MAI HAN-AKAT
+ 0x00d2: 0x0e32, # THAI CHARACTER SARA AA
+ 0x00d3: 0x0e33, # THAI CHARACTER SARA AM
+ 0x00d4: 0x0e34, # THAI CHARACTER SARA I
+ 0x00d5: 0x0e35, # THAI CHARACTER SARA II
+ 0x00d6: 0x0e36, # THAI CHARACTER SARA UE
+ 0x00d7: 0x0e37, # THAI CHARACTER SARA UEE
+ 0x00d8: 0x0e38, # THAI CHARACTER SARA U
+ 0x00d9: 0x0e39, # THAI CHARACTER SARA UU
+ 0x00da: 0x0e3a, # THAI CHARACTER PHINTHU
+ 0x00db: None, # UNDEFINED
+ 0x00dc: None, # UNDEFINED
+ 0x00dd: None, # UNDEFINED
+ 0x00de: None, # UNDEFINED
+ 0x00df: 0x0e3f, # THAI CURRENCY SYMBOL BAHT
+ 0x00e0: 0x0e40, # THAI CHARACTER SARA E
+ 0x00e1: 0x0e41, # THAI CHARACTER SARA AE
+ 0x00e2: 0x0e42, # THAI CHARACTER SARA O
+ 0x00e3: 0x0e43, # THAI CHARACTER SARA AI MAIMUAN
+ 0x00e4: 0x0e44, # THAI CHARACTER SARA AI MAIMALAI
+ 0x00e5: 0x0e45, # THAI CHARACTER LAKKHANGYAO
+ 0x00e6: 0x0e46, # THAI CHARACTER MAIYAMOK
+ 0x00e7: 0x0e47, # THAI CHARACTER MAITAIKHU
+ 0x00e8: 0x0e48, # THAI CHARACTER MAI EK
+ 0x00e9: 0x0e49, # THAI CHARACTER MAI THO
+ 0x00ea: 0x0e4a, # THAI CHARACTER MAI TRI
+ 0x00eb: 0x0e4b, # THAI CHARACTER MAI CHATTAWA
+ 0x00ec: 0x0e4c, # THAI CHARACTER THANTHAKHAT
+ 0x00ed: 0x0e4d, # THAI CHARACTER NIKHAHIT
+ 0x00ee: 0x0e4e, # THAI CHARACTER YAMAKKAN
+ 0x00ef: 0x0e4f, # THAI CHARACTER FONGMAN
+ 0x00f0: 0x0e50, # THAI DIGIT ZERO
+ 0x00f1: 0x0e51, # THAI DIGIT ONE
+ 0x00f2: 0x0e52, # THAI DIGIT TWO
+ 0x00f3: 0x0e53, # THAI DIGIT THREE
+ 0x00f4: 0x0e54, # THAI DIGIT FOUR
+ 0x00f5: 0x0e55, # THAI DIGIT FIVE
+ 0x00f6: 0x0e56, # THAI DIGIT SIX
+ 0x00f7: 0x0e57, # THAI DIGIT SEVEN
+ 0x00f8: 0x0e58, # THAI DIGIT EIGHT
+ 0x00f9: 0x0e59, # THAI DIGIT NINE
+ 0x00fa: 0x0e5a, # THAI CHARACTER ANGKHANKHU
+ 0x00fb: 0x0e5b, # THAI CHARACTER KHOMUT
+ 0x00fc: None, # UNDEFINED
+ 0x00fd: None, # UNDEFINED
+ 0x00fe: None, # UNDEFINED
+ 0x00ff: None, # UNDEFINED
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/cp875.py b/lib/jython/Lib/encodings/cp875.py new file mode 100644 index 000000000..40166ff2d --- /dev/null +++ b/lib/jython/Lib/encodings/cp875.py @@ -0,0 +1,283 @@ +""" Python Character Mapping Codec generated from 'CP875.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0004: 0x009c, # CONTROL
+ 0x0005: 0x0009, # HORIZONTAL TABULATION
+ 0x0006: 0x0086, # CONTROL
+ 0x0007: 0x007f, # DELETE
+ 0x0008: 0x0097, # CONTROL
+ 0x0009: 0x008d, # CONTROL
+ 0x000a: 0x008e, # CONTROL
+ 0x0014: 0x009d, # CONTROL
+ 0x0015: 0x0085, # CONTROL
+ 0x0016: 0x0008, # BACKSPACE
+ 0x0017: 0x0087, # CONTROL
+ 0x001a: 0x0092, # CONTROL
+ 0x001b: 0x008f, # CONTROL
+ 0x0020: 0x0080, # CONTROL
+ 0x0021: 0x0081, # CONTROL
+ 0x0022: 0x0082, # CONTROL
+ 0x0023: 0x0083, # CONTROL
+ 0x0024: 0x0084, # CONTROL
+ 0x0025: 0x000a, # LINE FEED
+ 0x0026: 0x0017, # END OF TRANSMISSION BLOCK
+ 0x0027: 0x001b, # ESCAPE
+ 0x0028: 0x0088, # CONTROL
+ 0x0029: 0x0089, # CONTROL
+ 0x002a: 0x008a, # CONTROL
+ 0x002b: 0x008b, # CONTROL
+ 0x002c: 0x008c, # CONTROL
+ 0x002d: 0x0005, # ENQUIRY
+ 0x002e: 0x0006, # ACKNOWLEDGE
+ 0x002f: 0x0007, # BELL
+ 0x0030: 0x0090, # CONTROL
+ 0x0031: 0x0091, # CONTROL
+ 0x0032: 0x0016, # SYNCHRONOUS IDLE
+ 0x0033: 0x0093, # CONTROL
+ 0x0034: 0x0094, # CONTROL
+ 0x0035: 0x0095, # CONTROL
+ 0x0036: 0x0096, # CONTROL
+ 0x0037: 0x0004, # END OF TRANSMISSION
+ 0x0038: 0x0098, # CONTROL
+ 0x0039: 0x0099, # CONTROL
+ 0x003a: 0x009a, # CONTROL
+ 0x003b: 0x009b, # CONTROL
+ 0x003c: 0x0014, # DEVICE CONTROL FOUR
+ 0x003d: 0x0015, # NEGATIVE ACKNOWLEDGE
+ 0x003e: 0x009e, # CONTROL
+ 0x003f: 0x001a, # SUBSTITUTE
+ 0x0040: 0x0020, # SPACE
+ 0x0041: 0x0391, # GREEK CAPITAL LETTER ALPHA
+ 0x0042: 0x0392, # GREEK CAPITAL LETTER BETA
+ 0x0043: 0x0393, # GREEK CAPITAL LETTER GAMMA
+ 0x0044: 0x0394, # GREEK CAPITAL LETTER DELTA
+ 0x0045: 0x0395, # GREEK CAPITAL LETTER EPSILON
+ 0x0046: 0x0396, # GREEK CAPITAL LETTER ZETA
+ 0x0047: 0x0397, # GREEK CAPITAL LETTER ETA
+ 0x0048: 0x0398, # GREEK CAPITAL LETTER THETA
+ 0x0049: 0x0399, # GREEK CAPITAL LETTER IOTA
+ 0x004a: 0x005b, # LEFT SQUARE BRACKET
+ 0x004b: 0x002e, # FULL STOP
+ 0x004c: 0x003c, # LESS-THAN SIGN
+ 0x004d: 0x0028, # LEFT PARENTHESIS
+ 0x004e: 0x002b, # PLUS SIGN
+ 0x004f: 0x0021, # EXCLAMATION MARK
+ 0x0050: 0x0026, # AMPERSAND
+ 0x0051: 0x039a, # GREEK CAPITAL LETTER KAPPA
+ 0x0052: 0x039b, # GREEK CAPITAL LETTER LAMDA
+ 0x0053: 0x039c, # GREEK CAPITAL LETTER MU
+ 0x0054: 0x039d, # GREEK CAPITAL LETTER NU
+ 0x0055: 0x039e, # GREEK CAPITAL LETTER XI
+ 0x0056: 0x039f, # GREEK CAPITAL LETTER OMICRON
+ 0x0057: 0x03a0, # GREEK CAPITAL LETTER PI
+ 0x0058: 0x03a1, # GREEK CAPITAL LETTER RHO
+ 0x0059: 0x03a3, # GREEK CAPITAL LETTER SIGMA
+ 0x005a: 0x005d, # RIGHT SQUARE BRACKET
+ 0x005b: 0x0024, # DOLLAR SIGN
+ 0x005c: 0x002a, # ASTERISK
+ 0x005d: 0x0029, # RIGHT PARENTHESIS
+ 0x005e: 0x003b, # SEMICOLON
+ 0x005f: 0x005e, # CIRCUMFLEX ACCENT
+ 0x0060: 0x002d, # HYPHEN-MINUS
+ 0x0061: 0x002f, # SOLIDUS
+ 0x0062: 0x03a4, # GREEK CAPITAL LETTER TAU
+ 0x0063: 0x03a5, # GREEK CAPITAL LETTER UPSILON
+ 0x0064: 0x03a6, # GREEK CAPITAL LETTER PHI
+ 0x0065: 0x03a7, # GREEK CAPITAL LETTER CHI
+ 0x0066: 0x03a8, # GREEK CAPITAL LETTER PSI
+ 0x0067: 0x03a9, # GREEK CAPITAL LETTER OMEGA
+ 0x0068: 0x03aa, # GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
+ 0x0069: 0x03ab, # GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
+ 0x006a: 0x007c, # VERTICAL LINE
+ 0x006b: 0x002c, # COMMA
+ 0x006c: 0x0025, # PERCENT SIGN
+ 0x006d: 0x005f, # LOW LINE
+ 0x006e: 0x003e, # GREATER-THAN SIGN
+ 0x006f: 0x003f, # QUESTION MARK
+ 0x0070: 0x00a8, # DIAERESIS
+ 0x0071: 0x0386, # GREEK CAPITAL LETTER ALPHA WITH TONOS
+ 0x0072: 0x0388, # GREEK CAPITAL LETTER EPSILON WITH TONOS
+ 0x0073: 0x0389, # GREEK CAPITAL LETTER ETA WITH TONOS
+ 0x0074: 0x00a0, # NO-BREAK SPACE
+ 0x0075: 0x038a, # GREEK CAPITAL LETTER IOTA WITH TONOS
+ 0x0076: 0x038c, # GREEK CAPITAL LETTER OMICRON WITH TONOS
+ 0x0077: 0x038e, # GREEK CAPITAL LETTER UPSILON WITH TONOS
+ 0x0078: 0x038f, # GREEK CAPITAL LETTER OMEGA WITH TONOS
+ 0x0079: 0x0060, # GRAVE ACCENT
+ 0x007a: 0x003a, # COLON
+ 0x007b: 0x0023, # NUMBER SIGN
+ 0x007c: 0x0040, # COMMERCIAL AT
+ 0x007d: 0x0027, # APOSTROPHE
+ 0x007e: 0x003d, # EQUALS SIGN
+ 0x007f: 0x0022, # QUOTATION MARK
+ 0x0080: 0x0385, # GREEK DIALYTIKA TONOS
+ 0x0081: 0x0061, # LATIN SMALL LETTER A
+ 0x0082: 0x0062, # LATIN SMALL LETTER B
+ 0x0083: 0x0063, # LATIN SMALL LETTER C
+ 0x0084: 0x0064, # LATIN SMALL LETTER D
+ 0x0085: 0x0065, # LATIN SMALL LETTER E
+ 0x0086: 0x0066, # LATIN SMALL LETTER F
+ 0x0087: 0x0067, # LATIN SMALL LETTER G
+ 0x0088: 0x0068, # LATIN SMALL LETTER H
+ 0x0089: 0x0069, # LATIN SMALL LETTER I
+ 0x008a: 0x03b1, # GREEK SMALL LETTER ALPHA
+ 0x008b: 0x03b2, # GREEK SMALL LETTER BETA
+ 0x008c: 0x03b3, # GREEK SMALL LETTER GAMMA
+ 0x008d: 0x03b4, # GREEK SMALL LETTER DELTA
+ 0x008e: 0x03b5, # GREEK SMALL LETTER EPSILON
+ 0x008f: 0x03b6, # GREEK SMALL LETTER ZETA
+ 0x0090: 0x00b0, # DEGREE SIGN
+ 0x0091: 0x006a, # LATIN SMALL LETTER J
+ 0x0092: 0x006b, # LATIN SMALL LETTER K
+ 0x0093: 0x006c, # LATIN SMALL LETTER L
+ 0x0094: 0x006d, # LATIN SMALL LETTER M
+ 0x0095: 0x006e, # LATIN SMALL LETTER N
+ 0x0096: 0x006f, # LATIN SMALL LETTER O
+ 0x0097: 0x0070, # LATIN SMALL LETTER P
+ 0x0098: 0x0071, # LATIN SMALL LETTER Q
+ 0x0099: 0x0072, # LATIN SMALL LETTER R
+ 0x009a: 0x03b7, # GREEK SMALL LETTER ETA
+ 0x009b: 0x03b8, # GREEK SMALL LETTER THETA
+ 0x009c: 0x03b9, # GREEK SMALL LETTER IOTA
+ 0x009d: 0x03ba, # GREEK SMALL LETTER KAPPA
+ 0x009e: 0x03bb, # GREEK SMALL LETTER LAMDA
+ 0x009f: 0x03bc, # GREEK SMALL LETTER MU
+ 0x00a0: 0x00b4, # ACUTE ACCENT
+ 0x00a1: 0x007e, # TILDE
+ 0x00a2: 0x0073, # LATIN SMALL LETTER S
+ 0x00a3: 0x0074, # LATIN SMALL LETTER T
+ 0x00a4: 0x0075, # LATIN SMALL LETTER U
+ 0x00a5: 0x0076, # LATIN SMALL LETTER V
+ 0x00a6: 0x0077, # LATIN SMALL LETTER W
+ 0x00a7: 0x0078, # LATIN SMALL LETTER X
+ 0x00a8: 0x0079, # LATIN SMALL LETTER Y
+ 0x00a9: 0x007a, # LATIN SMALL LETTER Z
+ 0x00aa: 0x03bd, # GREEK SMALL LETTER NU
+ 0x00ab: 0x03be, # GREEK SMALL LETTER XI
+ 0x00ac: 0x03bf, # GREEK SMALL LETTER OMICRON
+ 0x00ad: 0x03c0, # GREEK SMALL LETTER PI
+ 0x00ae: 0x03c1, # GREEK SMALL LETTER RHO
+ 0x00af: 0x03c3, # GREEK SMALL LETTER SIGMA
+ 0x00b0: 0x00a3, # POUND SIGN
+ 0x00b1: 0x03ac, # GREEK SMALL LETTER ALPHA WITH TONOS
+ 0x00b2: 0x03ad, # GREEK SMALL LETTER EPSILON WITH TONOS
+ 0x00b3: 0x03ae, # GREEK SMALL LETTER ETA WITH TONOS
+ 0x00b4: 0x03ca, # GREEK SMALL LETTER IOTA WITH DIALYTIKA
+ 0x00b5: 0x03af, # GREEK SMALL LETTER IOTA WITH TONOS
+ 0x00b6: 0x03cc, # GREEK SMALL LETTER OMICRON WITH TONOS
+ 0x00b7: 0x03cd, # GREEK SMALL LETTER UPSILON WITH TONOS
+ 0x00b8: 0x03cb, # GREEK SMALL LETTER UPSILON WITH DIALYTIKA
+ 0x00b9: 0x03ce, # GREEK SMALL LETTER OMEGA WITH TONOS
+ 0x00ba: 0x03c2, # GREEK SMALL LETTER FINAL SIGMA
+ 0x00bb: 0x03c4, # GREEK SMALL LETTER TAU
+ 0x00bc: 0x03c5, # GREEK SMALL LETTER UPSILON
+ 0x00bd: 0x03c6, # GREEK SMALL LETTER PHI
+ 0x00be: 0x03c7, # GREEK SMALL LETTER CHI
+ 0x00bf: 0x03c8, # GREEK SMALL LETTER PSI
+ 0x00c0: 0x007b, # LEFT CURLY BRACKET
+ 0x00c1: 0x0041, # LATIN CAPITAL LETTER A
+ 0x00c2: 0x0042, # LATIN CAPITAL LETTER B
+ 0x00c3: 0x0043, # LATIN CAPITAL LETTER C
+ 0x00c4: 0x0044, # LATIN CAPITAL LETTER D
+ 0x00c5: 0x0045, # LATIN CAPITAL LETTER E
+ 0x00c6: 0x0046, # LATIN CAPITAL LETTER F
+ 0x00c7: 0x0047, # LATIN CAPITAL LETTER G
+ 0x00c8: 0x0048, # LATIN CAPITAL LETTER H
+ 0x00c9: 0x0049, # LATIN CAPITAL LETTER I
+ 0x00ca: 0x00ad, # SOFT HYPHEN
+ 0x00cb: 0x03c9, # GREEK SMALL LETTER OMEGA
+ 0x00cc: 0x0390, # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
+ 0x00cd: 0x03b0, # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
+ 0x00ce: 0x2018, # LEFT SINGLE QUOTATION MARK
+ 0x00cf: 0x2015, # HORIZONTAL BAR
+ 0x00d0: 0x007d, # RIGHT CURLY BRACKET
+ 0x00d1: 0x004a, # LATIN CAPITAL LETTER J
+ 0x00d2: 0x004b, # LATIN CAPITAL LETTER K
+ 0x00d3: 0x004c, # LATIN CAPITAL LETTER L
+ 0x00d4: 0x004d, # LATIN CAPITAL LETTER M
+ 0x00d5: 0x004e, # LATIN CAPITAL LETTER N
+ 0x00d6: 0x004f, # LATIN CAPITAL LETTER O
+ 0x00d7: 0x0050, # LATIN CAPITAL LETTER P
+ 0x00d8: 0x0051, # LATIN CAPITAL LETTER Q
+ 0x00d9: 0x0052, # LATIN CAPITAL LETTER R
+ 0x00da: 0x00b1, # PLUS-MINUS SIGN
+ 0x00db: 0x00bd, # VULGAR FRACTION ONE HALF
+ 0x00dc: 0x001a, # SUBSTITUTE
+ 0x00dd: 0x0387, # GREEK ANO TELEIA
+ 0x00de: 0x2019, # RIGHT SINGLE QUOTATION MARK
+ 0x00df: 0x00a6, # BROKEN BAR
+ 0x00e0: 0x005c, # REVERSE SOLIDUS
+ 0x00e1: 0x001a, # SUBSTITUTE
+ 0x00e2: 0x0053, # LATIN CAPITAL LETTER S
+ 0x00e3: 0x0054, # LATIN CAPITAL LETTER T
+ 0x00e4: 0x0055, # LATIN CAPITAL LETTER U
+ 0x00e5: 0x0056, # LATIN CAPITAL LETTER V
+ 0x00e6: 0x0057, # LATIN CAPITAL LETTER W
+ 0x00e7: 0x0058, # LATIN CAPITAL LETTER X
+ 0x00e8: 0x0059, # LATIN CAPITAL LETTER Y
+ 0x00e9: 0x005a, # LATIN CAPITAL LETTER Z
+ 0x00ea: 0x00b2, # SUPERSCRIPT TWO
+ 0x00eb: 0x00a7, # SECTION SIGN
+ 0x00ec: 0x001a, # SUBSTITUTE
+ 0x00ed: 0x001a, # SUBSTITUTE
+ 0x00ee: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00ef: 0x00ac, # NOT SIGN
+ 0x00f0: 0x0030, # DIGIT ZERO
+ 0x00f1: 0x0031, # DIGIT ONE
+ 0x00f2: 0x0032, # DIGIT TWO
+ 0x00f3: 0x0033, # DIGIT THREE
+ 0x00f4: 0x0034, # DIGIT FOUR
+ 0x00f5: 0x0035, # DIGIT FIVE
+ 0x00f6: 0x0036, # DIGIT SIX
+ 0x00f7: 0x0037, # DIGIT SEVEN
+ 0x00f8: 0x0038, # DIGIT EIGHT
+ 0x00f9: 0x0039, # DIGIT NINE
+ 0x00fa: 0x00b3, # SUPERSCRIPT THREE
+ 0x00fb: 0x00a9, # COPYRIGHT SIGN
+ 0x00fc: 0x001a, # SUBSTITUTE
+ 0x00fd: 0x001a, # SUBSTITUTE
+ 0x00fe: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00ff: 0x009f, # CONTROL
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/iso8859_1.py b/lib/jython/Lib/encodings/iso8859_1.py new file mode 100644 index 000000000..4535de387 --- /dev/null +++ b/lib/jython/Lib/encodings/iso8859_1.py @@ -0,0 +1,46 @@ +""" Python Character Mapping Codec generated from '8859-1.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/iso8859_10.py b/lib/jython/Lib/encodings/iso8859_10.py new file mode 100644 index 000000000..e814a672b --- /dev/null +++ b/lib/jython/Lib/encodings/iso8859_10.py @@ -0,0 +1,92 @@ +""" Python Character Mapping Codec generated from '8859-10.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x00a1: 0x0104, # LATIN CAPITAL LETTER A WITH OGONEK
+ 0x00a2: 0x0112, # LATIN CAPITAL LETTER E WITH MACRON
+ 0x00a3: 0x0122, # LATIN CAPITAL LETTER G WITH CEDILLA
+ 0x00a4: 0x012a, # LATIN CAPITAL LETTER I WITH MACRON
+ 0x00a5: 0x0128, # LATIN CAPITAL LETTER I WITH TILDE
+ 0x00a6: 0x0136, # LATIN CAPITAL LETTER K WITH CEDILLA
+ 0x00a8: 0x013b, # LATIN CAPITAL LETTER L WITH CEDILLA
+ 0x00a9: 0x0110, # LATIN CAPITAL LETTER D WITH STROKE
+ 0x00aa: 0x0160, # LATIN CAPITAL LETTER S WITH CARON
+ 0x00ab: 0x0166, # LATIN CAPITAL LETTER T WITH STROKE
+ 0x00ac: 0x017d, # LATIN CAPITAL LETTER Z WITH CARON
+ 0x00ae: 0x016a, # LATIN CAPITAL LETTER U WITH MACRON
+ 0x00af: 0x014a, # LATIN CAPITAL LETTER ENG
+ 0x00b1: 0x0105, # LATIN SMALL LETTER A WITH OGONEK
+ 0x00b2: 0x0113, # LATIN SMALL LETTER E WITH MACRON
+ 0x00b3: 0x0123, # LATIN SMALL LETTER G WITH CEDILLA
+ 0x00b4: 0x012b, # LATIN SMALL LETTER I WITH MACRON
+ 0x00b5: 0x0129, # LATIN SMALL LETTER I WITH TILDE
+ 0x00b6: 0x0137, # LATIN SMALL LETTER K WITH CEDILLA
+ 0x00b8: 0x013c, # LATIN SMALL LETTER L WITH CEDILLA
+ 0x00b9: 0x0111, # LATIN SMALL LETTER D WITH STROKE
+ 0x00ba: 0x0161, # LATIN SMALL LETTER S WITH CARON
+ 0x00bb: 0x0167, # LATIN SMALL LETTER T WITH STROKE
+ 0x00bc: 0x017e, # LATIN SMALL LETTER Z WITH CARON
+ 0x00bd: 0x2015, # HORIZONTAL BAR
+ 0x00be: 0x016b, # LATIN SMALL LETTER U WITH MACRON
+ 0x00bf: 0x014b, # LATIN SMALL LETTER ENG
+ 0x00c0: 0x0100, # LATIN CAPITAL LETTER A WITH MACRON
+ 0x00c7: 0x012e, # LATIN CAPITAL LETTER I WITH OGONEK
+ 0x00c8: 0x010c, # LATIN CAPITAL LETTER C WITH CARON
+ 0x00ca: 0x0118, # LATIN CAPITAL LETTER E WITH OGONEK
+ 0x00cc: 0x0116, # LATIN CAPITAL LETTER E WITH DOT ABOVE
+ 0x00d1: 0x0145, # LATIN CAPITAL LETTER N WITH CEDILLA
+ 0x00d2: 0x014c, # LATIN CAPITAL LETTER O WITH MACRON
+ 0x00d7: 0x0168, # LATIN CAPITAL LETTER U WITH TILDE
+ 0x00d9: 0x0172, # LATIN CAPITAL LETTER U WITH OGONEK
+ 0x00e0: 0x0101, # LATIN SMALL LETTER A WITH MACRON
+ 0x00e7: 0x012f, # LATIN SMALL LETTER I WITH OGONEK
+ 0x00e8: 0x010d, # LATIN SMALL LETTER C WITH CARON
+ 0x00ea: 0x0119, # LATIN SMALL LETTER E WITH OGONEK
+ 0x00ec: 0x0117, # LATIN SMALL LETTER E WITH DOT ABOVE
+ 0x00f1: 0x0146, # LATIN SMALL LETTER N WITH CEDILLA
+ 0x00f2: 0x014d, # LATIN SMALL LETTER O WITH MACRON
+ 0x00f7: 0x0169, # LATIN SMALL LETTER U WITH TILDE
+ 0x00f9: 0x0173, # LATIN SMALL LETTER U WITH OGONEK
+ 0x00ff: 0x0138, # LATIN SMALL LETTER KRA
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/iso8859_13.py b/lib/jython/Lib/encodings/iso8859_13.py new file mode 100644 index 000000000..230714a59 --- /dev/null +++ b/lib/jython/Lib/encodings/iso8859_13.py @@ -0,0 +1,102 @@ +""" Python Character Mapping Codec generated from '8859-13.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x00a1: 0x201d, # RIGHT DOUBLE QUOTATION MARK
+ 0x00a5: 0x201e, # DOUBLE LOW-9 QUOTATION MARK
+ 0x00a8: 0x00d8, # LATIN CAPITAL LETTER O WITH STROKE
+ 0x00aa: 0x0156, # LATIN CAPITAL LETTER R WITH CEDILLA
+ 0x00af: 0x00c6, # LATIN CAPITAL LETTER AE
+ 0x00b4: 0x201c, # LEFT DOUBLE QUOTATION MARK
+ 0x00b8: 0x00f8, # LATIN SMALL LETTER O WITH STROKE
+ 0x00ba: 0x0157, # LATIN SMALL LETTER R WITH CEDILLA
+ 0x00bf: 0x00e6, # LATIN SMALL LETTER AE
+ 0x00c0: 0x0104, # LATIN CAPITAL LETTER A WITH OGONEK
+ 0x00c1: 0x012e, # LATIN CAPITAL LETTER I WITH OGONEK
+ 0x00c2: 0x0100, # LATIN CAPITAL LETTER A WITH MACRON
+ 0x00c3: 0x0106, # LATIN CAPITAL LETTER C WITH ACUTE
+ 0x00c6: 0x0118, # LATIN CAPITAL LETTER E WITH OGONEK
+ 0x00c7: 0x0112, # LATIN CAPITAL LETTER E WITH MACRON
+ 0x00c8: 0x010c, # LATIN CAPITAL LETTER C WITH CARON
+ 0x00ca: 0x0179, # LATIN CAPITAL LETTER Z WITH ACUTE
+ 0x00cb: 0x0116, # LATIN CAPITAL LETTER E WITH DOT ABOVE
+ 0x00cc: 0x0122, # LATIN CAPITAL LETTER G WITH CEDILLA
+ 0x00cd: 0x0136, # LATIN CAPITAL LETTER K WITH CEDILLA
+ 0x00ce: 0x012a, # LATIN CAPITAL LETTER I WITH MACRON
+ 0x00cf: 0x013b, # LATIN CAPITAL LETTER L WITH CEDILLA
+ 0x00d0: 0x0160, # LATIN CAPITAL LETTER S WITH CARON
+ 0x00d1: 0x0143, # LATIN CAPITAL LETTER N WITH ACUTE
+ 0x00d2: 0x0145, # LATIN CAPITAL LETTER N WITH CEDILLA
+ 0x00d4: 0x014c, # LATIN CAPITAL LETTER O WITH MACRON
+ 0x00d8: 0x0172, # LATIN CAPITAL LETTER U WITH OGONEK
+ 0x00d9: 0x0141, # LATIN CAPITAL LETTER L WITH STROKE
+ 0x00da: 0x015a, # LATIN CAPITAL LETTER S WITH ACUTE
+ 0x00db: 0x016a, # LATIN CAPITAL LETTER U WITH MACRON
+ 0x00dd: 0x017b, # LATIN CAPITAL LETTER Z WITH DOT ABOVE
+ 0x00de: 0x017d, # LATIN CAPITAL LETTER Z WITH CARON
+ 0x00e0: 0x0105, # LATIN SMALL LETTER A WITH OGONEK
+ 0x00e1: 0x012f, # LATIN SMALL LETTER I WITH OGONEK
+ 0x00e2: 0x0101, # LATIN SMALL LETTER A WITH MACRON
+ 0x00e3: 0x0107, # LATIN SMALL LETTER C WITH ACUTE
+ 0x00e6: 0x0119, # LATIN SMALL LETTER E WITH OGONEK
+ 0x00e7: 0x0113, # LATIN SMALL LETTER E WITH MACRON
+ 0x00e8: 0x010d, # LATIN SMALL LETTER C WITH CARON
+ 0x00ea: 0x017a, # LATIN SMALL LETTER Z WITH ACUTE
+ 0x00eb: 0x0117, # LATIN SMALL LETTER E WITH DOT ABOVE
+ 0x00ec: 0x0123, # LATIN SMALL LETTER G WITH CEDILLA
+ 0x00ed: 0x0137, # LATIN SMALL LETTER K WITH CEDILLA
+ 0x00ee: 0x012b, # LATIN SMALL LETTER I WITH MACRON
+ 0x00ef: 0x013c, # LATIN SMALL LETTER L WITH CEDILLA
+ 0x00f0: 0x0161, # LATIN SMALL LETTER S WITH CARON
+ 0x00f1: 0x0144, # LATIN SMALL LETTER N WITH ACUTE
+ 0x00f2: 0x0146, # LATIN SMALL LETTER N WITH CEDILLA
+ 0x00f4: 0x014d, # LATIN SMALL LETTER O WITH MACRON
+ 0x00f8: 0x0173, # LATIN SMALL LETTER U WITH OGONEK
+ 0x00f9: 0x0142, # LATIN SMALL LETTER L WITH STROKE
+ 0x00fa: 0x015b, # LATIN SMALL LETTER S WITH ACUTE
+ 0x00fb: 0x016b, # LATIN SMALL LETTER U WITH MACRON
+ 0x00fd: 0x017c, # LATIN SMALL LETTER Z WITH DOT ABOVE
+ 0x00fe: 0x017e, # LATIN SMALL LETTER Z WITH CARON
+ 0x00ff: 0x2019, # RIGHT SINGLE QUOTATION MARK
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/iso8859_14.py b/lib/jython/Lib/encodings/iso8859_14.py new file mode 100644 index 000000000..a9d273959 --- /dev/null +++ b/lib/jython/Lib/encodings/iso8859_14.py @@ -0,0 +1,77 @@ +""" Python Character Mapping Codec generated from '8859-14.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x00a1: 0x1e02, # LATIN CAPITAL LETTER B WITH DOT ABOVE
+ 0x00a2: 0x1e03, # LATIN SMALL LETTER B WITH DOT ABOVE
+ 0x00a4: 0x010a, # LATIN CAPITAL LETTER C WITH DOT ABOVE
+ 0x00a5: 0x010b, # LATIN SMALL LETTER C WITH DOT ABOVE
+ 0x00a6: 0x1e0a, # LATIN CAPITAL LETTER D WITH DOT ABOVE
+ 0x00a8: 0x1e80, # LATIN CAPITAL LETTER W WITH GRAVE
+ 0x00aa: 0x1e82, # LATIN CAPITAL LETTER W WITH ACUTE
+ 0x00ab: 0x1e0b, # LATIN SMALL LETTER D WITH DOT ABOVE
+ 0x00ac: 0x1ef2, # LATIN CAPITAL LETTER Y WITH GRAVE
+ 0x00af: 0x0178, # LATIN CAPITAL LETTER Y WITH DIAERESIS
+ 0x00b0: 0x1e1e, # LATIN CAPITAL LETTER F WITH DOT ABOVE
+ 0x00b1: 0x1e1f, # LATIN SMALL LETTER F WITH DOT ABOVE
+ 0x00b2: 0x0120, # LATIN CAPITAL LETTER G WITH DOT ABOVE
+ 0x00b3: 0x0121, # LATIN SMALL LETTER G WITH DOT ABOVE
+ 0x00b4: 0x1e40, # LATIN CAPITAL LETTER M WITH DOT ABOVE
+ 0x00b5: 0x1e41, # LATIN SMALL LETTER M WITH DOT ABOVE
+ 0x00b7: 0x1e56, # LATIN CAPITAL LETTER P WITH DOT ABOVE
+ 0x00b8: 0x1e81, # LATIN SMALL LETTER W WITH GRAVE
+ 0x00b9: 0x1e57, # LATIN SMALL LETTER P WITH DOT ABOVE
+ 0x00ba: 0x1e83, # LATIN SMALL LETTER W WITH ACUTE
+ 0x00bb: 0x1e60, # LATIN CAPITAL LETTER S WITH DOT ABOVE
+ 0x00bc: 0x1ef3, # LATIN SMALL LETTER Y WITH GRAVE
+ 0x00bd: 0x1e84, # LATIN CAPITAL LETTER W WITH DIAERESIS
+ 0x00be: 0x1e85, # LATIN SMALL LETTER W WITH DIAERESIS
+ 0x00bf: 0x1e61, # LATIN SMALL LETTER S WITH DOT ABOVE
+ 0x00d0: 0x0174, # LATIN CAPITAL LETTER W WITH CIRCUMFLEX
+ 0x00d7: 0x1e6a, # LATIN CAPITAL LETTER T WITH DOT ABOVE
+ 0x00de: 0x0176, # LATIN CAPITAL LETTER Y WITH CIRCUMFLEX
+ 0x00f0: 0x0175, # LATIN SMALL LETTER W WITH CIRCUMFLEX
+ 0x00f7: 0x1e6b, # LATIN SMALL LETTER T WITH DOT ABOVE
+ 0x00fe: 0x0177, # LATIN SMALL LETTER Y WITH CIRCUMFLEX
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/iso8859_15.py b/lib/jython/Lib/encodings/iso8859_15.py new file mode 100644 index 000000000..fd6b3da38 --- /dev/null +++ b/lib/jython/Lib/encodings/iso8859_15.py @@ -0,0 +1,54 @@ +""" Python Character Mapping Codec generated from '8859-15.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x00a4: 0x20ac, # EURO SIGN
+ 0x00a6: 0x0160, # LATIN CAPITAL LETTER S WITH CARON
+ 0x00a8: 0x0161, # LATIN SMALL LETTER S WITH CARON
+ 0x00b4: 0x017d, # LATIN CAPITAL LETTER Z WITH CARON
+ 0x00b8: 0x017e, # LATIN SMALL LETTER Z WITH CARON
+ 0x00bc: 0x0152, # LATIN CAPITAL LIGATURE OE
+ 0x00bd: 0x0153, # LATIN SMALL LIGATURE OE
+ 0x00be: 0x0178, # LATIN CAPITAL LETTER Y WITH DIAERESIS
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/iso8859_2.py b/lib/jython/Lib/encodings/iso8859_2.py new file mode 100644 index 000000000..536e1ecc1 --- /dev/null +++ b/lib/jython/Lib/encodings/iso8859_2.py @@ -0,0 +1,103 @@ +""" Python Character Mapping Codec generated from '8859-2.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x00a1: 0x0104, # LATIN CAPITAL LETTER A WITH OGONEK
+ 0x00a2: 0x02d8, # BREVE
+ 0x00a3: 0x0141, # LATIN CAPITAL LETTER L WITH STROKE
+ 0x00a5: 0x013d, # LATIN CAPITAL LETTER L WITH CARON
+ 0x00a6: 0x015a, # LATIN CAPITAL LETTER S WITH ACUTE
+ 0x00a9: 0x0160, # LATIN CAPITAL LETTER S WITH CARON
+ 0x00aa: 0x015e, # LATIN CAPITAL LETTER S WITH CEDILLA
+ 0x00ab: 0x0164, # LATIN CAPITAL LETTER T WITH CARON
+ 0x00ac: 0x0179, # LATIN CAPITAL LETTER Z WITH ACUTE
+ 0x00ae: 0x017d, # LATIN CAPITAL LETTER Z WITH CARON
+ 0x00af: 0x017b, # LATIN CAPITAL LETTER Z WITH DOT ABOVE
+ 0x00b1: 0x0105, # LATIN SMALL LETTER A WITH OGONEK
+ 0x00b2: 0x02db, # OGONEK
+ 0x00b3: 0x0142, # LATIN SMALL LETTER L WITH STROKE
+ 0x00b5: 0x013e, # LATIN SMALL LETTER L WITH CARON
+ 0x00b6: 0x015b, # LATIN SMALL LETTER S WITH ACUTE
+ 0x00b7: 0x02c7, # CARON
+ 0x00b9: 0x0161, # LATIN SMALL LETTER S WITH CARON
+ 0x00ba: 0x015f, # LATIN SMALL LETTER S WITH CEDILLA
+ 0x00bb: 0x0165, # LATIN SMALL LETTER T WITH CARON
+ 0x00bc: 0x017a, # LATIN SMALL LETTER Z WITH ACUTE
+ 0x00bd: 0x02dd, # DOUBLE ACUTE ACCENT
+ 0x00be: 0x017e, # LATIN SMALL LETTER Z WITH CARON
+ 0x00bf: 0x017c, # LATIN SMALL LETTER Z WITH DOT ABOVE
+ 0x00c0: 0x0154, # LATIN CAPITAL LETTER R WITH ACUTE
+ 0x00c3: 0x0102, # LATIN CAPITAL LETTER A WITH BREVE
+ 0x00c5: 0x0139, # LATIN CAPITAL LETTER L WITH ACUTE
+ 0x00c6: 0x0106, # LATIN CAPITAL LETTER C WITH ACUTE
+ 0x00c8: 0x010c, # LATIN CAPITAL LETTER C WITH CARON
+ 0x00ca: 0x0118, # LATIN CAPITAL LETTER E WITH OGONEK
+ 0x00cc: 0x011a, # LATIN CAPITAL LETTER E WITH CARON
+ 0x00cf: 0x010e, # LATIN CAPITAL LETTER D WITH CARON
+ 0x00d0: 0x0110, # LATIN CAPITAL LETTER D WITH STROKE
+ 0x00d1: 0x0143, # LATIN CAPITAL LETTER N WITH ACUTE
+ 0x00d2: 0x0147, # LATIN CAPITAL LETTER N WITH CARON
+ 0x00d5: 0x0150, # LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
+ 0x00d8: 0x0158, # LATIN CAPITAL LETTER R WITH CARON
+ 0x00d9: 0x016e, # LATIN CAPITAL LETTER U WITH RING ABOVE
+ 0x00db: 0x0170, # LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
+ 0x00de: 0x0162, # LATIN CAPITAL LETTER T WITH CEDILLA
+ 0x00e0: 0x0155, # LATIN SMALL LETTER R WITH ACUTE
+ 0x00e3: 0x0103, # LATIN SMALL LETTER A WITH BREVE
+ 0x00e5: 0x013a, # LATIN SMALL LETTER L WITH ACUTE
+ 0x00e6: 0x0107, # LATIN SMALL LETTER C WITH ACUTE
+ 0x00e8: 0x010d, # LATIN SMALL LETTER C WITH CARON
+ 0x00ea: 0x0119, # LATIN SMALL LETTER E WITH OGONEK
+ 0x00ec: 0x011b, # LATIN SMALL LETTER E WITH CARON
+ 0x00ef: 0x010f, # LATIN SMALL LETTER D WITH CARON
+ 0x00f0: 0x0111, # LATIN SMALL LETTER D WITH STROKE
+ 0x00f1: 0x0144, # LATIN SMALL LETTER N WITH ACUTE
+ 0x00f2: 0x0148, # LATIN SMALL LETTER N WITH CARON
+ 0x00f5: 0x0151, # LATIN SMALL LETTER O WITH DOUBLE ACUTE
+ 0x00f8: 0x0159, # LATIN SMALL LETTER R WITH CARON
+ 0x00f9: 0x016f, # LATIN SMALL LETTER U WITH RING ABOVE
+ 0x00fb: 0x0171, # LATIN SMALL LETTER U WITH DOUBLE ACUTE
+ 0x00fe: 0x0163, # LATIN SMALL LETTER T WITH CEDILLA
+ 0x00ff: 0x02d9, # DOT ABOVE
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/iso8859_3.py b/lib/jython/Lib/encodings/iso8859_3.py new file mode 100644 index 000000000..684041538 --- /dev/null +++ b/lib/jython/Lib/encodings/iso8859_3.py @@ -0,0 +1,81 @@ +""" Python Character Mapping Codec generated from '8859-3.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x00a1: 0x0126, # LATIN CAPITAL LETTER H WITH STROKE
+ 0x00a2: 0x02d8, # BREVE
+ 0x00a5: None,
+ 0x00a6: 0x0124, # LATIN CAPITAL LETTER H WITH CIRCUMFLEX
+ 0x00a9: 0x0130, # LATIN CAPITAL LETTER I WITH DOT ABOVE
+ 0x00aa: 0x015e, # LATIN CAPITAL LETTER S WITH CEDILLA
+ 0x00ab: 0x011e, # LATIN CAPITAL LETTER G WITH BREVE
+ 0x00ac: 0x0134, # LATIN CAPITAL LETTER J WITH CIRCUMFLEX
+ 0x00ae: None,
+ 0x00af: 0x017b, # LATIN CAPITAL LETTER Z WITH DOT ABOVE
+ 0x00b1: 0x0127, # LATIN SMALL LETTER H WITH STROKE
+ 0x00b6: 0x0125, # LATIN SMALL LETTER H WITH CIRCUMFLEX
+ 0x00b9: 0x0131, # LATIN SMALL LETTER DOTLESS I
+ 0x00ba: 0x015f, # LATIN SMALL LETTER S WITH CEDILLA
+ 0x00bb: 0x011f, # LATIN SMALL LETTER G WITH BREVE
+ 0x00bc: 0x0135, # LATIN SMALL LETTER J WITH CIRCUMFLEX
+ 0x00be: None,
+ 0x00bf: 0x017c, # LATIN SMALL LETTER Z WITH DOT ABOVE
+ 0x00c3: None,
+ 0x00c5: 0x010a, # LATIN CAPITAL LETTER C WITH DOT ABOVE
+ 0x00c6: 0x0108, # LATIN CAPITAL LETTER C WITH CIRCUMFLEX
+ 0x00d0: None,
+ 0x00d5: 0x0120, # LATIN CAPITAL LETTER G WITH DOT ABOVE
+ 0x00d8: 0x011c, # LATIN CAPITAL LETTER G WITH CIRCUMFLEX
+ 0x00dd: 0x016c, # LATIN CAPITAL LETTER U WITH BREVE
+ 0x00de: 0x015c, # LATIN CAPITAL LETTER S WITH CIRCUMFLEX
+ 0x00e3: None,
+ 0x00e5: 0x010b, # LATIN SMALL LETTER C WITH DOT ABOVE
+ 0x00e6: 0x0109, # LATIN SMALL LETTER C WITH CIRCUMFLEX
+ 0x00f0: None,
+ 0x00f5: 0x0121, # LATIN SMALL LETTER G WITH DOT ABOVE
+ 0x00f8: 0x011d, # LATIN SMALL LETTER G WITH CIRCUMFLEX
+ 0x00fd: 0x016d, # LATIN SMALL LETTER U WITH BREVE
+ 0x00fe: 0x015d, # LATIN SMALL LETTER S WITH CIRCUMFLEX
+ 0x00ff: 0x02d9, # DOT ABOVE
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/iso8859_4.py b/lib/jython/Lib/encodings/iso8859_4.py new file mode 100644 index 000000000..7e80b38ce --- /dev/null +++ b/lib/jython/Lib/encodings/iso8859_4.py @@ -0,0 +1,96 @@ +""" Python Character Mapping Codec generated from '8859-4.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x00a1: 0x0104, # LATIN CAPITAL LETTER A WITH OGONEK
+ 0x00a2: 0x0138, # LATIN SMALL LETTER KRA
+ 0x00a3: 0x0156, # LATIN CAPITAL LETTER R WITH CEDILLA
+ 0x00a5: 0x0128, # LATIN CAPITAL LETTER I WITH TILDE
+ 0x00a6: 0x013b, # LATIN CAPITAL LETTER L WITH CEDILLA
+ 0x00a9: 0x0160, # LATIN CAPITAL LETTER S WITH CARON
+ 0x00aa: 0x0112, # LATIN CAPITAL LETTER E WITH MACRON
+ 0x00ab: 0x0122, # LATIN CAPITAL LETTER G WITH CEDILLA
+ 0x00ac: 0x0166, # LATIN CAPITAL LETTER T WITH STROKE
+ 0x00ae: 0x017d, # LATIN CAPITAL LETTER Z WITH CARON
+ 0x00b1: 0x0105, # LATIN SMALL LETTER A WITH OGONEK
+ 0x00b2: 0x02db, # OGONEK
+ 0x00b3: 0x0157, # LATIN SMALL LETTER R WITH CEDILLA
+ 0x00b5: 0x0129, # LATIN SMALL LETTER I WITH TILDE
+ 0x00b6: 0x013c, # LATIN SMALL LETTER L WITH CEDILLA
+ 0x00b7: 0x02c7, # CARON
+ 0x00b9: 0x0161, # LATIN SMALL LETTER S WITH CARON
+ 0x00ba: 0x0113, # LATIN SMALL LETTER E WITH MACRON
+ 0x00bb: 0x0123, # LATIN SMALL LETTER G WITH CEDILLA
+ 0x00bc: 0x0167, # LATIN SMALL LETTER T WITH STROKE
+ 0x00bd: 0x014a, # LATIN CAPITAL LETTER ENG
+ 0x00be: 0x017e, # LATIN SMALL LETTER Z WITH CARON
+ 0x00bf: 0x014b, # LATIN SMALL LETTER ENG
+ 0x00c0: 0x0100, # LATIN CAPITAL LETTER A WITH MACRON
+ 0x00c7: 0x012e, # LATIN CAPITAL LETTER I WITH OGONEK
+ 0x00c8: 0x010c, # LATIN CAPITAL LETTER C WITH CARON
+ 0x00ca: 0x0118, # LATIN CAPITAL LETTER E WITH OGONEK
+ 0x00cc: 0x0116, # LATIN CAPITAL LETTER E WITH DOT ABOVE
+ 0x00cf: 0x012a, # LATIN CAPITAL LETTER I WITH MACRON
+ 0x00d0: 0x0110, # LATIN CAPITAL LETTER D WITH STROKE
+ 0x00d1: 0x0145, # LATIN CAPITAL LETTER N WITH CEDILLA
+ 0x00d2: 0x014c, # LATIN CAPITAL LETTER O WITH MACRON
+ 0x00d3: 0x0136, # LATIN CAPITAL LETTER K WITH CEDILLA
+ 0x00d9: 0x0172, # LATIN CAPITAL LETTER U WITH OGONEK
+ 0x00dd: 0x0168, # LATIN CAPITAL LETTER U WITH TILDE
+ 0x00de: 0x016a, # LATIN CAPITAL LETTER U WITH MACRON
+ 0x00e0: 0x0101, # LATIN SMALL LETTER A WITH MACRON
+ 0x00e7: 0x012f, # LATIN SMALL LETTER I WITH OGONEK
+ 0x00e8: 0x010d, # LATIN SMALL LETTER C WITH CARON
+ 0x00ea: 0x0119, # LATIN SMALL LETTER E WITH OGONEK
+ 0x00ec: 0x0117, # LATIN SMALL LETTER E WITH DOT ABOVE
+ 0x00ef: 0x012b, # LATIN SMALL LETTER I WITH MACRON
+ 0x00f0: 0x0111, # LATIN SMALL LETTER D WITH STROKE
+ 0x00f1: 0x0146, # LATIN SMALL LETTER N WITH CEDILLA
+ 0x00f2: 0x014d, # LATIN SMALL LETTER O WITH MACRON
+ 0x00f3: 0x0137, # LATIN SMALL LETTER K WITH CEDILLA
+ 0x00f9: 0x0173, # LATIN SMALL LETTER U WITH OGONEK
+ 0x00fd: 0x0169, # LATIN SMALL LETTER U WITH TILDE
+ 0x00fe: 0x016b, # LATIN SMALL LETTER U WITH MACRON
+ 0x00ff: 0x02d9, # DOT ABOVE
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/iso8859_5.py b/lib/jython/Lib/encodings/iso8859_5.py new file mode 100644 index 000000000..766f1a0a8 --- /dev/null +++ b/lib/jython/Lib/encodings/iso8859_5.py @@ -0,0 +1,140 @@ +""" Python Character Mapping Codec generated from '8859-5.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x00a1: 0x0401, # CYRILLIC CAPITAL LETTER IO
+ 0x00a2: 0x0402, # CYRILLIC CAPITAL LETTER DJE
+ 0x00a3: 0x0403, # CYRILLIC CAPITAL LETTER GJE
+ 0x00a4: 0x0404, # CYRILLIC CAPITAL LETTER UKRAINIAN IE
+ 0x00a5: 0x0405, # CYRILLIC CAPITAL LETTER DZE
+ 0x00a6: 0x0406, # CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
+ 0x00a7: 0x0407, # CYRILLIC CAPITAL LETTER YI
+ 0x00a8: 0x0408, # CYRILLIC CAPITAL LETTER JE
+ 0x00a9: 0x0409, # CYRILLIC CAPITAL LETTER LJE
+ 0x00aa: 0x040a, # CYRILLIC CAPITAL LETTER NJE
+ 0x00ab: 0x040b, # CYRILLIC CAPITAL LETTER TSHE
+ 0x00ac: 0x040c, # CYRILLIC CAPITAL LETTER KJE
+ 0x00ae: 0x040e, # CYRILLIC CAPITAL LETTER SHORT U
+ 0x00af: 0x040f, # CYRILLIC CAPITAL LETTER DZHE
+ 0x00b0: 0x0410, # CYRILLIC CAPITAL LETTER A
+ 0x00b1: 0x0411, # CYRILLIC CAPITAL LETTER BE
+ 0x00b2: 0x0412, # CYRILLIC CAPITAL LETTER VE
+ 0x00b3: 0x0413, # CYRILLIC CAPITAL LETTER GHE
+ 0x00b4: 0x0414, # CYRILLIC CAPITAL LETTER DE
+ 0x00b5: 0x0415, # CYRILLIC CAPITAL LETTER IE
+ 0x00b6: 0x0416, # CYRILLIC CAPITAL LETTER ZHE
+ 0x00b7: 0x0417, # CYRILLIC CAPITAL LETTER ZE
+ 0x00b8: 0x0418, # CYRILLIC CAPITAL LETTER I
+ 0x00b9: 0x0419, # CYRILLIC CAPITAL LETTER SHORT I
+ 0x00ba: 0x041a, # CYRILLIC CAPITAL LETTER KA
+ 0x00bb: 0x041b, # CYRILLIC CAPITAL LETTER EL
+ 0x00bc: 0x041c, # CYRILLIC CAPITAL LETTER EM
+ 0x00bd: 0x041d, # CYRILLIC CAPITAL LETTER EN
+ 0x00be: 0x041e, # CYRILLIC CAPITAL LETTER O
+ 0x00bf: 0x041f, # CYRILLIC CAPITAL LETTER PE
+ 0x00c0: 0x0420, # CYRILLIC CAPITAL LETTER ER
+ 0x00c1: 0x0421, # CYRILLIC CAPITAL LETTER ES
+ 0x00c2: 0x0422, # CYRILLIC CAPITAL LETTER TE
+ 0x00c3: 0x0423, # CYRILLIC CAPITAL LETTER U
+ 0x00c4: 0x0424, # CYRILLIC CAPITAL LETTER EF
+ 0x00c5: 0x0425, # CYRILLIC CAPITAL LETTER HA
+ 0x00c6: 0x0426, # CYRILLIC CAPITAL LETTER TSE
+ 0x00c7: 0x0427, # CYRILLIC CAPITAL LETTER CHE
+ 0x00c8: 0x0428, # CYRILLIC CAPITAL LETTER SHA
+ 0x00c9: 0x0429, # CYRILLIC CAPITAL LETTER SHCHA
+ 0x00ca: 0x042a, # CYRILLIC CAPITAL LETTER HARD SIGN
+ 0x00cb: 0x042b, # CYRILLIC CAPITAL LETTER YERU
+ 0x00cc: 0x042c, # CYRILLIC CAPITAL LETTER SOFT SIGN
+ 0x00cd: 0x042d, # CYRILLIC CAPITAL LETTER E
+ 0x00ce: 0x042e, # CYRILLIC CAPITAL LETTER YU
+ 0x00cf: 0x042f, # CYRILLIC CAPITAL LETTER YA
+ 0x00d0: 0x0430, # CYRILLIC SMALL LETTER A
+ 0x00d1: 0x0431, # CYRILLIC SMALL LETTER BE
+ 0x00d2: 0x0432, # CYRILLIC SMALL LETTER VE
+ 0x00d3: 0x0433, # CYRILLIC SMALL LETTER GHE
+ 0x00d4: 0x0434, # CYRILLIC SMALL LETTER DE
+ 0x00d5: 0x0435, # CYRILLIC SMALL LETTER IE
+ 0x00d6: 0x0436, # CYRILLIC SMALL LETTER ZHE
+ 0x00d7: 0x0437, # CYRILLIC SMALL LETTER ZE
+ 0x00d8: 0x0438, # CYRILLIC SMALL LETTER I
+ 0x00d9: 0x0439, # CYRILLIC SMALL LETTER SHORT I
+ 0x00da: 0x043a, # CYRILLIC SMALL LETTER KA
+ 0x00db: 0x043b, # CYRILLIC SMALL LETTER EL
+ 0x00dc: 0x043c, # CYRILLIC SMALL LETTER EM
+ 0x00dd: 0x043d, # CYRILLIC SMALL LETTER EN
+ 0x00de: 0x043e, # CYRILLIC SMALL LETTER O
+ 0x00df: 0x043f, # CYRILLIC SMALL LETTER PE
+ 0x00e0: 0x0440, # CYRILLIC SMALL LETTER ER
+ 0x00e1: 0x0441, # CYRILLIC SMALL LETTER ES
+ 0x00e2: 0x0442, # CYRILLIC SMALL LETTER TE
+ 0x00e3: 0x0443, # CYRILLIC SMALL LETTER U
+ 0x00e4: 0x0444, # CYRILLIC SMALL LETTER EF
+ 0x00e5: 0x0445, # CYRILLIC SMALL LETTER HA
+ 0x00e6: 0x0446, # CYRILLIC SMALL LETTER TSE
+ 0x00e7: 0x0447, # CYRILLIC SMALL LETTER CHE
+ 0x00e8: 0x0448, # CYRILLIC SMALL LETTER SHA
+ 0x00e9: 0x0449, # CYRILLIC SMALL LETTER SHCHA
+ 0x00ea: 0x044a, # CYRILLIC SMALL LETTER HARD SIGN
+ 0x00eb: 0x044b, # CYRILLIC SMALL LETTER YERU
+ 0x00ec: 0x044c, # CYRILLIC SMALL LETTER SOFT SIGN
+ 0x00ed: 0x044d, # CYRILLIC SMALL LETTER E
+ 0x00ee: 0x044e, # CYRILLIC SMALL LETTER YU
+ 0x00ef: 0x044f, # CYRILLIC SMALL LETTER YA
+ 0x00f0: 0x2116, # NUMERO SIGN
+ 0x00f1: 0x0451, # CYRILLIC SMALL LETTER IO
+ 0x00f2: 0x0452, # CYRILLIC SMALL LETTER DJE
+ 0x00f3: 0x0453, # CYRILLIC SMALL LETTER GJE
+ 0x00f4: 0x0454, # CYRILLIC SMALL LETTER UKRAINIAN IE
+ 0x00f5: 0x0455, # CYRILLIC SMALL LETTER DZE
+ 0x00f6: 0x0456, # CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
+ 0x00f7: 0x0457, # CYRILLIC SMALL LETTER YI
+ 0x00f8: 0x0458, # CYRILLIC SMALL LETTER JE
+ 0x00f9: 0x0459, # CYRILLIC SMALL LETTER LJE
+ 0x00fa: 0x045a, # CYRILLIC SMALL LETTER NJE
+ 0x00fb: 0x045b, # CYRILLIC SMALL LETTER TSHE
+ 0x00fc: 0x045c, # CYRILLIC SMALL LETTER KJE
+ 0x00fd: 0x00a7, # SECTION SIGN
+ 0x00fe: 0x045e, # CYRILLIC SMALL LETTER SHORT U
+ 0x00ff: 0x045f, # CYRILLIC SMALL LETTER DZHE
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/iso8859_6.py b/lib/jython/Lib/encodings/iso8859_6.py new file mode 100644 index 000000000..8b101ef73 --- /dev/null +++ b/lib/jython/Lib/encodings/iso8859_6.py @@ -0,0 +1,139 @@ +""" Python Character Mapping Codec generated from '8859-6.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x00a1: None,
+ 0x00a2: None,
+ 0x00a3: None,
+ 0x00a5: None,
+ 0x00a6: None,
+ 0x00a7: None,
+ 0x00a8: None,
+ 0x00a9: None,
+ 0x00aa: None,
+ 0x00ab: None,
+ 0x00ac: 0x060c, # ARABIC COMMA
+ 0x00ae: None,
+ 0x00af: None,
+ 0x00b0: None,
+ 0x00b1: None,
+ 0x00b2: None,
+ 0x00b3: None,
+ 0x00b4: None,
+ 0x00b5: None,
+ 0x00b6: None,
+ 0x00b7: None,
+ 0x00b8: None,
+ 0x00b9: None,
+ 0x00ba: None,
+ 0x00bb: 0x061b, # ARABIC SEMICOLON
+ 0x00bc: None,
+ 0x00bd: None,
+ 0x00be: None,
+ 0x00bf: 0x061f, # ARABIC QUESTION MARK
+ 0x00c0: None,
+ 0x00c1: 0x0621, # ARABIC LETTER HAMZA
+ 0x00c2: 0x0622, # ARABIC LETTER ALEF WITH MADDA ABOVE
+ 0x00c3: 0x0623, # ARABIC LETTER ALEF WITH HAMZA ABOVE
+ 0x00c4: 0x0624, # ARABIC LETTER WAW WITH HAMZA ABOVE
+ 0x00c5: 0x0625, # ARABIC LETTER ALEF WITH HAMZA BELOW
+ 0x00c6: 0x0626, # ARABIC LETTER YEH WITH HAMZA ABOVE
+ 0x00c7: 0x0627, # ARABIC LETTER ALEF
+ 0x00c8: 0x0628, # ARABIC LETTER BEH
+ 0x00c9: 0x0629, # ARABIC LETTER TEH MARBUTA
+ 0x00ca: 0x062a, # ARABIC LETTER TEH
+ 0x00cb: 0x062b, # ARABIC LETTER THEH
+ 0x00cc: 0x062c, # ARABIC LETTER JEEM
+ 0x00cd: 0x062d, # ARABIC LETTER HAH
+ 0x00ce: 0x062e, # ARABIC LETTER KHAH
+ 0x00cf: 0x062f, # ARABIC LETTER DAL
+ 0x00d0: 0x0630, # ARABIC LETTER THAL
+ 0x00d1: 0x0631, # ARABIC LETTER REH
+ 0x00d2: 0x0632, # ARABIC LETTER ZAIN
+ 0x00d3: 0x0633, # ARABIC LETTER SEEN
+ 0x00d4: 0x0634, # ARABIC LETTER SHEEN
+ 0x00d5: 0x0635, # ARABIC LETTER SAD
+ 0x00d6: 0x0636, # ARABIC LETTER DAD
+ 0x00d7: 0x0637, # ARABIC LETTER TAH
+ 0x00d8: 0x0638, # ARABIC LETTER ZAH
+ 0x00d9: 0x0639, # ARABIC LETTER AIN
+ 0x00da: 0x063a, # ARABIC LETTER GHAIN
+ 0x00db: None,
+ 0x00dc: None,
+ 0x00dd: None,
+ 0x00de: None,
+ 0x00df: None,
+ 0x00e0: 0x0640, # ARABIC TATWEEL
+ 0x00e1: 0x0641, # ARABIC LETTER FEH
+ 0x00e2: 0x0642, # ARABIC LETTER QAF
+ 0x00e3: 0x0643, # ARABIC LETTER KAF
+ 0x00e4: 0x0644, # ARABIC LETTER LAM
+ 0x00e5: 0x0645, # ARABIC LETTER MEEM
+ 0x00e6: 0x0646, # ARABIC LETTER NOON
+ 0x00e7: 0x0647, # ARABIC LETTER HEH
+ 0x00e8: 0x0648, # ARABIC LETTER WAW
+ 0x00e9: 0x0649, # ARABIC LETTER ALEF MAKSURA
+ 0x00ea: 0x064a, # ARABIC LETTER YEH
+ 0x00eb: 0x064b, # ARABIC FATHATAN
+ 0x00ec: 0x064c, # ARABIC DAMMATAN
+ 0x00ed: 0x064d, # ARABIC KASRATAN
+ 0x00ee: 0x064e, # ARABIC FATHA
+ 0x00ef: 0x064f, # ARABIC DAMMA
+ 0x00f0: 0x0650, # ARABIC KASRA
+ 0x00f1: 0x0651, # ARABIC SHADDA
+ 0x00f2: 0x0652, # ARABIC SUKUN
+ 0x00f3: None,
+ 0x00f4: None,
+ 0x00f5: None,
+ 0x00f6: None,
+ 0x00f7: None,
+ 0x00f8: None,
+ 0x00f9: None,
+ 0x00fa: None,
+ 0x00fb: None,
+ 0x00fc: None,
+ 0x00fd: None,
+ 0x00fe: None,
+ 0x00ff: None,
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/iso8859_7.py b/lib/jython/Lib/encodings/iso8859_7.py new file mode 100644 index 000000000..45894756f --- /dev/null +++ b/lib/jython/Lib/encodings/iso8859_7.py @@ -0,0 +1,126 @@ +""" Python Character Mapping Codec generated from '8859-7.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x00a1: 0x2018, # LEFT SINGLE QUOTATION MARK
+ 0x00a2: 0x2019, # RIGHT SINGLE QUOTATION MARK
+ 0x00a4: None,
+ 0x00a5: None,
+ 0x00aa: None,
+ 0x00ae: None,
+ 0x00af: 0x2015, # HORIZONTAL BAR
+ 0x00b4: 0x0384, # GREEK TONOS
+ 0x00b5: 0x0385, # GREEK DIALYTIKA TONOS
+ 0x00b6: 0x0386, # GREEK CAPITAL LETTER ALPHA WITH TONOS
+ 0x00b8: 0x0388, # GREEK CAPITAL LETTER EPSILON WITH TONOS
+ 0x00b9: 0x0389, # GREEK CAPITAL LETTER ETA WITH TONOS
+ 0x00ba: 0x038a, # GREEK CAPITAL LETTER IOTA WITH TONOS
+ 0x00bc: 0x038c, # GREEK CAPITAL LETTER OMICRON WITH TONOS
+ 0x00be: 0x038e, # GREEK CAPITAL LETTER UPSILON WITH TONOS
+ 0x00bf: 0x038f, # GREEK CAPITAL LETTER OMEGA WITH TONOS
+ 0x00c0: 0x0390, # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
+ 0x00c1: 0x0391, # GREEK CAPITAL LETTER ALPHA
+ 0x00c2: 0x0392, # GREEK CAPITAL LETTER BETA
+ 0x00c3: 0x0393, # GREEK CAPITAL LETTER GAMMA
+ 0x00c4: 0x0394, # GREEK CAPITAL LETTER DELTA
+ 0x00c5: 0x0395, # GREEK CAPITAL LETTER EPSILON
+ 0x00c6: 0x0396, # GREEK CAPITAL LETTER ZETA
+ 0x00c7: 0x0397, # GREEK CAPITAL LETTER ETA
+ 0x00c8: 0x0398, # GREEK CAPITAL LETTER THETA
+ 0x00c9: 0x0399, # GREEK CAPITAL LETTER IOTA
+ 0x00ca: 0x039a, # GREEK CAPITAL LETTER KAPPA
+ 0x00cb: 0x039b, # GREEK CAPITAL LETTER LAMDA
+ 0x00cc: 0x039c, # GREEK CAPITAL LETTER MU
+ 0x00cd: 0x039d, # GREEK CAPITAL LETTER NU
+ 0x00ce: 0x039e, # GREEK CAPITAL LETTER XI
+ 0x00cf: 0x039f, # GREEK CAPITAL LETTER OMICRON
+ 0x00d0: 0x03a0, # GREEK CAPITAL LETTER PI
+ 0x00d1: 0x03a1, # GREEK CAPITAL LETTER RHO
+ 0x00d2: None,
+ 0x00d3: 0x03a3, # GREEK CAPITAL LETTER SIGMA
+ 0x00d4: 0x03a4, # GREEK CAPITAL LETTER TAU
+ 0x00d5: 0x03a5, # GREEK CAPITAL LETTER UPSILON
+ 0x00d6: 0x03a6, # GREEK CAPITAL LETTER PHI
+ 0x00d7: 0x03a7, # GREEK CAPITAL LETTER CHI
+ 0x00d8: 0x03a8, # GREEK CAPITAL LETTER PSI
+ 0x00d9: 0x03a9, # GREEK CAPITAL LETTER OMEGA
+ 0x00da: 0x03aa, # GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
+ 0x00db: 0x03ab, # GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
+ 0x00dc: 0x03ac, # GREEK SMALL LETTER ALPHA WITH TONOS
+ 0x00dd: 0x03ad, # GREEK SMALL LETTER EPSILON WITH TONOS
+ 0x00de: 0x03ae, # GREEK SMALL LETTER ETA WITH TONOS
+ 0x00df: 0x03af, # GREEK SMALL LETTER IOTA WITH TONOS
+ 0x00e0: 0x03b0, # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
+ 0x00e1: 0x03b1, # GREEK SMALL LETTER ALPHA
+ 0x00e2: 0x03b2, # GREEK SMALL LETTER BETA
+ 0x00e3: 0x03b3, # GREEK SMALL LETTER GAMMA
+ 0x00e4: 0x03b4, # GREEK SMALL LETTER DELTA
+ 0x00e5: 0x03b5, # GREEK SMALL LETTER EPSILON
+ 0x00e6: 0x03b6, # GREEK SMALL LETTER ZETA
+ 0x00e7: 0x03b7, # GREEK SMALL LETTER ETA
+ 0x00e8: 0x03b8, # GREEK SMALL LETTER THETA
+ 0x00e9: 0x03b9, # GREEK SMALL LETTER IOTA
+ 0x00ea: 0x03ba, # GREEK SMALL LETTER KAPPA
+ 0x00eb: 0x03bb, # GREEK SMALL LETTER LAMDA
+ 0x00ec: 0x03bc, # GREEK SMALL LETTER MU
+ 0x00ed: 0x03bd, # GREEK SMALL LETTER NU
+ 0x00ee: 0x03be, # GREEK SMALL LETTER XI
+ 0x00ef: 0x03bf, # GREEK SMALL LETTER OMICRON
+ 0x00f0: 0x03c0, # GREEK SMALL LETTER PI
+ 0x00f1: 0x03c1, # GREEK SMALL LETTER RHO
+ 0x00f2: 0x03c2, # GREEK SMALL LETTER FINAL SIGMA
+ 0x00f3: 0x03c3, # GREEK SMALL LETTER SIGMA
+ 0x00f4: 0x03c4, # GREEK SMALL LETTER TAU
+ 0x00f5: 0x03c5, # GREEK SMALL LETTER UPSILON
+ 0x00f6: 0x03c6, # GREEK SMALL LETTER PHI
+ 0x00f7: 0x03c7, # GREEK SMALL LETTER CHI
+ 0x00f8: 0x03c8, # GREEK SMALL LETTER PSI
+ 0x00f9: 0x03c9, # GREEK SMALL LETTER OMEGA
+ 0x00fa: 0x03ca, # GREEK SMALL LETTER IOTA WITH DIALYTIKA
+ 0x00fb: 0x03cb, # GREEK SMALL LETTER UPSILON WITH DIALYTIKA
+ 0x00fc: 0x03cc, # GREEK SMALL LETTER OMICRON WITH TONOS
+ 0x00fd: 0x03cd, # GREEK SMALL LETTER UPSILON WITH TONOS
+ 0x00fe: 0x03ce, # GREEK SMALL LETTER OMEGA WITH TONOS
+ 0x00ff: None,
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/iso8859_8.py b/lib/jython/Lib/encodings/iso8859_8.py new file mode 100644 index 000000000..1468df787 --- /dev/null +++ b/lib/jython/Lib/encodings/iso8859_8.py @@ -0,0 +1,114 @@ +""" Python Character Mapping Codec generated from '8859-8.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x00a1: None,
+ 0x00aa: 0x00d7, # MULTIPLICATION SIGN
+ 0x00ba: 0x00f7, # DIVISION SIGN
+ 0x00bf: None,
+ 0x00c0: None,
+ 0x00c1: None,
+ 0x00c2: None,
+ 0x00c3: None,
+ 0x00c4: None,
+ 0x00c5: None,
+ 0x00c6: None,
+ 0x00c7: None,
+ 0x00c8: None,
+ 0x00c9: None,
+ 0x00ca: None,
+ 0x00cb: None,
+ 0x00cc: None,
+ 0x00cd: None,
+ 0x00ce: None,
+ 0x00cf: None,
+ 0x00d0: None,
+ 0x00d1: None,
+ 0x00d2: None,
+ 0x00d3: None,
+ 0x00d4: None,
+ 0x00d5: None,
+ 0x00d6: None,
+ 0x00d7: None,
+ 0x00d8: None,
+ 0x00d9: None,
+ 0x00da: None,
+ 0x00db: None,
+ 0x00dc: None,
+ 0x00dd: None,
+ 0x00de: None,
+ 0x00df: 0x2017, # DOUBLE LOW LINE
+ 0x00e0: 0x05d0, # HEBREW LETTER ALEF
+ 0x00e1: 0x05d1, # HEBREW LETTER BET
+ 0x00e2: 0x05d2, # HEBREW LETTER GIMEL
+ 0x00e3: 0x05d3, # HEBREW LETTER DALET
+ 0x00e4: 0x05d4, # HEBREW LETTER HE
+ 0x00e5: 0x05d5, # HEBREW LETTER VAV
+ 0x00e6: 0x05d6, # HEBREW LETTER ZAYIN
+ 0x00e7: 0x05d7, # HEBREW LETTER HET
+ 0x00e8: 0x05d8, # HEBREW LETTER TET
+ 0x00e9: 0x05d9, # HEBREW LETTER YOD
+ 0x00ea: 0x05da, # HEBREW LETTER FINAL KAF
+ 0x00eb: 0x05db, # HEBREW LETTER KAF
+ 0x00ec: 0x05dc, # HEBREW LETTER LAMED
+ 0x00ed: 0x05dd, # HEBREW LETTER FINAL MEM
+ 0x00ee: 0x05de, # HEBREW LETTER MEM
+ 0x00ef: 0x05df, # HEBREW LETTER FINAL NUN
+ 0x00f0: 0x05e0, # HEBREW LETTER NUN
+ 0x00f1: 0x05e1, # HEBREW LETTER SAMEKH
+ 0x00f2: 0x05e2, # HEBREW LETTER AYIN
+ 0x00f3: 0x05e3, # HEBREW LETTER FINAL PE
+ 0x00f4: 0x05e4, # HEBREW LETTER PE
+ 0x00f5: 0x05e5, # HEBREW LETTER FINAL TSADI
+ 0x00f6: 0x05e6, # HEBREW LETTER TSADI
+ 0x00f7: 0x05e7, # HEBREW LETTER QOF
+ 0x00f8: 0x05e8, # HEBREW LETTER RESH
+ 0x00f9: 0x05e9, # HEBREW LETTER SHIN
+ 0x00fa: 0x05ea, # HEBREW LETTER TAV
+ 0x00fb: None,
+ 0x00fc: None,
+ 0x00fd: 0x200e, # LEFT-TO-RIGHT MARK
+ 0x00fe: 0x200f, # RIGHT-TO-LEFT MARK
+ 0x00ff: None,
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/iso8859_9.py b/lib/jython/Lib/encodings/iso8859_9.py new file mode 100644 index 000000000..fd902c489 --- /dev/null +++ b/lib/jython/Lib/encodings/iso8859_9.py @@ -0,0 +1,52 @@ +""" Python Character Mapping Codec generated from '8859-9.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x00d0: 0x011e, # LATIN CAPITAL LETTER G WITH BREVE
+ 0x00dd: 0x0130, # LATIN CAPITAL LETTER I WITH DOT ABOVE
+ 0x00de: 0x015e, # LATIN CAPITAL LETTER S WITH CEDILLA
+ 0x00f0: 0x011f, # LATIN SMALL LETTER G WITH BREVE
+ 0x00fd: 0x0131, # LATIN SMALL LETTER DOTLESS I
+ 0x00fe: 0x015f, # LATIN SMALL LETTER S WITH CEDILLA
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/koi8_r.py b/lib/jython/Lib/encodings/koi8_r.py new file mode 100644 index 000000000..92775b44d --- /dev/null +++ b/lib/jython/Lib/encodings/koi8_r.py @@ -0,0 +1,174 @@ +""" Python Character Mapping Codec generated from 'KOI8-R.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x2500, # BOX DRAWINGS LIGHT HORIZONTAL
+ 0x0081: 0x2502, # BOX DRAWINGS LIGHT VERTICAL
+ 0x0082: 0x250c, # BOX DRAWINGS LIGHT DOWN AND RIGHT
+ 0x0083: 0x2510, # BOX DRAWINGS LIGHT DOWN AND LEFT
+ 0x0084: 0x2514, # BOX DRAWINGS LIGHT UP AND RIGHT
+ 0x0085: 0x2518, # BOX DRAWINGS LIGHT UP AND LEFT
+ 0x0086: 0x251c, # BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+ 0x0087: 0x2524, # BOX DRAWINGS LIGHT VERTICAL AND LEFT
+ 0x0088: 0x252c, # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+ 0x0089: 0x2534, # BOX DRAWINGS LIGHT UP AND HORIZONTAL
+ 0x008a: 0x253c, # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+ 0x008b: 0x2580, # UPPER HALF BLOCK
+ 0x008c: 0x2584, # LOWER HALF BLOCK
+ 0x008d: 0x2588, # FULL BLOCK
+ 0x008e: 0x258c, # LEFT HALF BLOCK
+ 0x008f: 0x2590, # RIGHT HALF BLOCK
+ 0x0090: 0x2591, # LIGHT SHADE
+ 0x0091: 0x2592, # MEDIUM SHADE
+ 0x0092: 0x2593, # DARK SHADE
+ 0x0093: 0x2320, # TOP HALF INTEGRAL
+ 0x0094: 0x25a0, # BLACK SQUARE
+ 0x0095: 0x2219, # BULLET OPERATOR
+ 0x0096: 0x221a, # SQUARE ROOT
+ 0x0097: 0x2248, # ALMOST EQUAL TO
+ 0x0098: 0x2264, # LESS-THAN OR EQUAL TO
+ 0x0099: 0x2265, # GREATER-THAN OR EQUAL TO
+ 0x009a: 0x00a0, # NO-BREAK SPACE
+ 0x009b: 0x2321, # BOTTOM HALF INTEGRAL
+ 0x009c: 0x00b0, # DEGREE SIGN
+ 0x009d: 0x00b2, # SUPERSCRIPT TWO
+ 0x009e: 0x00b7, # MIDDLE DOT
+ 0x009f: 0x00f7, # DIVISION SIGN
+ 0x00a0: 0x2550, # BOX DRAWINGS DOUBLE HORIZONTAL
+ 0x00a1: 0x2551, # BOX DRAWINGS DOUBLE VERTICAL
+ 0x00a2: 0x2552, # BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
+ 0x00a3: 0x0451, # CYRILLIC SMALL LETTER IO
+ 0x00a4: 0x2553, # BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
+ 0x00a5: 0x2554, # BOX DRAWINGS DOUBLE DOWN AND RIGHT
+ 0x00a6: 0x2555, # BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
+ 0x00a7: 0x2556, # BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
+ 0x00a8: 0x2557, # BOX DRAWINGS DOUBLE DOWN AND LEFT
+ 0x00a9: 0x2558, # BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
+ 0x00aa: 0x2559, # BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
+ 0x00ab: 0x255a, # BOX DRAWINGS DOUBLE UP AND RIGHT
+ 0x00ac: 0x255b, # BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
+ 0x00ad: 0x255c, # BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
+ 0x00ae: 0x255d, # BOX DRAWINGS DOUBLE UP AND LEFT
+ 0x00af: 0x255e, # BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
+ 0x00b0: 0x255f, # BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
+ 0x00b1: 0x2560, # BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+ 0x00b2: 0x2561, # BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
+ 0x00b3: 0x0401, # CYRILLIC CAPITAL LETTER IO
+ 0x00b4: 0x2562, # BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
+ 0x00b5: 0x2563, # BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+ 0x00b6: 0x2564, # BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
+ 0x00b7: 0x2565, # BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
+ 0x00b8: 0x2566, # BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+ 0x00b9: 0x2567, # BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
+ 0x00ba: 0x2568, # BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
+ 0x00bb: 0x2569, # BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+ 0x00bc: 0x256a, # BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
+ 0x00bd: 0x256b, # BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
+ 0x00be: 0x256c, # BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+ 0x00bf: 0x00a9, # COPYRIGHT SIGN
+ 0x00c0: 0x044e, # CYRILLIC SMALL LETTER YU
+ 0x00c1: 0x0430, # CYRILLIC SMALL LETTER A
+ 0x00c2: 0x0431, # CYRILLIC SMALL LETTER BE
+ 0x00c3: 0x0446, # CYRILLIC SMALL LETTER TSE
+ 0x00c4: 0x0434, # CYRILLIC SMALL LETTER DE
+ 0x00c5: 0x0435, # CYRILLIC SMALL LETTER IE
+ 0x00c6: 0x0444, # CYRILLIC SMALL LETTER EF
+ 0x00c7: 0x0433, # CYRILLIC SMALL LETTER GHE
+ 0x00c8: 0x0445, # CYRILLIC SMALL LETTER HA
+ 0x00c9: 0x0438, # CYRILLIC SMALL LETTER I
+ 0x00ca: 0x0439, # CYRILLIC SMALL LETTER SHORT I
+ 0x00cb: 0x043a, # CYRILLIC SMALL LETTER KA
+ 0x00cc: 0x043b, # CYRILLIC SMALL LETTER EL
+ 0x00cd: 0x043c, # CYRILLIC SMALL LETTER EM
+ 0x00ce: 0x043d, # CYRILLIC SMALL LETTER EN
+ 0x00cf: 0x043e, # CYRILLIC SMALL LETTER O
+ 0x00d0: 0x043f, # CYRILLIC SMALL LETTER PE
+ 0x00d1: 0x044f, # CYRILLIC SMALL LETTER YA
+ 0x00d2: 0x0440, # CYRILLIC SMALL LETTER ER
+ 0x00d3: 0x0441, # CYRILLIC SMALL LETTER ES
+ 0x00d4: 0x0442, # CYRILLIC SMALL LETTER TE
+ 0x00d5: 0x0443, # CYRILLIC SMALL LETTER U
+ 0x00d6: 0x0436, # CYRILLIC SMALL LETTER ZHE
+ 0x00d7: 0x0432, # CYRILLIC SMALL LETTER VE
+ 0x00d8: 0x044c, # CYRILLIC SMALL LETTER SOFT SIGN
+ 0x00d9: 0x044b, # CYRILLIC SMALL LETTER YERU
+ 0x00da: 0x0437, # CYRILLIC SMALL LETTER ZE
+ 0x00db: 0x0448, # CYRILLIC SMALL LETTER SHA
+ 0x00dc: 0x044d, # CYRILLIC SMALL LETTER E
+ 0x00dd: 0x0449, # CYRILLIC SMALL LETTER SHCHA
+ 0x00de: 0x0447, # CYRILLIC SMALL LETTER CHE
+ 0x00df: 0x044a, # CYRILLIC SMALL LETTER HARD SIGN
+ 0x00e0: 0x042e, # CYRILLIC CAPITAL LETTER YU
+ 0x00e1: 0x0410, # CYRILLIC CAPITAL LETTER A
+ 0x00e2: 0x0411, # CYRILLIC CAPITAL LETTER BE
+ 0x00e3: 0x0426, # CYRILLIC CAPITAL LETTER TSE
+ 0x00e4: 0x0414, # CYRILLIC CAPITAL LETTER DE
+ 0x00e5: 0x0415, # CYRILLIC CAPITAL LETTER IE
+ 0x00e6: 0x0424, # CYRILLIC CAPITAL LETTER EF
+ 0x00e7: 0x0413, # CYRILLIC CAPITAL LETTER GHE
+ 0x00e8: 0x0425, # CYRILLIC CAPITAL LETTER HA
+ 0x00e9: 0x0418, # CYRILLIC CAPITAL LETTER I
+ 0x00ea: 0x0419, # CYRILLIC CAPITAL LETTER SHORT I
+ 0x00eb: 0x041a, # CYRILLIC CAPITAL LETTER KA
+ 0x00ec: 0x041b, # CYRILLIC CAPITAL LETTER EL
+ 0x00ed: 0x041c, # CYRILLIC CAPITAL LETTER EM
+ 0x00ee: 0x041d, # CYRILLIC CAPITAL LETTER EN
+ 0x00ef: 0x041e, # CYRILLIC CAPITAL LETTER O
+ 0x00f0: 0x041f, # CYRILLIC CAPITAL LETTER PE
+ 0x00f1: 0x042f, # CYRILLIC CAPITAL LETTER YA
+ 0x00f2: 0x0420, # CYRILLIC CAPITAL LETTER ER
+ 0x00f3: 0x0421, # CYRILLIC CAPITAL LETTER ES
+ 0x00f4: 0x0422, # CYRILLIC CAPITAL LETTER TE
+ 0x00f5: 0x0423, # CYRILLIC CAPITAL LETTER U
+ 0x00f6: 0x0416, # CYRILLIC CAPITAL LETTER ZHE
+ 0x00f7: 0x0412, # CYRILLIC CAPITAL LETTER VE
+ 0x00f8: 0x042c, # CYRILLIC CAPITAL LETTER SOFT SIGN
+ 0x00f9: 0x042b, # CYRILLIC CAPITAL LETTER YERU
+ 0x00fa: 0x0417, # CYRILLIC CAPITAL LETTER ZE
+ 0x00fb: 0x0428, # CYRILLIC CAPITAL LETTER SHA
+ 0x00fc: 0x042d, # CYRILLIC CAPITAL LETTER E
+ 0x00fd: 0x0429, # CYRILLIC CAPITAL LETTER SHCHA
+ 0x00fe: 0x0427, # CYRILLIC CAPITAL LETTER CHE
+ 0x00ff: 0x042a, # CYRILLIC CAPITAL LETTER HARD SIGN
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/latin_1.py b/lib/jython/Lib/encodings/latin_1.py new file mode 100644 index 000000000..bb08b52f3 --- /dev/null +++ b/lib/jython/Lib/encodings/latin_1.py @@ -0,0 +1,35 @@ +""" Python 'latin-1' Codec
+
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+
+"""
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ # Note: Binding these as C functions will result in the class not
+ # converting them to methods. This is intended.
+ encode = codecs.latin_1_encode
+ decode = codecs.latin_1_decode
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+class StreamConverter(StreamWriter,StreamReader):
+
+ encode = codecs.latin_1_decode
+ decode = codecs.latin_1_encode
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec.encode,Codec.decode,StreamReader,StreamWriter)
diff --git a/lib/jython/Lib/encodings/mac_cyrillic.py b/lib/jython/Lib/encodings/mac_cyrillic.py new file mode 100644 index 000000000..61624a15a --- /dev/null +++ b/lib/jython/Lib/encodings/mac_cyrillic.py @@ -0,0 +1,169 @@ +""" Python Character Mapping Codec generated from 'CYRILLIC.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x0410, # CYRILLIC CAPITAL LETTER A
+ 0x0081: 0x0411, # CYRILLIC CAPITAL LETTER BE
+ 0x0082: 0x0412, # CYRILLIC CAPITAL LETTER VE
+ 0x0083: 0x0413, # CYRILLIC CAPITAL LETTER GHE
+ 0x0084: 0x0414, # CYRILLIC CAPITAL LETTER DE
+ 0x0085: 0x0415, # CYRILLIC CAPITAL LETTER IE
+ 0x0086: 0x0416, # CYRILLIC CAPITAL LETTER ZHE
+ 0x0087: 0x0417, # CYRILLIC CAPITAL LETTER ZE
+ 0x0088: 0x0418, # CYRILLIC CAPITAL LETTER I
+ 0x0089: 0x0419, # CYRILLIC CAPITAL LETTER SHORT I
+ 0x008a: 0x041a, # CYRILLIC CAPITAL LETTER KA
+ 0x008b: 0x041b, # CYRILLIC CAPITAL LETTER EL
+ 0x008c: 0x041c, # CYRILLIC CAPITAL LETTER EM
+ 0x008d: 0x041d, # CYRILLIC CAPITAL LETTER EN
+ 0x008e: 0x041e, # CYRILLIC CAPITAL LETTER O
+ 0x008f: 0x041f, # CYRILLIC CAPITAL LETTER PE
+ 0x0090: 0x0420, # CYRILLIC CAPITAL LETTER ER
+ 0x0091: 0x0421, # CYRILLIC CAPITAL LETTER ES
+ 0x0092: 0x0422, # CYRILLIC CAPITAL LETTER TE
+ 0x0093: 0x0423, # CYRILLIC CAPITAL LETTER U
+ 0x0094: 0x0424, # CYRILLIC CAPITAL LETTER EF
+ 0x0095: 0x0425, # CYRILLIC CAPITAL LETTER HA
+ 0x0096: 0x0426, # CYRILLIC CAPITAL LETTER TSE
+ 0x0097: 0x0427, # CYRILLIC CAPITAL LETTER CHE
+ 0x0098: 0x0428, # CYRILLIC CAPITAL LETTER SHA
+ 0x0099: 0x0429, # CYRILLIC CAPITAL LETTER SHCHA
+ 0x009a: 0x042a, # CYRILLIC CAPITAL LETTER HARD SIGN
+ 0x009b: 0x042b, # CYRILLIC CAPITAL LETTER YERU
+ 0x009c: 0x042c, # CYRILLIC CAPITAL LETTER SOFT SIGN
+ 0x009d: 0x042d, # CYRILLIC CAPITAL LETTER E
+ 0x009e: 0x042e, # CYRILLIC CAPITAL LETTER YU
+ 0x009f: 0x042f, # CYRILLIC CAPITAL LETTER YA
+ 0x00a0: 0x2020, # DAGGER
+ 0x00a1: 0x00b0, # DEGREE SIGN
+ 0x00a4: 0x00a7, # SECTION SIGN
+ 0x00a5: 0x2022, # BULLET
+ 0x00a6: 0x00b6, # PILCROW SIGN
+ 0x00a7: 0x0406, # CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
+ 0x00a8: 0x00ae, # REGISTERED SIGN
+ 0x00aa: 0x2122, # TRADE MARK SIGN
+ 0x00ab: 0x0402, # CYRILLIC CAPITAL LETTER DJE
+ 0x00ac: 0x0452, # CYRILLIC SMALL LETTER DJE
+ 0x00ad: 0x2260, # NOT EQUAL TO
+ 0x00ae: 0x0403, # CYRILLIC CAPITAL LETTER GJE
+ 0x00af: 0x0453, # CYRILLIC SMALL LETTER GJE
+ 0x00b0: 0x221e, # INFINITY
+ 0x00b2: 0x2264, # LESS-THAN OR EQUAL TO
+ 0x00b3: 0x2265, # GREATER-THAN OR EQUAL TO
+ 0x00b4: 0x0456, # CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
+ 0x00b6: 0x2202, # PARTIAL DIFFERENTIAL
+ 0x00b7: 0x0408, # CYRILLIC CAPITAL LETTER JE
+ 0x00b8: 0x0404, # CYRILLIC CAPITAL LETTER UKRAINIAN IE
+ 0x00b9: 0x0454, # CYRILLIC SMALL LETTER UKRAINIAN IE
+ 0x00ba: 0x0407, # CYRILLIC CAPITAL LETTER YI
+ 0x00bb: 0x0457, # CYRILLIC SMALL LETTER YI
+ 0x00bc: 0x0409, # CYRILLIC CAPITAL LETTER LJE
+ 0x00bd: 0x0459, # CYRILLIC SMALL LETTER LJE
+ 0x00be: 0x040a, # CYRILLIC CAPITAL LETTER NJE
+ 0x00bf: 0x045a, # CYRILLIC SMALL LETTER NJE
+ 0x00c0: 0x0458, # CYRILLIC SMALL LETTER JE
+ 0x00c1: 0x0405, # CYRILLIC CAPITAL LETTER DZE
+ 0x00c2: 0x00ac, # NOT SIGN
+ 0x00c3: 0x221a, # SQUARE ROOT
+ 0x00c4: 0x0192, # LATIN SMALL LETTER F WITH HOOK
+ 0x00c5: 0x2248, # ALMOST EQUAL TO
+ 0x00c6: 0x2206, # INCREMENT
+ 0x00c7: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00c8: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00c9: 0x2026, # HORIZONTAL ELLIPSIS
+ 0x00ca: 0x00a0, # NO-BREAK SPACE
+ 0x00cb: 0x040b, # CYRILLIC CAPITAL LETTER TSHE
+ 0x00cc: 0x045b, # CYRILLIC SMALL LETTER TSHE
+ 0x00cd: 0x040c, # CYRILLIC CAPITAL LETTER KJE
+ 0x00ce: 0x045c, # CYRILLIC SMALL LETTER KJE
+ 0x00cf: 0x0455, # CYRILLIC SMALL LETTER DZE
+ 0x00d0: 0x2013, # EN DASH
+ 0x00d1: 0x2014, # EM DASH
+ 0x00d2: 0x201c, # LEFT DOUBLE QUOTATION MARK
+ 0x00d3: 0x201d, # RIGHT DOUBLE QUOTATION MARK
+ 0x00d4: 0x2018, # LEFT SINGLE QUOTATION MARK
+ 0x00d5: 0x2019, # RIGHT SINGLE QUOTATION MARK
+ 0x00d6: 0x00f7, # DIVISION SIGN
+ 0x00d7: 0x201e, # DOUBLE LOW-9 QUOTATION MARK
+ 0x00d8: 0x040e, # CYRILLIC CAPITAL LETTER SHORT U
+ 0x00d9: 0x045e, # CYRILLIC SMALL LETTER SHORT U
+ 0x00da: 0x040f, # CYRILLIC CAPITAL LETTER DZHE
+ 0x00db: 0x045f, # CYRILLIC SMALL LETTER DZHE
+ 0x00dc: 0x2116, # NUMERO SIGN
+ 0x00dd: 0x0401, # CYRILLIC CAPITAL LETTER IO
+ 0x00de: 0x0451, # CYRILLIC SMALL LETTER IO
+ 0x00df: 0x044f, # CYRILLIC SMALL LETTER YA
+ 0x00e0: 0x0430, # CYRILLIC SMALL LETTER A
+ 0x00e1: 0x0431, # CYRILLIC SMALL LETTER BE
+ 0x00e2: 0x0432, # CYRILLIC SMALL LETTER VE
+ 0x00e3: 0x0433, # CYRILLIC SMALL LETTER GHE
+ 0x00e4: 0x0434, # CYRILLIC SMALL LETTER DE
+ 0x00e5: 0x0435, # CYRILLIC SMALL LETTER IE
+ 0x00e6: 0x0436, # CYRILLIC SMALL LETTER ZHE
+ 0x00e7: 0x0437, # CYRILLIC SMALL LETTER ZE
+ 0x00e8: 0x0438, # CYRILLIC SMALL LETTER I
+ 0x00e9: 0x0439, # CYRILLIC SMALL LETTER SHORT I
+ 0x00ea: 0x043a, # CYRILLIC SMALL LETTER KA
+ 0x00eb: 0x043b, # CYRILLIC SMALL LETTER EL
+ 0x00ec: 0x043c, # CYRILLIC SMALL LETTER EM
+ 0x00ed: 0x043d, # CYRILLIC SMALL LETTER EN
+ 0x00ee: 0x043e, # CYRILLIC SMALL LETTER O
+ 0x00ef: 0x043f, # CYRILLIC SMALL LETTER PE
+ 0x00f0: 0x0440, # CYRILLIC SMALL LETTER ER
+ 0x00f1: 0x0441, # CYRILLIC SMALL LETTER ES
+ 0x00f2: 0x0442, # CYRILLIC SMALL LETTER TE
+ 0x00f3: 0x0443, # CYRILLIC SMALL LETTER U
+ 0x00f4: 0x0444, # CYRILLIC SMALL LETTER EF
+ 0x00f5: 0x0445, # CYRILLIC SMALL LETTER HA
+ 0x00f6: 0x0446, # CYRILLIC SMALL LETTER TSE
+ 0x00f7: 0x0447, # CYRILLIC SMALL LETTER CHE
+ 0x00f8: 0x0448, # CYRILLIC SMALL LETTER SHA
+ 0x00f9: 0x0449, # CYRILLIC SMALL LETTER SHCHA
+ 0x00fa: 0x044a, # CYRILLIC SMALL LETTER HARD SIGN
+ 0x00fb: 0x044b, # CYRILLIC SMALL LETTER YERU
+ 0x00fc: 0x044c, # CYRILLIC SMALL LETTER SOFT SIGN
+ 0x00fd: 0x044d, # CYRILLIC SMALL LETTER E
+ 0x00fe: 0x044e, # CYRILLIC SMALL LETTER YU
+ 0x00ff: 0x00a4, # CURRENCY SIGN
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/mac_greek.py b/lib/jython/Lib/encodings/mac_greek.py new file mode 100644 index 000000000..13f90ba4e --- /dev/null +++ b/lib/jython/Lib/encodings/mac_greek.py @@ -0,0 +1,172 @@ +""" Python Character Mapping Codec generated from 'GREEK.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x00c4, # LATIN CAPITAL LETTER A WITH DIAERESIS
+ 0x0081: 0x00b9, # SUPERSCRIPT ONE
+ 0x0082: 0x00b2, # SUPERSCRIPT TWO
+ 0x0083: 0x00c9, # LATIN CAPITAL LETTER E WITH ACUTE
+ 0x0084: 0x00b3, # SUPERSCRIPT THREE
+ 0x0085: 0x00d6, # LATIN CAPITAL LETTER O WITH DIAERESIS
+ 0x0086: 0x00dc, # LATIN CAPITAL LETTER U WITH DIAERESIS
+ 0x0087: 0x0385, # GREEK DIALYTIKA TONOS
+ 0x0088: 0x00e0, # LATIN SMALL LETTER A WITH GRAVE
+ 0x0089: 0x00e2, # LATIN SMALL LETTER A WITH CIRCUMFLEX
+ 0x008a: 0x00e4, # LATIN SMALL LETTER A WITH DIAERESIS
+ 0x008b: 0x0384, # GREEK TONOS
+ 0x008c: 0x00a8, # DIAERESIS
+ 0x008d: 0x00e7, # LATIN SMALL LETTER C WITH CEDILLA
+ 0x008e: 0x00e9, # LATIN SMALL LETTER E WITH ACUTE
+ 0x008f: 0x00e8, # LATIN SMALL LETTER E WITH GRAVE
+ 0x0090: 0x00ea, # LATIN SMALL LETTER E WITH CIRCUMFLEX
+ 0x0091: 0x00eb, # LATIN SMALL LETTER E WITH DIAERESIS
+ 0x0092: 0x00a3, # POUND SIGN
+ 0x0093: 0x2122, # TRADE MARK SIGN
+ 0x0094: 0x00ee, # LATIN SMALL LETTER I WITH CIRCUMFLEX
+ 0x0095: 0x00ef, # LATIN SMALL LETTER I WITH DIAERESIS
+ 0x0096: 0x2022, # BULLET
+ 0x0097: 0x00bd, # VULGAR FRACTION ONE HALF
+ 0x0098: 0x2030, # PER MILLE SIGN
+ 0x0099: 0x00f4, # LATIN SMALL LETTER O WITH CIRCUMFLEX
+ 0x009a: 0x00f6, # LATIN SMALL LETTER O WITH DIAERESIS
+ 0x009b: 0x00a6, # BROKEN BAR
+ 0x009c: 0x00ad, # SOFT HYPHEN
+ 0x009d: 0x00f9, # LATIN SMALL LETTER U WITH GRAVE
+ 0x009e: 0x00fb, # LATIN SMALL LETTER U WITH CIRCUMFLEX
+ 0x009f: 0x00fc, # LATIN SMALL LETTER U WITH DIAERESIS
+ 0x00a0: 0x2020, # DAGGER
+ 0x00a1: 0x0393, # GREEK CAPITAL LETTER GAMMA
+ 0x00a2: 0x0394, # GREEK CAPITAL LETTER DELTA
+ 0x00a3: 0x0398, # GREEK CAPITAL LETTER THETA
+ 0x00a4: 0x039b, # GREEK CAPITAL LETTER LAMBDA
+ 0x00a5: 0x039e, # GREEK CAPITAL LETTER XI
+ 0x00a6: 0x03a0, # GREEK CAPITAL LETTER PI
+ 0x00a7: 0x00df, # LATIN SMALL LETTER SHARP S
+ 0x00a8: 0x00ae, # REGISTERED SIGN
+ 0x00aa: 0x03a3, # GREEK CAPITAL LETTER SIGMA
+ 0x00ab: 0x03aa, # GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
+ 0x00ac: 0x00a7, # SECTION SIGN
+ 0x00ad: 0x2260, # NOT EQUAL TO
+ 0x00ae: 0x00b0, # DEGREE SIGN
+ 0x00af: 0x0387, # GREEK ANO TELEIA
+ 0x00b0: 0x0391, # GREEK CAPITAL LETTER ALPHA
+ 0x00b2: 0x2264, # LESS-THAN OR EQUAL TO
+ 0x00b3: 0x2265, # GREATER-THAN OR EQUAL TO
+ 0x00b4: 0x00a5, # YEN SIGN
+ 0x00b5: 0x0392, # GREEK CAPITAL LETTER BETA
+ 0x00b6: 0x0395, # GREEK CAPITAL LETTER EPSILON
+ 0x00b7: 0x0396, # GREEK CAPITAL LETTER ZETA
+ 0x00b8: 0x0397, # GREEK CAPITAL LETTER ETA
+ 0x00b9: 0x0399, # GREEK CAPITAL LETTER IOTA
+ 0x00ba: 0x039a, # GREEK CAPITAL LETTER KAPPA
+ 0x00bb: 0x039c, # GREEK CAPITAL LETTER MU
+ 0x00bc: 0x03a6, # GREEK CAPITAL LETTER PHI
+ 0x00bd: 0x03ab, # GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
+ 0x00be: 0x03a8, # GREEK CAPITAL LETTER PSI
+ 0x00bf: 0x03a9, # GREEK CAPITAL LETTER OMEGA
+ 0x00c0: 0x03ac, # GREEK SMALL LETTER ALPHA WITH TONOS
+ 0x00c1: 0x039d, # GREEK CAPITAL LETTER NU
+ 0x00c2: 0x00ac, # NOT SIGN
+ 0x00c3: 0x039f, # GREEK CAPITAL LETTER OMICRON
+ 0x00c4: 0x03a1, # GREEK CAPITAL LETTER RHO
+ 0x00c5: 0x2248, # ALMOST EQUAL TO
+ 0x00c6: 0x03a4, # GREEK CAPITAL LETTER TAU
+ 0x00c7: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00c8: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00c9: 0x2026, # HORIZONTAL ELLIPSIS
+ 0x00ca: 0x00a0, # NO-BREAK SPACE
+ 0x00cb: 0x03a5, # GREEK CAPITAL LETTER UPSILON
+ 0x00cc: 0x03a7, # GREEK CAPITAL LETTER CHI
+ 0x00cd: 0x0386, # GREEK CAPITAL LETTER ALPHA WITH TONOS
+ 0x00ce: 0x0388, # GREEK CAPITAL LETTER EPSILON WITH TONOS
+ 0x00cf: 0x0153, # LATIN SMALL LIGATURE OE
+ 0x00d0: 0x2013, # EN DASH
+ 0x00d1: 0x2015, # HORIZONTAL BAR
+ 0x00d2: 0x201c, # LEFT DOUBLE QUOTATION MARK
+ 0x00d3: 0x201d, # RIGHT DOUBLE QUOTATION MARK
+ 0x00d4: 0x2018, # LEFT SINGLE QUOTATION MARK
+ 0x00d5: 0x2019, # RIGHT SINGLE QUOTATION MARK
+ 0x00d6: 0x00f7, # DIVISION SIGN
+ 0x00d7: 0x0389, # GREEK CAPITAL LETTER ETA WITH TONOS
+ 0x00d8: 0x038a, # GREEK CAPITAL LETTER IOTA WITH TONOS
+ 0x00d9: 0x038c, # GREEK CAPITAL LETTER OMICRON WITH TONOS
+ 0x00da: 0x038e, # GREEK CAPITAL LETTER UPSILON WITH TONOS
+ 0x00db: 0x03ad, # GREEK SMALL LETTER EPSILON WITH TONOS
+ 0x00dc: 0x03ae, # GREEK SMALL LETTER ETA WITH TONOS
+ 0x00dd: 0x03af, # GREEK SMALL LETTER IOTA WITH TONOS
+ 0x00de: 0x03cc, # GREEK SMALL LETTER OMICRON WITH TONOS
+ 0x00df: 0x038f, # GREEK CAPITAL LETTER OMEGA WITH TONOS
+ 0x00e0: 0x03cd, # GREEK SMALL LETTER UPSILON WITH TONOS
+ 0x00e1: 0x03b1, # GREEK SMALL LETTER ALPHA
+ 0x00e2: 0x03b2, # GREEK SMALL LETTER BETA
+ 0x00e3: 0x03c8, # GREEK SMALL LETTER PSI
+ 0x00e4: 0x03b4, # GREEK SMALL LETTER DELTA
+ 0x00e5: 0x03b5, # GREEK SMALL LETTER EPSILON
+ 0x00e6: 0x03c6, # GREEK SMALL LETTER PHI
+ 0x00e7: 0x03b3, # GREEK SMALL LETTER GAMMA
+ 0x00e8: 0x03b7, # GREEK SMALL LETTER ETA
+ 0x00e9: 0x03b9, # GREEK SMALL LETTER IOTA
+ 0x00ea: 0x03be, # GREEK SMALL LETTER XI
+ 0x00eb: 0x03ba, # GREEK SMALL LETTER KAPPA
+ 0x00ec: 0x03bb, # GREEK SMALL LETTER LAMBDA
+ 0x00ed: 0x03bc, # GREEK SMALL LETTER MU
+ 0x00ee: 0x03bd, # GREEK SMALL LETTER NU
+ 0x00ef: 0x03bf, # GREEK SMALL LETTER OMICRON
+ 0x00f0: 0x03c0, # GREEK SMALL LETTER PI
+ 0x00f1: 0x03ce, # GREEK SMALL LETTER OMEGA WITH TONOS
+ 0x00f2: 0x03c1, # GREEK SMALL LETTER RHO
+ 0x00f3: 0x03c3, # GREEK SMALL LETTER SIGMA
+ 0x00f4: 0x03c4, # GREEK SMALL LETTER TAU
+ 0x00f5: 0x03b8, # GREEK SMALL LETTER THETA
+ 0x00f6: 0x03c9, # GREEK SMALL LETTER OMEGA
+ 0x00f7: 0x03c2, # GREEK SMALL LETTER FINAL SIGMA
+ 0x00f8: 0x03c7, # GREEK SMALL LETTER CHI
+ 0x00f9: 0x03c5, # GREEK SMALL LETTER UPSILON
+ 0x00fa: 0x03b6, # GREEK SMALL LETTER ZETA
+ 0x00fb: 0x03ca, # GREEK SMALL LETTER IOTA WITH DIALYTIKA
+ 0x00fc: 0x03cb, # GREEK SMALL LETTER UPSILON WITH DIALYTIKA
+ 0x00fd: 0x0390, # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
+ 0x00fe: 0x03b0, # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
+ 0x00ff: None, # UNDEFINED
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/mac_iceland.py b/lib/jython/Lib/encodings/mac_iceland.py new file mode 100644 index 000000000..d3d172037 --- /dev/null +++ b/lib/jython/Lib/encodings/mac_iceland.py @@ -0,0 +1,168 @@ +""" Python Character Mapping Codec generated from 'ICELAND.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x00c4, # LATIN CAPITAL LETTER A WITH DIAERESIS
+ 0x0081: 0x00c5, # LATIN CAPITAL LETTER A WITH RING ABOVE
+ 0x0082: 0x00c7, # LATIN CAPITAL LETTER C WITH CEDILLA
+ 0x0083: 0x00c9, # LATIN CAPITAL LETTER E WITH ACUTE
+ 0x0084: 0x00d1, # LATIN CAPITAL LETTER N WITH TILDE
+ 0x0085: 0x00d6, # LATIN CAPITAL LETTER O WITH DIAERESIS
+ 0x0086: 0x00dc, # LATIN CAPITAL LETTER U WITH DIAERESIS
+ 0x0087: 0x00e1, # LATIN SMALL LETTER A WITH ACUTE
+ 0x0088: 0x00e0, # LATIN SMALL LETTER A WITH GRAVE
+ 0x0089: 0x00e2, # LATIN SMALL LETTER A WITH CIRCUMFLEX
+ 0x008a: 0x00e4, # LATIN SMALL LETTER A WITH DIAERESIS
+ 0x008b: 0x00e3, # LATIN SMALL LETTER A WITH TILDE
+ 0x008c: 0x00e5, # LATIN SMALL LETTER A WITH RING ABOVE
+ 0x008d: 0x00e7, # LATIN SMALL LETTER C WITH CEDILLA
+ 0x008e: 0x00e9, # LATIN SMALL LETTER E WITH ACUTE
+ 0x008f: 0x00e8, # LATIN SMALL LETTER E WITH GRAVE
+ 0x0090: 0x00ea, # LATIN SMALL LETTER E WITH CIRCUMFLEX
+ 0x0091: 0x00eb, # LATIN SMALL LETTER E WITH DIAERESIS
+ 0x0092: 0x00ed, # LATIN SMALL LETTER I WITH ACUTE
+ 0x0093: 0x00ec, # LATIN SMALL LETTER I WITH GRAVE
+ 0x0094: 0x00ee, # LATIN SMALL LETTER I WITH CIRCUMFLEX
+ 0x0095: 0x00ef, # LATIN SMALL LETTER I WITH DIAERESIS
+ 0x0096: 0x00f1, # LATIN SMALL LETTER N WITH TILDE
+ 0x0097: 0x00f3, # LATIN SMALL LETTER O WITH ACUTE
+ 0x0098: 0x00f2, # LATIN SMALL LETTER O WITH GRAVE
+ 0x0099: 0x00f4, # LATIN SMALL LETTER O WITH CIRCUMFLEX
+ 0x009a: 0x00f6, # LATIN SMALL LETTER O WITH DIAERESIS
+ 0x009b: 0x00f5, # LATIN SMALL LETTER O WITH TILDE
+ 0x009c: 0x00fa, # LATIN SMALL LETTER U WITH ACUTE
+ 0x009d: 0x00f9, # LATIN SMALL LETTER U WITH GRAVE
+ 0x009e: 0x00fb, # LATIN SMALL LETTER U WITH CIRCUMFLEX
+ 0x009f: 0x00fc, # LATIN SMALL LETTER U WITH DIAERESIS
+ 0x00a0: 0x00dd, # LATIN CAPITAL LETTER Y WITH ACUTE
+ 0x00a1: 0x00b0, # DEGREE SIGN
+ 0x00a4: 0x00a7, # SECTION SIGN
+ 0x00a5: 0x2022, # BULLET
+ 0x00a6: 0x00b6, # PILCROW SIGN
+ 0x00a7: 0x00df, # LATIN SMALL LETTER SHARP S
+ 0x00a8: 0x00ae, # REGISTERED SIGN
+ 0x00aa: 0x2122, # TRADE MARK SIGN
+ 0x00ab: 0x00b4, # ACUTE ACCENT
+ 0x00ac: 0x00a8, # DIAERESIS
+ 0x00ad: 0x2260, # NOT EQUAL TO
+ 0x00ae: 0x00c6, # LATIN CAPITAL LIGATURE AE
+ 0x00af: 0x00d8, # LATIN CAPITAL LETTER O WITH STROKE
+ 0x00b0: 0x221e, # INFINITY
+ 0x00b2: 0x2264, # LESS-THAN OR EQUAL TO
+ 0x00b3: 0x2265, # GREATER-THAN OR EQUAL TO
+ 0x00b4: 0x00a5, # YEN SIGN
+ 0x00b6: 0x2202, # PARTIAL DIFFERENTIAL
+ 0x00b7: 0x2211, # N-ARY SUMMATION
+ 0x00b8: 0x220f, # N-ARY PRODUCT
+ 0x00b9: 0x03c0, # GREEK SMALL LETTER PI
+ 0x00ba: 0x222b, # INTEGRAL
+ 0x00bb: 0x00aa, # FEMININE ORDINAL INDICATOR
+ 0x00bc: 0x00ba, # MASCULINE ORDINAL INDICATOR
+ 0x00bd: 0x2126, # OHM SIGN
+ 0x00be: 0x00e6, # LATIN SMALL LIGATURE AE
+ 0x00bf: 0x00f8, # LATIN SMALL LETTER O WITH STROKE
+ 0x00c0: 0x00bf, # INVERTED QUESTION MARK
+ 0x00c1: 0x00a1, # INVERTED EXCLAMATION MARK
+ 0x00c2: 0x00ac, # NOT SIGN
+ 0x00c3: 0x221a, # SQUARE ROOT
+ 0x00c4: 0x0192, # LATIN SMALL LETTER F WITH HOOK
+ 0x00c5: 0x2248, # ALMOST EQUAL TO
+ 0x00c6: 0x2206, # INCREMENT
+ 0x00c7: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00c8: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00c9: 0x2026, # HORIZONTAL ELLIPSIS
+ 0x00ca: 0x00a0, # NO-BREAK SPACE
+ 0x00cb: 0x00c0, # LATIN CAPITAL LETTER A WITH GRAVE
+ 0x00cc: 0x00c3, # LATIN CAPITAL LETTER A WITH TILDE
+ 0x00cd: 0x00d5, # LATIN CAPITAL LETTER O WITH TILDE
+ 0x00ce: 0x0152, # LATIN CAPITAL LIGATURE OE
+ 0x00cf: 0x0153, # LATIN SMALL LIGATURE OE
+ 0x00d0: 0x2013, # EN DASH
+ 0x00d1: 0x2014, # EM DASH
+ 0x00d2: 0x201c, # LEFT DOUBLE QUOTATION MARK
+ 0x00d3: 0x201d, # RIGHT DOUBLE QUOTATION MARK
+ 0x00d4: 0x2018, # LEFT SINGLE QUOTATION MARK
+ 0x00d5: 0x2019, # RIGHT SINGLE QUOTATION MARK
+ 0x00d6: 0x00f7, # DIVISION SIGN
+ 0x00d7: 0x25ca, # LOZENGE
+ 0x00d8: 0x00ff, # LATIN SMALL LETTER Y WITH DIAERESIS
+ 0x00d9: 0x0178, # LATIN CAPITAL LETTER Y WITH DIAERESIS
+ 0x00da: 0x2044, # FRACTION SLASH
+ 0x00db: 0x00a4, # CURRENCY SIGN
+ 0x00dc: 0x00d0, # LATIN CAPITAL LETTER ETH
+ 0x00dd: 0x00f0, # LATIN SMALL LETTER ETH
+ 0x00df: 0x00fe, # LATIN SMALL LETTER THORN
+ 0x00e0: 0x00fd, # LATIN SMALL LETTER Y WITH ACUTE
+ 0x00e1: 0x00b7, # MIDDLE DOT
+ 0x00e2: 0x201a, # SINGLE LOW-9 QUOTATION MARK
+ 0x00e3: 0x201e, # DOUBLE LOW-9 QUOTATION MARK
+ 0x00e4: 0x2030, # PER MILLE SIGN
+ 0x00e5: 0x00c2, # LATIN CAPITAL LETTER A WITH CIRCUMFLEX
+ 0x00e6: 0x00ca, # LATIN CAPITAL LETTER E WITH CIRCUMFLEX
+ 0x00e7: 0x00c1, # LATIN CAPITAL LETTER A WITH ACUTE
+ 0x00e8: 0x00cb, # LATIN CAPITAL LETTER E WITH DIAERESIS
+ 0x00e9: 0x00c8, # LATIN CAPITAL LETTER E WITH GRAVE
+ 0x00ea: 0x00cd, # LATIN CAPITAL LETTER I WITH ACUTE
+ 0x00eb: 0x00ce, # LATIN CAPITAL LETTER I WITH CIRCUMFLEX
+ 0x00ec: 0x00cf, # LATIN CAPITAL LETTER I WITH DIAERESIS
+ 0x00ed: 0x00cc, # LATIN CAPITAL LETTER I WITH GRAVE
+ 0x00ee: 0x00d3, # LATIN CAPITAL LETTER O WITH ACUTE
+ 0x00ef: 0x00d4, # LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+ 0x00f0: None, # UNDEFINED
+ 0x00f1: 0x00d2, # LATIN CAPITAL LETTER O WITH GRAVE
+ 0x00f2: 0x00da, # LATIN CAPITAL LETTER U WITH ACUTE
+ 0x00f3: 0x00db, # LATIN CAPITAL LETTER U WITH CIRCUMFLEX
+ 0x00f4: 0x00d9, # LATIN CAPITAL LETTER U WITH GRAVE
+ 0x00f5: 0x0131, # LATIN SMALL LETTER DOTLESS I
+ 0x00f6: 0x02c6, # MODIFIER LETTER CIRCUMFLEX ACCENT
+ 0x00f7: 0x02dc, # SMALL TILDE
+ 0x00f8: 0x00af, # MACRON
+ 0x00f9: 0x02d8, # BREVE
+ 0x00fa: 0x02d9, # DOT ABOVE
+ 0x00fb: 0x02da, # RING ABOVE
+ 0x00fc: 0x00b8, # CEDILLA
+ 0x00fd: 0x02dd, # DOUBLE ACUTE ACCENT
+ 0x00fe: 0x02db, # OGONEK
+ 0x00ff: 0x02c7, # CARON
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/mac_latin2.py b/lib/jython/Lib/encodings/mac_latin2.py new file mode 100644 index 000000000..9366cfbe5 --- /dev/null +++ b/lib/jython/Lib/encodings/mac_latin2.py @@ -0,0 +1,172 @@ +""" Python Character Mapping Codec generated from 'LATIN2.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x00c4, # LATIN CAPITAL LETTER A WITH DIAERESIS
+ 0x0081: 0x0100, # LATIN CAPITAL LETTER A WITH MACRON
+ 0x0082: 0x0101, # LATIN SMALL LETTER A WITH MACRON
+ 0x0083: 0x00c9, # LATIN CAPITAL LETTER E WITH ACUTE
+ 0x0084: 0x0104, # LATIN CAPITAL LETTER A WITH OGONEK
+ 0x0085: 0x00d6, # LATIN CAPITAL LETTER O WITH DIAERESIS
+ 0x0086: 0x00dc, # LATIN CAPITAL LETTER U WITH DIAERESIS
+ 0x0087: 0x00e1, # LATIN SMALL LETTER A WITH ACUTE
+ 0x0088: 0x0105, # LATIN SMALL LETTER A WITH OGONEK
+ 0x0089: 0x010c, # LATIN CAPITAL LETTER C WITH CARON
+ 0x008a: 0x00e4, # LATIN SMALL LETTER A WITH DIAERESIS
+ 0x008b: 0x010d, # LATIN SMALL LETTER C WITH CARON
+ 0x008c: 0x0106, # LATIN CAPITAL LETTER C WITH ACUTE
+ 0x008d: 0x0107, # LATIN SMALL LETTER C WITH ACUTE
+ 0x008e: 0x00e9, # LATIN SMALL LETTER E WITH ACUTE
+ 0x008f: 0x0179, # LATIN CAPITAL LETTER Z WITH ACUTE
+ 0x0090: 0x017a, # LATIN SMALL LETTER Z WITH ACUTE
+ 0x0091: 0x010e, # LATIN CAPITAL LETTER D WITH CARON
+ 0x0092: 0x00ed, # LATIN SMALL LETTER I WITH ACUTE
+ 0x0093: 0x010f, # LATIN SMALL LETTER D WITH CARON
+ 0x0094: 0x0112, # LATIN CAPITAL LETTER E WITH MACRON
+ 0x0095: 0x0113, # LATIN SMALL LETTER E WITH MACRON
+ 0x0096: 0x0116, # LATIN CAPITAL LETTER E WITH DOT ABOVE
+ 0x0097: 0x00f3, # LATIN SMALL LETTER O WITH ACUTE
+ 0x0098: 0x0117, # LATIN SMALL LETTER E WITH DOT ABOVE
+ 0x0099: 0x00f4, # LATIN SMALL LETTER O WITH CIRCUMFLEX
+ 0x009a: 0x00f6, # LATIN SMALL LETTER O WITH DIAERESIS
+ 0x009b: 0x00f5, # LATIN SMALL LETTER O WITH TILDE
+ 0x009c: 0x00fa, # LATIN SMALL LETTER U WITH ACUTE
+ 0x009d: 0x011a, # LATIN CAPITAL LETTER E WITH CARON
+ 0x009e: 0x011b, # LATIN SMALL LETTER E WITH CARON
+ 0x009f: 0x00fc, # LATIN SMALL LETTER U WITH DIAERESIS
+ 0x00a0: 0x2020, # DAGGER
+ 0x00a1: 0x00b0, # DEGREE SIGN
+ 0x00a2: 0x0118, # LATIN CAPITAL LETTER E WITH OGONEK
+ 0x00a4: 0x00a7, # SECTION SIGN
+ 0x00a5: 0x2022, # BULLET
+ 0x00a6: 0x00b6, # PILCROW SIGN
+ 0x00a7: 0x00df, # LATIN SMALL LETTER SHARP S
+ 0x00a8: 0x00ae, # REGISTERED SIGN
+ 0x00aa: 0x2122, # TRADE MARK SIGN
+ 0x00ab: 0x0119, # LATIN SMALL LETTER E WITH OGONEK
+ 0x00ac: 0x00a8, # DIAERESIS
+ 0x00ad: 0x2260, # NOT EQUAL TO
+ 0x00ae: 0x0123, # LATIN SMALL LETTER G WITH CEDILLA
+ 0x00af: 0x012e, # LATIN CAPITAL LETTER I WITH OGONEK
+ 0x00b0: 0x012f, # LATIN SMALL LETTER I WITH OGONEK
+ 0x00b1: 0x012a, # LATIN CAPITAL LETTER I WITH MACRON
+ 0x00b2: 0x2264, # LESS-THAN OR EQUAL TO
+ 0x00b3: 0x2265, # GREATER-THAN OR EQUAL TO
+ 0x00b4: 0x012b, # LATIN SMALL LETTER I WITH MACRON
+ 0x00b5: 0x0136, # LATIN CAPITAL LETTER K WITH CEDILLA
+ 0x00b6: 0x2202, # PARTIAL DIFFERENTIAL
+ 0x00b7: 0x2211, # N-ARY SUMMATION
+ 0x00b8: 0x0142, # LATIN SMALL LETTER L WITH STROKE
+ 0x00b9: 0x013b, # LATIN CAPITAL LETTER L WITH CEDILLA
+ 0x00ba: 0x013c, # LATIN SMALL LETTER L WITH CEDILLA
+ 0x00bb: 0x013d, # LATIN CAPITAL LETTER L WITH CARON
+ 0x00bc: 0x013e, # LATIN SMALL LETTER L WITH CARON
+ 0x00bd: 0x0139, # LATIN CAPITAL LETTER L WITH ACUTE
+ 0x00be: 0x013a, # LATIN SMALL LETTER L WITH ACUTE
+ 0x00bf: 0x0145, # LATIN CAPITAL LETTER N WITH CEDILLA
+ 0x00c0: 0x0146, # LATIN SMALL LETTER N WITH CEDILLA
+ 0x00c1: 0x0143, # LATIN CAPITAL LETTER N WITH ACUTE
+ 0x00c2: 0x00ac, # NOT SIGN
+ 0x00c3: 0x221a, # SQUARE ROOT
+ 0x00c4: 0x0144, # LATIN SMALL LETTER N WITH ACUTE
+ 0x00c5: 0x0147, # LATIN CAPITAL LETTER N WITH CARON
+ 0x00c6: 0x2206, # INCREMENT
+ 0x00c7: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00c8: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00c9: 0x2026, # HORIZONTAL ELLIPSIS
+ 0x00ca: 0x00a0, # NO-BREAK SPACE
+ 0x00cb: 0x0148, # LATIN SMALL LETTER N WITH CARON
+ 0x00cc: 0x0150, # LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
+ 0x00cd: 0x00d5, # LATIN CAPITAL LETTER O WITH TILDE
+ 0x00ce: 0x0151, # LATIN SMALL LETTER O WITH DOUBLE ACUTE
+ 0x00cf: 0x014c, # LATIN CAPITAL LETTER O WITH MACRON
+ 0x00d0: 0x2013, # EN DASH
+ 0x00d1: 0x2014, # EM DASH
+ 0x00d2: 0x201c, # LEFT DOUBLE QUOTATION MARK
+ 0x00d3: 0x201d, # RIGHT DOUBLE QUOTATION MARK
+ 0x00d4: 0x2018, # LEFT SINGLE QUOTATION MARK
+ 0x00d5: 0x2019, # RIGHT SINGLE QUOTATION MARK
+ 0x00d6: 0x00f7, # DIVISION SIGN
+ 0x00d7: 0x25ca, # LOZENGE
+ 0x00d8: 0x014d, # LATIN SMALL LETTER O WITH MACRON
+ 0x00d9: 0x0154, # LATIN CAPITAL LETTER R WITH ACUTE
+ 0x00da: 0x0155, # LATIN SMALL LETTER R WITH ACUTE
+ 0x00db: 0x0158, # LATIN CAPITAL LETTER R WITH CARON
+ 0x00dc: 0x2039, # SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ 0x00dd: 0x203a, # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ 0x00de: 0x0159, # LATIN SMALL LETTER R WITH CARON
+ 0x00df: 0x0156, # LATIN CAPITAL LETTER R WITH CEDILLA
+ 0x00e0: 0x0157, # LATIN SMALL LETTER R WITH CEDILLA
+ 0x00e1: 0x0160, # LATIN CAPITAL LETTER S WITH CARON
+ 0x00e2: 0x201a, # SINGLE LOW-9 QUOTATION MARK
+ 0x00e3: 0x201e, # DOUBLE LOW-9 QUOTATION MARK
+ 0x00e4: 0x0161, # LATIN SMALL LETTER S WITH CARON
+ 0x00e5: 0x015a, # LATIN CAPITAL LETTER S WITH ACUTE
+ 0x00e6: 0x015b, # LATIN SMALL LETTER S WITH ACUTE
+ 0x00e7: 0x00c1, # LATIN CAPITAL LETTER A WITH ACUTE
+ 0x00e8: 0x0164, # LATIN CAPITAL LETTER T WITH CARON
+ 0x00e9: 0x0165, # LATIN SMALL LETTER T WITH CARON
+ 0x00ea: 0x00cd, # LATIN CAPITAL LETTER I WITH ACUTE
+ 0x00eb: 0x017d, # LATIN CAPITAL LETTER Z WITH CARON
+ 0x00ec: 0x017e, # LATIN SMALL LETTER Z WITH CARON
+ 0x00ed: 0x016a, # LATIN CAPITAL LETTER U WITH MACRON
+ 0x00ee: 0x00d3, # LATIN CAPITAL LETTER O WITH ACUTE
+ 0x00ef: 0x00d4, # LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+ 0x00f0: 0x016b, # LATIN SMALL LETTER U WITH MACRON
+ 0x00f1: 0x016e, # LATIN CAPITAL LETTER U WITH RING ABOVE
+ 0x00f2: 0x00da, # LATIN CAPITAL LETTER U WITH ACUTE
+ 0x00f3: 0x016f, # LATIN SMALL LETTER U WITH RING ABOVE
+ 0x00f4: 0x0170, # LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
+ 0x00f5: 0x0171, # LATIN SMALL LETTER U WITH DOUBLE ACUTE
+ 0x00f6: 0x0172, # LATIN CAPITAL LETTER U WITH OGONEK
+ 0x00f7: 0x0173, # LATIN SMALL LETTER U WITH OGONEK
+ 0x00f8: 0x00dd, # LATIN CAPITAL LETTER Y WITH ACUTE
+ 0x00f9: 0x00fd, # LATIN SMALL LETTER Y WITH ACUTE
+ 0x00fa: 0x0137, # LATIN SMALL LETTER K WITH CEDILLA
+ 0x00fb: 0x017b, # LATIN CAPITAL LETTER Z WITH DOT ABOVE
+ 0x00fc: 0x0141, # LATIN CAPITAL LETTER L WITH STROKE
+ 0x00fd: 0x017c, # LATIN SMALL LETTER Z WITH DOT ABOVE
+ 0x00fe: 0x0122, # LATIN CAPITAL LETTER G WITH CEDILLA
+ 0x00ff: 0x02c7, # CARON
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/mac_roman.py b/lib/jython/Lib/encodings/mac_roman.py new file mode 100644 index 000000000..6d2244f82 --- /dev/null +++ b/lib/jython/Lib/encodings/mac_roman.py @@ -0,0 +1,169 @@ +""" Python Character Mapping Codec generated from 'ROMAN.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x00c4, # LATIN CAPITAL LETTER A WITH DIAERESIS
+ 0x0081: 0x00c5, # LATIN CAPITAL LETTER A WITH RING ABOVE
+ 0x0082: 0x00c7, # LATIN CAPITAL LETTER C WITH CEDILLA
+ 0x0083: 0x00c9, # LATIN CAPITAL LETTER E WITH ACUTE
+ 0x0084: 0x00d1, # LATIN CAPITAL LETTER N WITH TILDE
+ 0x0085: 0x00d6, # LATIN CAPITAL LETTER O WITH DIAERESIS
+ 0x0086: 0x00dc, # LATIN CAPITAL LETTER U WITH DIAERESIS
+ 0x0087: 0x00e1, # LATIN SMALL LETTER A WITH ACUTE
+ 0x0088: 0x00e0, # LATIN SMALL LETTER A WITH GRAVE
+ 0x0089: 0x00e2, # LATIN SMALL LETTER A WITH CIRCUMFLEX
+ 0x008a: 0x00e4, # LATIN SMALL LETTER A WITH DIAERESIS
+ 0x008b: 0x00e3, # LATIN SMALL LETTER A WITH TILDE
+ 0x008c: 0x00e5, # LATIN SMALL LETTER A WITH RING ABOVE
+ 0x008d: 0x00e7, # LATIN SMALL LETTER C WITH CEDILLA
+ 0x008e: 0x00e9, # LATIN SMALL LETTER E WITH ACUTE
+ 0x008f: 0x00e8, # LATIN SMALL LETTER E WITH GRAVE
+ 0x0090: 0x00ea, # LATIN SMALL LETTER E WITH CIRCUMFLEX
+ 0x0091: 0x00eb, # LATIN SMALL LETTER E WITH DIAERESIS
+ 0x0092: 0x00ed, # LATIN SMALL LETTER I WITH ACUTE
+ 0x0093: 0x00ec, # LATIN SMALL LETTER I WITH GRAVE
+ 0x0094: 0x00ee, # LATIN SMALL LETTER I WITH CIRCUMFLEX
+ 0x0095: 0x00ef, # LATIN SMALL LETTER I WITH DIAERESIS
+ 0x0096: 0x00f1, # LATIN SMALL LETTER N WITH TILDE
+ 0x0097: 0x00f3, # LATIN SMALL LETTER O WITH ACUTE
+ 0x0098: 0x00f2, # LATIN SMALL LETTER O WITH GRAVE
+ 0x0099: 0x00f4, # LATIN SMALL LETTER O WITH CIRCUMFLEX
+ 0x009a: 0x00f6, # LATIN SMALL LETTER O WITH DIAERESIS
+ 0x009b: 0x00f5, # LATIN SMALL LETTER O WITH TILDE
+ 0x009c: 0x00fa, # LATIN SMALL LETTER U WITH ACUTE
+ 0x009d: 0x00f9, # LATIN SMALL LETTER U WITH GRAVE
+ 0x009e: 0x00fb, # LATIN SMALL LETTER U WITH CIRCUMFLEX
+ 0x009f: 0x00fc, # LATIN SMALL LETTER U WITH DIAERESIS
+ 0x00a0: 0x2020, # DAGGER
+ 0x00a1: 0x00b0, # DEGREE SIGN
+ 0x00a4: 0x00a7, # SECTION SIGN
+ 0x00a5: 0x2022, # BULLET
+ 0x00a6: 0x00b6, # PILCROW SIGN
+ 0x00a7: 0x00df, # LATIN SMALL LETTER SHARP S
+ 0x00a8: 0x00ae, # REGISTERED SIGN
+ 0x00aa: 0x2122, # TRADE MARK SIGN
+ 0x00ab: 0x00b4, # ACUTE ACCENT
+ 0x00ac: 0x00a8, # DIAERESIS
+ 0x00ad: 0x2260, # NOT EQUAL TO
+ 0x00ae: 0x00c6, # LATIN CAPITAL LIGATURE AE
+ 0x00af: 0x00d8, # LATIN CAPITAL LETTER O WITH STROKE
+ 0x00b0: 0x221e, # INFINITY
+ 0x00b2: 0x2264, # LESS-THAN OR EQUAL TO
+ 0x00b3: 0x2265, # GREATER-THAN OR EQUAL TO
+ 0x00b4: 0x00a5, # YEN SIGN
+ 0x00b6: 0x2202, # PARTIAL DIFFERENTIAL
+ 0x00b7: 0x2211, # N-ARY SUMMATION
+ 0x00b8: 0x220f, # N-ARY PRODUCT
+ 0x00b9: 0x03c0, # GREEK SMALL LETTER PI
+ 0x00ba: 0x222b, # INTEGRAL
+ 0x00bb: 0x00aa, # FEMININE ORDINAL INDICATOR
+ 0x00bc: 0x00ba, # MASCULINE ORDINAL INDICATOR
+ 0x00bd: 0x2126, # OHM SIGN
+ 0x00be: 0x00e6, # LATIN SMALL LIGATURE AE
+ 0x00bf: 0x00f8, # LATIN SMALL LETTER O WITH STROKE
+ 0x00c0: 0x00bf, # INVERTED QUESTION MARK
+ 0x00c1: 0x00a1, # INVERTED EXCLAMATION MARK
+ 0x00c2: 0x00ac, # NOT SIGN
+ 0x00c3: 0x221a, # SQUARE ROOT
+ 0x00c4: 0x0192, # LATIN SMALL LETTER F WITH HOOK
+ 0x00c5: 0x2248, # ALMOST EQUAL TO
+ 0x00c6: 0x2206, # INCREMENT
+ 0x00c7: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00c8: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00c9: 0x2026, # HORIZONTAL ELLIPSIS
+ 0x00ca: 0x00a0, # NO-BREAK SPACE
+ 0x00cb: 0x00c0, # LATIN CAPITAL LETTER A WITH GRAVE
+ 0x00cc: 0x00c3, # LATIN CAPITAL LETTER A WITH TILDE
+ 0x00cd: 0x00d5, # LATIN CAPITAL LETTER O WITH TILDE
+ 0x00ce: 0x0152, # LATIN CAPITAL LIGATURE OE
+ 0x00cf: 0x0153, # LATIN SMALL LIGATURE OE
+ 0x00d0: 0x2013, # EN DASH
+ 0x00d1: 0x2014, # EM DASH
+ 0x00d2: 0x201c, # LEFT DOUBLE QUOTATION MARK
+ 0x00d3: 0x201d, # RIGHT DOUBLE QUOTATION MARK
+ 0x00d4: 0x2018, # LEFT SINGLE QUOTATION MARK
+ 0x00d5: 0x2019, # RIGHT SINGLE QUOTATION MARK
+ 0x00d6: 0x00f7, # DIVISION SIGN
+ 0x00d7: 0x25ca, # LOZENGE
+ 0x00d8: 0x00ff, # LATIN SMALL LETTER Y WITH DIAERESIS
+ 0x00d9: 0x0178, # LATIN CAPITAL LETTER Y WITH DIAERESIS
+ 0x00da: 0x2044, # FRACTION SLASH
+ 0x00db: 0x00a4, # CURRENCY SIGN
+ 0x00dc: 0x2039, # SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ 0x00dd: 0x203a, # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ 0x00de: 0xfb01, # LATIN SMALL LIGATURE FI
+ 0x00df: 0xfb02, # LATIN SMALL LIGATURE FL
+ 0x00e0: 0x2021, # DOUBLE DAGGER
+ 0x00e1: 0x00b7, # MIDDLE DOT
+ 0x00e2: 0x201a, # SINGLE LOW-9 QUOTATION MARK
+ 0x00e3: 0x201e, # DOUBLE LOW-9 QUOTATION MARK
+ 0x00e4: 0x2030, # PER MILLE SIGN
+ 0x00e5: 0x00c2, # LATIN CAPITAL LETTER A WITH CIRCUMFLEX
+ 0x00e6: 0x00ca, # LATIN CAPITAL LETTER E WITH CIRCUMFLEX
+ 0x00e7: 0x00c1, # LATIN CAPITAL LETTER A WITH ACUTE
+ 0x00e8: 0x00cb, # LATIN CAPITAL LETTER E WITH DIAERESIS
+ 0x00e9: 0x00c8, # LATIN CAPITAL LETTER E WITH GRAVE
+ 0x00ea: 0x00cd, # LATIN CAPITAL LETTER I WITH ACUTE
+ 0x00eb: 0x00ce, # LATIN CAPITAL LETTER I WITH CIRCUMFLEX
+ 0x00ec: 0x00cf, # LATIN CAPITAL LETTER I WITH DIAERESIS
+ 0x00ed: 0x00cc, # LATIN CAPITAL LETTER I WITH GRAVE
+ 0x00ee: 0x00d3, # LATIN CAPITAL LETTER O WITH ACUTE
+ 0x00ef: 0x00d4, # LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+ 0x00f0: None, # UNDEFINED
+ 0x00f1: 0x00d2, # LATIN CAPITAL LETTER O WITH GRAVE
+ 0x00f2: 0x00da, # LATIN CAPITAL LETTER U WITH ACUTE
+ 0x00f3: 0x00db, # LATIN CAPITAL LETTER U WITH CIRCUMFLEX
+ 0x00f4: 0x00d9, # LATIN CAPITAL LETTER U WITH GRAVE
+ 0x00f5: 0x0131, # LATIN SMALL LETTER DOTLESS I
+ 0x00f6: 0x02c6, # MODIFIER LETTER CIRCUMFLEX ACCENT
+ 0x00f7: 0x02dc, # SMALL TILDE
+ 0x00f8: 0x00af, # MACRON
+ 0x00f9: 0x02d8, # BREVE
+ 0x00fa: 0x02d9, # DOT ABOVE
+ 0x00fb: 0x02da, # RING ABOVE
+ 0x00fc: 0x00b8, # CEDILLA
+ 0x00fd: 0x02dd, # DOUBLE ACUTE ACCENT
+ 0x00fe: 0x02db, # OGONEK
+ 0x00ff: 0x02c7, # CARON
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/mac_turkish.py b/lib/jython/Lib/encodings/mac_turkish.py new file mode 100644 index 000000000..84a3f23c1 --- /dev/null +++ b/lib/jython/Lib/encodings/mac_turkish.py @@ -0,0 +1,169 @@ +""" Python Character Mapping Codec generated from 'TURKISH.TXT' with gencodec.py.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+(c) Copyright 2000 Guido van Rossum.
+
+"""#"
+
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+
+ return codecs.charmap_encode(input,errors,encoding_map)
+
+ def decode(self,input,errors='strict'):
+
+ return codecs.charmap_decode(input,errors,decoding_map)
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
+
+### Decoding Map
+
+decoding_map = codecs.make_identity_dict(range(256))
+decoding_map.update({
+ 0x0080: 0x00c4, # LATIN CAPITAL LETTER A WITH DIAERESIS
+ 0x0081: 0x00c5, # LATIN CAPITAL LETTER A WITH RING ABOVE
+ 0x0082: 0x00c7, # LATIN CAPITAL LETTER C WITH CEDILLA
+ 0x0083: 0x00c9, # LATIN CAPITAL LETTER E WITH ACUTE
+ 0x0084: 0x00d1, # LATIN CAPITAL LETTER N WITH TILDE
+ 0x0085: 0x00d6, # LATIN CAPITAL LETTER O WITH DIAERESIS
+ 0x0086: 0x00dc, # LATIN CAPITAL LETTER U WITH DIAERESIS
+ 0x0087: 0x00e1, # LATIN SMALL LETTER A WITH ACUTE
+ 0x0088: 0x00e0, # LATIN SMALL LETTER A WITH GRAVE
+ 0x0089: 0x00e2, # LATIN SMALL LETTER A WITH CIRCUMFLEX
+ 0x008a: 0x00e4, # LATIN SMALL LETTER A WITH DIAERESIS
+ 0x008b: 0x00e3, # LATIN SMALL LETTER A WITH TILDE
+ 0x008c: 0x00e5, # LATIN SMALL LETTER A WITH RING ABOVE
+ 0x008d: 0x00e7, # LATIN SMALL LETTER C WITH CEDILLA
+ 0x008e: 0x00e9, # LATIN SMALL LETTER E WITH ACUTE
+ 0x008f: 0x00e8, # LATIN SMALL LETTER E WITH GRAVE
+ 0x0090: 0x00ea, # LATIN SMALL LETTER E WITH CIRCUMFLEX
+ 0x0091: 0x00eb, # LATIN SMALL LETTER E WITH DIAERESIS
+ 0x0092: 0x00ed, # LATIN SMALL LETTER I WITH ACUTE
+ 0x0093: 0x00ec, # LATIN SMALL LETTER I WITH GRAVE
+ 0x0094: 0x00ee, # LATIN SMALL LETTER I WITH CIRCUMFLEX
+ 0x0095: 0x00ef, # LATIN SMALL LETTER I WITH DIAERESIS
+ 0x0096: 0x00f1, # LATIN SMALL LETTER N WITH TILDE
+ 0x0097: 0x00f3, # LATIN SMALL LETTER O WITH ACUTE
+ 0x0098: 0x00f2, # LATIN SMALL LETTER O WITH GRAVE
+ 0x0099: 0x00f4, # LATIN SMALL LETTER O WITH CIRCUMFLEX
+ 0x009a: 0x00f6, # LATIN SMALL LETTER O WITH DIAERESIS
+ 0x009b: 0x00f5, # LATIN SMALL LETTER O WITH TILDE
+ 0x009c: 0x00fa, # LATIN SMALL LETTER U WITH ACUTE
+ 0x009d: 0x00f9, # LATIN SMALL LETTER U WITH GRAVE
+ 0x009e: 0x00fb, # LATIN SMALL LETTER U WITH CIRCUMFLEX
+ 0x009f: 0x00fc, # LATIN SMALL LETTER U WITH DIAERESIS
+ 0x00a0: 0x2020, # DAGGER
+ 0x00a1: 0x00b0, # DEGREE SIGN
+ 0x00a4: 0x00a7, # SECTION SIGN
+ 0x00a5: 0x2022, # BULLET
+ 0x00a6: 0x00b6, # PILCROW SIGN
+ 0x00a7: 0x00df, # LATIN SMALL LETTER SHARP S
+ 0x00a8: 0x00ae, # REGISTERED SIGN
+ 0x00aa: 0x2122, # TRADE MARK SIGN
+ 0x00ab: 0x00b4, # ACUTE ACCENT
+ 0x00ac: 0x00a8, # DIAERESIS
+ 0x00ad: 0x2260, # NOT EQUAL TO
+ 0x00ae: 0x00c6, # LATIN CAPITAL LIGATURE AE
+ 0x00af: 0x00d8, # LATIN CAPITAL LETTER O WITH STROKE
+ 0x00b0: 0x221e, # INFINITY
+ 0x00b2: 0x2264, # LESS-THAN OR EQUAL TO
+ 0x00b3: 0x2265, # GREATER-THAN OR EQUAL TO
+ 0x00b4: 0x00a5, # YEN SIGN
+ 0x00b6: 0x2202, # PARTIAL DIFFERENTIAL
+ 0x00b7: 0x2211, # N-ARY SUMMATION
+ 0x00b8: 0x220f, # N-ARY PRODUCT
+ 0x00b9: 0x03c0, # GREEK SMALL LETTER PI
+ 0x00ba: 0x222b, # INTEGRAL
+ 0x00bb: 0x00aa, # FEMININE ORDINAL INDICATOR
+ 0x00bc: 0x00ba, # MASCULINE ORDINAL INDICATOR
+ 0x00bd: 0x2126, # OHM SIGN
+ 0x00be: 0x00e6, # LATIN SMALL LIGATURE AE
+ 0x00bf: 0x00f8, # LATIN SMALL LETTER O WITH STROKE
+ 0x00c0: 0x00bf, # INVERTED QUESTION MARK
+ 0x00c1: 0x00a1, # INVERTED EXCLAMATION MARK
+ 0x00c2: 0x00ac, # NOT SIGN
+ 0x00c3: 0x221a, # SQUARE ROOT
+ 0x00c4: 0x0192, # LATIN SMALL LETTER F WITH HOOK
+ 0x00c5: 0x2248, # ALMOST EQUAL TO
+ 0x00c6: 0x2206, # INCREMENT
+ 0x00c7: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00c8: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00c9: 0x2026, # HORIZONTAL ELLIPSIS
+ 0x00ca: 0x00a0, # NO-BREAK SPACE
+ 0x00cb: 0x00c0, # LATIN CAPITAL LETTER A WITH GRAVE
+ 0x00cc: 0x00c3, # LATIN CAPITAL LETTER A WITH TILDE
+ 0x00cd: 0x00d5, # LATIN CAPITAL LETTER O WITH TILDE
+ 0x00ce: 0x0152, # LATIN CAPITAL LIGATURE OE
+ 0x00cf: 0x0153, # LATIN SMALL LIGATURE OE
+ 0x00d0: 0x2013, # EN DASH
+ 0x00d1: 0x2014, # EM DASH
+ 0x00d2: 0x201c, # LEFT DOUBLE QUOTATION MARK
+ 0x00d3: 0x201d, # RIGHT DOUBLE QUOTATION MARK
+ 0x00d4: 0x2018, # LEFT SINGLE QUOTATION MARK
+ 0x00d5: 0x2019, # RIGHT SINGLE QUOTATION MARK
+ 0x00d6: 0x00f7, # DIVISION SIGN
+ 0x00d7: 0x25ca, # LOZENGE
+ 0x00d8: 0x00ff, # LATIN SMALL LETTER Y WITH DIAERESIS
+ 0x00d9: 0x0178, # LATIN CAPITAL LETTER Y WITH DIAERESIS
+ 0x00da: 0x011e, # LATIN CAPITAL LETTER G WITH BREVE
+ 0x00db: 0x011f, # LATIN SMALL LETTER G WITH BREVE
+ 0x00dc: 0x0130, # LATIN CAPITAL LETTER I WITH DOT ABOVE
+ 0x00dd: 0x0131, # LATIN SMALL LETTER DOTLESS I
+ 0x00de: 0x015e, # LATIN CAPITAL LETTER S WITH CEDILLA
+ 0x00df: 0x015f, # LATIN SMALL LETTER S WITH CEDILLA
+ 0x00e0: 0x2021, # DOUBLE DAGGER
+ 0x00e1: 0x00b7, # MIDDLE DOT
+ 0x00e2: 0x201a, # SINGLE LOW-9 QUOTATION MARK
+ 0x00e3: 0x201e, # DOUBLE LOW-9 QUOTATION MARK
+ 0x00e4: 0x2030, # PER MILLE SIGN
+ 0x00e5: 0x00c2, # LATIN CAPITAL LETTER A WITH CIRCUMFLEX
+ 0x00e6: 0x00ca, # LATIN CAPITAL LETTER E WITH CIRCUMFLEX
+ 0x00e7: 0x00c1, # LATIN CAPITAL LETTER A WITH ACUTE
+ 0x00e8: 0x00cb, # LATIN CAPITAL LETTER E WITH DIAERESIS
+ 0x00e9: 0x00c8, # LATIN CAPITAL LETTER E WITH GRAVE
+ 0x00ea: 0x00cd, # LATIN CAPITAL LETTER I WITH ACUTE
+ 0x00eb: 0x00ce, # LATIN CAPITAL LETTER I WITH CIRCUMFLEX
+ 0x00ec: 0x00cf, # LATIN CAPITAL LETTER I WITH DIAERESIS
+ 0x00ed: 0x00cc, # LATIN CAPITAL LETTER I WITH GRAVE
+ 0x00ee: 0x00d3, # LATIN CAPITAL LETTER O WITH ACUTE
+ 0x00ef: 0x00d4, # LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+ 0x00f0: None, # UNDEFINED
+ 0x00f1: 0x00d2, # LATIN CAPITAL LETTER O WITH GRAVE
+ 0x00f2: 0x00da, # LATIN CAPITAL LETTER U WITH ACUTE
+ 0x00f3: 0x00db, # LATIN CAPITAL LETTER U WITH CIRCUMFLEX
+ 0x00f4: 0x00d9, # LATIN CAPITAL LETTER U WITH GRAVE
+ 0x00f5: None, # UNDEFINED
+ 0x00f6: 0x02c6, # MODIFIER LETTER CIRCUMFLEX ACCENT
+ 0x00f7: 0x02dc, # SMALL TILDE
+ 0x00f8: 0x00af, # MACRON
+ 0x00f9: 0x02d8, # BREVE
+ 0x00fa: 0x02d9, # DOT ABOVE
+ 0x00fb: 0x02da, # RING ABOVE
+ 0x00fc: 0x00b8, # CEDILLA
+ 0x00fd: 0x02dd, # DOUBLE ACUTE ACCENT
+ 0x00fe: 0x02db, # OGONEK
+ 0x00ff: 0x02c7, # CARON
+})
+
+### Encoding Map
+
+encoding_map = {}
+for k,v in decoding_map.items():
+ encoding_map[v] = k
diff --git a/lib/jython/Lib/encodings/mbcs.py b/lib/jython/Lib/encodings/mbcs.py new file mode 100644 index 000000000..a264eaec8 --- /dev/null +++ b/lib/jython/Lib/encodings/mbcs.py @@ -0,0 +1,36 @@ +""" Python 'mbcs' Codec for Windows
+
+
+Cloned by Mark Hammond (mhammond@skippinet.com.au) from ascii.py,
+which was written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+
+"""
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ # Note: Binding these as C functions will result in the class not
+ # converting them to methods. This is intended.
+ encode = codecs.mbcs_encode
+ decode = codecs.mbcs_decode
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+class StreamConverter(StreamWriter,StreamReader):
+
+ encode = codecs.mbcs_decode
+ decode = codecs.mbcs_encode
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec.encode,Codec.decode,StreamReader,StreamWriter)
diff --git a/lib/jython/Lib/encodings/raw_unicode_escape.py b/lib/jython/Lib/encodings/raw_unicode_escape.py new file mode 100644 index 000000000..110613833 --- /dev/null +++ b/lib/jython/Lib/encodings/raw_unicode_escape.py @@ -0,0 +1,30 @@ +""" Python 'raw-unicode-escape' Codec
+
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+
+"""
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ # Note: Binding these as C functions will result in the class not
+ # converting them to methods. This is intended.
+ encode = codecs.raw_unicode_escape_encode
+ decode = codecs.raw_unicode_escape_decode
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec.encode,Codec.decode,StreamReader,StreamWriter)
diff --git a/lib/jython/Lib/encodings/undefined.py b/lib/jython/Lib/encodings/undefined.py new file mode 100644 index 000000000..3865c8d88 --- /dev/null +++ b/lib/jython/Lib/encodings/undefined.py @@ -0,0 +1,34 @@ +""" Python 'undefined' Codec
+
+ This codec will always raise a ValueError exception when being
+ used. It is intended for use by the site.py file to switch off
+ automatic string to Unicode coercion.
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+
+"""
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ def encode(self,input,errors='strict'):
+ raise UnicodeError, "undefined encoding"
+
+ def decode(self,input,errors='strict'):
+ raise UnicodeError, "undefined encoding"
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
diff --git a/lib/jython/Lib/encodings/unicode_escape.py b/lib/jython/Lib/encodings/unicode_escape.py new file mode 100644 index 000000000..48f7a3b55 --- /dev/null +++ b/lib/jython/Lib/encodings/unicode_escape.py @@ -0,0 +1,30 @@ +""" Python 'unicode-escape' Codec
+
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+
+"""
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ # Note: Binding these as C functions will result in the class not
+ # converting them to methods. This is intended.
+ encode = codecs.unicode_escape_encode
+ decode = codecs.unicode_escape_decode
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec.encode,Codec.decode,StreamReader,StreamWriter)
diff --git a/lib/jython/Lib/encodings/unicode_internal.py b/lib/jython/Lib/encodings/unicode_internal.py new file mode 100644 index 000000000..401e81b48 --- /dev/null +++ b/lib/jython/Lib/encodings/unicode_internal.py @@ -0,0 +1,30 @@ +""" Python 'unicode-internal' Codec
+
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+
+"""
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ # Note: Binding these as C functions will result in the class not
+ # converting them to methods. This is intended.
+ encode = codecs.unicode_internal_encode
+ decode = codecs.unicode_internal_decode
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec.encode,Codec.decode,StreamReader,StreamWriter)
diff --git a/lib/jython/Lib/encodings/utf_16.py b/lib/jython/Lib/encodings/utf_16.py new file mode 100644 index 000000000..747e4c4a0 --- /dev/null +++ b/lib/jython/Lib/encodings/utf_16.py @@ -0,0 +1,31 @@ +""" Python 'utf-16' Codec
+
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+
+"""
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ # Note: Binding these as C functions will result in the class not
+ # converting them to methods. This is intended.
+ encode = codecs.utf_16_encode
+ decode = codecs.utf_16_decode
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec.encode,Codec.decode,StreamReader,StreamWriter)
+
diff --git a/lib/jython/Lib/encodings/utf_16_be.py b/lib/jython/Lib/encodings/utf_16_be.py new file mode 100644 index 000000000..76f79cee5 --- /dev/null +++ b/lib/jython/Lib/encodings/utf_16_be.py @@ -0,0 +1,31 @@ +""" Python 'utf-16-be' Codec
+
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+
+"""
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ # Note: Binding these as C functions will result in the class not
+ # converting them to methods. This is intended.
+ encode = codecs.utf_16_be_encode
+ decode = codecs.utf_16_be_decode
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec.encode,Codec.decode,StreamReader,StreamWriter)
+
diff --git a/lib/jython/Lib/encodings/utf_16_le.py b/lib/jython/Lib/encodings/utf_16_le.py new file mode 100644 index 000000000..e0237e1db --- /dev/null +++ b/lib/jython/Lib/encodings/utf_16_le.py @@ -0,0 +1,31 @@ +""" Python 'utf-16-le' Codec
+
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+
+"""
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ # Note: Binding these as C functions will result in the class not
+ # converting them to methods. This is intended.
+ encode = codecs.utf_16_le_encode
+ decode = codecs.utf_16_le_decode
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec.encode,Codec.decode,StreamReader,StreamWriter)
+
diff --git a/lib/jython/Lib/encodings/utf_8.py b/lib/jython/Lib/encodings/utf_8.py new file mode 100644 index 000000000..4803ce9c2 --- /dev/null +++ b/lib/jython/Lib/encodings/utf_8.py @@ -0,0 +1,31 @@ +""" Python 'utf-8' Codec
+
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+
+"""
+import codecs
+
+### Codec APIs
+
+class Codec(codecs.Codec):
+
+ # Note: Binding these as C functions will result in the class not
+ # converting them to methods. This is intended.
+ encode = codecs.utf_8_encode
+ decode = codecs.utf_8_decode
+
+class StreamWriter(Codec,codecs.StreamWriter):
+ pass
+
+class StreamReader(Codec,codecs.StreamReader):
+ pass
+
+### encodings module API
+
+def getregentry():
+
+ return (Codec.encode,Codec.decode,StreamReader,StreamWriter)
+
diff --git a/lib/jython/Lib/fileinput.py b/lib/jython/Lib/fileinput.py new file mode 100644 index 000000000..aa4dd6744 --- /dev/null +++ b/lib/jython/Lib/fileinput.py @@ -0,0 +1,300 @@ +"""Helper class to quickly write a loop over all standard input files.
+
+Typical use is:
+
+ import fileinput
+ for line in fileinput.input():
+ process(line)
+
+This iterates over the lines of all files listed in sys.argv[1:],
+defaulting to sys.stdin if the list is empty. If a filename is '-' it
+is also replaced by sys.stdin. To specify an alternative list of
+filenames, pass it as the argument to input(). A single file name is
+also allowed.
+
+Functions filename(), lineno() return the filename and cumulative line
+number of the line that has just been read; filelineno() returns its
+line number in the current file; isfirstline() returns true iff the
+line just read is the first line of its file; isstdin() returns true
+iff the line was read from sys.stdin. Function nextfile() closes the
+current file so that the next iteration will read the first line from
+the next file (if any); lines not read from the file will not count
+towards the cumulative line count; the filename is not changed until
+after the first line of the next file has been read. Function close()
+closes the sequence.
+
+Before any lines have been read, filename() returns None and both line
+numbers are zero; nextfile() has no effect. After all lines have been
+read, filename() and the line number functions return the values
+pertaining to the last line read; nextfile() has no effect.
+
+All files are opened in text mode. If an I/O error occurs during
+opening or reading a file, the IOError exception is raised.
+
+If sys.stdin is used more than once, the second and further use will
+return no lines, except perhaps for interactive use, or if it has been
+explicitly reset (e.g. using sys.stdin.seek(0)).
+
+Empty files are opened and immediately closed; the only time their
+presence in the list of filenames is noticeable at all is when the
+last file opened is empty.
+
+It is possible that the last line of a file doesn't end in a newline
+character; otherwise lines are returned including the trailing
+newline.
+
+Class FileInput is the implementation; its methods filename(),
+lineno(), fileline(), isfirstline(), isstdin(), nextfile() and close()
+correspond to the functions in the module. In addition it has a
+readline() method which returns the next input line, and a
+__getitem__() method which implements the sequence behavior. The
+sequence must be accessed in strictly sequential order; sequence
+access and readline() cannot be mixed.
+
+Optional in-place filtering: if the keyword argument inplace=1 is
+passed to input() or to the FileInput constructor, the file is moved
+to a backup file and standard output is directed to the input file.
+This makes it possible to write a filter that rewrites its input file
+in place. If the keyword argument backup=".<some extension>" is also
+given, it specifies the extension for the backup file, and the backup
+file remains around; by default, the extension is ".bak" and it is
+deleted when the output file is closed. In-place filtering is
+disabled when standard input is read. XXX The current implementation
+does not work for MS-DOS 8+3 filesystems.
+
+Performance: this module is unfortunately one of the slower ways of
+processing large numbers of input lines. Nevertheless, a significant
+speed-up has been obtained by using readlines(bufsize) instead of
+readline(). A new keyword argument, bufsize=N, is present on the
+input() function and the FileInput() class to override the default
+buffer size.
+
+XXX Possible additions:
+
+- optional getopt argument processing
+- specify open mode ('r' or 'rb')
+- fileno()
+- isatty()
+- read(), read(size), even readlines()
+
+"""
+
+import sys, os, stat
+
+__all__ = ["input","close","nextfile","filename","lineno","filelineno",
+ "isfirstline","isstdin","FileInput"]
+
+_state = None
+
+DEFAULT_BUFSIZE = 8*1024
+
+def input(files=None, inplace=0, backup="", bufsize=0):
+ global _state
+ if _state and _state._file:
+ raise RuntimeError, "input() already active"
+ _state = FileInput(files, inplace, backup, bufsize)
+ return _state
+
+def close():
+ global _state
+ state = _state
+ _state = None
+ if state:
+ state.close()
+
+def nextfile():
+ if not _state:
+ raise RuntimeError, "no active input()"
+ return _state.nextfile()
+
+def filename():
+ if not _state:
+ raise RuntimeError, "no active input()"
+ return _state.filename()
+
+def lineno():
+ if not _state:
+ raise RuntimeError, "no active input()"
+ return _state.lineno()
+
+def filelineno():
+ if not _state:
+ raise RuntimeError, "no active input()"
+ return _state.filelineno()
+
+def isfirstline():
+ if not _state:
+ raise RuntimeError, "no active input()"
+ return _state.isfirstline()
+
+def isstdin():
+ if not _state:
+ raise RuntimeError, "no active input()"
+ return _state.isstdin()
+
+class FileInput:
+
+ def __init__(self, files=None, inplace=0, backup="", bufsize=0):
+ if type(files) == type(''):
+ files = (files,)
+ else:
+ if files is None:
+ files = sys.argv[1:]
+ if not files:
+ files = ('-',)
+ else:
+ files = tuple(files)
+ self._files = files
+ self._inplace = inplace
+ self._backup = backup
+ self._bufsize = bufsize or DEFAULT_BUFSIZE
+ self._savestdout = None
+ self._output = None
+ self._filename = None
+ self._lineno = 0
+ self._filelineno = 0
+ self._file = None
+ self._isstdin = 0
+ self._backupfilename = None
+ self._buffer = []
+ self._bufindex = 0
+
+ def __del__(self):
+ self.close()
+
+ def close(self):
+ self.nextfile()
+ self._files = ()
+
+ def __getitem__(self, i):
+ try:
+ line = self._buffer[self._bufindex]
+ except IndexError:
+ pass
+ else:
+ self._bufindex += 1
+ self._lineno += 1
+ self._filelineno += 1
+ return line
+ if i != self._lineno:
+ raise RuntimeError, "accessing lines out of order"
+ line = self.readline()
+ if not line:
+ raise IndexError, "end of input reached"
+ return line
+
+ def nextfile(self):
+ savestdout = self._savestdout
+ self._savestdout = 0
+ if savestdout:
+ sys.stdout = savestdout
+
+ output = self._output
+ self._output = 0
+ if output:
+ output.close()
+
+ file = self._file
+ self._file = 0
+ if file and not self._isstdin:
+ file.close()
+
+ backupfilename = self._backupfilename
+ self._backupfilename = 0
+ if backupfilename and not self._backup:
+ try: os.unlink(backupfilename)
+ except: pass
+
+ self._isstdin = 0
+ self._buffer = []
+ self._bufindex = 0
+
+ def readline(self):
+ try:
+ line = self._buffer[self._bufindex]
+ except IndexError:
+ pass
+ else:
+ self._bufindex += 1
+ self._lineno += 1
+ self._filelineno += 1
+ return line
+ if not self._file:
+ if not self._files:
+ return ""
+ self._filename = self._files[0]
+ self._files = self._files[1:]
+ self._filelineno = 0
+ self._file = None
+ self._isstdin = 0
+ self._backupfilename = 0
+ if self._filename == '-':
+ self._filename = '<stdin>'
+ self._file = sys.stdin
+ self._isstdin = 1
+ else:
+ if self._inplace:
+ self._backupfilename = (
+ self._filename + (self._backup or ".bak"))
+ try: os.unlink(self._backupfilename)
+ except os.error: pass
+ # The next few lines may raise IOError
+ os.rename(self._filename, self._backupfilename)
+ self._file = open(self._backupfilename, "r")
+ try:
+ perm = os.fstat(self._file.fileno())[stat.ST_MODE]
+ except:
+ self._output = open(self._filename, "w")
+ else:
+ fd = os.open(self._filename,
+ os.O_CREAT | os.O_WRONLY | os.O_TRUNC,
+ perm)
+ self._output = os.fdopen(fd, "w")
+ try:
+ os.chmod(self._filename, perm)
+ except:
+ pass
+ self._savestdout = sys.stdout
+ sys.stdout = self._output
+ else:
+ # This may raise IOError
+ self._file = open(self._filename, "r")
+ self._buffer = self._file.readlines(self._bufsize)
+ self._bufindex = 0
+ if not self._buffer:
+ self.nextfile()
+ # Recursive call
+ return self.readline()
+
+ def filename(self):
+ return self._filename
+
+ def lineno(self):
+ return self._lineno
+
+ def filelineno(self):
+ return self._filelineno
+
+ def isfirstline(self):
+ return self._filelineno == 1
+
+ def isstdin(self):
+ return self._isstdin
+
+def _test():
+ import getopt
+ inplace = 0
+ backup = 0
+ opts, args = getopt.getopt(sys.argv[1:], "ib:")
+ for o, a in opts:
+ if o == '-i': inplace = 1
+ if o == '-b': backup = a
+ for line in input(args, inplace=inplace, backup=backup):
+ if line[-1:] == '\n': line = line[:-1]
+ if line[-1:] == '\r': line = line[:-1]
+ print "%d: %s[%d]%s %s" % (lineno(), filename(), filelineno(),
+ isfirstline() and "*" or "", line)
+ print "%d: %s[%d]" % (lineno(), filename(), filelineno())
+
+if __name__ == '__main__':
+ _test()
diff --git a/lib/jython/Lib/fnmatch.py b/lib/jython/Lib/fnmatch.py new file mode 100644 index 000000000..f91ee9571 --- /dev/null +++ b/lib/jython/Lib/fnmatch.py @@ -0,0 +1,87 @@ +"""Filename matching with shell patterns.
+
+fnmatch(FILENAME, PATTERN) matches according to the local convention.
+fnmatchcase(FILENAME, PATTERN) always takes case in account.
+
+The functions operate by translating the pattern into a regular
+expression. They cache the compiled regular expressions for speed.
+
+The function translate(PATTERN) returns a regular expression
+corresponding to PATTERN. (It does not compile it.)
+"""
+
+import re
+
+__all__ = ["fnmatch","fnmatchcase","translate"]
+
+_cache = {}
+
+def fnmatch(name, pat):
+ """Test whether FILENAME matches PATTERN.
+
+ Patterns are Unix shell style:
+
+ * matches everything
+ ? matches any single character
+ [seq] matches any character in seq
+ [!seq] matches any char not in seq
+
+ An initial period in FILENAME is not special.
+ Both FILENAME and PATTERN are first case-normalized
+ if the operating system requires it.
+ If you don't want this, use fnmatchcase(FILENAME, PATTERN).
+ """
+
+ import os
+ name = os.path.normcase(name)
+ pat = os.path.normcase(pat)
+ return fnmatchcase(name, pat)
+
+def fnmatchcase(name, pat):
+ """Test whether FILENAME matches PATTERN, including case.
+
+ This is a version of fnmatch() which doesn't case-normalize
+ its arguments.
+ """
+
+ if not _cache.has_key(pat):
+ res = translate(pat)
+ _cache[pat] = re.compile(res)
+ return _cache[pat].match(name) is not None
+
+def translate(pat):
+ """Translate a shell PATTERN to a regular expression.
+
+ There is no way to quote meta-characters.
+ """
+
+ i, n = 0, len(pat)
+ res = ''
+ while i < n:
+ c = pat[i]
+ i = i+1
+ if c == '*':
+ res = res + '.*'
+ elif c == '?':
+ res = res + '.'
+ elif c == '[':
+ j = i
+ if j < n and pat[j] == '!':
+ j = j+1
+ if j < n and pat[j] == ']':
+ j = j+1
+ while j < n and pat[j] != ']':
+ j = j+1
+ if j >= n:
+ res = res + '\\['
+ else:
+ stuff = pat[i:j].replace('\\','\\\\')
+ i = j+1
+ if stuff[0] == '!':
+ stuff = '^' + stuff[1:]
+ elif stuff[0] == '^':
+ stuff = '\\' + stuff
+ res = '%s[%s]' % (res, stuff)
+ else:
+ res = res + re.escape(c)
+ return res + "$"
diff --git a/lib/jython/Lib/formatter.py b/lib/jython/Lib/formatter.py new file mode 100644 index 000000000..df51d8eda --- /dev/null +++ b/lib/jython/Lib/formatter.py @@ -0,0 +1,422 @@ +"""Generic output formatting.
+
+Formatter objects transform an abstract flow of formatting events into
+specific output events on writer objects. Formatters manage several stack
+structures to allow various properties of a writer object to be changed and
+restored; writers need not be able to handle relative changes nor any sort
+of ``change back'' operation. Specific writer properties which may be
+controlled via formatter objects are horizontal alignment, font, and left
+margin indentations. A mechanism is provided which supports providing
+arbitrary, non-exclusive style settings to a writer as well. Additional
+interfaces facilitate formatting events which are not reversible, such as
+paragraph separation.
+
+Writer objects encapsulate device interfaces. Abstract devices, such as
+file formats, are supported as well as physical devices. The provided
+implementations all work with abstract devices. The interface makes
+available mechanisms for setting the properties which formatter objects
+manage and inserting data into the output.
+"""
+
+import string
+import sys
+from types import StringType
+
+
+AS_IS = None
+
+
+class NullFormatter:
+
+ def __init__(self, writer=None):
+ if not writer:
+ writer = NullWriter()
+ self.writer = writer
+ def end_paragraph(self, blankline): pass
+ def add_line_break(self): pass
+ def add_hor_rule(self, *args, **kw): pass
+ def add_label_data(self, format, counter, blankline=None): 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:
+
+ # Space handling policy: blank spaces at the boundary between elements
+ # are handled by the outermost context. "Literal" data is not checked
+ # to determine context, so spaces in literal data are handled directly
+ # in all circumstances.
+
+ 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 label.upper()
+ 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
+ if self.softspace:
+ self.writer.send_flowing_data(" ")
+ 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.para_end = self.parskip = \
+ self.have_label = self.softspace = 0
+ self.nospace = 1
+ 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.para_end = self.softspace = 0
+ self.nospace = 1
+ 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.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.para_end = self.softspace = 0
+ self.nospace = 1
+ 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):
+ 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.parskip = self.have_label = 0
+
+
+class NullWriter:
+ """Minimal writer interface to use in testing & inheritance."""
+ def __init__(self): pass
+ def flush(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'*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 = data.rfind('\n')
+ if i >= 0:
+ self.col = 0
+ data = data[i+1:]
+ data = data.expandtabs()
+ 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 data.split():
+ 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/jython/Lib/fpformat.py b/lib/jython/Lib/fpformat.py new file mode 100644 index 000000000..21d2489ec --- /dev/null +++ b/lib/jython/Lib/fpformat.py @@ -0,0 +1,142 @@ +"""General floating point formatting functions.
+
+Functions:
+fix(x, digits_behind)
+sci(x, digits_behind)
+
+Each takes a number or a string and a number of digits as arguments.
+
+Parameters:
+x: number to be formatted; or a string resembling a number
+digits_behind: number of digits behind the decimal point
+"""
+
+import re
+
+__all__ = ["fix","sci","NotANumber"]
+
+# Compiled regular expression to "decode" a number
+decoder = re.compile(r'^([-+]?)0*(\d*)((?:\.\d*)?)(([eE][-+]?\d+)?)$')
+# \0 the whole thing
+# \1 leading sign or empty
+# \2 digits left of decimal point
+# \3 fraction (empty or begins with point)
+# \4 exponent part (empty or begins with 'e' or 'E')
+
+try:
+ class NotANumber(ValueError):
+ pass
+except TypeError:
+ NotANumber = 'fpformat.NotANumber'
+
+def extract(s):
+ """Return (sign, intpart, fraction, expo) or raise an exception:
+ sign is '+' or '-'
+ intpart is 0 or more digits beginning with a nonzero
+ fraction is 0 or more digits
+ expo is an integer"""
+ res = decoder.match(s)
+ if res is None: raise NotANumber, s
+ sign, intpart, fraction, exppart = res.group(1,2,3,4)
+ if sign == '+': sign = ''
+ if fraction: fraction = fraction[1:]
+ if exppart: expo = int(exppart[1:])
+ else: expo = 0
+ return sign, intpart, fraction, expo
+
+def unexpo(intpart, fraction, expo):
+ """Remove the exponent by changing intpart and fraction."""
+ if expo > 0: # Move the point left
+ f = len(fraction)
+ intpart, fraction = intpart + fraction[:expo], fraction[expo:]
+ if expo > f:
+ intpart = intpart + '0'*(expo-f)
+ elif expo < 0: # Move the point right
+ i = len(intpart)
+ intpart, fraction = intpart[:expo], intpart[expo:] + fraction
+ if expo < -i:
+ fraction = '0'*(-expo-i) + fraction
+ return intpart, fraction
+
+def roundfrac(intpart, fraction, digs):
+ """Round or extend the fraction to size digs."""
+ f = len(fraction)
+ if f <= digs:
+ return intpart, fraction + '0'*(digs-f)
+ i = len(intpart)
+ if i+digs < 0:
+ return '0'*-digs, ''
+ total = intpart + fraction
+ nextdigit = total[i+digs]
+ if nextdigit >= '5': # Hard case: increment last digit, may have carry!
+ n = i + digs - 1
+ while n >= 0:
+ if total[n] != '9': break
+ n = n-1
+ else:
+ total = '0' + total
+ i = i+1
+ n = 0
+ total = total[:n] + chr(ord(total[n]) + 1) + '0'*(len(total)-n-1)
+ intpart, fraction = total[:i], total[i:]
+ if digs >= 0:
+ return intpart, fraction[:digs]
+ else:
+ return intpart[:digs] + '0'*-digs, ''
+
+def fix(x, digs):
+ """Format x as [-]ddd.ddd with 'digs' digits after the point
+ and at least one digit before.
+ If digs <= 0, the point is suppressed."""
+ if type(x) != type(''): x = `x`
+ try:
+ sign, intpart, fraction, expo = extract(x)
+ except NotANumber:
+ return x
+ intpart, fraction = unexpo(intpart, fraction, expo)
+ intpart, fraction = roundfrac(intpart, fraction, digs)
+ while intpart and intpart[0] == '0': intpart = intpart[1:]
+ if intpart == '': intpart = '0'
+ if digs > 0: return sign + intpart + '.' + fraction
+ else: return sign + intpart
+
+def sci(x, digs):
+ """Format x as [-]d.dddE[+-]ddd with 'digs' digits after the point
+ and exactly one digit before.
+ If digs is <= 0, one digit is kept and the point is suppressed."""
+ if type(x) != type(''): x = `x`
+ sign, intpart, fraction, expo = extract(x)
+ if not intpart:
+ while fraction and fraction[0] == '0':
+ fraction = fraction[1:]
+ expo = expo - 1
+ if fraction:
+ intpart, fraction = fraction[0], fraction[1:]
+ expo = expo - 1
+ else:
+ intpart = '0'
+ else:
+ expo = expo + len(intpart) - 1
+ intpart, fraction = intpart[0], intpart[1:] + fraction
+ digs = max(0, digs)
+ intpart, fraction = roundfrac(intpart, fraction, digs)
+ if len(intpart) > 1:
+ intpart, fraction, expo = \
+ intpart[0], intpart[1:] + fraction[:-1], \
+ expo + len(intpart) - 1
+ s = sign + intpart
+ if digs > 0: s = s + '.' + fraction
+ e = `abs(expo)`
+ e = '0'*(3-len(e)) + e
+ if expo < 0: e = '-' + e
+ else: e = '+' + e
+ return s + 'e' + e
+
+def test():
+ """Interactive test run."""
+ try:
+ while 1:
+ x, digs = input('Enter (x, digs): ')
+ print x, fix(x, digs), sci(x, digs)
+ except (EOFError, KeyboardInterrupt):
+ pass
diff --git a/lib/jython/Lib/ftplib.py b/lib/jython/Lib/ftplib.py new file mode 100644 index 000000000..067c28541 --- /dev/null +++ b/lib/jython/Lib/ftplib.py @@ -0,0 +1,727 @@ +"""An FTP client class and some helper functions.
+
+Based on RFC 959: File Transfer Protocol (FTP), by J. Postel and J. Reynolds
+
+Example:
+
+>>> from ftplib import FTP
+>>> ftp = FTP('ftp.python.org') # connect to host, default port
+>>> ftp.login() # default, i.e.: user anonymous, passwd user@hostname
+'230 Guest login ok, access restrictions apply.'
+>>> ftp.retrlines('LIST') # list directory contents
+total 9
+drwxr-xr-x 8 root wheel 1024 Jan 3 1994 .
+drwxr-xr-x 8 root wheel 1024 Jan 3 1994 ..
+drwxr-xr-x 2 root wheel 1024 Jan 3 1994 bin
+drwxr-xr-x 2 root wheel 1024 Jan 3 1994 etc
+d-wxrwxr-x 2 ftp wheel 1024 Sep 5 13:43 incoming
+drwxr-xr-x 2 root wheel 1024 Nov 17 1993 lib
+drwxr-xr-x 6 1094 wheel 1024 Sep 13 19:07 pub
+drwxr-xr-x 3 root wheel 1024 Jan 3 1994 usr
+-rw-r--r-- 1 root root 312 Aug 1 1994 welcome.msg
+'226 Transfer complete.'
+>>> ftp.quit()
+'221 Goodbye.'
+>>>
+
+A nice test that reveals some of the network dialogue would be:
+python ftplib.py -d localhost -l -p -l
+"""
+
+#
+# Changes and improvements suggested by Steve Majewski.
+# Modified by Jack to work on the mac.
+# Modified by Siebren to support docstrings and PASV.
+#
+
+import os
+import sys
+import string
+
+# Import SOCKS module if it exists, else standard socket module socket
+try:
+ import SOCKS; socket = SOCKS; del SOCKS # import SOCKS as socket
+ from socket import getfqdn; socket.getfqdn = getfqdn; del getfqdn
+except ImportError:
+ import socket
+
+__all__ = ["FTP","Netrc"]
+
+# Magic number from <socket.h>
+MSG_OOB = 0x1 # Process data out of band
+
+
+# The standard FTP server control port
+FTP_PORT = 21
+
+
+# Exception raised when an error or invalid response is received
+class Error(Exception): pass
+class error_reply(Error): pass # unexpected [123]xx reply
+class error_temp(Error): pass # 4xx errors
+class error_perm(Error): pass # 5xx errors
+class error_proto(Error): pass # response does not begin with [1-5]
+
+
+# All exceptions (hopefully) that may be raised here and that aren't
+# (always) programming errors on our side
+all_errors = (Error, socket.error, IOError, EOFError)
+
+
+# Line terminators (we always output CRLF, but accept any of CRLF, CR, LF)
+CRLF = '\r\n'
+
+
+# The class itself
+class FTP:
+
+ '''An FTP client class.
+
+ To create a connection, call the class using these argument:
+ host, user, passwd, acct
+ These are all strings, and have default value ''.
+ Then use self.connect() with optional host and port argument.
+
+ To download a file, use ftp.retrlines('RETR ' + filename),
+ or ftp.retrbinary() with slightly different arguments.
+ To upload a file, use ftp.storlines() or ftp.storbinary(),
+ which have an open file as argument (see their definitions
+ below for details).
+ The download/upload functions first issue appropriate TYPE
+ and PORT or PASV commands.
+'''
+
+ debugging = 0
+ host = ''
+ port = FTP_PORT
+ sock = None
+ file = None
+ welcome = None
+ passiveserver = 1
+
+ # Initialization method (called by class instantiation).
+ # Initialize host to localhost, port to standard ftp port
+ # Optional arguments are host (for connect()),
+ # and user, passwd, acct (for login())
+ def __init__(self, host='', user='', passwd='', acct=''):
+ if host:
+ self.connect(host)
+ if user: self.login(user, passwd, acct)
+
+ def connect(self, host='', port=0):
+ '''Connect to host. Arguments are:
+ - host: hostname to connect to (string, default previous host)
+ - port: port to connect to (integer, default previous port)'''
+ if host: self.host = host
+ if port: self.port = port
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.sock.connect((self.host, self.port))
+ self.file = self.sock.makefile('rb')
+ self.welcome = self.getresp()
+ return self.welcome
+
+ def getwelcome(self):
+ '''Get the welcome message from the server.
+ (this is read and squirreled away by connect())'''
+ if self.debugging:
+ print '*welcome*', self.sanitize(self.welcome)
+ return self.welcome
+
+ def set_debuglevel(self, level):
+ '''Set the debugging level.
+ The required argument level means:
+ 0: no debugging output (default)
+ 1: print commands and responses but not body text etc.
+ 2: also print raw lines read and sent before stripping CR/LF'''
+ self.debugging = level
+ debug = set_debuglevel
+
+ def set_pasv(self, val):
+ '''Use passive or active mode for data transfers.
+ With a false argument, use the normal PORT mode,
+ With a true argument, use the PASV command.'''
+ self.passiveserver = val
+
+ # Internal: "sanitize" a string for printing
+ def sanitize(self, s):
+ if s[:5] == 'pass ' or s[:5] == 'PASS ':
+ i = len(s)
+ while i > 5 and s[i-1] in '\r\n':
+ i = i-1
+ s = s[:5] + '*'*(i-5) + s[i:]
+ return `s`
+
+ # Internal: send one line to the server, appending CRLF
+ def putline(self, line):
+ line = line + CRLF
+ if self.debugging > 1: print '*put*', self.sanitize(line)
+ self.sock.send(line)
+
+ # Internal: send one command to the server (through putline())
+ def putcmd(self, line):
+ if self.debugging: print '*cmd*', self.sanitize(line)
+ self.putline(line)
+
+ # Internal: return one line from the server, stripping CRLF.
+ # Raise EOFError if the connection is closed
+ def getline(self):
+ line = self.file.readline()
+ if self.debugging > 1:
+ print '*get*', self.sanitize(line)
+ if not line: raise EOFError
+ if line[-2:] == CRLF: line = line[:-2]
+ elif line[-1:] in CRLF: line = line[:-1]
+ return line
+
+ # Internal: get a response from the server, which may possibly
+ # consist of multiple lines. Return a single string with no
+ # trailing CRLF. If the response consists of multiple lines,
+ # these are separated by '\n' characters in the string
+ def getmultiline(self):
+ line = self.getline()
+ if line[3:4] == '-':
+ code = line[:3]
+ while 1:
+ nextline = self.getline()
+ line = line + ('\n' + nextline)
+ if nextline[:3] == code and \
+ nextline[3:4] != '-':
+ break
+ return line
+
+ # Internal: get a response from the server.
+ # Raise various errors if the response indicates an error
+ def getresp(self):
+ resp = self.getmultiline()
+ if self.debugging: print '*resp*', self.sanitize(resp)
+ self.lastresp = resp[:3]
+ c = resp[:1]
+ if c == '4':
+ raise error_temp, resp
+ if c == '5':
+ raise error_perm, resp
+ if c not in '123':
+ raise error_proto, resp
+ return resp
+
+ def voidresp(self):
+ """Expect a response beginning with '2'."""
+ resp = self.getresp()
+ if resp[0] != '2':
+ raise error_reply, resp
+ return resp
+
+ def abort(self):
+ '''Abort a file transfer. Uses out-of-band data.
+ This does not follow the procedure from the RFC to send Telnet
+ IP and Synch; that doesn't seem to work with the servers I've
+ tried. Instead, just send the ABOR command as OOB data.'''
+ line = 'ABOR' + CRLF
+ if self.debugging > 1: print '*put urgent*', self.sanitize(line)
+ self.sock.send(line, MSG_OOB)
+ resp = self.getmultiline()
+ if resp[:3] not in ('426', '226'):
+ raise error_proto, resp
+
+ def sendcmd(self, cmd):
+ '''Send a command and return the response.'''
+ self.putcmd(cmd)
+ return self.getresp()
+
+ def voidcmd(self, cmd):
+ """Send a command and expect a response beginning with '2'."""
+ self.putcmd(cmd)
+ return self.voidresp()
+
+ def sendport(self, host, port):
+ '''Send a PORT command with the current host and the given
+ port number.
+ '''
+ hbytes = host.split('.')
+ pbytes = [`port/256`, `port%256`]
+ bytes = hbytes + pbytes
+ cmd = 'PORT ' + ','.join(bytes)
+ return self.voidcmd(cmd)
+
+ def makeport(self):
+ '''Create a new socket and send a PORT command for it.'''
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sock.bind(('', 0))
+ sock.listen(1)
+ dummyhost, port = sock.getsockname() # Get proper port
+ host, dummyport = self.sock.getsockname() # Get proper host
+ resp = self.sendport(host, port)
+ return sock
+
+ def ntransfercmd(self, cmd, rest=None):
+ """Initiate a transfer over the data connection.
+
+ If the transfer is active, send a port command and the
+ transfer command, and accept the connection. If the server is
+ passive, send a pasv command, connect to it, and start the
+ transfer command. Either way, return the socket for the
+ connection and the expected size of the transfer. The
+ expected size may be None if it could not be determined.
+
+ Optional `rest' argument can be a string that is sent as the
+ argument to a RESTART command. This is essentially a server
+ marker used to tell the server to skip over any data up to the
+ given marker.
+ """
+ size = None
+ if self.passiveserver:
+ host, port = parse227(self.sendcmd('PASV'))
+ conn=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ conn.connect((host, port))
+ if rest is not None:
+ self.sendcmd("REST %s" % rest)
+ resp = self.sendcmd(cmd)
+ if resp[0] != '1':
+ raise error_reply, resp
+ else:
+ sock = self.makeport()
+ if rest is not None:
+ self.sendcmd("REST %s" % rest)
+ resp = self.sendcmd(cmd)
+ if resp[0] != '1':
+ raise error_reply, resp
+ conn, sockaddr = sock.accept()
+ if resp[:3] == '150':
+ # this is conditional in case we received a 125
+ size = parse150(resp)
+ return conn, size
+
+ def transfercmd(self, cmd, rest=None):
+ """Like nstransfercmd() but returns only the socket."""
+ return self.ntransfercmd(cmd, rest)[0]
+
+ def login(self, user = '', passwd = '', acct = ''):
+ '''Login, default anonymous.'''
+ if not user: user = 'anonymous'
+ if not passwd: passwd = ''
+ if not acct: acct = ''
+ if user == 'anonymous' and passwd in ('', '-'):
+ # get fully qualified domain name of local host
+ thishost = socket.getfqdn()
+ try:
+ if os.environ.has_key('LOGNAME'):
+ realuser = os.environ['LOGNAME']
+ elif os.environ.has_key('USER'):
+ realuser = os.environ['USER']
+ else:
+ realuser = 'anonymous'
+ except AttributeError:
+ # Not all systems have os.environ....
+ realuser = 'anonymous'
+ passwd = passwd + realuser + '@' + thishost
+ resp = self.sendcmd('USER ' + user)
+ if resp[0] == '3': resp = self.sendcmd('PASS ' + passwd)
+ if resp[0] == '3': resp = self.sendcmd('ACCT ' + acct)
+ if resp[0] != '2':
+ raise error_reply, resp
+ return resp
+
+ def retrbinary(self, cmd, callback, blocksize=8192, rest=None):
+ """Retrieve data in binary mode.
+
+ `cmd' is a RETR command. `callback' is a callback function is
+ called for each block. No more than `blocksize' number of
+ bytes will be read from the socket. Optional `rest' is passed
+ to transfercmd().
+
+ A new port is created for you. Return the response code.
+ """
+ self.voidcmd('TYPE I')
+ conn = self.transfercmd(cmd, rest)
+ while 1:
+ data = conn.recv(blocksize)
+ if not data:
+ break
+ callback(data)
+ conn.close()
+ return self.voidresp()
+
+ def retrlines(self, cmd, callback = None):
+ '''Retrieve data in line mode.
+ The argument is a RETR or LIST command.
+ The callback function (2nd argument) is called for each line,
+ with trailing CRLF stripped. This creates a new port for you.
+ print_line() is the default callback.'''
+ if not callback: callback = print_line
+ resp = self.sendcmd('TYPE A')
+ conn = self.transfercmd(cmd)
+ fp = conn.makefile('rb')
+ while 1:
+ line = fp.readline()
+ if self.debugging > 2: print '*retr*', `line`
+ if not line:
+ break
+ if line[-2:] == CRLF:
+ line = line[:-2]
+ elif line[-1:] == '\n':
+ line = line[:-1]
+ callback(line)
+ fp.close()
+ conn.close()
+ return self.voidresp()
+
+ def storbinary(self, cmd, fp, blocksize=8192):
+ '''Store a file in binary mode.'''
+ self.voidcmd('TYPE I')
+ conn = self.transfercmd(cmd)
+ while 1:
+ buf = fp.read(blocksize)
+ if not buf: break
+ conn.send(buf)
+ conn.close()
+ return self.voidresp()
+
+ def storlines(self, cmd, fp):
+ '''Store a file in line mode.'''
+ self.voidcmd('TYPE A')
+ conn = self.transfercmd(cmd)
+ while 1:
+ buf = fp.readline()
+ if not buf: break
+ if buf[-2:] != CRLF:
+ if buf[-1] in CRLF: buf = buf[:-1]
+ buf = buf + CRLF
+ conn.send(buf)
+ conn.close()
+ return self.voidresp()
+
+ def acct(self, password):
+ '''Send new account name.'''
+ cmd = 'ACCT ' + password
+ return self.voidcmd(cmd)
+
+ def nlst(self, *args):
+ '''Return a list of files in a given directory (default the current).'''
+ cmd = 'NLST'
+ for arg in args:
+ cmd = cmd + (' ' + arg)
+ files = []
+ self.retrlines(cmd, files.append)
+ return files
+
+ def dir(self, *args):
+ '''List a directory in long form.
+ By default list current directory to stdout.
+ Optional last argument is callback function; all
+ non-empty arguments before it are concatenated to the
+ LIST command. (This *should* only be used for a pathname.)'''
+ cmd = 'LIST'
+ func = None
+ if args[-1:] and type(args[-1]) != type(''):
+ args, func = args[:-1], args[-1]
+ for arg in args:
+ if arg:
+ cmd = cmd + (' ' + arg)
+ self.retrlines(cmd, func)
+
+ def rename(self, fromname, toname):
+ '''Rename a file.'''
+ resp = self.sendcmd('RNFR ' + fromname)
+ if resp[0] != '3':
+ raise error_reply, resp
+ return self.voidcmd('RNTO ' + toname)
+
+ def delete(self, filename):
+ '''Delete a file.'''
+ resp = self.sendcmd('DELE ' + filename)
+ if resp[:3] in ('250', '200'):
+ return resp
+ elif resp[:1] == '5':
+ raise error_perm, resp
+ else:
+ raise error_reply, resp
+
+ def cwd(self, dirname):
+ '''Change to a directory.'''
+ if dirname == '..':
+ try:
+ return self.voidcmd('CDUP')
+ except error_perm, msg:
+ if msg[:3] != '500':
+ raise error_perm, msg
+ elif dirname == '':
+ dirname = '.' # does nothing, but could return error
+ cmd = 'CWD ' + dirname
+ return self.voidcmd(cmd)
+
+ def size(self, filename):
+ '''Retrieve the size of a file.'''
+ # Note that the RFC doesn't say anything about 'SIZE'
+ resp = self.sendcmd('SIZE ' + filename)
+ if resp[:3] == '213':
+ return int(resp[3:].strip())
+
+ def mkd(self, dirname):
+ '''Make a directory, return its full pathname.'''
+ resp = self.sendcmd('MKD ' + dirname)
+ return parse257(resp)
+
+ def rmd(self, dirname):
+ '''Remove a directory.'''
+ return self.voidcmd('RMD ' + dirname)
+
+ def pwd(self):
+ '''Return current working directory.'''
+ resp = self.sendcmd('PWD')
+ return parse257(resp)
+
+ def quit(self):
+ '''Quit, and close the connection.'''
+ resp = self.voidcmd('QUIT')
+ self.close()
+ return resp
+
+ def close(self):
+ '''Close the connection without assuming anything about it.'''
+ if self.file:
+ self.file.close()
+ self.sock.close()
+ self.file = self.sock = None
+
+
+_150_re = None
+
+def parse150(resp):
+ '''Parse the '150' response for a RETR request.
+ Returns the expected transfer size or None; size is not guaranteed to
+ be present in the 150 message.
+ '''
+ if resp[:3] != '150':
+ raise error_reply, resp
+ global _150_re
+ if _150_re is None:
+ import re
+ _150_re = re.compile("150 .* \((\d+) bytes\)", re.IGNORECASE)
+ m = _150_re.match(resp)
+ if m:
+ return int(m.group(1))
+ return None
+
+
+def parse227(resp):
+ '''Parse the '227' response for a PASV request.
+ Raises error_proto if it does not contain '(h1,h2,h3,h4,p1,p2)'
+ Return ('host.addr.as.numbers', port#) tuple.'''
+
+ if resp[:3] != '227':
+ raise error_reply, resp
+ left = resp.find('(')
+ if left < 0: raise error_proto, resp
+ right = resp.find(')', left + 1)
+ if right < 0:
+ raise error_proto, resp # should contain '(h1,h2,h3,h4,p1,p2)'
+ numbers = resp[left+1:right].split(',')
+ if len(numbers) != 6:
+ raise error_proto, resp
+ host = '.'.join(numbers[:4])
+ port = (int(numbers[4]) << 8) + int(numbers[5])
+ return host, port
+
+
+def parse257(resp):
+ '''Parse the '257' response for a MKD or PWD request.
+ This is a response to a MKD or PWD request: a directory name.
+ Returns the directoryname in the 257 reply.'''
+
+ if resp[:3] != '257':
+ raise error_reply, resp
+ if resp[3:5] != ' "':
+ return '' # Not compliant to RFC 959, but UNIX ftpd does this
+ dirname = ''
+ i = 5
+ n = len(resp)
+ while i < n:
+ c = resp[i]
+ i = i+1
+ if c == '"':
+ if i >= n or resp[i] != '"':
+ break
+ i = i+1
+ dirname = dirname + c
+ return dirname
+
+
+def print_line(line):
+ '''Default retrlines callback to print a line.'''
+ print line
+
+
+def ftpcp(source, sourcename, target, targetname = '', type = 'I'):
+ '''Copy file from one FTP-instance to another.'''
+ if not targetname: targetname = sourcename
+ type = 'TYPE ' + type
+ source.voidcmd(type)
+ target.voidcmd(type)
+ sourcehost, sourceport = parse227(source.sendcmd('PASV'))
+ target.sendport(sourcehost, sourceport)
+ # RFC 959: the user must "listen" [...] BEFORE sending the
+ # transfer request.
+ # So: STOR before RETR, because here the target is a "user".
+ treply = target.sendcmd('STOR ' + targetname)
+ if treply[:3] not in ('125', '150'): raise error_proto # RFC 959
+ sreply = source.sendcmd('RETR ' + sourcename)
+ if sreply[:3] not in ('125', '150'): raise error_proto # RFC 959
+ source.voidresp()
+ target.voidresp()
+
+
+class Netrc:
+ """Class to parse & provide access to 'netrc' format files.
+
+ See the netrc(4) man page for information on the file format.
+
+ WARNING: This class is obsolete -- use module netrc instead.
+
+ """
+ __defuser = None
+ __defpasswd = None
+ __defacct = None
+
+ def __init__(self, filename=None):
+ if not filename:
+ if os.environ.has_key("HOME"):
+ filename = os.path.join(os.environ["HOME"],
+ ".netrc")
+ else:
+ raise IOError, \
+ "specify file to load or set $HOME"
+ self.__hosts = {}
+ self.__macros = {}
+ fp = open(filename, "r")
+ in_macro = 0
+ while 1:
+ line = fp.readline()
+ if not line: break
+ if in_macro and line.strip():
+ macro_lines.append(line)
+ continue
+ elif in_macro:
+ self.__macros[macro_name] = tuple(macro_lines)
+ in_macro = 0
+ words = line.split()
+ host = user = passwd = acct = None
+ default = 0
+ i = 0
+ while i < len(words):
+ w1 = words[i]
+ if i+1 < len(words):
+ w2 = words[i + 1]
+ else:
+ w2 = None
+ if w1 == 'default':
+ default = 1
+ elif w1 == 'machine' and w2:
+ host = w2.lower()
+ i = i + 1
+ elif w1 == 'login' and w2:
+ user = w2
+ i = i + 1
+ elif w1 == 'password' and w2:
+ passwd = w2
+ i = i + 1
+ elif w1 == 'account' and w2:
+ acct = w2
+ i = i + 1
+ elif w1 == 'macdef' and w2:
+ macro_name = w2
+ macro_lines = []
+ in_macro = 1
+ break
+ i = i + 1
+ if default:
+ self.__defuser = user or self.__defuser
+ self.__defpasswd = passwd or self.__defpasswd
+ self.__defacct = acct or self.__defacct
+ if host:
+ if self.__hosts.has_key(host):
+ ouser, opasswd, oacct = \
+ self.__hosts[host]
+ user = user or ouser
+ passwd = passwd or opasswd
+ acct = acct or oacct
+ self.__hosts[host] = user, passwd, acct
+ fp.close()
+
+ def get_hosts(self):
+ """Return a list of hosts mentioned in the .netrc file."""
+ return self.__hosts.keys()
+
+ def get_account(self, host):
+ """Returns login information for the named host.
+
+ The return value is a triple containing userid,
+ password, and the accounting field.
+
+ """
+ host = host.lower()
+ user = passwd = acct = None
+ if self.__hosts.has_key(host):
+ user, passwd, acct = self.__hosts[host]
+ user = user or self.__defuser
+ passwd = passwd or self.__defpasswd
+ acct = acct or self.__defacct
+ return user, passwd, acct
+
+ def get_macros(self):
+ """Return a list of all defined macro names."""
+ return self.__macros.keys()
+
+ def get_macro(self, macro):
+ """Return a sequence of lines which define a named macro."""
+ return self.__macros[macro]
+
+
+
+def test():
+ '''Test program.
+ Usage: ftp [-d] [-r[file]] host [-l[dir]] [-d[dir]] [-p] [file] ...'''
+
+ debugging = 0
+ rcfile = None
+ while sys.argv[1] == '-d':
+ debugging = debugging+1
+ del sys.argv[1]
+ if sys.argv[1][:2] == '-r':
+ # get name of alternate ~/.netrc file:
+ rcfile = sys.argv[1][2:]
+ del sys.argv[1]
+ host = sys.argv[1]
+ ftp = FTP(host)
+ ftp.set_debuglevel(debugging)
+ userid = passwd = acct = ''
+ try:
+ netrc = Netrc(rcfile)
+ except IOError:
+ if rcfile is not None:
+ sys.stderr.write("Could not open account file"
+ " -- using anonymous login.")
+ else:
+ try:
+ userid, passwd, acct = netrc.get_account(host)
+ except KeyError:
+ # no account for host
+ sys.stderr.write(
+ "No account -- using anonymous login.")
+ ftp.login(userid, passwd, acct)
+ for file in sys.argv[2:]:
+ if file[:2] == '-l':
+ ftp.dir(file[2:])
+ elif file[:2] == '-d':
+ cmd = 'CWD'
+ if file[2:]: cmd = cmd + ' ' + file[2:]
+ resp = ftp.sendcmd(cmd)
+ elif file == '-p':
+ ftp.set_pasv(not ftp.passiveserver)
+ else:
+ ftp.retrbinary('RETR ' + file, \
+ sys.stdout.write, 1024)
+ ftp.quit()
+
+
+if __name__ == '__main__':
+ test()
diff --git a/lib/jython/Lib/getopt.py b/lib/jython/Lib/getopt.py new file mode 100644 index 000000000..20d8fcf6c --- /dev/null +++ b/lib/jython/Lib/getopt.py @@ -0,0 +1,143 @@ +"""Parser for command line options.
+
+This module helps scripts to parse the command line arguments in
+sys.argv. It supports the same conventions as the Unix getopt()
+function (including the special meanings of arguments of the form `-'
+and `--'). Long options similar to those supported by GNU software
+may be used as well via an optional third argument. This module
+provides a single function and an exception:
+
+getopt() -- Parse command line options
+GetoptError -- exception (class) raised with 'opt' attribute, which is the
+option involved with the exception.
+"""
+
+# Long option support added by Lars Wirzenius <liw@iki.fi>.
+
+# Gerrit Holl <gerrit@nl.linux.org> moved the string-based exceptions
+# to class-based exceptions.
+
+__all__ = ["GetoptError","error","getopt"]
+
+class GetoptError(Exception):
+ opt = ''
+ msg = ''
+ def __init__(self, msg, opt):
+ self.msg = msg
+ self.opt = opt
+ Exception.__init__(self, msg, opt)
+
+ def __str__(self):
+ return self.msg
+
+error = GetoptError # backward compatibility
+
+def getopt(args, shortopts, longopts = []):
+ """getopt(args, options[, long_options]) -> opts, args
+
+ Parses command line options and parameter list. args is the
+ argument list to be parsed, without the leading reference to the
+ running program. Typically, this means "sys.argv[1:]". shortopts
+ is the string of option letters that the script wants to
+ recognize, with options that require an argument followed by a
+ colon (i.e., the same format that Unix getopt() uses). If
+ specified, longopts is a list of strings with the names of the
+ long options which should be supported. The leading '--'
+ characters should not be included in the option name. Options
+ which require an argument should be followed by an equal sign
+ ('=').
+
+ The return value consists of two elements: the first is a list of
+ (option, value) pairs; the second is the list of program arguments
+ left after the option list was stripped (this is a trailing slice
+ of the first argument). Each option-and-value pair returned has
+ the option as its first element, prefixed with a hyphen (e.g.,
+ '-x'), and the option argument as its second element, or an empty
+ string if the option has no argument. The options occur in the
+ list in the same order in which they were found, thus allowing
+ multiple occurrences. Long and short options may be mixed.
+
+ """
+
+ opts = []
+ if type(longopts) == type(""):
+ longopts = [longopts]
+ else:
+ longopts = list(longopts)
+ while args and args[0].startswith('-') and args[0] != '-':
+ if args[0] == '--':
+ args = args[1:]
+ break
+ if args[0][:2] == '--':
+ opts, args = do_longs(opts, args[0][2:], longopts, args[1:])
+ else:
+ opts, args = do_shorts(opts, args[0][1:], shortopts, args[1:])
+
+ return opts, args
+
+def do_longs(opts, opt, longopts, args):
+ try:
+ i = opt.index('=')
+ except ValueError:
+ optarg = None
+ else:
+ opt, optarg = opt[:i], opt[i+1:]
+
+ has_arg, opt = long_has_args(opt, longopts)
+ if has_arg:
+ if optarg is None:
+ if not args:
+ raise GetoptError('option --%s requires argument' % opt, opt)
+ optarg, args = args[0], args[1:]
+ elif optarg:
+ raise GetoptError('option --%s must not have an argument' % opt, opt)
+ opts.append(('--' + opt, optarg or ''))
+ return opts, args
+
+# Return:
+# has_arg?
+# full option name
+def long_has_args(opt, longopts):
+ possibilities = [o for o in longopts if o.startswith(opt)]
+ if not possibilities:
+ raise GetoptError('option --%s not recognized' % opt, opt)
+ # Is there an exact match?
+ if opt in possibilities:
+ return 0, opt
+ elif opt + '=' in possibilities:
+ return 1, opt
+ # No exact match, so better be unique.
+ if len(possibilities) > 1:
+ # XXX since possibilities contains all valid continuations, might be
+ # nice to work them into the error msg
+ raise GetoptError('option --%s not a unique prefix' % opt, opt)
+ assert len(possibilities) == 1
+ unique_match = possibilities[0]
+ has_arg = unique_match.endswith('=')
+ if has_arg:
+ unique_match = unique_match[:-1]
+ return has_arg, unique_match
+
+def do_shorts(opts, optstring, shortopts, args):
+ while optstring != '':
+ opt, optstring = optstring[0], optstring[1:]
+ if short_has_arg(opt, shortopts):
+ if optstring == '':
+ if not args:
+ raise GetoptError('option -%s requires argument' % opt, opt)
+ optstring, args = args[0], args[1:]
+ optarg, optstring = optstring, ''
+ else:
+ optarg = ''
+ opts.append(('-' + opt, optarg))
+ return opts, args
+
+def short_has_arg(opt, shortopts):
+ for i in range(len(shortopts)):
+ if opt == shortopts[i] != ':':
+ return shortopts[i+1:i+2] == ':'
+ raise GetoptError('option -%s not recognized' % opt, opt)
+
+if __name__ == '__main__':
+ import sys
+ print getopt(sys.argv[1:], "a:b", ["alpha=", "beta"])
diff --git a/lib/jython/Lib/glob.py b/lib/jython/Lib/glob.py new file mode 100644 index 000000000..3ddbd78c2 --- /dev/null +++ b/lib/jython/Lib/glob.py @@ -0,0 +1,57 @@ +"""Filename globbing utility."""
+
+import os
+import fnmatch
+import re
+
+__all__ = ["glob"]
+
+def glob(pathname):
+ """Return a list of paths matching a pathname pattern.
+
+ The pattern may contain simple shell-style wildcards a la fnmatch.
+
+ """
+ if not has_magic(pathname):
+ if os.path.exists(pathname):
+ return [pathname]
+ else:
+ return []
+ dirname, basename = os.path.split(pathname)
+ if has_magic(dirname):
+ list = glob(dirname)
+ else:
+ list = [dirname]
+ if not has_magic(basename):
+ result = []
+ for dirname in list:
+ if basename or os.path.isdir(dirname):
+ name = os.path.join(dirname, basename)
+ if os.path.exists(name):
+ result.append(name)
+ else:
+ result = []
+ for dirname in list:
+ sublist = glob1(dirname, basename)
+ for name in sublist:
+ result.append(os.path.join(dirname, name))
+ return result
+
+def glob1(dirname, pattern):
+ if not dirname: dirname = os.curdir
+ try:
+ names = os.listdir(dirname)
+ except os.error:
+ return []
+ result = []
+ for name in names:
+ if name[0] != '.' or pattern[0] == '.':
+ if fnmatch.fnmatch(name, pattern):
+ result.append(name)
+ return result
+
+
+magic_check = re.compile('[*?[]')
+
+def has_magic(s):
+ return magic_check.search(s) is not None
diff --git a/lib/jython/Lib/gopherlib.py b/lib/jython/Lib/gopherlib.py new file mode 100644 index 000000000..a93a01af1 --- /dev/null +++ b/lib/jython/Lib/gopherlib.py @@ -0,0 +1,206 @@ +"""Gopher protocol client interface."""
+
+__all__ = ["send_selector","send_query"]
+
+# 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 = '<'
+
+
+_names = dir()
+_type_to_name_map = {}
+def type_to_name(gtype):
+ """Map all file types to strings; unknown types become TYPE='x'."""
+ global _type_to_name_map
+ if _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'
+
+def send_selector(selector, host, port = 0):
+ """Send a selector to a given host and port, return a file with the reply."""
+ import socket
+ if not port:
+ i = host.find(':')
+ if i >= 0:
+ host, port = host[:i], int(host[i+1:])
+ if not port:
+ port = DEF_PORT
+ elif type(port) == type(''):
+ port = int(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')
+
+def send_query(selector, query, host, port = 0):
+ """Send a selector and a query string."""
+ return send_selector(selector + '\t' + query, host, port)
+
+def path_to_selector(path):
+ """Takes a path as returned by urlparse and returns the appropriate selector."""
+ if path=="/":
+ return "/"
+ else:
+ return path[2:] # Cuts initial slash and data type identifier
+
+def path_to_datatype_name(path):
+ """Takes a path as returned by urlparse and maps it to a string.
+ See section 3.4 of RFC 1738 for details."""
+ if path=="/":
+ # No way to tell, although "INDEX" is likely
+ return "TYPE='unknown'"
+ else:
+ return type_to_name(path[1])
+
+# The following functions interpret the data returned by the gopher
+# server according to the expected type, e.g. textfile or directory
+
+def get_directory(f):
+ """Get a directory in the form of a list of entries."""
+ 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 = line[1:].split(TAB)
+ if len(parts) < 4:
+ print '(Bad line from server:', `line`, ')'
+ continue
+ if len(parts) > 4:
+ if parts[4:] != ['+']:
+ print '(Extra info from server:',
+ print parts[4:], ')'
+ else:
+ parts.append('')
+ parts.insert(0, gtype)
+ list.append(parts)
+ return list
+
+def get_textfile(f):
+ """Get a text file as a list of lines, with trailing CRLF stripped."""
+ list = []
+ get_alt_textfile(f, list.append)
+ return list
+
+def get_alt_textfile(f, func):
+ """Get a text file and pass each line to a function, with trailing CRLF stripped."""
+ 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)
+
+def get_binary(f):
+ """Get a binary file as one solid data block."""
+ data = f.read()
+ return data
+
+def get_alt_binary(f, func, blocksize):
+ """Get a binary file and pass each block to a function."""
+ while 1:
+ data = f.read(blocksize)
+ if not data:
+ break
+ func(data)
+
+def test():
+ """Trivial test program."""
+ 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/jython/Lib/gzip.py b/lib/jython/Lib/gzip.py new file mode 100644 index 000000000..2b23dfa3e --- /dev/null +++ b/lib/jython/Lib/gzip.py @@ -0,0 +1,359 @@ +"""Functions that read and write gzipped files.
+
+The user of the file doesn't have to worry about the compression,
+but random access is not allowed."""
+
+# based on Andrew Kuchling's minigzip.py distributed with the zlib module
+
+import struct, sys, time
+import zlib
+import __builtin__
+
+__all__ = ["GzipFile","open"]
+
+FTEXT, FHCRC, FEXTRA, FNAME, FCOMMENT = 1, 2, 4, 8, 16
+
+READ, WRITE = 1, 2
+
+def write32(output, value):
+ output.write(struct.pack("<l", value))
+
+def write32u(output, value):
+ if value < 0:
+ value = value + 0x100000000L
+ output.write(struct.pack("<L", value))
+
+def read32(input):
+ return struct.unpack("<l", input.read(4))[0]
+
+def open(filename, mode="rb", compresslevel=9):
+ return GzipFile(filename, mode, compresslevel)
+
+class GzipFile:
+
+ myfileobj = None
+
+ def __init__(self, filename=None, mode=None,
+ compresslevel=9, fileobj=None):
+ if fileobj is None:
+ fileobj = self.myfileobj = __builtin__.open(filename, mode or 'rb')
+ if filename is None:
+ if hasattr(fileobj, 'name'): filename = fileobj.name
+ else: filename = ''
+ if mode is None:
+ if hasattr(fileobj, 'mode'): mode = fileobj.mode
+ else: mode = 'rb'
+
+ if mode[0:1] == 'r':
+ self.mode = READ
+ # Set flag indicating start of a new member
+ self._new_member = 1
+ self.extrabuf = ""
+ self.extrasize = 0
+ self.filename = filename
+
+ elif mode[0:1] == 'w' or mode[0:1] == 'a':
+ self.mode = WRITE
+ self._init_write(filename)
+ self.compress = zlib.compressobj(compresslevel,
+ zlib.DEFLATED,
+ -zlib.MAX_WBITS,
+ zlib.DEF_MEM_LEVEL,
+ 0)
+ else:
+ raise ValueError, "Mode " + mode + " not supported"
+
+ self.fileobj = fileobj
+
+ if self.mode == WRITE:
+ self._write_gzip_header()
+
+ def __repr__(self):
+ s = repr(self.fileobj)
+ return '<gzip ' + s[1:-1] + ' ' + hex(id(self)) + '>'
+
+ def _init_write(self, filename):
+ if filename[-3:] != '.gz':
+ filename = filename + '.gz'
+ self.filename = filename
+ self.crc = zlib.crc32("")
+ self.size = 0
+ self.writebuf = []
+ self.bufsize = 0
+
+ def _write_gzip_header(self):
+ self.fileobj.write('\037\213') # magic header
+ self.fileobj.write('\010') # compression method
+ fname = self.filename[:-3]
+ flags = 0
+ if fname:
+ flags = FNAME
+ self.fileobj.write(chr(flags))
+ write32u(self.fileobj, long(time.time()))
+ self.fileobj.write('\002')
+ self.fileobj.write('\377')
+ if fname:
+ self.fileobj.write(fname + '\000')
+
+ def _init_read(self):
+ self.crc = zlib.crc32("")
+ self.size = 0
+
+ def _read_gzip_header(self):
+ magic = self.fileobj.read(2)
+ if magic != '\037\213':
+ raise IOError, 'Not a gzipped file'
+ method = ord( self.fileobj.read(1) )
+ if method != 8:
+ raise IOError, 'Unknown compression method'
+ flag = ord( self.fileobj.read(1) )
+ # modtime = self.fileobj.read(4)
+ # extraflag = self.fileobj.read(1)
+ # os = self.fileobj.read(1)
+ self.fileobj.read(6)
+
+ if flag & FEXTRA:
+ # Read & discard the extra field, if present
+ xlen=ord(self.fileobj.read(1))
+ xlen=xlen+256*ord(self.fileobj.read(1))
+ self.fileobj.read(xlen)
+ if flag & FNAME:
+ # Read and discard a null-terminated string containing the filename
+ while (1):
+ s=self.fileobj.read(1)
+ if not s or s=='\000': break
+ if flag & FCOMMENT:
+ # Read and discard a null-terminated string containing a comment
+ while (1):
+ s=self.fileobj.read(1)
+ if not s or s=='\000': break
+ if flag & FHCRC:
+ self.fileobj.read(2) # Read & discard the 16-bit header CRC
+
+
+ def write(self,data):
+ if self.fileobj is None:
+ raise ValueError, "write() on closed GzipFile object"
+ if len(data) > 0:
+ self.size = self.size + len(data)
+ self.crc = zlib.crc32(data, self.crc)
+ self.fileobj.write( self.compress.compress(data) )
+
+ def writelines(self,lines):
+ self.write(" ".join(lines))
+
+ def read(self, size=-1):
+ if self.extrasize <= 0 and self.fileobj is None:
+ return ''
+
+ readsize = 1024
+ if size < 0: # get the whole thing
+ try:
+ while 1:
+ self._read(readsize)
+ readsize = readsize * 2
+ except EOFError:
+ size = self.extrasize
+ else: # just get some more of it
+ try:
+ while size > self.extrasize:
+ self._read(readsize)
+ readsize = readsize * 2
+ except EOFError:
+ if size > self.extrasize:
+ size = self.extrasize
+
+ chunk = self.extrabuf[:size]
+ self.extrabuf = self.extrabuf[size:]
+ self.extrasize = self.extrasize - size
+
+ return chunk
+
+ def _unread(self, buf):
+ self.extrabuf = buf + self.extrabuf
+ self.extrasize = len(buf) + self.extrasize
+
+ def _read(self, size=1024):
+ if self.fileobj is None: raise EOFError, "Reached EOF"
+
+ if self._new_member:
+ # If the _new_member flag is set, we have to
+ # jump to the next member, if there is one.
+ #
+ # First, check if we're at the end of the file;
+ # if so, it's time to stop; no more members to read.
+ pos = self.fileobj.tell() # Save current position
+ self.fileobj.seek(0, 2) # Seek to end of file
+ if pos == self.fileobj.tell():
+ self.fileobj = None
+ raise EOFError, "Reached EOF"
+ else:
+ self.fileobj.seek( pos ) # Return to original position
+
+ self._init_read()
+ self._read_gzip_header()
+ self.decompress = zlib.decompressobj(-zlib.MAX_WBITS)
+ self._new_member = 0
+
+ # Read a chunk of data from the file
+ buf = self.fileobj.read(size)
+
+ # If the EOF has been reached, flush the decompression object
+ # and mark this object as finished.
+
+ if buf == "":
+ uncompress = self.decompress.flush()
+ self._read_eof()
+ self.fileobj = None
+ self._add_read_data( uncompress )
+ raise EOFError, 'Reached EOF'
+
+ uncompress = self.decompress.decompress(buf)
+ self._add_read_data( uncompress )
+
+ if self.decompress.unused_data != "":
+ # Ending case: we've come to the end of a member in the file,
+ # so seek back to the start of the unused data, finish up
+ # this member, and read a new gzip header.
+ # (The number of bytes to seek back is the length of the unused
+ # data, minus 8 because _read_eof() will rewind a further 8 bytes)
+ self.fileobj.seek( -len(self.decompress.unused_data)+8, 1)
+
+ # Check the CRC and file size, and set the flag so we read
+ # a new member on the next call
+ self._read_eof()
+ self._new_member = 1
+
+ def _add_read_data(self, data):
+ self.crc = zlib.crc32(data, self.crc)
+ self.extrabuf = self.extrabuf + data
+ self.extrasize = self.extrasize + len(data)
+ self.size = self.size + len(data)
+
+ def _read_eof(self):
+ # We've read to the end of the file, so we have to rewind in order
+ # to reread the 8 bytes containing the CRC and the file size.
+ # We check the that the computed CRC and size of the
+ # uncompressed data matches the stored values.
+ self.fileobj.seek(-8, 1)
+ crc32 = read32(self.fileobj)
+ isize = read32(self.fileobj)
+ if crc32%0x100000000L != self.crc%0x100000000L:
+ raise ValueError, "CRC check failed"
+ elif isize != self.size:
+ raise ValueError, "Incorrect length of data produced"
+
+ def close(self):
+ if self.mode == WRITE:
+ self.fileobj.write(self.compress.flush())
+ write32(self.fileobj, self.crc)
+ write32(self.fileobj, self.size)
+ self.fileobj = None
+ elif self.mode == READ:
+ self.fileobj = None
+ if self.myfileobj:
+ self.myfileobj.close()
+ self.myfileobj = None
+
+ def __del__(self):
+ try:
+ if (self.myfileobj is None and
+ self.fileobj is None):
+ return
+ except AttributeError:
+ return
+ self.close()
+
+ def flush(self):
+ self.fileobj.flush()
+
+ def isatty(self):
+ return 0
+
+ def readline(self, size=-1):
+ if size < 0: size = sys.maxint
+ bufs = []
+ orig_size = size
+ readsize = min(100, size) # Read from the file in small chunks
+ while 1:
+ if size == 0:
+ return "".join(bufs) # Return resulting line
+
+ c = self.read(readsize)
+ i = c.find('\n')
+ if size is not None:
+ # We set i=size to break out of the loop under two
+ # conditions: 1) there's no newline, and the chunk is
+ # larger than size, or 2) there is a newline, but the
+ # resulting line would be longer than 'size'.
+ if i==-1 and len(c) > size: i=size-1
+ elif size <= i: i = size -1
+
+ if i >= 0 or c == '':
+ bufs.append(c[:i+1]) # Add portion of last chunk
+ self._unread(c[i+1:]) # Push back rest of chunk
+ return ''.join(bufs) # Return resulting line
+
+ # Append chunk to list, decrease 'size',
+ bufs.append(c)
+ size = size - len(c)
+ readsize = min(size, readsize * 2)
+
+ def readlines(self, sizehint=0):
+ # Negative numbers result in reading all the lines
+ if sizehint <= 0: sizehint = sys.maxint
+ L = []
+ while sizehint > 0:
+ line = self.readline()
+ if line == "": break
+ L.append( line )
+ sizehint = sizehint - len(line)
+
+ return L
+
+ def writelines(self, L):
+ for line in L:
+ self.write(line)
+
+
+def _test():
+ # Act like gzip; with -d, act like gunzip.
+ # The input file is not deleted, however, nor are any other gzip
+ # options or features supported.
+ import sys
+ args = sys.argv[1:]
+ decompress = args and args[0] == "-d"
+ if decompress:
+ args = args[1:]
+ if not args:
+ args = ["-"]
+ for arg in args:
+ if decompress:
+ if arg == "-":
+ f = GzipFile(filename="", mode="rb", fileobj=sys.stdin)
+ g = sys.stdout
+ else:
+ if arg[-3:] != ".gz":
+ print "filename doesn't end in .gz:", `arg`
+ continue
+ f = open(arg, "rb")
+ g = __builtin__.open(arg[:-3], "wb")
+ else:
+ if arg == "-":
+ f = sys.stdin
+ g = GzipFile(filename="", mode="wb", fileobj=sys.stdout)
+ else:
+ f = __builtin__.open(arg, "rb")
+ g = open(arg + ".gz", "wb")
+ while 1:
+ chunk = f.read(1024)
+ if not chunk:
+ break
+ g.write(chunk)
+ if g is not sys.stdout:
+ g.close()
+ if f is not sys.stdin:
+ f.close()
+
+if __name__ == '__main__':
+ _test()
diff --git a/lib/jython/Lib/htmlentitydefs.py b/lib/jython/Lib/htmlentitydefs.py new file mode 100644 index 000000000..4a26f4c28 --- /dev/null +++ b/lib/jython/Lib/htmlentitydefs.py @@ -0,0 +1,257 @@ +"""HTML character entity references."""
+
+entitydefs = {
+ 'AElig': '\306', # latin capital letter AE = latin capital ligature AE, U+00C6 ISOlat1
+ 'Aacute': '\301', # latin capital letter A with acute, U+00C1 ISOlat1
+ 'Acirc': '\302', # latin capital letter A with circumflex, U+00C2 ISOlat1
+ 'Agrave': '\300', # latin capital letter A with grave = latin capital letter A grave, U+00C0 ISOlat1
+ 'Alpha': 'Α', # greek capital letter alpha, U+0391
+ 'Aring': '\305', # latin capital letter A with ring above = latin capital letter A ring, U+00C5 ISOlat1
+ 'Atilde': '\303', # latin capital letter A with tilde, U+00C3 ISOlat1
+ 'Auml': '\304', # latin capital letter A with diaeresis, U+00C4 ISOlat1
+ 'Beta': 'Β', # greek capital letter beta, U+0392
+ 'Ccedil': '\307', # latin capital letter C with cedilla, U+00C7 ISOlat1
+ 'Chi': 'Χ', # greek capital letter chi, U+03A7
+ 'Dagger': '‡', # double dagger, U+2021 ISOpub
+ 'Delta': 'Δ', # greek capital letter delta, U+0394 ISOgrk3
+ 'ETH': '\320', # latin capital letter ETH, U+00D0 ISOlat1
+ 'Eacute': '\311', # latin capital letter E with acute, U+00C9 ISOlat1
+ 'Ecirc': '\312', # latin capital letter E with circumflex, U+00CA ISOlat1
+ 'Egrave': '\310', # latin capital letter E with grave, U+00C8 ISOlat1
+ 'Epsilon': 'Ε', # greek capital letter epsilon, U+0395
+ 'Eta': 'Η', # greek capital letter eta, U+0397
+ 'Euml': '\313', # latin capital letter E with diaeresis, U+00CB ISOlat1
+ 'Gamma': 'Γ', # greek capital letter gamma, U+0393 ISOgrk3
+ 'Iacute': '\315', # latin capital letter I with acute, U+00CD ISOlat1
+ 'Icirc': '\316', # latin capital letter I with circumflex, U+00CE ISOlat1
+ 'Igrave': '\314', # latin capital letter I with grave, U+00CC ISOlat1
+ 'Iota': 'Ι', # greek capital letter iota, U+0399
+ 'Iuml': '\317', # latin capital letter I with diaeresis, U+00CF ISOlat1
+ 'Kappa': 'Κ', # greek capital letter kappa, U+039A
+ 'Lambda': 'Λ', # greek capital letter lambda, U+039B ISOgrk3
+ 'Mu': 'Μ', # greek capital letter mu, U+039C
+ 'Ntilde': '\321', # latin capital letter N with tilde, U+00D1 ISOlat1
+ 'Nu': 'Ν', # greek capital letter nu, U+039D
+ 'OElig': 'Œ', # latin capital ligature OE, U+0152 ISOlat2
+ 'Oacute': '\323', # latin capital letter O with acute, U+00D3 ISOlat1
+ 'Ocirc': '\324', # latin capital letter O with circumflex, U+00D4 ISOlat1
+ 'Ograve': '\322', # latin capital letter O with grave, U+00D2 ISOlat1
+ 'Omega': 'Ω', # greek capital letter omega, U+03A9 ISOgrk3
+ 'Omicron': 'Ο', # greek capital letter omicron, U+039F
+ 'Oslash': '\330', # latin capital letter O with stroke = latin capital letter O slash, U+00D8 ISOlat1
+ 'Otilde': '\325', # latin capital letter O with tilde, U+00D5 ISOlat1
+ 'Ouml': '\326', # latin capital letter O with diaeresis, U+00D6 ISOlat1
+ 'Phi': 'Φ', # greek capital letter phi, U+03A6 ISOgrk3
+ 'Pi': 'Π', # greek capital letter pi, U+03A0 ISOgrk3
+ 'Prime': '″', # double prime = seconds = inches, U+2033 ISOtech
+ 'Psi': 'Ψ', # greek capital letter psi, U+03A8 ISOgrk3
+ 'Rho': 'Ρ', # greek capital letter rho, U+03A1
+ 'Scaron': 'Š', # latin capital letter S with caron, U+0160 ISOlat2
+ 'Sigma': 'Σ', # greek capital letter sigma, U+03A3 ISOgrk3
+ 'THORN': '\336', # latin capital letter THORN, U+00DE ISOlat1
+ 'Tau': 'Τ', # greek capital letter tau, U+03A4
+ 'Theta': 'Θ', # greek capital letter theta, U+0398 ISOgrk3
+ 'Uacute': '\332', # latin capital letter U with acute, U+00DA ISOlat1
+ 'Ucirc': '\333', # latin capital letter U with circumflex, U+00DB ISOlat1
+ 'Ugrave': '\331', # latin capital letter U with grave, U+00D9 ISOlat1
+ 'Upsilon': 'Υ', # greek capital letter upsilon, U+03A5 ISOgrk3
+ 'Uuml': '\334', # latin capital letter U with diaeresis, U+00DC ISOlat1
+ 'Xi': 'Ξ', # greek capital letter xi, U+039E ISOgrk3
+ 'Yacute': '\335', # latin capital letter Y with acute, U+00DD ISOlat1
+ 'Yuml': 'Ÿ', # latin capital letter Y with diaeresis, U+0178 ISOlat2
+ 'Zeta': 'Ζ', # greek capital letter zeta, U+0396
+ 'aacute': '\341', # latin small letter a with acute, U+00E1 ISOlat1
+ 'acirc': '\342', # latin small letter a with circumflex, U+00E2 ISOlat1
+ 'acute': '\264', # acute accent = spacing acute, U+00B4 ISOdia
+ 'aelig': '\346', # latin small letter ae = latin small ligature ae, U+00E6 ISOlat1
+ 'agrave': '\340', # latin small letter a with grave = latin small letter a grave, U+00E0 ISOlat1
+ 'alefsym': 'ℵ', # alef symbol = first transfinite cardinal, U+2135 NEW
+ 'alpha': 'α', # greek small letter alpha, U+03B1 ISOgrk3
+ 'amp': '\46', # ampersand, U+0026 ISOnum
+ 'and': '∧', # logical and = wedge, U+2227 ISOtech
+ 'ang': '∠', # angle, U+2220 ISOamso
+ 'aring': '\345', # latin small letter a with ring above = latin small letter a ring, U+00E5 ISOlat1
+ 'asymp': '≈', # almost equal to = asymptotic to, U+2248 ISOamsr
+ 'atilde': '\343', # latin small letter a with tilde, U+00E3 ISOlat1
+ 'auml': '\344', # latin small letter a with diaeresis, U+00E4 ISOlat1
+ 'bdquo': '„', # double low-9 quotation mark, U+201E NEW
+ 'beta': 'β', # greek small letter beta, U+03B2 ISOgrk3
+ 'brvbar': '\246', # broken bar = broken vertical bar, U+00A6 ISOnum
+ 'bull': '•', # bullet = black small circle, U+2022 ISOpub
+ 'cap': '∩', # intersection = cap, U+2229 ISOtech
+ 'ccedil': '\347', # latin small letter c with cedilla, U+00E7 ISOlat1
+ 'cedil': '\270', # cedilla = spacing cedilla, U+00B8 ISOdia
+ 'cent': '\242', # cent sign, U+00A2 ISOnum
+ 'chi': 'χ', # greek small letter chi, U+03C7 ISOgrk3
+ 'circ': 'ˆ', # modifier letter circumflex accent, U+02C6 ISOpub
+ 'clubs': '♣', # black club suit = shamrock, U+2663 ISOpub
+ 'cong': '≅', # approximately equal to, U+2245 ISOtech
+ 'copy': '\251', # copyright sign, U+00A9 ISOnum
+ 'crarr': '↵', # downwards arrow with corner leftwards = carriage return, U+21B5 NEW
+ 'cup': '∪', # union = cup, U+222A ISOtech
+ 'curren': '\244', # currency sign, U+00A4 ISOnum
+ 'dArr': '⇓', # downwards double arrow, U+21D3 ISOamsa
+ 'dagger': '†', # dagger, U+2020 ISOpub
+ 'darr': '↓', # downwards arrow, U+2193 ISOnum
+ 'deg': '\260', # degree sign, U+00B0 ISOnum
+ 'delta': 'δ', # greek small letter delta, U+03B4 ISOgrk3
+ 'diams': '♦', # black diamond suit, U+2666 ISOpub
+ 'divide': '\367', # division sign, U+00F7 ISOnum
+ 'eacute': '\351', # latin small letter e with acute, U+00E9 ISOlat1
+ 'ecirc': '\352', # latin small letter e with circumflex, U+00EA ISOlat1
+ 'egrave': '\350', # latin small letter e with grave, U+00E8 ISOlat1
+ 'empty': '∅', # empty set = null set = diameter, U+2205 ISOamso
+ 'emsp': ' ', # em space, U+2003 ISOpub
+ 'ensp': ' ', # en space, U+2002 ISOpub
+ 'epsilon': 'ε', # greek small letter epsilon, U+03B5 ISOgrk3
+ 'equiv': '≡', # identical to, U+2261 ISOtech
+ 'eta': 'η', # greek small letter eta, U+03B7 ISOgrk3
+ 'eth': '\360', # latin small letter eth, U+00F0 ISOlat1
+ 'euml': '\353', # latin small letter e with diaeresis, U+00EB ISOlat1
+ 'euro': '€', # euro sign, U+20AC NEW
+ 'exist': '∃', # there exists, U+2203 ISOtech
+ 'fnof': 'ƒ', # latin small f with hook = function = florin, U+0192 ISOtech
+ 'forall': '∀', # for all, U+2200 ISOtech
+ 'frac12': '\275', # vulgar fraction one half = fraction one half, U+00BD ISOnum
+ 'frac14': '\274', # vulgar fraction one quarter = fraction one quarter, U+00BC ISOnum
+ 'frac34': '\276', # vulgar fraction three quarters = fraction three quarters, U+00BE ISOnum
+ 'frasl': '⁄', # fraction slash, U+2044 NEW
+ 'gamma': 'γ', # greek small letter gamma, U+03B3 ISOgrk3
+ 'ge': '≥', # greater-than or equal to, U+2265 ISOtech
+ 'gt': '\76', # greater-than sign, U+003E ISOnum
+ 'hArr': '⇔', # left right double arrow, U+21D4 ISOamsa
+ 'harr': '↔', # left right arrow, U+2194 ISOamsa
+ 'hearts': '♥', # black heart suit = valentine, U+2665 ISOpub
+ 'hellip': '…', # horizontal ellipsis = three dot leader, U+2026 ISOpub
+ 'iacute': '\355', # latin small letter i with acute, U+00ED ISOlat1
+ 'icirc': '\356', # latin small letter i with circumflex, U+00EE ISOlat1
+ 'iexcl': '\241', # inverted exclamation mark, U+00A1 ISOnum
+ 'igrave': '\354', # latin small letter i with grave, U+00EC ISOlat1
+ 'image': 'ℑ', # blackletter capital I = imaginary part, U+2111 ISOamso
+ 'infin': '∞', # infinity, U+221E ISOtech
+ 'int': '∫', # integral, U+222B ISOtech
+ 'iota': 'ι', # greek small letter iota, U+03B9 ISOgrk3
+ 'iquest': '\277', # inverted question mark = turned question mark, U+00BF ISOnum
+ 'isin': '∈', # element of, U+2208 ISOtech
+ 'iuml': '\357', # latin small letter i with diaeresis, U+00EF ISOlat1
+ 'kappa': 'κ', # greek small letter kappa, U+03BA ISOgrk3
+ 'lArr': '⇐', # leftwards double arrow, U+21D0 ISOtech
+ 'lambda': 'λ', # greek small letter lambda, U+03BB ISOgrk3
+ 'lang': '〈', # left-pointing angle bracket = bra, U+2329 ISOtech
+ 'laquo': '\253', # left-pointing double angle quotation mark = left pointing guillemet, U+00AB ISOnum
+ 'larr': '←', # leftwards arrow, U+2190 ISOnum
+ 'lceil': '⌈', # left ceiling = apl upstile, U+2308 ISOamsc
+ 'ldquo': '“', # left double quotation mark, U+201C ISOnum
+ 'le': '≤', # less-than or equal to, U+2264 ISOtech
+ 'lfloor': '⌊', # left floor = apl downstile, U+230A ISOamsc
+ 'lowast': '∗', # asterisk operator, U+2217 ISOtech
+ 'loz': '◊', # lozenge, U+25CA ISOpub
+ 'lrm': '‎', # left-to-right mark, U+200E NEW RFC 2070
+ 'lsaquo': '‹', # single left-pointing angle quotation mark, U+2039 ISO proposed
+ 'lsquo': '‘', # left single quotation mark, U+2018 ISOnum
+ 'lt': '\74', # less-than sign, U+003C ISOnum
+ 'macr': '\257', # macron = spacing macron = overline = APL overbar, U+00AF ISOdia
+ 'mdash': '—', # em dash, U+2014 ISOpub
+ 'micro': '\265', # micro sign, U+00B5 ISOnum
+ 'middot': '\267', # middle dot = Georgian comma = Greek middle dot, U+00B7 ISOnum
+ 'minus': '−', # minus sign, U+2212 ISOtech
+ 'mu': 'μ', # greek small letter mu, U+03BC ISOgrk3
+ 'nabla': '∇', # nabla = backward difference, U+2207 ISOtech
+ 'nbsp': '\240', # no-break space = non-breaking space, U+00A0 ISOnum
+ 'ndash': '–', # en dash, U+2013 ISOpub
+ 'ne': '≠', # not equal to, U+2260 ISOtech
+ 'ni': '∋', # contains as member, U+220B ISOtech
+ 'not': '\254', # not sign, U+00AC ISOnum
+ 'notin': '∉', # not an element of, U+2209 ISOtech
+ 'nsub': '⊄', # not a subset of, U+2284 ISOamsn
+ 'ntilde': '\361', # latin small letter n with tilde, U+00F1 ISOlat1
+ 'nu': 'ν', # greek small letter nu, U+03BD ISOgrk3
+ 'oacute': '\363', # latin small letter o with acute, U+00F3 ISOlat1
+ 'ocirc': '\364', # latin small letter o with circumflex, U+00F4 ISOlat1
+ 'oelig': 'œ', # latin small ligature oe, U+0153 ISOlat2
+ 'ograve': '\362', # latin small letter o with grave, U+00F2 ISOlat1
+ 'oline': '‾', # overline = spacing overscore, U+203E NEW
+ 'omega': 'ω', # greek small letter omega, U+03C9 ISOgrk3
+ 'omicron': 'ο', # greek small letter omicron, U+03BF NEW
+ 'oplus': '⊕', # circled plus = direct sum, U+2295 ISOamsb
+ 'or': '∨', # logical or = vee, U+2228 ISOtech
+ 'ordf': '\252', # feminine ordinal indicator, U+00AA ISOnum
+ 'ordm': '\272', # masculine ordinal indicator, U+00BA ISOnum
+ 'oslash': '\370', # latin small letter o with stroke, = latin small letter o slash, U+00F8 ISOlat1
+ 'otilde': '\365', # latin small letter o with tilde, U+00F5 ISOlat1
+ 'otimes': '⊗', # circled times = vector product, U+2297 ISOamsb
+ 'ouml': '\366', # latin small letter o with diaeresis, U+00F6 ISOlat1
+ 'para': '\266', # pilcrow sign = paragraph sign, U+00B6 ISOnum
+ 'part': '∂', # partial differential, U+2202 ISOtech
+ 'permil': '‰', # per mille sign, U+2030 ISOtech
+ 'perp': '⊥', # up tack = orthogonal to = perpendicular, U+22A5 ISOtech
+ 'phi': 'φ', # greek small letter phi, U+03C6 ISOgrk3
+ 'pi': 'π', # greek small letter pi, U+03C0 ISOgrk3
+ 'piv': 'ϖ', # greek pi symbol, U+03D6 ISOgrk3
+ 'plusmn': '\261', # plus-minus sign = plus-or-minus sign, U+00B1 ISOnum
+ 'pound': '\243', # pound sign, U+00A3 ISOnum
+ 'prime': '′', # prime = minutes = feet, U+2032 ISOtech
+ 'prod': '∏', # n-ary product = product sign, U+220F ISOamsb
+ 'prop': '∝', # proportional to, U+221D ISOtech
+ 'psi': 'ψ', # greek small letter psi, U+03C8 ISOgrk3
+ 'quot': '\42', # quotation mark = APL quote, U+0022 ISOnum
+ 'rArr': '⇒', # rightwards double arrow, U+21D2 ISOtech
+ 'radic': '√', # square root = radical sign, U+221A ISOtech
+ 'rang': '〉', # right-pointing angle bracket = ket, U+232A ISOtech
+ 'raquo': '\273', # right-pointing double angle quotation mark = right pointing guillemet, U+00BB ISOnum
+ 'rarr': '→', # rightwards arrow, U+2192 ISOnum
+ 'rceil': '⌉', # right ceiling, U+2309 ISOamsc
+ 'rdquo': '”', # right double quotation mark, U+201D ISOnum
+ 'real': 'ℜ', # blackletter capital R = real part symbol, U+211C ISOamso
+ 'reg': '\256', # registered sign = registered trade mark sign, U+00AE ISOnum
+ 'rfloor': '⌋', # right floor, U+230B ISOamsc
+ 'rho': 'ρ', # greek small letter rho, U+03C1 ISOgrk3
+ 'rlm': '‏', # right-to-left mark, U+200F NEW RFC 2070
+ 'rsaquo': '›', # single right-pointing angle quotation mark, U+203A ISO proposed
+ 'rsquo': '’', # right single quotation mark, U+2019 ISOnum
+ 'sbquo': '‚', # single low-9 quotation mark, U+201A NEW
+ 'scaron': 'š', # latin small letter s with caron, U+0161 ISOlat2
+ 'sdot': '⋅', # dot operator, U+22C5 ISOamsb
+ 'sect': '\247', # section sign, U+00A7 ISOnum
+ 'shy': '\255', # soft hyphen = discretionary hyphen, U+00AD ISOnum
+ 'sigma': 'σ', # greek small letter sigma, U+03C3 ISOgrk3
+ 'sigmaf': 'ς', # greek small letter final sigma, U+03C2 ISOgrk3
+ 'sim': '∼', # tilde operator = varies with = similar to, U+223C ISOtech
+ 'spades': '♠', # black spade suit, U+2660 ISOpub
+ 'sub': '⊂', # subset of, U+2282 ISOtech
+ 'sube': '⊆', # subset of or equal to, U+2286 ISOtech
+ 'sum': '∑', # n-ary sumation, U+2211 ISOamsb
+ 'sup': '⊃', # superset of, U+2283 ISOtech
+ 'sup1': '\271', # superscript one = superscript digit one, U+00B9 ISOnum
+ 'sup2': '\262', # superscript two = superscript digit two = squared, U+00B2 ISOnum
+ 'sup3': '\263', # superscript three = superscript digit three = cubed, U+00B3 ISOnum
+ 'supe': '⊇', # superset of or equal to, U+2287 ISOtech
+ 'szlig': '\337', # latin small letter sharp s = ess-zed, U+00DF ISOlat1
+ 'tau': 'τ', # greek small letter tau, U+03C4 ISOgrk3
+ 'there4': '∴', # therefore, U+2234 ISOtech
+ 'theta': 'θ', # greek small letter theta, U+03B8 ISOgrk3
+ 'thetasym': 'ϑ', # greek small letter theta symbol, U+03D1 NEW
+ 'thinsp': ' ', # thin space, U+2009 ISOpub
+ 'thorn': '\376', # latin small letter thorn with, U+00FE ISOlat1
+ 'tilde': '˜', # small tilde, U+02DC ISOdia
+ 'times': '\327', # multiplication sign, U+00D7 ISOnum
+ 'trade': '™', # trade mark sign, U+2122 ISOnum
+ 'uArr': '⇑', # upwards double arrow, U+21D1 ISOamsa
+ 'uacute': '\372', # latin small letter u with acute, U+00FA ISOlat1
+ 'uarr': '↑', # upwards arrow, U+2191 ISOnum
+ 'ucirc': '\373', # latin small letter u with circumflex, U+00FB ISOlat1
+ 'ugrave': '\371', # latin small letter u with grave, U+00F9 ISOlat1
+ 'uml': '\250', # diaeresis = spacing diaeresis, U+00A8 ISOdia
+ 'upsih': 'ϒ', # greek upsilon with hook symbol, U+03D2 NEW
+ 'upsilon': 'υ', # greek small letter upsilon, U+03C5 ISOgrk3
+ 'uuml': '\374', # latin small letter u with diaeresis, U+00FC ISOlat1
+ 'weierp': '℘', # script capital P = power set = Weierstrass p, U+2118 ISOamso
+ 'xi': 'ξ', # greek small letter xi, U+03BE ISOgrk3
+ 'yacute': '\375', # latin small letter y with acute, U+00FD ISOlat1
+ 'yen': '\245', # yen sign = yuan sign, U+00A5 ISOnum
+ 'yuml': '\377', # latin small letter y with diaeresis, U+00FF ISOlat1
+ 'zeta': 'ζ', # greek small letter zeta, U+03B6 ISOgrk3
+ 'zwj': '‍', # zero width joiner, U+200D NEW RFC 2070
+ 'zwnj': '‌', # zero width non-joiner, U+200C NEW RFC 2070
+
+}
diff --git a/lib/jython/Lib/htmllib.py b/lib/jython/Lib/htmllib.py new file mode 100644 index 000000000..1ab49a119 --- /dev/null +++ b/lib/jython/Lib/htmllib.py @@ -0,0 +1,426 @@ +"""HTML 2.0 parser.
+
+See the HTML 2.0 specification:
+http://www.w3.org/hypertext/WWW/MarkUp/html-spec/html-spec_toc.html
+"""
+
+
+from sgmllib import SGMLParser
+from formatter import AS_IS
+
+__all__ = ["HTMLParser"]
+
+class HTMLParser(SGMLParser):
+
+ from htmlentitydefs import entitydefs
+
+ def __init__(self, formatter, verbose=0):
+ SGMLParser.__init__(self, verbose)
+ self.formatter = formatter
+ self.savedata = None
+ self.isindex = 0
+ self.title = None
+ self.base = None
+ self.anchor = None
+ self.anchorlist = []
+ self.nofill = 0
+ self.list_stack = []
+
+ # ------ Methods used internally; some may be overridden
+
+ # --- Formatter interface, taking care of 'savedata' mode;
+ # shouldn't need to be overridden
+
+ def handle_data(self, data):
+ if self.savedata is not None:
+ self.savedata = self.savedata + data
+ else:
+ if self.nofill:
+ self.formatter.add_literal_data(data)
+ else:
+ self.formatter.add_flowing_data(data)
+
+ # --- Hooks to save data; shouldn't need to be overridden
+
+ def save_bgn(self):
+ self.savedata = ''
+
+ def save_end(self):
+ data = self.savedata
+ self.savedata = None
+ if not self.nofill:
+ data = ' '.join(data.split())
+ return data
+
+ # --- Hooks for anchors; should probably be overridden
+
+ def anchor_bgn(self, href, name, type):
+ self.anchor = href
+ if self.anchor:
+ self.anchorlist.append(href)
+
+ def anchor_end(self):
+ if self.anchor:
+ self.handle_data("[%d]" % len(self.anchorlist))
+ self.anchor = None
+
+ # --- Hook for images; should probably be overridden
+
+ def handle_image(self, src, alt, *args):
+ self.handle_data(alt)
+
+ # --------- Top level elememts
+
+ def start_html(self, attrs): pass
+ def end_html(self): pass
+
+ def start_head(self, attrs): pass
+ def end_head(self): pass
+
+ def start_body(self, attrs): pass
+ def end_body(self): pass
+
+ # ------ Head elements
+
+ def start_title(self, attrs):
+ self.save_bgn()
+
+ def end_title(self):
+ self.title = self.save_end()
+
+ def do_base(self, attrs):
+ for a, v in attrs:
+ if a == 'href':
+ self.base = v
+
+ def do_isindex(self, attrs):
+ self.isindex = 1
+
+ def do_link(self, attrs):
+ pass
+
+ def do_meta(self, attrs):
+ pass
+
+ def do_nextid(self, attrs): # Deprecated
+ pass
+
+ # ------ Body elements
+
+ # --- Headings
+
+ def start_h1(self, attrs):
+ self.formatter.end_paragraph(1)
+ self.formatter.push_font(('h1', 0, 1, 0))
+
+ def end_h1(self):
+ self.formatter.end_paragraph(1)
+ self.formatter.pop_font()
+
+ def start_h2(self, attrs):
+ self.formatter.end_paragraph(1)
+ self.formatter.push_font(('h2', 0, 1, 0))
+
+ def end_h2(self):
+ self.formatter.end_paragraph(1)
+ self.formatter.pop_font()
+
+ def start_h3(self, attrs):
+ self.formatter.end_paragraph(1)
+ self.formatter.push_font(('h3', 0, 1, 0))
+
+ def end_h3(self):
+ self.formatter.end_paragraph(1)
+ self.formatter.pop_font()
+
+ def start_h4(self, attrs):
+ self.formatter.end_paragraph(1)
+ self.formatter.push_font(('h4', 0, 1, 0))
+
+ def end_h4(self):
+ self.formatter.end_paragraph(1)
+ self.formatter.pop_font()
+
+ def start_h5(self, attrs):
+ self.formatter.end_paragraph(1)
+ self.formatter.push_font(('h5', 0, 1, 0))
+
+ def end_h5(self):
+ self.formatter.end_paragraph(1)
+ self.formatter.pop_font()
+
+ def start_h6(self, attrs):
+ self.formatter.end_paragraph(1)
+ self.formatter.push_font(('h6', 0, 1, 0))
+
+ def end_h6(self):
+ self.formatter.end_paragraph(1)
+ self.formatter.pop_font()
+
+ # --- Block Structuring Elements
+
+ def do_p(self, attrs):
+ self.formatter.end_paragraph(1)
+
+ def start_pre(self, attrs):
+ self.formatter.end_paragraph(1)
+ self.formatter.push_font((AS_IS, AS_IS, AS_IS, 1))
+ self.nofill = self.nofill + 1
+
+ def end_pre(self):
+ self.formatter.end_paragraph(1)
+ self.formatter.pop_font()
+ self.nofill = max(0, self.nofill - 1)
+
+ def start_xmp(self, attrs):
+ self.start_pre(attrs)
+ self.setliteral('xmp') # Tell SGML parser
+
+ def end_xmp(self):
+ self.end_pre()
+
+ def start_listing(self, attrs):
+ self.start_pre(attrs)
+ self.setliteral('listing') # Tell SGML parser
+
+ def end_listing(self):
+ self.end_pre()
+
+ def start_address(self, attrs):
+ self.formatter.end_paragraph(0)
+ self.formatter.push_font((AS_IS, 1, AS_IS, AS_IS))
+
+ def end_address(self):
+ self.formatter.end_paragraph(0)
+ self.formatter.pop_font()
+
+ def start_blockquote(self, attrs):
+ self.formatter.end_paragraph(1)
+ self.formatter.push_margin('blockquote')
+
+ def end_blockquote(self):
+ self.formatter.end_paragraph(1)
+ self.formatter.pop_margin()
+
+ # --- List Elements
+
+ def start_ul(self, attrs):
+ self.formatter.end_paragraph(not self.list_stack)
+ self.formatter.push_margin('ul')
+ self.list_stack.append(['ul', '*', 0])
+
+ def end_ul(self):
+ if self.list_stack: del self.list_stack[-1]
+ self.formatter.end_paragraph(not self.list_stack)
+ self.formatter.pop_margin()
+
+ def do_li(self, attrs):
+ self.formatter.end_paragraph(0)
+ if self.list_stack:
+ [dummy, label, counter] = top = self.list_stack[-1]
+ top[2] = counter = counter+1
+ else:
+ label, counter = '*', 0
+ self.formatter.add_label_data(label, counter)
+
+ def start_ol(self, attrs):
+ self.formatter.end_paragraph(not self.list_stack)
+ self.formatter.push_margin('ol')
+ label = '1.'
+ for a, v in attrs:
+ if a == 'type':
+ if len(v) == 1: v = v + '.'
+ label = v
+ self.list_stack.append(['ol', label, 0])
+
+ def end_ol(self):
+ if self.list_stack: del self.list_stack[-1]
+ self.formatter.end_paragraph(not self.list_stack)
+ self.formatter.pop_margin()
+
+ def start_menu(self, attrs):
+ self.start_ul(attrs)
+
+ def end_menu(self):
+ self.end_ul()
+
+ def start_dir(self, attrs):
+ self.start_ul(attrs)
+
+ def end_dir(self):
+ self.end_ul()
+
+ def start_dl(self, attrs):
+ self.formatter.end_paragraph(1)
+ self.list_stack.append(['dl', '', 0])
+
+ def end_dl(self):
+ self.ddpop(1)
+ if self.list_stack: del self.list_stack[-1]
+
+ def do_dt(self, attrs):
+ self.ddpop()
+
+ def do_dd(self, attrs):
+ self.ddpop()
+ self.formatter.push_margin('dd')
+ self.list_stack.append(['dd', '', 0])
+
+ def ddpop(self, bl=0):
+ self.formatter.end_paragraph(bl)
+ if self.list_stack:
+ if self.list_stack[-1][0] == 'dd':
+ del self.list_stack[-1]
+ self.formatter.pop_margin()
+
+ # --- Phrase Markup
+
+ # Idiomatic Elements
+
+ def start_cite(self, attrs): self.start_i(attrs)
+ def end_cite(self): self.end_i()
+
+ def start_code(self, attrs): self.start_tt(attrs)
+ def end_code(self): self.end_tt()
+
+ def start_em(self, attrs): self.start_i(attrs)
+ def end_em(self): self.end_i()
+
+ def start_kbd(self, attrs): self.start_tt(attrs)
+ def end_kbd(self): self.end_tt()
+
+ def start_samp(self, attrs): self.start_tt(attrs)
+ def end_samp(self): self.end_tt()
+
+ def start_strong(self, attrs): self.start_b(attrs)
+ def end_strong(self): self.end_b()
+
+ def start_var(self, attrs): self.start_i(attrs)
+ def end_var(self): self.end_i()
+
+ # Typographic Elements
+
+ def start_i(self, attrs):
+ self.formatter.push_font((AS_IS, 1, AS_IS, AS_IS))
+ def end_i(self):
+ self.formatter.pop_font()
+
+ def start_b(self, attrs):
+ self.formatter.push_font((AS_IS, AS_IS, 1, AS_IS))
+ def end_b(self):
+ self.formatter.pop_font()
+
+ def start_tt(self, attrs):
+ self.formatter.push_font((AS_IS, AS_IS, AS_IS, 1))
+ def end_tt(self):
+ self.formatter.pop_font()
+
+ def start_a(self, attrs):
+ href = ''
+ name = ''
+ type = ''
+ for attrname, value in attrs:
+ value = value.strip()
+ if attrname == 'href':
+ href = value
+ if attrname == 'name':
+ name = value
+ if attrname == 'type':
+ type = value.lower()
+ self.anchor_bgn(href, name, type)
+
+ def end_a(self):
+ self.anchor_end()
+
+ # --- Line Break
+
+ def do_br(self, attrs):
+ self.formatter.add_line_break()
+
+ # --- Horizontal Rule
+
+ def do_hr(self, attrs):
+ self.formatter.add_hor_rule()
+
+ # --- Image
+
+ def do_img(self, attrs):
+ align = ''
+ alt = '(image)'
+ ismap = ''
+ src = ''
+ width = 0
+ height = 0
+ for attrname, value in attrs:
+ if attrname == 'align':
+ align = value
+ if attrname == 'alt':
+ alt = value
+ if attrname == 'ismap':
+ ismap = value
+ if attrname == 'src':
+ src = value
+ if attrname == 'width':
+ try: width = int(value)
+ except: pass
+ if attrname == 'height':
+ try: height = int(value)
+ except: pass
+ self.handle_image(src, alt, ismap, align, width, height)
+
+ # --- Really Old Unofficial Deprecated Stuff
+
+ def do_plaintext(self, attrs):
+ self.start_pre(attrs)
+ self.setnomoretags() # Tell SGML parser
+
+ # --- Unhandled tags
+
+ def unknown_starttag(self, tag, attrs):
+ pass
+
+ def unknown_endtag(self, tag):
+ pass
+
+
+def test(args = None):
+ import sys, formatter
+
+ if not args:
+ args = sys.argv[1:]
+
+ silent = args and args[0] == '-s'
+ if silent:
+ del args[0]
+
+ if args:
+ file = args[0]
+ else:
+ file = 'test.html'
+
+ if file == '-':
+ f = sys.stdin
+ else:
+ try:
+ f = open(file, 'r')
+ except IOError, msg:
+ print file, ":", msg
+ sys.exit(1)
+
+ data = f.read()
+
+ if f is not sys.stdin:
+ f.close()
+
+ if silent:
+ f = formatter.NullFormatter()
+ else:
+ f = formatter.AbstractFormatter(formatter.DumbWriter())
+
+ p = HTMLParser(f)
+ p.feed(data)
+ p.close()
+
+
+if __name__ == '__main__':
+ test()
diff --git a/lib/jython/Lib/httplib.py b/lib/jython/Lib/httplib.py new file mode 100644 index 000000000..6ccf6953e --- /dev/null +++ b/lib/jython/Lib/httplib.py @@ -0,0 +1,842 @@ +"""HTTP/1.1 client library
+
+<intro stuff goes here>
+<other stuff, too>
+
+HTTPConnection go through a number of "states", which defines when a client
+may legally make another request or fetch the response for a particular
+request. This diagram details these state transitions:
+
+ (null)
+ |
+ | HTTPConnection()
+ v
+ Idle
+ |
+ | putrequest()
+ v
+ Request-started
+ |
+ | ( putheader() )* endheaders()
+ v
+ Request-sent
+ |
+ | response = getresponse()
+ v
+ Unread-response [Response-headers-read]
+ |\____________________
+ | |
+ | response.read() | putrequest()
+ v v
+ Idle Req-started-unread-response
+ ______/|
+ / |
+ response.read() | | ( putheader() )* endheaders()
+ v v
+ Request-started Req-sent-unread-response
+ |
+ | response.read()
+ v
+ Request-sent
+
+This diagram presents the following rules:
+ -- a second request may not be started until {response-headers-read}
+ -- a response [object] cannot be retrieved until {request-sent}
+ -- there is no differentiation between an unread response body and a
+ partially read response body
+
+Note: this enforcement is applied by the HTTPConnection class. The
+ HTTPResponse class does not enforce this state machine, which
+ implies sophisticated clients may accelerate the request/response
+ pipeline. Caution should be taken, though: accelerating the states
+ beyond the above pattern may imply knowledge of the server's
+ connection-close behavior for certain requests. For example, it
+ is impossible to tell whether the server will close the connection
+ UNTIL the response headers have been read; this means that further
+ requests cannot be placed into the pipeline until it is known that
+ the server will NOT be closing the connection.
+
+Logical State __state __response
+------------- ------- ----------
+Idle _CS_IDLE None
+Request-started _CS_REQ_STARTED None
+Request-sent _CS_REQ_SENT None
+Unread-response _CS_IDLE <response_class>
+Req-started-unread-response _CS_REQ_STARTED <response_class>
+Req-sent-unread-response _CS_REQ_SENT <response_class>
+"""
+
+import socket
+import mimetools
+
+try:
+ from cStringIO import StringIO
+except ImportError:
+ from StringIO import StringIO
+
+__all__ = ["HTTP", "HTTPResponse", "HTTPConnection", "HTTPSConnection",
+ "HTTPException", "NotConnected", "UnknownProtocol",
+ "UnknownTransferEncoding", "IllegalKeywordArgument",
+ "UnimplementedFileMode", "IncompleteRead",
+ "ImproperConnectionState", "CannotSendRequest", "CannotSendHeader",
+ "ResponseNotReady", "BadStatusLine", "error"]
+
+HTTP_PORT = 80
+HTTPS_PORT = 443
+
+_UNKNOWN = 'UNKNOWN'
+
+# connection states
+_CS_IDLE = 'Idle'
+_CS_REQ_STARTED = 'Request-started'
+_CS_REQ_SENT = 'Request-sent'
+
+
+class HTTPResponse:
+ def __init__(self, sock, debuglevel=0):
+ self.fp = sock.makefile('rb', 0)
+ self.debuglevel = debuglevel
+
+ self.msg = None
+
+ # from the Status-Line of the response
+ self.version = _UNKNOWN # HTTP-Version
+ self.status = _UNKNOWN # Status-Code
+ self.reason = _UNKNOWN # Reason-Phrase
+
+ self.chunked = _UNKNOWN # is "chunked" being used?
+ self.chunk_left = _UNKNOWN # bytes left to read in current chunk
+ self.length = _UNKNOWN # number of bytes left in response
+ self.will_close = _UNKNOWN # conn will close at end of response
+
+ def begin(self):
+ if self.msg is not None:
+ # we've already started reading the response
+ return
+
+ line = self.fp.readline()
+ if self.debuglevel > 0:
+ print "reply:", repr(line)
+ try:
+ [version, status, reason] = line.split(None, 2)
+ except ValueError:
+ try:
+ [version, status] = line.split(None, 1)
+ reason = ""
+ except ValueError:
+ version = "HTTP/0.9"
+ status = "200"
+ reason = ""
+ if version[:5] != 'HTTP/':
+ self.close()
+ raise BadStatusLine(line)
+
+ # The status code is a three-digit number
+ try:
+ self.status = status = int(status)
+ if status < 100 or status > 999:
+ raise BadStatusLine(line)
+ except ValueError:
+ raise BadStatusLine(line)
+ self.reason = reason.strip()
+
+ if version == 'HTTP/1.0':
+ self.version = 10
+ elif version.startswith('HTTP/1.'):
+ self.version = 11 # use HTTP/1.1 code for HTTP/1.x where x>=1
+ elif version == 'HTTP/0.9':
+ self.version = 9
+ else:
+ raise UnknownProtocol(version)
+
+ if self.version == 9:
+ self.msg = mimetools.Message(StringIO())
+ return
+
+ self.msg = mimetools.Message(self.fp, 0)
+ if self.debuglevel > 0:
+ for hdr in self.msg.headers:
+ print "header:", hdr,
+
+ # don't let the msg keep an fp
+ self.msg.fp = None
+
+ # are we using the chunked-style of transfer encoding?
+ tr_enc = self.msg.getheader('transfer-encoding')
+ if tr_enc:
+ if tr_enc.lower() != 'chunked':
+ raise UnknownTransferEncoding()
+ self.chunked = 1
+ self.chunk_left = None
+ else:
+ self.chunked = 0
+
+ # will the connection close at the end of the response?
+ conn = self.msg.getheader('connection')
+ if conn:
+ conn = conn.lower()
+ # a "Connection: close" will always close the connection. if we
+ # don't see that and this is not HTTP/1.1, then the connection will
+ # close unless we see a Keep-Alive header.
+ self.will_close = conn.find('close') != -1 or \
+ ( self.version != 11 and \
+ not self.msg.getheader('keep-alive') )
+ else:
+ # for HTTP/1.1, the connection will always remain open
+ # otherwise, it will remain open IFF we see a Keep-Alive header
+ self.will_close = self.version != 11 and \
+ not self.msg.getheader('keep-alive')
+
+ # do we have a Content-Length?
+ # NOTE: RFC 2616, S4.4, #3 says we ignore this if tr_enc is "chunked"
+ length = self.msg.getheader('content-length')
+ if length and not self.chunked:
+ try:
+ self.length = int(length)
+ except ValueError:
+ self.length = None
+ else:
+ self.length = None
+
+ # does the body have a fixed length? (of zero)
+ if (status == 204 or # No Content
+ status == 304 or # Not Modified
+ 100 <= status < 200): # 1xx codes
+ self.length = 0
+
+ # if the connection remains open, and we aren't using chunked, and
+ # a content-length was not provided, then assume that the connection
+ # WILL close.
+ if not self.will_close and \
+ not self.chunked and \
+ self.length is None:
+ self.will_close = 1
+
+ def close(self):
+ if self.fp:
+ self.fp.close()
+ self.fp = None
+
+ def isclosed(self):
+ # NOTE: it is possible that we will not ever call self.close(). This
+ # case occurs when will_close is TRUE, length is None, and we
+ # read up to the last byte, but NOT past it.
+ #
+ # IMPLIES: if will_close is FALSE, then self.close() will ALWAYS be
+ # called, meaning self.isclosed() is meaningful.
+ return self.fp is None
+
+ def read(self, amt=None):
+ if self.fp is None:
+ return ''
+
+ if self.chunked:
+ chunk_left = self.chunk_left
+ value = ''
+ while 1:
+ if chunk_left is None:
+ line = self.fp.readline()
+ i = line.find(';')
+ if i >= 0:
+ line = line[:i] # strip chunk-extensions
+ chunk_left = int(line, 16)
+ if chunk_left == 0:
+ break
+ if amt is None:
+ value = value + self._safe_read(chunk_left)
+ elif amt < chunk_left:
+ value = value + self._safe_read(amt)
+ self.chunk_left = chunk_left - amt
+ return value
+ elif amt == chunk_left:
+ value = value + self._safe_read(amt)
+ self._safe_read(2) # toss the CRLF at the end of the chunk
+ self.chunk_left = None
+ return value
+ else:
+ value = value + self._safe_read(chunk_left)
+ amt = amt - chunk_left
+
+ # we read the whole chunk, get another
+ self._safe_read(2) # toss the CRLF at the end of the chunk
+ chunk_left = None
+
+ # read and discard trailer up to the CRLF terminator
+ ### note: we shouldn't have any trailers!
+ while 1:
+ line = self.fp.readline()
+ if line == '\r\n':
+ break
+
+ # we read everything; close the "file"
+ self.close()
+
+ return value
+
+ elif amt is None:
+ # unbounded read
+ if self.will_close:
+ s = self.fp.read()
+ else:
+ s = self._safe_read(self.length)
+ self.close() # we read everything
+ return s
+
+ if self.length is not None:
+ if amt > self.length:
+ # clip the read to the "end of response"
+ amt = self.length
+ self.length = self.length - amt
+
+ # we do not use _safe_read() here because this may be a .will_close
+ # connection, and the user is reading more bytes than will be provided
+ # (for example, reading in 1k chunks)
+ s = self.fp.read(amt)
+
+ return s
+
+ def _safe_read(self, amt):
+ """Read the number of bytes requested, compensating for partial reads.
+
+ Normally, we have a blocking socket, but a read() can be interrupted
+ by a signal (resulting in a partial read).
+
+ Note that we cannot distinguish between EOF and an interrupt when zero
+ bytes have been read. IncompleteRead() will be raised in this
+ situation.
+
+ This function should be used when <amt> bytes "should" be present for
+ reading. If the bytes are truly not available (due to EOF), then the
+ IncompleteRead exception can be used to detect the problem.
+ """
+ s = ''
+ while amt > 0:
+ chunk = self.fp.read(amt)
+ if not chunk:
+ raise IncompleteRead(s)
+ s = s + chunk
+ amt = amt - len(chunk)
+ return s
+
+ def getheader(self, name, default=None):
+ if self.msg is None:
+ raise ResponseNotReady()
+ return self.msg.getheader(name, default)
+
+
+class HTTPConnection:
+
+ _http_vsn = 11
+ _http_vsn_str = 'HTTP/1.1'
+
+ response_class = HTTPResponse
+ default_port = HTTP_PORT
+ auto_open = 1
+ debuglevel = 0
+
+ def __init__(self, host, port=None):
+ self.sock = None
+ self.__response = None
+ self.__state = _CS_IDLE
+
+ self._set_hostport(host, port)
+
+ def _set_hostport(self, host, port):
+ if port is None:
+ i = host.find(':')
+ if i >= 0:
+ port = int(host[i+1:])
+ host = host[:i]
+ else:
+ port = self.default_port
+ self.host = host
+ self.port = port
+
+ def set_debuglevel(self, level):
+ self.debuglevel = level
+
+ def connect(self):
+ """Connect to the host and port specified in __init__."""
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ if self.debuglevel > 0:
+ print "connect: (%s, %s)" % (self.host, self.port)
+ self.sock.connect((self.host, self.port))
+
+ def close(self):
+ """Close the connection to the HTTP server."""
+ if self.sock:
+ self.sock.close() # close it manually... there may be other refs
+ self.sock = None
+ if self.__response:
+ self.__response.close()
+ self.__response = None
+ self.__state = _CS_IDLE
+
+ def send(self, str):
+ """Send `str' to the server."""
+ if self.sock is None:
+ if self.auto_open:
+ self.connect()
+ else:
+ raise NotConnected()
+
+ # send the data to the server. if we get a broken pipe, then close
+ # the socket. we want to reconnect when somebody tries to send again.
+ #
+ # NOTE: we DO propagate the error, though, because we cannot simply
+ # ignore the error... the caller will know if they can retry.
+ if self.debuglevel > 0:
+ print "send:", repr(str)
+ try:
+ self.sock.send(str)
+ except socket.error, v:
+ if v[0] == 32: # Broken pipe
+ self.close()
+ raise
+
+ def putrequest(self, method, url):
+ """Send a request to the server.
+
+ `method' specifies an HTTP request method, e.g. 'GET'.
+ `url' specifies the object being requested, e.g. '/index.html'.
+ """
+
+ # check if a prior response has been completed
+ if self.__response and self.__response.isclosed():
+ self.__response = None
+
+ #
+ # in certain cases, we cannot issue another request on this connection.
+ # this occurs when:
+ # 1) we are in the process of sending a request. (_CS_REQ_STARTED)
+ # 2) a response to a previous request has signalled that it is going
+ # to close the connection upon completion.
+ # 3) the headers for the previous response have not been read, thus
+ # we cannot determine whether point (2) is true. (_CS_REQ_SENT)
+ #
+ # if there is no prior response, then we can request at will.
+ #
+ # if point (2) is true, then we will have passed the socket to the
+ # response (effectively meaning, "there is no prior response"), and
+ # will open a new one when a new request is made.
+ #
+ # Note: if a prior response exists, then we *can* start a new request.
+ # We are not allowed to begin fetching the response to this new
+ # request, however, until that prior response is complete.
+ #
+ if self.__state == _CS_IDLE:
+ self.__state = _CS_REQ_STARTED
+ else:
+ raise CannotSendRequest()
+
+ if not url:
+ url = '/'
+ str = '%s %s %s\r\n' % (method, url, self._http_vsn_str)
+
+ try:
+ self.send(str)
+ except socket.error, v:
+ # trap 'Broken pipe' if we're allowed to automatically reconnect
+ if v[0] != 32 or not self.auto_open:
+ raise
+ # try one more time (the socket was closed; this will reopen)
+ self.send(str)
+
+ if self._http_vsn == 11:
+ # Issue some standard headers for better HTTP/1.1 compliance
+
+ # this header is issued *only* for HTTP/1.1 connections. more
+ # specifically, this means it is only issued when the client uses
+ # the new HTTPConnection() class. backwards-compat clients will
+ # be using HTTP/1.0 and those clients may be issuing this header
+ # themselves. we should NOT issue it twice; some web servers (such
+ # as Apache) barf when they see two Host: headers
+
+ # if we need a non-standard port,include it in the header
+ if self.port == HTTP_PORT:
+ self.putheader('Host', self.host)
+ else:
+ self.putheader('Host', "%s:%s" % (self.host, self.port))
+
+ # note: we are assuming that clients will not attempt to set these
+ # headers since *this* library must deal with the
+ # consequences. this also means that when the supporting
+ # libraries are updated to recognize other forms, then this
+ # code should be changed (removed or updated).
+
+ # we only want a Content-Encoding of "identity" since we don't
+ # support encodings such as x-gzip or x-deflate.
+ self.putheader('Accept-Encoding', 'identity')
+
+ # we can accept "chunked" Transfer-Encodings, but no others
+ # NOTE: no TE header implies *only* "chunked"
+ #self.putheader('TE', 'chunked')
+
+ # if TE is supplied in the header, then it must appear in a
+ # Connection header.
+ #self.putheader('Connection', 'TE')
+
+ else:
+ # For HTTP/1.0, the server will assume "not chunked"
+ pass
+
+ def putheader(self, header, value):
+ """Send a request header line to the server.
+
+ For example: h.putheader('Accept', 'text/html')
+ """
+ if self.__state != _CS_REQ_STARTED:
+ raise CannotSendHeader()
+
+ str = '%s: %s\r\n' % (header, value)
+ self.send(str)
+
+ def endheaders(self):
+ """Indicate that the last header line has been sent to the server."""
+
+ if self.__state == _CS_REQ_STARTED:
+ self.__state = _CS_REQ_SENT
+ else:
+ raise CannotSendHeader()
+
+ self.send('\r\n')
+
+ def request(self, method, url, body=None, headers={}):
+ """Send a complete request to the server."""
+
+ try:
+ self._send_request(method, url, body, headers)
+ except socket.error, v:
+ # trap 'Broken pipe' if we're allowed to automatically reconnect
+ if v[0] != 32 or not self.auto_open:
+ raise
+ # try one more time
+ self._send_request(method, url, body, headers)
+
+ def _send_request(self, method, url, body, headers):
+ self.putrequest(method, url)
+
+ if body:
+ self.putheader('Content-Length', str(len(body)))
+ for hdr, value in headers.items():
+ self.putheader(hdr, value)
+ self.endheaders()
+
+ if body:
+ self.send(body)
+
+ def getresponse(self):
+ "Get the response from the server."
+
+ # check if a prior response has been completed
+ if self.__response and self.__response.isclosed():
+ self.__response = None
+
+ #
+ # if a prior response exists, then it must be completed (otherwise, we
+ # cannot read this response's header to determine the connection-close
+ # behavior)
+ #
+ # note: if a prior response existed, but was connection-close, then the
+ # socket and response were made independent of this HTTPConnection
+ # object since a new request requires that we open a whole new
+ # connection
+ #
+ # this means the prior response had one of two states:
+ # 1) will_close: this connection was reset and the prior socket and
+ # response operate independently
+ # 2) persistent: the response was retained and we await its
+ # isclosed() status to become true.
+ #
+ if self.__state != _CS_REQ_SENT or self.__response:
+ raise ResponseNotReady()
+
+ if self.debuglevel > 0:
+ response = self.response_class(self.sock, self.debuglevel)
+ else:
+ response = self.response_class(self.sock)
+
+ response.begin()
+ self.__state = _CS_IDLE
+
+ if response.will_close:
+ # this effectively passes the connection to the response
+ self.close()
+ else:
+ # remember this, so we can tell when it is complete
+ self.__response = response
+
+ return response
+
+
+class FakeSocket:
+ def __init__(self, sock, ssl):
+ self.__sock = sock
+ self.__ssl = ssl
+
+ def makefile(self, mode, bufsize=None):
+ """Return a readable file-like object with data from socket.
+
+ This method offers only partial support for the makefile
+ interface of a real socket. It only supports modes 'r' and
+ 'rb' and the bufsize argument is ignored.
+
+ The returned object contains *all* of the file data
+ """
+ if mode != 'r' and mode != 'rb':
+ raise UnimplementedFileMode()
+
+ msgbuf = []
+ while 1:
+ try:
+ buf = self.__ssl.read()
+ except socket.sslerror, msg:
+ break
+ if buf == '':
+ break
+ msgbuf.append(buf)
+ return StringIO("".join(msgbuf))
+
+ def send(self, stuff, flags = 0):
+ return self.__ssl.write(stuff)
+
+ def recv(self, len = 1024, flags = 0):
+ return self.__ssl.read(len)
+
+ def __getattr__(self, attr):
+ return getattr(self.__sock, attr)
+
+
+class HTTPSConnection(HTTPConnection):
+ "This class allows communication via SSL."
+
+ default_port = HTTPS_PORT
+
+ def __init__(self, host, port=None, **x509):
+ keys = x509.keys()
+ try:
+ keys.remove('key_file')
+ except ValueError:
+ pass
+ try:
+ keys.remove('cert_file')
+ except ValueError:
+ pass
+ if keys:
+ raise IllegalKeywordArgument()
+ HTTPConnection.__init__(self, host, port)
+ self.key_file = x509.get('key_file')
+ self.cert_file = x509.get('cert_file')
+
+ def connect(self):
+ "Connect to a host on a given (SSL) port."
+
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sock.connect((self.host, self.port))
+ realsock = sock
+ if hasattr(sock, "_sock"):
+ realsock = sock._sock
+ ssl = socket.ssl(realsock, self.key_file, self.cert_file)
+ self.sock = FakeSocket(sock, ssl)
+
+
+class HTTP:
+ "Compatibility class with httplib.py from 1.5."
+
+ _http_vsn = 10
+ _http_vsn_str = 'HTTP/1.0'
+
+ debuglevel = 0
+
+ _connection_class = HTTPConnection
+
+ def __init__(self, host='', port=None, **x509):
+ "Provide a default host, since the superclass requires one."
+
+ # some joker passed 0 explicitly, meaning default port
+ if port == 0:
+ port = None
+
+ # Note that we may pass an empty string as the host; this will throw
+ # an error when we attempt to connect. Presumably, the client code
+ # will call connect before then, with a proper host.
+ self._conn = self._connection_class(host, port)
+ # set up delegation to flesh out interface
+ self.send = self._conn.send
+ self.putrequest = self._conn.putrequest
+ self.endheaders = self._conn.endheaders
+ self._conn._http_vsn = self._http_vsn
+ self._conn._http_vsn_str = self._http_vsn_str
+
+ # we never actually use these for anything, but we keep them here for
+ # compatibility with post-1.5.2 CVS.
+ self.key_file = x509.get('key_file')
+ self.cert_file = x509.get('cert_file')
+
+ self.file = None
+
+ def connect(self, host=None, port=None):
+ "Accept arguments to set the host/port, since the superclass doesn't."
+
+ if host is not None:
+ self._conn._set_hostport(host, port)
+ self._conn.connect()
+
+ def set_debuglevel(self, debuglevel):
+ self._conn.set_debuglevel(debuglevel)
+
+ def getfile(self):
+ "Provide a getfile, since the superclass' does not use this concept."
+ return self.file
+
+ def putheader(self, header, *values):
+ "The superclass allows only one value argument."
+ self._conn.putheader(header, '\r\n\t'.join(values))
+
+ def getreply(self):
+ """Compat definition since superclass does not define it.
+
+ Returns a tuple consisting of:
+ - server status code (e.g. '200' if all goes well)
+ - server "reason" corresponding to status code
+ - any RFC822 headers in the response from the server
+ """
+ try:
+ response = self._conn.getresponse()
+ except BadStatusLine, e:
+ ### hmm. if getresponse() ever closes the socket on a bad request,
+ ### then we are going to have problems with self.sock
+
+ ### should we keep this behavior? do people use it?
+ # keep the socket open (as a file), and return it
+ self.file = self._conn.sock.makefile('rb', 0)
+
+ # close our socket -- we want to restart after any protocol error
+ self.close()
+
+ self.headers = None
+ return -1, e.line, None
+
+ self.headers = response.msg
+ self.file = response.fp
+ return response.status, response.reason, response.msg
+
+ def close(self):
+ self._conn.close()
+
+ # note that self.file == response.fp, which gets closed by the
+ # superclass. just clear the object ref here.
+ ### hmm. messy. if status==-1, then self.file is owned by us.
+ ### well... we aren't explicitly closing, but losing this ref will
+ ### do it
+ self.file = None
+
+if hasattr(socket, 'ssl'):
+ class HTTPS(HTTP):
+ """Compatibility with 1.5 httplib interface
+
+ Python 1.5.2 did not have an HTTPS class, but it defined an
+ interface for sending http requests that is also useful for
+ https.
+ """
+
+ _connection_class = HTTPSConnection
+
+
+class HTTPException(Exception):
+ pass
+
+class NotConnected(HTTPException):
+ pass
+
+class UnknownProtocol(HTTPException):
+ def __init__(self, version):
+ self.version = version
+
+class UnknownTransferEncoding(HTTPException):
+ pass
+
+class IllegalKeywordArgument(HTTPException):
+ pass
+
+class UnimplementedFileMode(HTTPException):
+ pass
+
+class IncompleteRead(HTTPException):
+ def __init__(self, partial):
+ self.partial = partial
+
+class ImproperConnectionState(HTTPException):
+ pass
+
+class CannotSendRequest(ImproperConnectionState):
+ pass
+
+class CannotSendHeader(ImproperConnectionState):
+ pass
+
+class ResponseNotReady(ImproperConnectionState):
+ pass
+
+class BadStatusLine(HTTPException):
+ def __init__(self, line):
+ self.line = line
+
+# for backwards compatibility
+error = HTTPException
+
+
+#
+# snarfed from httplib.py for now...
+#
+def test():
+ """Test this module.
+
+ The test consists of retrieving and displaying the Python
+ home page, along with the error code and error string returned
+ by the www.python.org server.
+ """
+
+ import sys
+ import getopt
+ opts, args = getopt.getopt(sys.argv[1:], 'd')
+ dl = 0
+ for o, a in opts:
+ if o == '-d': dl = dl + 1
+ host = 'www.python.org'
+ selector = '/'
+ if args[0:]: host = args[0]
+ if args[1:]: selector = args[1]
+ h = HTTP()
+ h.set_debuglevel(dl)
+ h.connect(host)
+ h.putrequest('GET', selector)
+ h.endheaders()
+ status, reason, headers = h.getreply()
+ print 'status =', status
+ print 'reason =', reason
+ print
+ if headers:
+ for header in headers.headers: print header.strip()
+ print
+ print h.getfile().read()
+
+ if hasattr(socket, 'ssl'):
+ host = 'sourceforge.net'
+ selector = '/projects/python'
+ hs = HTTPS()
+ hs.connect(host)
+ hs.putrequest('GET', selector)
+ hs.endheaders()
+ status, reason, headers = hs.getreply()
+ print 'status =', status
+ print 'reason =', reason
+ print
+ if headers:
+ for header in headers.headers: print header.strip()
+ print
+ print hs.getfile().read()
+
+
+if __name__ == '__main__':
+ test()
diff --git a/lib/jython/Lib/imaplib.py b/lib/jython/Lib/imaplib.py new file mode 100644 index 000000000..83c830901 --- /dev/null +++ b/lib/jython/Lib/imaplib.py @@ -0,0 +1,1125 @@ +"""IMAP4 client.
+
+Based on RFC 2060.
+
+Public class: IMAP4
+Public variable: Debug
+Public functions: Internaldate2tuple
+ Int2AP
+ ParseFlags
+ Time2Internaldate
+"""
+
+# Author: Piers Lauder <piers@cs.su.oz.au> December 1997.
+#
+# Authentication code contributed by Donn Cave <donn@u.washington.edu> June 1998.
+# String method conversion by ESR, February 2001.
+
+__version__ = "2.40"
+
+import binascii, re, socket, time, random, sys
+
+__all__ = ["IMAP4", "Internaldate2tuple",
+ "Int2AP", "ParseFlags", "Time2Internaldate"]
+
+# Globals
+
+CRLF = '\r\n'
+Debug = 0
+IMAP4_PORT = 143
+AllowedVersions = ('IMAP4REV1', 'IMAP4') # Most recent first
+
+# Commands
+
+Commands = {
+ # name valid states
+ 'APPEND': ('AUTH', 'SELECTED'),
+ 'AUTHENTICATE': ('NONAUTH',),
+ 'CAPABILITY': ('NONAUTH', 'AUTH', 'SELECTED', 'LOGOUT'),
+ 'CHECK': ('SELECTED',),
+ 'CLOSE': ('SELECTED',),
+ 'COPY': ('SELECTED',),
+ 'CREATE': ('AUTH', 'SELECTED'),
+ 'DELETE': ('AUTH', 'SELECTED'),
+ 'EXAMINE': ('AUTH', 'SELECTED'),
+ 'EXPUNGE': ('SELECTED',),
+ 'FETCH': ('SELECTED',),
+ 'LIST': ('AUTH', 'SELECTED'),
+ 'LOGIN': ('NONAUTH',),
+ 'LOGOUT': ('NONAUTH', 'AUTH', 'SELECTED', 'LOGOUT'),
+ 'LSUB': ('AUTH', 'SELECTED'),
+ 'NOOP': ('NONAUTH', 'AUTH', 'SELECTED', 'LOGOUT'),
+ 'PARTIAL': ('SELECTED',),
+ 'RENAME': ('AUTH', 'SELECTED'),
+ 'SEARCH': ('SELECTED',),
+ 'SELECT': ('AUTH', 'SELECTED'),
+ 'STATUS': ('AUTH', 'SELECTED'),
+ 'STORE': ('SELECTED',),
+ 'SUBSCRIBE': ('AUTH', 'SELECTED'),
+ 'UID': ('SELECTED',),
+ 'UNSUBSCRIBE': ('AUTH', 'SELECTED'),
+ }
+
+# Patterns to match server responses
+
+Continuation = re.compile(r'\+( (?P<data>.*))?')
+Flags = re.compile(r'.*FLAGS \((?P<flags>[^\)]*)\)')
+InternalDate = re.compile(r'.*INTERNALDATE "'
+ r'(?P<day>[ 123][0-9])-(?P<mon>[A-Z][a-z][a-z])-(?P<year>[0-9][0-9][0-9][0-9])'
+ r' (?P<hour>[0-9][0-9]):(?P<min>[0-9][0-9]):(?P<sec>[0-9][0-9])'
+ r' (?P<zonen>[-+])(?P<zoneh>[0-9][0-9])(?P<zonem>[0-9][0-9])'
+ r'"')
+Literal = re.compile(r'.*{(?P<size>\d+)}$')
+Response_code = re.compile(r'\[(?P<type>[A-Z-]+)( (?P<data>[^\]]*))?\]')
+Untagged_response = re.compile(r'\* (?P<type>[A-Z-]+)( (?P<data>.*))?')
+Untagged_status = re.compile(r'\* (?P<data>\d+) (?P<type>[A-Z-]+)( (?P<data2>.*))?')
+
+
+
+class IMAP4:
+
+ """IMAP4 client class.
+
+ Instantiate with: IMAP4([host[, port]])
+
+ host - host's name (default: localhost);
+ port - port number (default: standard IMAP4 port).
+
+ All IMAP4rev1 commands are supported by methods of the same
+ name (in lower-case).
+
+ All arguments to commands are converted to strings, except for
+ AUTHENTICATE, and the last argument to APPEND which is passed as
+ an IMAP4 literal. If necessary (the string contains any
+ non-printing characters or white-space and isn't enclosed with
+ either parentheses or double quotes) each string is quoted.
+ However, the 'password' argument to the LOGIN command is always
+ quoted. If you want to avoid having an argument string quoted
+ (eg: the 'flags' argument to STORE) then enclose the string in
+ parentheses (eg: "(\Deleted)").
+
+ Each command returns a tuple: (type, [data, ...]) where 'type'
+ is usually 'OK' or 'NO', and 'data' is either the text from the
+ tagged response, or untagged results from command.
+
+ Errors raise the exception class <instance>.error("<reason>").
+ IMAP4 server errors raise <instance>.abort("<reason>"),
+ which is a sub-class of 'error'. Mailbox status changes
+ from READ-WRITE to READ-ONLY raise the exception class
+ <instance>.readonly("<reason>"), which is a sub-class of 'abort'.
+
+ "error" exceptions imply a program error.
+ "abort" exceptions imply the connection should be reset, and
+ the command re-tried.
+ "readonly" exceptions imply the command should be re-tried.
+
+ Note: to use this module, you must read the RFCs pertaining
+ to the IMAP4 protocol, as the semantics of the arguments to
+ each IMAP4 command are left to the invoker, not to mention
+ the results.
+ """
+
+ class error(Exception): pass # Logical errors - debug required
+ class abort(error): pass # Service errors - close and retry
+ class readonly(abort): pass # Mailbox status changed to READ-ONLY
+
+ mustquote = re.compile(r"[^\w!#$%&'*+,.:;<=>?^`|~-]")
+
+ def __init__(self, host = '', port = IMAP4_PORT):
+ self.host = host
+ self.port = port
+ self.debug = Debug
+ self.state = 'LOGOUT'
+ self.literal = None # A literal argument to a command
+ self.tagged_commands = {} # Tagged commands awaiting response
+ self.untagged_responses = {} # {typ: [data, ...], ...}
+ self.continuation_response = '' # Last continuation response
+ self.is_readonly = None # READ-ONLY desired state
+ self.tagnum = 0
+
+ # Open socket to server.
+
+ self.open(host, port)
+
+ # Create unique tag for this session,
+ # and compile tagged response matcher.
+
+ self.tagpre = Int2AP(random.randint(0, 31999))
+ self.tagre = re.compile(r'(?P<tag>'
+ + self.tagpre
+ + r'\d+) (?P<type>[A-Z]+) (?P<data>.*)')
+
+ # Get server welcome message,
+ # request and store CAPABILITY response.
+
+ if __debug__:
+ if self.debug >= 1:
+ _mesg('new IMAP4 connection, tag=%s' % self.tagpre)
+
+ self.welcome = self._get_response()
+ if self.untagged_responses.has_key('PREAUTH'):
+ self.state = 'AUTH'
+ elif self.untagged_responses.has_key('OK'):
+ self.state = 'NONAUTH'
+ else:
+ raise self.error(self.welcome)
+
+ cap = 'CAPABILITY'
+ self._simple_command(cap)
+ if not self.untagged_responses.has_key(cap):
+ raise self.error('no CAPABILITY response from server')
+ self.capabilities = tuple(self.untagged_responses[cap][-1].upper().split())
+
+ if __debug__:
+ if self.debug >= 3:
+ _mesg('CAPABILITIES: %s' % `self.capabilities`)
+
+ for version in AllowedVersions:
+ if not version in self.capabilities:
+ continue
+ self.PROTOCOL_VERSION = version
+ return
+
+ raise self.error('server not IMAP4 compliant')
+
+
+ def __getattr__(self, attr):
+ # Allow UPPERCASE variants of IMAP4 command methods.
+ if Commands.has_key(attr):
+ return eval("self.%s" % attr.lower())
+ raise AttributeError("Unknown IMAP4 command: '%s'" % attr)
+
+
+
+ # Public methods
+
+
+ def open(self, host, port):
+ """Setup 'self.sock' and 'self.file'."""
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.sock.connect((self.host, self.port))
+ self.file = self.sock.makefile('rb')
+
+
+ def recent(self):
+ """Return most recent 'RECENT' responses if any exist,
+ else prompt server for an update using the 'NOOP' command.
+
+ (typ, [data]) = <instance>.recent()
+
+ 'data' is None if no new messages,
+ else list of RECENT responses, most recent last.
+ """
+ name = 'RECENT'
+ typ, dat = self._untagged_response('OK', [None], name)
+ if dat[-1]:
+ return typ, dat
+ typ, dat = self.noop() # Prod server for response
+ return self._untagged_response(typ, dat, name)
+
+
+ def response(self, code):
+ """Return data for response 'code' if received, or None.
+
+ Old value for response 'code' is cleared.
+
+ (code, [data]) = <instance>.response(code)
+ """
+ return self._untagged_response(code, [None], code.upper())
+
+
+ def socket(self):
+ """Return socket instance used to connect to IMAP4 server.
+
+ socket = <instance>.socket()
+ """
+ return self.sock
+
+
+
+ # IMAP4 commands
+
+
+ def append(self, mailbox, flags, date_time, message):
+ """Append message to named mailbox.
+
+ (typ, [data]) = <instance>.append(mailbox, flags, date_time, message)
+
+ All args except `message' can be None.
+ """
+ name = 'APPEND'
+ if not mailbox:
+ mailbox = 'INBOX'
+ if flags:
+ if (flags[0],flags[-1]) != ('(',')'):
+ flags = '(%s)' % flags
+ else:
+ flags = None
+ if date_time:
+ date_time = Time2Internaldate(date_time)
+ else:
+ date_time = None
+ self.literal = message
+ return self._simple_command(name, mailbox, flags, date_time)
+
+
+ def authenticate(self, mechanism, authobject):
+ """Authenticate command - requires response processing.
+
+ 'mechanism' specifies which authentication mechanism is to
+ be used - it must appear in <instance>.capabilities in the
+ form AUTH=<mechanism>.
+
+ 'authobject' must be a callable object:
+
+ data = authobject(response)
+
+ It will be called to process server continuation responses.
+ It should return data that will be encoded and sent to server.
+ It should return None if the client abort response '*' should
+ be sent instead.
+ """
+ mech = mechanism.upper()
+ cap = 'AUTH=%s' % mech
+ if not cap in self.capabilities:
+ raise self.error("Server doesn't allow %s authentication." % mech)
+ self.literal = _Authenticator(authobject).process
+ typ, dat = self._simple_command('AUTHENTICATE', mech)
+ if typ != 'OK':
+ raise self.error(dat[-1])
+ self.state = 'AUTH'
+ return typ, dat
+
+
+ def check(self):
+ """Checkpoint mailbox on server.
+
+ (typ, [data]) = <instance>.check()
+ """
+ return self._simple_command('CHECK')
+
+
+ def close(self):
+ """Close currently selected mailbox.
+
+ Deleted messages are removed from writable mailbox.
+ This is the recommended command before 'LOGOUT'.
+
+ (typ, [data]) = <instance>.close()
+ """
+ try:
+ typ, dat = self._simple_command('CLOSE')
+ finally:
+ self.state = 'AUTH'
+ return typ, dat
+
+
+ def copy(self, message_set, new_mailbox):
+ """Copy 'message_set' messages onto end of 'new_mailbox'.
+
+ (typ, [data]) = <instance>.copy(message_set, new_mailbox)
+ """
+ return self._simple_command('COPY', message_set, new_mailbox)
+
+
+ def create(self, mailbox):
+ """Create new mailbox.
+
+ (typ, [data]) = <instance>.create(mailbox)
+ """
+ return self._simple_command('CREATE', mailbox)
+
+
+ def delete(self, mailbox):
+ """Delete old mailbox.
+
+ (typ, [data]) = <instance>.delete(mailbox)
+ """
+ return self._simple_command('DELETE', mailbox)
+
+
+ def expunge(self):
+ """Permanently remove deleted items from selected mailbox.
+
+ Generates 'EXPUNGE' response for each deleted message.
+
+ (typ, [data]) = <instance>.expunge()
+
+ 'data' is list of 'EXPUNGE'd message numbers in order received.
+ """
+ name = 'EXPUNGE'
+ typ, dat = self._simple_command(name)
+ return self._untagged_response(typ, dat, name)
+
+
+ def fetch(self, message_set, message_parts):
+ """Fetch (parts of) messages.
+
+ (typ, [data, ...]) = <instance>.fetch(message_set, message_parts)
+
+ 'message_parts' should be a string of selected parts
+ enclosed in parentheses, eg: "(UID BODY[TEXT])".
+
+ 'data' are tuples of message part envelope and data.
+ """
+ name = 'FETCH'
+ typ, dat = self._simple_command(name, message_set, message_parts)
+ return self._untagged_response(typ, dat, name)
+
+
+ def list(self, directory='""', pattern='*'):
+ """List mailbox names in directory matching pattern.
+
+ (typ, [data]) = <instance>.list(directory='""', pattern='*')
+
+ 'data' is list of LIST responses.
+ """
+ name = 'LIST'
+ typ, dat = self._simple_command(name, directory, pattern)
+ return self._untagged_response(typ, dat, name)
+
+
+ def login(self, user, password):
+ """Identify client using plaintext password.
+
+ (typ, [data]) = <instance>.login(user, password)
+
+ NB: 'password' will be quoted.
+ """
+ #if not 'AUTH=LOGIN' in self.capabilities:
+ # raise self.error("Server doesn't allow LOGIN authentication." % mech)
+ typ, dat = self._simple_command('LOGIN', user, self._quote(password))
+ if typ != 'OK':
+ raise self.error(dat[-1])
+ self.state = 'AUTH'
+ return typ, dat
+
+
+ def logout(self):
+ """Shutdown connection to server.
+
+ (typ, [data]) = <instance>.logout()
+
+ Returns server 'BYE' response.
+ """
+ self.state = 'LOGOUT'
+ try: typ, dat = self._simple_command('LOGOUT')
+ except: typ, dat = 'NO', ['%s: %s' % sys.exc_info()[:2]]
+ self.file.close()
+ self.sock.close()
+ if self.untagged_responses.has_key('BYE'):
+ return 'BYE', self.untagged_responses['BYE']
+ return typ, dat
+
+
+ def lsub(self, directory='""', pattern='*'):
+ """List 'subscribed' mailbox names in directory matching pattern.
+
+ (typ, [data, ...]) = <instance>.lsub(directory='""', pattern='*')
+
+ 'data' are tuples of message part envelope and data.
+ """
+ name = 'LSUB'
+ typ, dat = self._simple_command(name, directory, pattern)
+ return self._untagged_response(typ, dat, name)
+
+
+ def noop(self):
+ """Send NOOP command.
+
+ (typ, data) = <instance>.noop()
+ """
+ if __debug__:
+ if self.debug >= 3:
+ _dump_ur(self.untagged_responses)
+ return self._simple_command('NOOP')
+
+
+ def partial(self, message_num, message_part, start, length):
+ """Fetch truncated part of a message.
+
+ (typ, [data, ...]) = <instance>.partial(message_num, message_part, start, length)
+
+ 'data' is tuple of message part envelope and data.
+ """
+ name = 'PARTIAL'
+ typ, dat = self._simple_command(name, message_num, message_part, start, length)
+ return self._untagged_response(typ, dat, 'FETCH')
+
+
+ def rename(self, oldmailbox, newmailbox):
+ """Rename old mailbox name to new.
+
+ (typ, data) = <instance>.rename(oldmailbox, newmailbox)
+ """
+ return self._simple_command('RENAME', oldmailbox, newmailbox)
+
+
+ def search(self, charset, *criteria):
+ """Search mailbox for matching messages.
+
+ (typ, [data]) = <instance>.search(charset, criterium, ...)
+
+ 'data' is space separated list of matching message numbers.
+ """
+ name = 'SEARCH'
+ if charset:
+ charset = 'CHARSET ' + charset
+ typ, dat = apply(self._simple_command, (name, charset) + criteria)
+ return self._untagged_response(typ, dat, name)
+
+
+ def select(self, mailbox='INBOX', readonly=None):
+ """Select a mailbox.
+
+ Flush all untagged responses.
+
+ (typ, [data]) = <instance>.select(mailbox='INBOX', readonly=None)
+
+ 'data' is count of messages in mailbox ('EXISTS' response).
+ """
+ # Mandated responses are ('FLAGS', 'EXISTS', 'RECENT', 'UIDVALIDITY')
+ self.untagged_responses = {} # Flush old responses.
+ self.is_readonly = readonly
+ if readonly:
+ name = 'EXAMINE'
+ else:
+ name = 'SELECT'
+ typ, dat = self._simple_command(name, mailbox)
+ if typ != 'OK':
+ self.state = 'AUTH' # Might have been 'SELECTED'
+ return typ, dat
+ self.state = 'SELECTED'
+ if self.untagged_responses.has_key('READ-ONLY') \
+ and not readonly:
+ if __debug__:
+ if self.debug >= 1:
+ _dump_ur(self.untagged_responses)
+ raise self.readonly('%s is not writable' % mailbox)
+ return typ, self.untagged_responses.get('EXISTS', [None])
+
+
+ def status(self, mailbox, names):
+ """Request named status conditions for mailbox.
+
+ (typ, [data]) = <instance>.status(mailbox, names)
+ """
+ name = 'STATUS'
+ if self.PROTOCOL_VERSION == 'IMAP4':
+ raise self.error('%s unimplemented in IMAP4 (obtain IMAP4rev1 server, or re-code)' % name)
+ typ, dat = self._simple_command(name, mailbox, names)
+ return self._untagged_response(typ, dat, name)
+
+
+ def store(self, message_set, command, flags):
+ """Alters flag dispositions for messages in mailbox.
+
+ (typ, [data]) = <instance>.store(message_set, command, flags)
+ """
+ if (flags[0],flags[-1]) != ('(',')'):
+ flags = '(%s)' % flags # Avoid quoting the flags
+ typ, dat = self._simple_command('STORE', message_set, command, flags)
+ return self._untagged_response(typ, dat, 'FETCH')
+
+
+ def subscribe(self, mailbox):
+ """Subscribe to new mailbox.
+
+ (typ, [data]) = <instance>.subscribe(mailbox)
+ """
+ return self._simple_command('SUBSCRIBE', mailbox)
+
+
+ def uid(self, command, *args):
+ """Execute "command arg ..." with messages identified by UID,
+ rather than message number.
+
+ (typ, [data]) = <instance>.uid(command, arg1, arg2, ...)
+
+ Returns response appropriate to 'command'.
+ """
+ command = command.upper()
+ if not Commands.has_key(command):
+ raise self.error("Unknown IMAP4 UID command: %s" % command)
+ if self.state not in Commands[command]:
+ raise self.error('command %s illegal in state %s'
+ % (command, self.state))
+ name = 'UID'
+ typ, dat = apply(self._simple_command, (name, command) + args)
+ if command == 'SEARCH':
+ name = 'SEARCH'
+ else:
+ name = 'FETCH'
+ return self._untagged_response(typ, dat, name)
+
+
+ def unsubscribe(self, mailbox):
+ """Unsubscribe from old mailbox.
+
+ (typ, [data]) = <instance>.unsubscribe(mailbox)
+ """
+ return self._simple_command('UNSUBSCRIBE', mailbox)
+
+
+ def xatom(self, name, *args):
+ """Allow simple extension commands
+ notified by server in CAPABILITY response.
+
+ (typ, [data]) = <instance>.xatom(name, arg, ...)
+ """
+ if name[0] != 'X' or not name in self.capabilities:
+ raise self.error('unknown extension command: %s' % name)
+ return apply(self._simple_command, (name,) + args)
+
+
+
+ # Private methods
+
+
+ def _append_untagged(self, typ, dat):
+
+ if dat is None: dat = ''
+ ur = self.untagged_responses
+ if __debug__:
+ if self.debug >= 5:
+ _mesg('untagged_responses[%s] %s += ["%s"]' %
+ (typ, len(ur.get(typ,'')), dat))
+ if ur.has_key(typ):
+ ur[typ].append(dat)
+ else:
+ ur[typ] = [dat]
+
+
+ def _check_bye(self):
+ bye = self.untagged_responses.get('BYE')
+ if bye:
+ raise self.abort(bye[-1])
+
+
+ def _command(self, name, *args):
+
+ if self.state not in Commands[name]:
+ self.literal = None
+ raise self.error(
+ 'command %s illegal in state %s' % (name, self.state))
+
+ for typ in ('OK', 'NO', 'BAD'):
+ if self.untagged_responses.has_key(typ):
+ del self.untagged_responses[typ]
+
+ if self.untagged_responses.has_key('READ-ONLY') \
+ and not self.is_readonly:
+ raise self.readonly('mailbox status changed to READ-ONLY')
+
+ tag = self._new_tag()
+ data = '%s %s' % (tag, name)
+ for arg in args:
+ if arg is None: continue
+ data = '%s %s' % (data, self._checkquote(arg))
+
+ literal = self.literal
+ if literal is not None:
+ self.literal = None
+ if type(literal) is type(self._command):
+ literator = literal
+ else:
+ literator = None
+ data = '%s {%s}' % (data, len(literal))
+
+ if __debug__:
+ if self.debug >= 4:
+ _mesg('> %s' % data)
+ else:
+ _log('> %s' % data)
+
+ try:
+ self.sock.send('%s%s' % (data, CRLF))
+ except socket.error, val:
+ raise self.abort('socket error: %s' % val)
+
+ if literal is None:
+ return tag
+
+ while 1:
+ # Wait for continuation response
+
+ while self._get_response():
+ if self.tagged_commands[tag]: # BAD/NO?
+ return tag
+
+ # Send literal
+
+ if literator:
+ literal = literator(self.continuation_response)
+
+ if __debug__:
+ if self.debug >= 4:
+ _mesg('write literal size %s' % len(literal))
+
+ try:
+ self.sock.send(literal)
+ self.sock.send(CRLF)
+ except socket.error, val:
+ raise self.abort('socket error: %s' % val)
+
+ if not literator:
+ break
+
+ return tag
+
+
+ def _command_complete(self, name, tag):
+ self._check_bye()
+ try:
+ typ, data = self._get_tagged_response(tag)
+ except self.abort, val:
+ raise self.abort('command: %s => %s' % (name, val))
+ except self.error, val:
+ raise self.error('command: %s => %s' % (name, val))
+ self._check_bye()
+ if typ == 'BAD':
+ raise self.error('%s command error: %s %s' % (name, typ, data))
+ return typ, data
+
+
+ def _get_response(self):
+
+ # Read response and store.
+ #
+ # Returns None for continuation responses,
+ # otherwise first response line received.
+
+ resp = self._get_line()
+
+ # Command completion response?
+
+ if self._match(self.tagre, resp):
+ tag = self.mo.group('tag')
+ if not self.tagged_commands.has_key(tag):
+ raise self.abort('unexpected tagged response: %s' % resp)
+
+ typ = self.mo.group('type')
+ dat = self.mo.group('data')
+ self.tagged_commands[tag] = (typ, [dat])
+ else:
+ dat2 = None
+
+ # '*' (untagged) responses?
+
+ if not self._match(Untagged_response, resp):
+ if self._match(Untagged_status, resp):
+ dat2 = self.mo.group('data2')
+
+ if self.mo is None:
+ # Only other possibility is '+' (continuation) response...
+
+ if self._match(Continuation, resp):
+ self.continuation_response = self.mo.group('data')
+ return None # NB: indicates continuation
+
+ raise self.abort("unexpected response: '%s'" % resp)
+
+ typ = self.mo.group('type')
+ dat = self.mo.group('data')
+ if dat is None: dat = '' # Null untagged response
+ if dat2: dat = dat + ' ' + dat2
+
+ # Is there a literal to come?
+
+ while self._match(Literal, dat):
+
+ # Read literal direct from connection.
+
+ size = int(self.mo.group('size'))
+ if __debug__:
+ if self.debug >= 4:
+ _mesg('read literal size %s' % size)
+ data = self.file.read(size)
+
+ # Store response with literal as tuple
+
+ self._append_untagged(typ, (dat, data))
+
+ # Read trailer - possibly containing another literal
+
+ dat = self._get_line()
+
+ self._append_untagged(typ, dat)
+
+ # Bracketed response information?
+
+ if typ in ('OK', 'NO', 'BAD') and self._match(Response_code, dat):
+ self._append_untagged(self.mo.group('type'), self.mo.group('data'))
+
+ if __debug__:
+ if self.debug >= 1 and typ in ('NO', 'BAD', 'BYE'):
+ _mesg('%s response: %s' % (typ, dat))
+
+ return resp
+
+
+ def _get_tagged_response(self, tag):
+
+ while 1:
+ result = self.tagged_commands[tag]
+ if result is not None:
+ del self.tagged_commands[tag]
+ return result
+
+ # Some have reported "unexpected response" exceptions.
+ # Note that ignoring them here causes loops.
+ # Instead, send me details of the unexpected response and
+ # I'll update the code in `_get_response()'.
+
+ try:
+ self._get_response()
+ except self.abort, val:
+ if __debug__:
+ if self.debug >= 1:
+ print_log()
+ raise
+
+
+ def _get_line(self):
+
+ line = self.file.readline()
+ if not line:
+ raise self.abort('socket error: EOF')
+
+ # Protocol mandates all lines terminated by CRLF
+
+ line = line[:-2]
+ if __debug__:
+ if self.debug >= 4:
+ _mesg('< %s' % line)
+ else:
+ _log('< %s' % line)
+ return line
+
+
+ def _match(self, cre, s):
+
+ # Run compiled regular expression match method on 's'.
+ # Save result, return success.
+
+ self.mo = cre.match(s)
+ if __debug__:
+ if self.mo is not None and self.debug >= 5:
+ _mesg("\tmatched r'%s' => %s" % (cre.pattern, `self.mo.groups()`))
+ return self.mo is not None
+
+
+ def _new_tag(self):
+
+ tag = '%s%s' % (self.tagpre, self.tagnum)
+ self.tagnum = self.tagnum + 1
+ self.tagged_commands[tag] = None
+ return tag
+
+
+ def _checkquote(self, arg):
+
+ # Must quote command args if non-alphanumeric chars present,
+ # and not already quoted.
+
+ if type(arg) is not type(''):
+ return arg
+ if (arg[0],arg[-1]) in (('(',')'),('"','"')):
+ return arg
+ if self.mustquote.search(arg) is None:
+ return arg
+ return self._quote(arg)
+
+
+ def _quote(self, arg):
+
+ arg = arg.replace('\\', '\\\\')
+ arg = arg.replace('"', '\\"')
+
+ return '"%s"' % arg
+
+
+ def _simple_command(self, name, *args):
+
+ return self._command_complete(name, apply(self._command, (name,) + args))
+
+
+ def _untagged_response(self, typ, dat, name):
+
+ if typ == 'NO':
+ return typ, dat
+ if not self.untagged_responses.has_key(name):
+ return typ, [None]
+ data = self.untagged_responses[name]
+ if __debug__:
+ if self.debug >= 5:
+ _mesg('untagged_responses[%s] => %s' % (name, data))
+ del self.untagged_responses[name]
+ return typ, data
+
+
+
+class _Authenticator:
+
+ """Private class to provide en/decoding
+ for base64-based authentication conversation.
+ """
+
+ def __init__(self, mechinst):
+ self.mech = mechinst # Callable object to provide/process data
+
+ def process(self, data):
+ ret = self.mech(self.decode(data))
+ if ret is None:
+ return '*' # Abort conversation
+ return self.encode(ret)
+
+ def encode(self, inp):
+ #
+ # Invoke binascii.b2a_base64 iteratively with
+ # short even length buffers, strip the trailing
+ # line feed from the result and append. "Even"
+ # means a number that factors to both 6 and 8,
+ # so when it gets to the end of the 8-bit input
+ # there's no partial 6-bit output.
+ #
+ oup = ''
+ while inp:
+ if len(inp) > 48:
+ t = inp[:48]
+ inp = inp[48:]
+ else:
+ t = inp
+ inp = ''
+ e = binascii.b2a_base64(t)
+ if e:
+ oup = oup + e[:-1]
+ return oup
+
+ def decode(self, inp):
+ if not inp:
+ return ''
+ return binascii.a2b_base64(inp)
+
+
+
+Mon2num = {'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6,
+ 'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12}
+
+def Internaldate2tuple(resp):
+ """Convert IMAP4 INTERNALDATE to UT.
+
+ Returns Python time module tuple.
+ """
+
+ mo = InternalDate.match(resp)
+ if not mo:
+ return None
+
+ mon = Mon2num[mo.group('mon')]
+ zonen = mo.group('zonen')
+
+ day = int(mo.group('day'))
+ year = int(mo.group('year'))
+ hour = int(mo.group('hour'))
+ min = int(mo.group('min'))
+ sec = int(mo.group('sec'))
+ zoneh = int(mo.group('zoneh'))
+ zonem = int(mo.group('zonem'))
+
+ # INTERNALDATE timezone must be subtracted to get UT
+
+ zone = (zoneh*60 + zonem)*60
+ if zonen == '-':
+ zone = -zone
+
+ tt = (year, mon, day, hour, min, sec, -1, -1, -1)
+
+ utc = time.mktime(tt)
+
+ # Following is necessary because the time module has no 'mkgmtime'.
+ # 'mktime' assumes arg in local timezone, so adds timezone/altzone.
+
+ lt = time.localtime(utc)
+ if time.daylight and lt[-1]:
+ zone = zone + time.altzone
+ else:
+ zone = zone + time.timezone
+
+ return time.localtime(utc - zone)
+
+
+
+def Int2AP(num):
+
+ """Convert integer to A-P string representation."""
+
+ val = ''; AP = 'ABCDEFGHIJKLMNOP'
+ num = int(abs(num))
+ while num:
+ num, mod = divmod(num, 16)
+ val = AP[mod] + val
+ return val
+
+
+
+def ParseFlags(resp):
+
+ """Convert IMAP4 flags response to python tuple."""
+
+ mo = Flags.match(resp)
+ if not mo:
+ return ()
+
+ return tuple(mo.group('flags').split())
+
+
+def Time2Internaldate(date_time):
+
+ """Convert 'date_time' to IMAP4 INTERNALDATE representation.
+
+ Return string in form: '"DD-Mmm-YYYY HH:MM:SS +HHMM"'
+ """
+
+ dttype = type(date_time)
+ if dttype is type(1) or dttype is type(1.1):
+ tt = time.localtime(date_time)
+ elif dttype is type(()):
+ tt = date_time
+ elif dttype is type(""):
+ return date_time # Assume in correct format
+ else: raise ValueError
+
+ dt = time.strftime("%d-%b-%Y %H:%M:%S", tt)
+ if dt[0] == '0':
+ dt = ' ' + dt[1:]
+ if time.daylight and tt[-1]:
+ zone = -time.altzone
+ else:
+ zone = -time.timezone
+ return '"' + dt + " %+02d%02d" % divmod(zone/60, 60) + '"'
+
+
+
+if __debug__:
+
+ def _mesg(s, secs=None):
+ if secs is None:
+ secs = time.time()
+ tm = time.strftime('%M:%S', time.localtime(secs))
+ sys.stderr.write(' %s.%02d %s\n' % (tm, (secs*100)%100, s))
+ sys.stderr.flush()
+
+ def _dump_ur(dict):
+ # Dump untagged responses (in `dict').
+ l = dict.items()
+ if not l: return
+ t = '\n\t\t'
+ l = map(lambda x:'%s: "%s"' % (x[0], x[1][0] and '" "'.join(x[1]) or ''), l)
+ _mesg('untagged responses dump:%s%s' % (t, t.join(l)))
+
+ _cmd_log = [] # Last `_cmd_log_len' interactions
+ _cmd_log_len = 10
+
+ def _log(line):
+ # Keep log of last `_cmd_log_len' interactions for debugging.
+ if len(_cmd_log) == _cmd_log_len:
+ del _cmd_log[0]
+ _cmd_log.append((time.time(), line))
+
+ def print_log():
+ _mesg('last %d IMAP4 interactions:' % len(_cmd_log))
+ for secs,line in _cmd_log:
+ _mesg(line, secs)
+
+
+
+if __name__ == '__main__':
+
+ import getopt, getpass, sys
+
+ try:
+ optlist, args = getopt.getopt(sys.argv[1:], 'd:')
+ except getopt.error, val:
+ pass
+
+ for opt,val in optlist:
+ if opt == '-d':
+ Debug = int(val)
+
+ if not args: args = ('',)
+
+ host = args[0]
+
+ USER = getpass.getuser()
+ PASSWD = getpass.getpass("IMAP password for %s on %s:" % (USER, host or "localhost"))
+
+ test_mesg = 'From: %s@localhost\nSubject: IMAP4 test\n\ndata...\n' % USER
+ test_seq1 = (
+ ('login', (USER, PASSWD)),
+ ('create', ('/tmp/xxx 1',)),
+ ('rename', ('/tmp/xxx 1', '/tmp/yyy')),
+ ('CREATE', ('/tmp/yyz 2',)),
+ ('append', ('/tmp/yyz 2', None, None, test_mesg)),
+ ('list', ('/tmp', 'yy*')),
+ ('select', ('/tmp/yyz 2',)),
+ ('search', (None, 'SUBJECT', 'test')),
+ ('partial', ('1', 'RFC822', 1, 1024)),
+ ('store', ('1', 'FLAGS', '(\Deleted)')),
+ ('expunge', ()),
+ ('recent', ()),
+ ('close', ()),
+ )
+
+ test_seq2 = (
+ ('select', ()),
+ ('response',('UIDVALIDITY',)),
+ ('uid', ('SEARCH', 'ALL')),
+ ('response', ('EXISTS',)),
+ ('append', (None, None, None, test_mesg)),
+ ('recent', ()),
+ ('logout', ()),
+ )
+
+ def run(cmd, args):
+ _mesg('%s %s' % (cmd, args))
+ typ, dat = apply(eval('M.%s' % cmd), args)
+ _mesg('%s => %s %s' % (cmd, typ, dat))
+ return dat
+
+ try:
+ M = IMAP4(host)
+ _mesg('PROTOCOL_VERSION = %s' % M.PROTOCOL_VERSION)
+
+ for cmd,args in test_seq1:
+ run(cmd, args)
+
+ for ml in run('list', ('/tmp/', 'yy%')):
+ mo = re.match(r'.*"([^"]+)"$', ml)
+ if mo: path = mo.group(1)
+ else: path = ml.split()[-1]
+ run('delete', (path,))
+
+ for cmd,args in test_seq2:
+ dat = run(cmd, args)
+
+ if (cmd,args) != ('uid', ('SEARCH', 'ALL')):
+ continue
+
+ uid = dat[-1].split()
+ if not uid: continue
+ run('uid', ('FETCH', '%s' % uid[-1],
+ '(FLAGS INTERNALDATE RFC822.SIZE RFC822.HEADER RFC822.TEXT)'))
+
+ print '\nAll tests OK.'
+
+ except:
+ print '\nTests failed.'
+
+ if not Debug:
+ print '''
+If you would like to see debugging output,
+try: %s -d5
+''' % sys.argv[0]
+
+ raise
diff --git a/lib/jython/Lib/imghdr.py b/lib/jython/Lib/imghdr.py new file mode 100644 index 000000000..5fd578175 --- /dev/null +++ b/lib/jython/Lib/imghdr.py @@ -0,0 +1,154 @@ +"""Recognize image file formats based on their first few bytes."""
+
+__all__ = ["what"]
+
+#-------------------------#
+# Recognize image headers #
+#-------------------------#
+
+def what(file, h=None):
+ if h is None:
+ if type(file) == type(''):
+ f = open(file, 'rb')
+ h = f.read(32)
+ else:
+ location = file.tell()
+ h = file.read(32)
+ file.seek(location)
+ f = None
+ else:
+ f = None
+ try:
+ for tf in tests:
+ res = tf(h, f)
+ if res:
+ return res
+ finally:
+ if f: f.close()
+ return None
+
+
+#---------------------------------#
+# Subroutines per image file type #
+#---------------------------------#
+
+tests = []
+
+def test_rgb(h, f):
+ """SGI image library"""
+ if h[:2] == '\001\332':
+ return 'rgb'
+
+tests.append(test_rgb)
+
+def test_gif(h, f):
+ """GIF ('87 and '89 variants)"""
+ if h[:6] in ('GIF87a', 'GIF89a'):
+ return 'gif'
+
+tests.append(test_gif)
+
+def test_pbm(h, f):
+ """PBM (portable bitmap)"""
+ if len(h) >= 3 and \
+ h[0] == 'P' and h[1] in '14' and h[2] in ' \t\n\r':
+ return 'pbm'
+
+tests.append(test_pbm)
+
+def test_pgm(h, f):
+ """PGM (portable graymap)"""
+ if len(h) >= 3 and \
+ h[0] == 'P' and h[1] in '25' and h[2] in ' \t\n\r':
+ return 'pgm'
+
+tests.append(test_pgm)
+
+def test_ppm(h, f):
+ """PPM (portable pixmap)"""
+ if len(h) >= 3 and \
+ h[0] == 'P' and h[1] in '36' and h[2] in ' \t\n\r':
+ return 'ppm'
+
+tests.append(test_ppm)
+
+def test_tiff(h, f):
+ """TIFF (can be in Motorola or Intel byte order)"""
+ if h[:2] in ('MM', 'II'):
+ return 'tiff'
+
+tests.append(test_tiff)
+
+def test_rast(h, f):
+ """Sun raster file"""
+ if h[:4] == '\x59\xA6\x6A\x95':
+ return 'rast'
+
+tests.append(test_rast)
+
+def test_xbm(h, f):
+ """X bitmap (X10 or X11)"""
+ s = '#define '
+ if h[:len(s)] == s:
+ return 'xbm'
+
+tests.append(test_xbm)
+
+def test_jpeg(h, f):
+ """JPEG data in JFIF format"""
+ if h[6:10] == 'JFIF':
+ return 'jpeg'
+
+tests.append(test_jpeg)
+
+def test_bmp(h, f):
+ if h[:2] == 'BM':
+ return 'bmp'
+
+tests.append(test_bmp)
+
+def test_png(h, f):
+ if h[:8] == "\211PNG\r\n\032\n":
+ return 'png'
+
+tests.append(test_png)
+
+#--------------------#
+# 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/jython/Lib/isql.py b/lib/jython/Lib/isql.py new file mode 100644 index 000000000..aecc32868 --- /dev/null +++ b/lib/jython/Lib/isql.py @@ -0,0 +1,145 @@ +# $Id: isql.py,v 1.1 2001/11/20 04:55:18 bzimmer Exp $
+
+import dbexts, cmd, sys
+
+"""
+Isql works in conjunction with dbexts to provide an interactive environment
+for database work.
+"""
+
+__version__ = "$Revision: 1.1 $"[11:-2]
+
+class Prompt:
+ """
+ This class fixes a problem with the cmd.Cmd class since it uses an ivar 'prompt'
+ as opposed to a method 'prompt()'. To get around this, this class is plugged in
+ as a 'prompt' attribute and when invoked the '__str__' method is called which
+ figures out the appropriate prompt to display. I still think, even though this
+ is clever, the attribute version of 'prompt' is poor design.
+ """
+ def __init__(self, isql):
+ self.isql = isql
+ def __str__(self):
+ prompt = "%s> " % (self.isql.db.dbname)
+ if len(self.isql.sqlbuffer) > 0:
+ prompt = "... "
+ return prompt
+
+class IsqlCmd(cmd.Cmd):
+
+ def __init__(self, db=None, delimiter=";"):
+ cmd.Cmd.__init__(self)
+ if db is None or type(db) == type(""):
+ self.db = dbexts.dbexts(db)
+ else:
+ self.db = db
+ self.kw = {}
+ self.sqlbuffer = []
+ self.delimiter = delimiter
+ self.prompt = Prompt(self)
+
+ def do_which(self, arg):
+ """\nPrints the current db connection parameters.\n"""
+ print self.db
+ return None
+
+ def do_EOF(self, arg):
+ return None
+
+ def do_p(self, arg):
+ """\nExecute a python expression.\n"""
+ try:
+ exec arg.strip() in globals()
+ except:
+ print sys.exc_info()[1]
+ return None
+
+ def do_use(self, arg):
+ """\nUse a new database connection.\n"""
+ self.db = dbexts.dbexts(arg.strip())
+ return None
+
+ def do_table(self, arg):
+ """\nPrints table meta-data. If no table name, prints all tables.\n"""
+ if len(arg.strip()):
+ apply(self.db.table, (arg,), self.kw)
+ else:
+ apply(self.db.table, (None,), self.kw)
+ return None
+
+ def do_proc(self, arg):
+ """\nPrints store procedure meta-data.\n"""
+ if len(arg.strip()):
+ apply(self.db.proc, (arg,), self.kw)
+ else:
+ apply(self.db.proc, (None,), self.kw)
+ return None
+
+ def do_schema(self, arg):
+ """\nPrints schema information.\n"""
+ print
+ self.db.schema(arg)
+ print
+ return None
+
+ def do_delimiter(self, arg):
+ """\nChange the delimiter.\n"""
+ delimiter = arg.strip()
+ if len(delimiter) > 0:
+ self.delimiter = delimiter
+
+ def do_q(self, arg):
+ """\nQuit.\n"""
+ return 1
+
+ def do_set(self, arg):
+ """\nSet a parameter. Some examples:\n set owner = 'informix'\n set types = ['VIEW', 'TABLE']\nThe right hand side is evaluated using `eval()`\n"""
+ d = filter(lambda x: len(x) > 0, map(lambda x: x.strip(), arg.split("=")))
+ if len(d) == 1:
+ if self.kw.has_key(d[0]):
+ del self.kw[d[0]]
+ else:
+ self.kw[d[0]] = eval(d[1])
+
+ def default(self, arg):
+ try:
+ token = arg.strip()
+ # is it possible the line contains the delimiter
+ if len(token) >= len(self.delimiter):
+ # does the line end with the delimiter
+ if token[-1 * len(self.delimiter):] == self.delimiter:
+ # now add all up to the delimiter
+ self.sqlbuffer.append(token[:-1 * len(self.delimiter)])
+ if self.sqlbuffer:
+ self.db.isql(" ".join(self.sqlbuffer))
+ self.sqlbuffer = []
+ return None
+ if token:
+ self.sqlbuffer.append(token)
+ except:
+ self.sqlbuffer = []
+ print sys.exc_info()[1]
+ return None
+
+ def emptyline(self):
+ return None
+
+if __name__ == '__main__':
+ import getopt
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "b:", [])
+ except getopt.error, msg:
+ print
+ print msg
+ print "Try `%s --help` for more information." % (sys.argv[0])
+ sys.exit(0)
+
+ dbname = None
+ for opt, arg in opts:
+ if opt == '-b':
+ dbname = arg
+
+ intro = "\nisql - interactive sql (%s)\n" % (__version__)
+
+ IsqlCmd(dbname).cmdloop(intro)
diff --git a/lib/jython/Lib/javaos.py b/lib/jython/Lib/javaos.py new file mode 100644 index 000000000..ef5436132 --- /dev/null +++ b/lib/jython/Lib/javaos.py @@ -0,0 +1,467 @@ +r"""OS routines for Java, with some attempts to support DOS, NT, and
+Posix functionality.
+
+This exports:
+ - all functions from posix, nt, dos, os2, mac, or ce, e.g. unlink, stat, etc.
+ - os.path is one of the modules posixpath, ntpath, macpath, or dospath
+ - os.name is 'posix', 'nt', 'dos', 'os2', 'mac', 'ce' or 'riscos'
+ - os.curdir is a string representing the current directory ('.' or ':')
+ - os.pardir is a string representing the parent directory ('..' or '::')
+ - os.sep is the (or a most common) pathname separator ('/' or ':' or '\\')
+ - os.altsep is the alternate pathname separator (None or '/')
+ - os.pathsep is the component separator used in $PATH etc
+ - os.linesep is the line separator in text files ('\r' or '\n' or '\r\n')
+ - os.defpath is the default search path for executables
+
+Programs that import and use 'os' stand a better chance of being
+portable between different platforms. Of course, they must then
+only use functions that are defined by all platforms (e.g., unlink
+and opendir), and leave all pathname manipulation to os.path
+(e.g., split and join).
+"""
+
+__all__ = ["altsep", "curdir", "pardir", "sep", "pathsep", "linesep",
+ "defpath", "name"]
+
+import java
+from java.io import File, BufferedReader, InputStreamReader, IOException
+import javapath as path
+from UserDict import UserDict
+import string
+import exceptions
+import re
+import sys
+import thread
+
+
+error = OSError
+
+name = 'java' # discriminate based on JDK version?
+curdir = '.' # default to Posix for directory behavior, override below
+pardir = '..'
+sep = java.io.File.separator
+altsep = None
+pathsep = java.io.File.pathSeparator
+defpath = '.'
+linesep = java.lang.System.getProperty('line.separator')
+
+def _exit(n=0):
+ java.lang.System.exit(n)
+
+def getcwd():
+ foo = File(File("foo").getAbsolutePath())
+ return foo.getParent()
+
+def chdir(path):
+ raise OSError(0, 'chdir not supported in Java', path)
+
+def listdir(path):
+ l = File(path).list()
+ if l is None:
+ raise OSError(0, 'No such directory', path)
+ return list(l)
+
+def mkdir(path, mode='ignored'):
+ if not File(path).mkdir():
+ raise OSError(0, "couldn't make directory", path)
+
+def makedirs(path, mode='ignored'):
+ if not File(path).mkdirs():
+ raise OSError(0, "couldn't make directories", path)
+
+def remove(path):
+ if not File(path).delete():
+ raise OSError(0, "couldn't delete file", path)
+
+def rename(path, newpath):
+ if not File(path).renameTo(File(newpath)):
+ raise OSError(0, "couldn't rename file", path)
+
+def rmdir(path):
+ if not File(path).delete():
+ raise OSError(0, "couldn't delete directory", path)
+
+unlink = remove
+
+def stat(path):
+ """The Java stat implementation only returns a small subset of
+ the standard fields"""
+ f = File(path)
+ size = f.length()
+ # Sadly, if the returned length is zero, we don't really know if the file
+ # is zero sized or does not exist.
+ if size == 0 and not f.exists():
+ raise OSError(0, 'No such file or directory', path)
+ mtime = f.lastModified() / 1000.0
+ return (0, 0, 0, 0, 0, 0, size, mtime, mtime, 0)
+
+def utime(path, times):
+ # Only the modification time is changed (and only on java2).
+ if times and hasattr(File, "setLastModified"):
+ File(path).setLastModified(long(times[1] * 1000.0))
+
+class LazyDict( UserDict ):
+ """A lazy-populating User Dictionary.
+ Lazy initialization is not thread-safe.
+ """
+ def __init__( self,
+ dict=None,
+ populate=None,
+ keyTransform=None ):
+ """dict: starting dictionary of values
+ populate: function that returns the populated dictionary
+ keyTransform: function to normalize the keys (e.g., toupper/None)
+ """
+ UserDict.__init__( self, dict )
+ self._populated = 0
+ self.__populateFunc = populate or (lambda: {})
+ self._keyTransform = keyTransform or (lambda key: key)
+
+ def __populate( self ):
+ if not self._populated:
+ self.data = self.__populateFunc()
+ self._populated = 1 # race condition
+
+ ########## extend methods from UserDict by pre-populating
+ def __repr__(self):
+ self.__populate()
+ return UserDict.__repr__( self )
+ def __cmp__(self, dict):
+ self.__populate()
+ return UserDict.__cmp__( self, dict )
+ def __len__(self):
+ self.__populate()
+ return UserDict.__len__( self )
+ def __getitem__(self, key):
+ self.__populate()
+ return UserDict.__getitem__( self, self._keyTransform(key) )
+ def __setitem__(self, key, item):
+ self.__populate()
+ UserDict.__setitem__( self, self._keyTransform(key), item )
+ def __delitem__(self, key):
+ self.__populate()
+ UserDict.__delitem__( self, self._keyTransform(key) )
+ def clear(self):
+ self.__populate()
+ UserDict.clear( self )
+ def copy(self):
+ self.__populate()
+ return UserDict.copy( self )
+ def keys(self):
+ self.__populate()
+ return UserDict.keys( self )
+ def items(self):
+ self.__populate()
+ return UserDict.items( self )
+ def values(self):
+ self.__populate()
+ return UserDict.values( self )
+ def has_key(self, key):
+ self.__populate()
+ return UserDict.has_key( self, self._keyTransform(key) )
+ def update(self, dict):
+ self.__populate()
+ UserDict.update( self, dict )
+ def get(self, key, failobj=None):
+ self.__populate()
+ return UserDict.get( self, self._keyTransform(key), failobj )
+ def setdefault(self, key, failobj=None):
+ self.__populate()
+ return UserDict.setdefault( self, self._keyTransform(key), failobj )
+ def popitem(self):
+ self.__populate()
+ return UserDict.popitem( self )
+
+
+class _ShellEnv:
+ """Provide environment derived by spawning a subshell and parsing its
+ environment. Also supports system functions and provides empty
+ environment support for platforms with unknown shell
+ functionality.
+ """
+ def __init__( self, cmd=None, getEnv=None, keyTransform=None ):
+ """cmd: list of exec() arguments to run command in subshell, or None
+ getEnv: shell command to list environment variables, or None
+ keyTransform: normalization function for environment keys, or None
+ """
+ self.cmd = cmd
+ self.getEnv = getEnv
+ self.environment = LazyDict(populate=self._getEnvironment,
+ keyTransform=keyTransform)
+ self._keyTransform = self.environment._keyTransform
+
+ ########## system
+ def system( self, cmd ):
+ """Imitate the standard library 'system' call.
+ Execute 'cmd' in a shell, and send output to stdout & stderr.
+ """
+ p = self.execute( cmd )
+
+ def println( arg, write=sys.stdout.write ):
+ write( arg + "\n" )
+ def printlnStdErr( arg, write=sys.stderr.write ):
+ write( arg + "\n" )
+
+ # read stderr in new thread
+ thread.start_new_thread( self._readLines,
+ ( p.getErrorStream(), printlnStdErr ))
+ # read stdin in main thread
+ self._readLines( p.getInputStream(), println )
+
+ return p.waitFor()
+
+ def execute( self, cmd ):
+ """Execute cmd in a shell, and return the process instance"""
+ shellCmd = self._formatCmd( cmd )
+ if self.environment._populated:
+ env = self._formatEnvironment( self.environment )
+ else:
+ env = None
+ try:
+ p = java.lang.Runtime.getRuntime().exec( shellCmd, env )
+ return p
+ except IOException, ex:
+ raise OSError(
+ 0,
+ "Failed to execute command (%s): %s" % ( shellCmd, ex )
+ )
+
+ ########## utility methods
+ def _readLines( self, stream, func=None ):
+ """Read lines of stream, and either append them to return
+ array of lines, or call func on each line.
+ """
+ lines = []
+ func = func or lines.append
+ # should read both stderror and stdout in separate threads...
+ bufStream = BufferedReader( InputStreamReader( stream ))
+ while 1:
+ line = bufStream.readLine()
+ if line is None: break
+ func( line )
+ return lines or None
+
+ def _formatCmd( self, cmd ):
+ """Format a command for execution in a shell."""
+ if self.cmd is None:
+ msgFmt = "Unable to execute commands in subshell because shell" \
+ " functionality not implemented for OS %s with shell" \
+ " setting %s. Failed command=%s"""
+ raise OSError( 0, msgFmt % ( _osType, _envType, cmd ))
+
+ return self.cmd + [cmd]
+
+ def _formatEnvironment( self, env ):
+ """Format enviroment in lines suitable for Runtime.exec"""
+ lines = []
+ for keyValue in env.items():
+ lines.append( "%s=%s" % keyValue )
+ return lines
+
+ def _getEnvironment( self ):
+ """Get the environment variables by spawning a subshell.
+ This allows multi-line variables as long as subsequent lines do
+ not have '=' signs.
+ """
+ env = {}
+ if self.getEnv:
+ try:
+ p = self.execute( self.getEnv )
+ lines = self._readLines( p.getInputStream() )
+ if '=' not in lines[0]:
+ print "getEnv command (%s) did not print environment.\n" \
+ "Output=%s" % (
+ self.getEnv, '\n'.join( lines )
+ )
+ return env
+
+ for line in lines:
+ try:
+ i = line.index( '=' )
+ key = self._keyTransform(line[:i])
+ value = line[i+1:]
+ except ValueError:
+ # found no '=', so line is part of previous value
+ value = '%s\n%s' % ( value, line )
+ env[ key ] = value
+ except OSError, ex:
+ print "Failed to get environment, environ will be empty:", ex
+ return env
+
+def _getOsType( os=None ):
+ """Select the OS behavior based on os argument, 'python.os' registry
+ setting and 'os.name' Java property.
+ os: explicitly select desired OS. os=None to autodetect, os='None' to
+ disable
+ """
+ os = os or sys.registry.getProperty( "python.os" ) or \
+ java.lang.System.getProperty( "os.name" )
+
+ _osTypeMap = (
+ ( "nt", r"(nt)|(Windows NT)|(Windows NT 4.0)|(WindowsNT)|"
+ r"(Windows 2000)|(Windows XP)|(Windows CE)" ),
+ ( "dos", r"(dos)|(Windows 95)|(Windows 98)|(Windows ME)" ),
+ ( "mac", r"(mac)|(MacOS.*)|(Darwin)" ),
+ ( "None", r"(None)" ),
+ ( "posix", r"(.*)" ), # default - posix seems to vary mast widely
+ )
+ for osType, pattern in _osTypeMap:
+ if re.match( pattern, os ):
+ break
+ return osType
+
+def _getShellEnv( envType, shellCmd, envCmd, envTransform ):
+ """Create the desired environment type.
+ envType: 'shell' or None
+ """
+ if envType == "shell":
+ return _ShellEnv( shellCmd, envCmd, envTransform )
+ else:
+ return _ShellEnv()
+
+_osType = _getOsType()
+_envType = sys.registry.getProperty("python.environment", "shell")
+
+# default to None/empty for shell and environment behavior
+_shellCmd = None
+_envCmd = None
+_envTransform = None
+
+# override defaults based on _osType
+if _osType == "nt":
+ _shellCmd = ["cmd", "/c"]
+ _envCmd = "set"
+ _envTransform = string.upper
+elif _osType == "dos":
+ _shellCmd = ["command.com", "/c"]
+ _envCmd = "set"
+ _envTransform = string.upper
+elif _osType == "posix":
+ _shellCmd = ["sh", "-c"]
+ _envCmd = "env"
+elif _osType == "mac":
+ curdir = ':' # override Posix directories
+ pardir = '::'
+elif _osType == "None":
+ pass
+# else:
+# # may want a warning, but only at high verbosity:
+# warn( "Unknown os type '%s', using default behavior." % _osType )
+
+_shellEnv = _getShellEnv( _envType, _shellCmd, _envCmd, _envTransform )
+
+# provide environ, putenv, getenv
+environ = _shellEnv.environment
+putenv = environ.__setitem__
+getenv = environ.__getitem__
+# provide system
+system = _shellEnv.system
+
+########## test code
+def _testGetOsType():
+ testVals = {
+ "Windows NT": "nt",
+ "Windows 95": "dos",
+ "MacOS": "mac",
+ "Solaris": "posix",
+ "Linux": "posix",
+ "None": "None"
+ }
+
+ msgFmt = "_getOsType( '%s' ) should return '%s', not '%s'"
+ # test basic mappings
+ for key, val in testVals.items():
+ got = _getOsType( key )
+ assert got == val, msgFmt % ( key, val, got )
+
+def _testCmds( _shellEnv, testCmds, whichEnv ):
+ # test commands (key) and compare output to expected output (value).
+ # this actually executes all the commands twice, testing the return
+ # code by calling system(), and testing some of the output by calling
+ # execute()
+ for cmd, pattern in testCmds:
+ print "\nExecuting '%s' with %s environment" % (cmd, whichEnv)
+ assert not _shellEnv.system( cmd ), \
+ "%s failed with %s environment" % (cmd, whichEnv)
+ line = _shellEnv._readLines(
+ _shellEnv.execute(cmd).getInputStream())[0]
+ assert re.match( pattern, line ), \
+ "expected match for %s, got %s" % ( pattern, line )
+
+def _testSystem( shellEnv=_shellEnv ):
+ # test system and environment functionality
+ key, value = "testKey", "testValue"
+ org = environ
+ testCmds = [
+ # test commands and regexes to match first line of expected
+ # output on first and second runs
+ # Note that the validation is incomplete for several of these
+ # - they should validate depending on platform and pre-post, but
+ # they don't.
+
+ # no quotes, should output both words
+ ("echo hello there", "hello there"),
+ # should print PATH (on NT)
+ ("echo PATH=%PATH%", "(PATH=.*;.*)|(PATH=%PATH%)"),
+ # should print 'testKey=%testKey%' on NT before initialization,
+ # should print 'testKey=' on 95 before initialization,
+ # and 'testKey=testValue' after
+ ("echo %s=%%%s%%" % (key,key),
+ "(%s=)" % (key,)),
+ # should print PATH (on Unix)
+ ( "echo PATH=$PATH", "PATH=.*" ),
+ # should print 'testKey=testValue' on Unix after initialization
+ ( "echo %s=$%s" % (key,key),
+ "(%s=$%s)|(%s=)|(%s=%s)" % (key, key, key, key, value ) ),
+ # should output quotes on NT but not on Unix
+ ( 'echo "hello there"', '"?hello there"?' ),
+ # should print 'why' to stdout.
+ ( r'''jython -c "import sys;sys.stdout.write( 'why\n' )"''', "why" ),
+ # should print 'why' to stderr, but it won't right now. Have
+ # to add the print to give some output...empty string matches every
+ # thing...
+ ( r'''jython -c "import sys;sys.stderr.write('why\n');print " ''',
+ "" )
+ ]
+
+ assert not environ._populated, \
+ "before population, environ._populated should be false"
+
+ _testCmds( _shellEnv, testCmds, "default" )
+
+ # trigger initialization of environment
+ environ[ key ] = value
+
+ assert environ._populated, \
+ "after population, environ._populated should be true"
+ assert org.get( key, None ) == value, \
+ "expected stub to have %s set" % key
+ assert environ.get( key, None ) == value, \
+ "expected real environment to have %s set" % key
+
+ # test system using the non-default environment
+ _testCmds( _shellEnv, testCmds, "initialized" )
+
+ assert environ.has_key( "PATH" ), \
+ "expected environment to have PATH attribute " \
+ "(this may not apply to all platforms!)"
+
+def _testBadShell():
+ # attempt to get an environment with a shell that is not startable
+ se2 = _ShellEnv( ["badshell", "-c"], "set" )
+ str(se2.environment) # trigger initialization
+ assert not se2.environment.items(), "environment should be empty"
+
+def _testBadGetEnv():
+ # attempt to get an environment with a command that does not print an environment
+ se2 = _getShellEnv( "shell", _shellCmd, _envCmd, _envTransform )
+ se2.getEnv="echo This command does not print environment"
+ str(se2.environment) # trigger initialization
+ assert not se2.environment.items(), "environment should be empty"
+
+def _test():
+ _testGetOsType()
+ _testBadShell()
+ _testBadGetEnv()
+ _testSystem()
+
diff --git a/lib/jython/Lib/javapath.py b/lib/jython/Lib/javapath.py new file mode 100644 index 000000000..8292331b9 --- /dev/null +++ b/lib/jython/Lib/javapath.py @@ -0,0 +1,331 @@ +"""Common pathname manipulations, JDK version.
+
+Instead of importing this module directly, import os and refer to this
+module as os.path.
+
+"""
+
+# Incompletely implemented:
+# islink -- How?
+# ismount -- How?
+# splitdrive -- How?
+# normcase -- How?
+
+# Missing:
+# sameopenfile -- Java doesn't have fstat nor file descriptors?
+# samestat -- How?
+
+import java
+from java.io import File
+from java.lang import System
+import os
+
+def _tostr(s, method):
+ if isinstance(s, "".__class__):
+ return s
+ import org
+ raise TypeError, "%s() argument must be a string object, not %s" % (
+ method, org.python.core.Py.safeRepr(s))
+
+def dirname(path):
+ """Return the directory component of a pathname"""
+ path = _tostr(path, "dirname")
+ result = File(path).getParent()
+ if not result:
+ if isabs(path):
+ result = path # Must be root
+ else:
+ result = ""
+ return result
+
+def basename(path):
+ """Return the final component of a pathname"""
+ path = _tostr(path, "basename")
+ return File(path).getName()
+
+def split(path):
+ """Split a pathname.
+
+ Return tuple "(head, tail)" where "tail" is everything after the
+ final slash. Either part may be empty.
+
+ """
+ path = _tostr(path, "split")
+ return (dirname(path), basename(path))
+
+def splitext(path):
+ """Split the extension from a pathname.
+
+ Extension is everything from the last dot to the end. Return
+ "(root, ext)", either part may be empty.
+
+ """
+ i = 0
+ n = -1
+ for c in path:
+ if c == '.': n = i
+ i = i+1
+ if n < 0:
+ return (path, "")
+ else:
+ return (path[:n], path[n:])
+
+def splitdrive(path):
+ """Split a pathname into drive and path.
+
+ On JDK, drive is always empty.
+ XXX This isn't correct for JDK on DOS/Windows!
+
+ """
+ return ("", path)
+
+def exists(path):
+ """Test whether a path exists.
+
+ Returns false for broken symbolic links.
+
+ """
+ path = _tostr(path, "exists")
+ return File(path).exists()
+
+def isabs(path):
+ """Test whether a path is absolute"""
+ path = _tostr(path, "isabs")
+ return File(path).isAbsolute()
+
+def isfile(path):
+ """Test whether a path is a regular file"""
+ path = _tostr(path, "isfile")
+ return File(path).isFile()
+
+def isdir(path):
+ """Test whether a path is a directory"""
+ path = _tostr(path, "isdir")
+ return File(path).isDirectory()
+
+def join(path, *args):
+ """Join two or more pathname components, inserting os.sep as needed"""
+ path = _tostr(path, "join")
+ f = File(path)
+ for a in args:
+ a = _tostr(a, "join")
+ g = File(a)
+ if g.isAbsolute() or len(f.getPath()) == 0:
+ f = g
+ else:
+ f = File(f, a)
+ return f.getPath()
+
+def normcase(path):
+ """Normalize case of pathname.
+
+ XXX Not done right under JDK.
+
+ """
+ path = _tostr(path, "normcase")
+ return File(path).getPath()
+
+def commonprefix(m):
+ "Given a list of pathnames, return the longest common leading component"
+ 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
+
+def islink(path):
+ """Test whether a path is a symbolic link.
+
+ XXX This incorrectly always returns false under JDK.
+
+ """
+ return 0
+
+def samefile(path, path2):
+ """Test whether two pathnames reference the same actual file"""
+ path = _tostr(path, "samefile")
+ path2 = _tostr(path2, "samefile")
+ f = File(path)
+ f2 = File(path2)
+ return f.getCanonicalPath() == f2.getCanonicalPath()
+
+def ismount(path):
+ """Test whether a path is a mount point.
+
+ XXX This incorrectly always returns false under JDK.
+
+ """
+ return 0
+
+
+def walk(top, func, arg):
+ """Walk a directory tree.
+
+ walk(top,func,args) calls func(arg, d, files) for each directory
+ "d" in the tree rooted at "top" (including "top" itself). "files"
+ is a list of all the files and subdirs in directory "d".
+
+ """
+ try:
+ names = os.listdir(top)
+ except os.error:
+ return
+ func(arg, top, names)
+ for name in names:
+ name = join(top, name)
+ if isdir(name) and not islink(name):
+ walk(name, func, arg)
+
+def expanduser(path):
+ if path[:1] == "~":
+ c = path[1:2]
+ if not c:
+ return gethome()
+ if c == os.sep:
+ return File(gethome(), path[2:]).getPath()
+ return path
+
+def getuser():
+ return System.getProperty("user.name")
+
+def gethome():
+ return System.getProperty("user.home")
+
+
+# normpath() from Python 1.5.2, with Java appropriate generalizations
+
+# 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):
+ """Normalize path, eliminating double slashes, etc."""
+ sep = os.sep
+ if sep == '\\':
+ path = path.replace("/", sep)
+ curdir = os.curdir
+ pardir = os.pardir
+ import string
+ # Treat initial slashes specially
+ slashes = ''
+ while path[:1] == sep:
+ slashes = slashes + sep
+ path = path[1:]
+ comps = string.splitfields(path, sep)
+ i = 0
+ while i < len(comps):
+ if comps[i] == curdir:
+ del comps[i]
+ while i < len(comps) and comps[i] == '':
+ del comps[i]
+ elif comps[i] == pardir and i > 0 and comps[i-1] not in ('', pardir):
+ 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(curdir)
+ return slashes + string.joinfields(comps, sep)
+
+# Return an absolute path.
+def abspath(path):
+ path = _tostr(path, "abspath")
+ return File(path).getAbsolutePath()
+
+
+def getsize(path):
+ path = _tostr(path, "getsize")
+ f = File(path)
+ size = f.length()
+ # Sadly, if the returned length is zero, we don't really know if the file
+ # is zero sized or does not exist.
+ if size == 0 and not f.exists():
+ raise OSError(0, 'No such file or directory', path)
+ return size
+
+def getmtime(path):
+ path = _tostr(path, "getmtime")
+ f = File(path)
+ return f.lastModified() / 1000.0
+
+def getatime(path):
+ # We can't detect access time so we return modification time. This
+ # matches the behaviour in os.stat().
+ path = _tostr(path, "getatime")
+ f = File(path)
+ return f.lastModified() / 1000.0
+
+
+# expandvars is stolen from CPython-2.1.1's Lib/ntpath.py:
+
+# Expand paths containing shell variable substitutions.
+# The following rules apply:
+# - no expansion within single quotes
+# - no escape character, except for '$$' which is translated into '$'
+# - ${varname} is accepted.
+# - varnames can be made out of letters, digits and the character '_'
+# XXX With COMMAND.COM you can use any characters in a variable name,
+# XXX except '^|<>='.
+
+def expandvars(path):
+ """Expand shell variables of form $var and ${var}.
+
+ Unknown variables are left unchanged."""
+ if '$' not in path:
+ return path
+ import string
+ varchars = string.letters + string.digits + '_-'
+ res = ''
+ index = 0
+ pathlen = len(path)
+ while index < pathlen:
+ c = path[index]
+ if c == '\'': # no expansion within single quotes
+ path = path[index + 1:]
+ pathlen = len(path)
+ try:
+ index = path.index('\'')
+ res = res + '\'' + path[:index + 1]
+ except ValueError:
+ res = res + path
+ index = pathlen - 1
+ elif c == '$': # variable or '$$'
+ if path[index + 1:index + 2] == '$':
+ res = res + c
+ index = index + 1
+ elif path[index + 1:index + 2] == '{':
+ path = path[index+2:]
+ pathlen = len(path)
+ try:
+ index = path.index('}')
+ var = path[:index]
+ if os.environ.has_key(var):
+ res = res + os.environ[var]
+ except ValueError:
+ res = res + path
+ index = pathlen - 1
+ else:
+ var = ''
+ index = index + 1
+ c = path[index:index + 1]
+ while c != '' and c in varchars:
+ var = var + c
+ index = index + 1
+ c = path[index:index + 1]
+ if os.environ.has_key(var):
+ res = res + os.environ[var]
+ if c != '':
+ res = res + c
+ else:
+ res = res + c
+ index = index + 1
+ return res
+
+
+
diff --git a/lib/jython/Lib/jreload.py b/lib/jython/Lib/jreload.py new file mode 100644 index 000000000..80029ec42 --- /dev/null +++ b/lib/jython/Lib/jreload.py @@ -0,0 +1,119 @@ +# java classes reload support (experimental)
+# Copyright 2000 Samuele Pedroni
+
+# ?? could have problem with import pkg.jclass.inner (this should not be used in any case)
+# ?? using import * with a load-set together with reloading can be confusing
+# cannot be fixed => anyway import * is not for production code
+
+__version__ = "0.3"
+
+import sys
+from org.python.core import imp,PyJavaPackage,PyJavaClass
+from _jython import is_lazy as _is_lazy
+
+import jxxload_help
+
+
+class _LoaderFactory(jxxload_help.JavaLoaderFactory):
+ def __init__(self,path):
+ vfs = jxxload_help.PathVFS()
+ for fname in path:
+ vfs.addVFS(fname)
+ self.vfs = vfs
+
+ def makeLoader(self):
+ return jxxload_help.PathVFSJavaLoader(self.vfs,imp.getSyspathJavaLoader())
+
+class _Unload:
+
+ def __init__(self,ls):
+ self.ls = ls
+ self.ls_name = ls._name
+ self.loader = ls._mgr.loader
+
+ def do_unload(self,pkg):
+ for n in pkg.__dict__.keys():
+ e = pkg.__dict__[n]
+ if isinstance(e,PyJavaClass):
+ if _is_lazy(e): continue
+ if e.classLoader is self.loader:
+ del pkg.__dict__[n]
+ if pkg.__name__:
+ n = self.ls_name + '.' + pkg.__name__ + '.' +n
+ else:
+ n = self.ls_name + '.' + n
+ if sys.modules.has_key(n): del sys.modules[n]
+
+ elif isinstance(e,PyJavaPackage):
+ self.do_unload(e)
+
+ def __call__(self):
+ if self.loader:
+ if self.ls._mgr.checkLoader() is self.loader:
+ self.do_unload(self.ls._top)
+ self.ls._mgr.resetLoader()
+ loader = self.loader
+ jxxload_help.DiscardHelp.discard(loader,loader.interfaces)
+ self.loader = None
+
+class LoadSet:
+# ?? for the moment from import * and dir do not work for LoadSet, but work for
+# contained pkgs
+# need java impl as PyObject
+
+ def __init__(self,name,path):
+ mgr = jxxload_help.PackageManager(path,_LoaderFactory(path))
+ self._name = name
+ self._mgr = mgr
+ self._top = mgr.topLevelPackage
+
+ def __getattr__(self,name):
+ try:
+ return getattr(self._top,name)
+ except:
+ if name == 'unload': return _Unload(self)
+ raise
+
+
+ def __repr__(self):
+ return "<java load-set %s>" % self._name
+
+def unloadf(ls):
+ if not isinstance(ls,LoadSet): raise TypeError,"unloadf(): arg is not a load-set"
+ return _Unload(ls)
+
+def makeLoadSet(name,path):
+ if sys.modules.has_key(name): return sys.modules[name]
+ sys.modules[name] = ls = LoadSet(name,path)
+ return ls
+
+_reload = reload
+
+def _do_reload(ls_name,mgr,pkg):
+ pkg_name = pkg.__name__
+ for n in pkg.__dict__.keys():
+ e = pkg.__dict__[n]
+ if isinstance(e,PyJavaClass):
+ if _is_lazy(e): continue
+ del pkg.__dict__[n]
+ try :
+ c = mgr.findClass(pkg_name,n);
+ if c:
+ pkg.__dict__[n] = c
+ if pkg_name:
+ n = ls_name + '.' + pkg_name + '.' + n
+ else:
+ n = ls_name + '.' + n
+ if sys.modules.has_key(n): sys.modules[n] = c
+ except:
+ pass
+ elif isinstance(e,PyJavaPackage):
+ _do_reload(ls_name,mgr,e)
+
+def reload(ls):
+ if isinstance(ls,LoadSet):
+ ls._mgr.resetLoader()
+ _do_reload(ls._name,ls._mgr,ls._top)
+ return ls
+ else:
+ return _reload(ls)
diff --git a/lib/jython/Lib/jxxload_help/DiscardHelp.java b/lib/jython/Lib/jxxload_help/DiscardHelp.java new file mode 100644 index 000000000..19d203c00 --- /dev/null +++ b/lib/jython/Lib/jxxload_help/DiscardHelp.java @@ -0,0 +1,59 @@ +// Copyright 2000 Samuele Pedroni + +package jxxload_help; + +import org.python.core.PyJavaClass; + +public class DiscardHelp extends Object { + + private DiscardHelp() { + } + + private static boolean check(Class c,ClassLoader loader,java.util.Vector interfaces) { + try { + Class s = c; + do { + if (s.getClassLoader() == loader) return true; + s = s.getSuperclass(); + } while (s != null); + + for(java.util.Enumeration enum=interfaces.elements(); enum.hasMoreElements();) { + Class intf = (Class)enum.nextElement(); + if (intf.isAssignableFrom(c)) return true; + } + + } catch(SecurityException e) { + } + return false; + } + + // clearly not thread safe + public static void discard(ClassLoader loader,java.util.Vector interfaces) { + + org.python.core.InternalTables tbl = PyJavaClass.getInternalTables(); + + tbl._beginCanonical(); + + PyJavaClass jc; + while ((jc = (PyJavaClass)tbl._next()) != null ) { + Class c = (Class)jc.__tojava__(Class.class); + if(check(c,loader,interfaces)) tbl._flushCurrent(); + } + + tbl._beginOverAdapterClasses(); + + Class c; + + while ((c = (Class)tbl._next()) != null) { + if(interfaces.contains(c)) tbl._flushCurrent(); + } + + tbl._beginOverAdapters(); + + while ((c = (Class)tbl._next()) != null) { + if(interfaces.contains(c)) tbl._flushCurrent(); + } + + } + +} diff --git a/lib/jython/Lib/jxxload_help/JavaLoaderFactory.java b/lib/jython/Lib/jxxload_help/JavaLoaderFactory.java new file mode 100644 index 000000000..50e57dcf9 --- /dev/null +++ b/lib/jython/Lib/jxxload_help/JavaLoaderFactory.java @@ -0,0 +1,9 @@ +// Copyright 2000 Samuele Pedroni + +package jxxload_help; + +public interface JavaLoaderFactory { + + public ClassLoader makeLoader(); + +} diff --git a/lib/jython/Lib/jxxload_help/Makefile b/lib/jython/Lib/jxxload_help/Makefile new file mode 100644 index 000000000..7aac1299c --- /dev/null +++ b/lib/jython/Lib/jxxload_help/Makefile @@ -0,0 +1,3 @@ +include ../../Misc/make.rules
+CLASSPATH = ../..:..
+
diff --git a/lib/jython/Lib/jxxload_help/PackageManager.java b/lib/jython/Lib/jxxload_help/PackageManager.java new file mode 100644 index 000000000..18775debf --- /dev/null +++ b/lib/jython/Lib/jxxload_help/PackageManager.java @@ -0,0 +1,58 @@ +// Copyright 2000 Samuele Pedroni + +package jxxload_help; + +public class PackageManager extends org.python.core.PathPackageManager { + + private JavaLoaderFactory factory; + private ClassLoader loader; + + public synchronized ClassLoader getLoader() { + if (loader == null) loader = factory.makeLoader(); + return loader; + } + + public synchronized ClassLoader checkLoader() { + return loader; + } + + public synchronized void resetLoader() { + loader = null; + } + + // ??pending add cache support? + public PackageManager(org.python.core.PyList path,JavaLoaderFactory factory) { + this.factory = factory; + + for (int i = 0; i < path.__len__(); i++) { + String entry = path.__finditem__(i).toString(); + if (entry.endsWith(".jar") || entry.endsWith(".zip")) { + addJarToPackages(new java.io.File(entry),false); + } else { + java.io.File dir = new java.io.File(entry); + if (entry.length() == 0 || dir.isDirectory()) addDirectory(dir); + } + } + } + + public Class findClass(String pkg,String name,String reason) { + if (pkg != null && pkg.length()>0) name = pkg + '.' + name; + try { + return getLoader().loadClass(name); + } + catch(ClassNotFoundException e) { + return null; + } + catch (LinkageError e) { + throw org.python.core.Py.JavaError(e); + } + } + + public void addJarDir(String jdir, boolean cache) { + throw new RuntimeException("addJarDir not supported for reloadable packages"); + } + + public void addJar(String jdir, boolean cache) { + throw new RuntimeException("addDir not supported for reloadable packages"); + } +} diff --git a/lib/jython/Lib/jxxload_help/PathVFS.java b/lib/jython/Lib/jxxload_help/PathVFS.java new file mode 100644 index 000000000..0be51e3cd --- /dev/null +++ b/lib/jython/Lib/jxxload_help/PathVFS.java @@ -0,0 +1,98 @@ +// Copyright 2000 Samuele Pedroni + +package jxxload_help; + +import java.util.Vector; +import java.util.Hashtable; +import java.util.Enumeration; +import java.util.zip.ZipFile; +import java.util.zip.ZipEntry; +import java.io.*; + +public class PathVFS extends Object { + + public interface VFS { + + public InputStream open(String id); + + } + + public static class JarVFS implements VFS { + private ZipFile zipfile; + + public JarVFS(String fname) throws IOException { + zipfile = new ZipFile(fname); + } + + public InputStream open(String id) { + ZipEntry ent = zipfile.getEntry(id); + if (ent == null) return null; + try { + return zipfile.getInputStream(ent); + } catch(IOException e) { + return null; + } + } + + } + + public static class DirVFS implements VFS { + private String prefix; + + public DirVFS(String dir) { + if (dir.length() == 0) + prefix = null; + else + prefix = dir; + } + + public InputStream open(String id) { + File file = new File(prefix,id.replace('/',File.separatorChar)); + if (file.isFile()) { + try { + return new BufferedInputStream(new FileInputStream(file)); + } catch(IOException e) { + return null; + } + } + return null; + } + } + + private Vector vfs = new Vector(); + private Hashtable once = new Hashtable(); + + private final static Object PRESENT = new Object(); + + public void addVFS(String fname) { + if (fname.length() == 0) { + if (!once.containsKey("")) { + once.put("",PRESENT); + vfs.addElement(new DirVFS("")); + } + return; + } + try { + File file = new File(fname); + String canon = file.getCanonicalPath().toString(); + if (!once.containsKey(canon)) { + once.put(canon,PRESENT); + if (file.isDirectory()) vfs.addElement(new DirVFS(fname)); + else if (file.exists() && (fname.endsWith(".jar") || fname.endsWith(".zip"))) { + vfs.addElement(new JarVFS(fname)); + } + } + + } catch(IOException e) {} + } + + public InputStream open(String id) { + for(Enumeration enum = vfs.elements(); enum.hasMoreElements();) { + VFS v = (VFS)enum.nextElement(); + InputStream stream = v.open(id); + if (stream != null) return stream; + } + return null; + } + +} diff --git a/lib/jython/Lib/jxxload_help/PathVFSJavaLoader.java b/lib/jython/Lib/jxxload_help/PathVFSJavaLoader.java new file mode 100644 index 000000000..c0aa4d1cf --- /dev/null +++ b/lib/jython/Lib/jxxload_help/PathVFSJavaLoader.java @@ -0,0 +1,54 @@ +// Copyright 2000 Samuele Pedroni + +package jxxload_help; + +public class PathVFSJavaLoader extends ClassLoader { + private ClassLoader parent; + + private PathVFS vfs; + + public java.util.Vector interfaces = new java.util.Vector(); + + public PathVFSJavaLoader(PathVFS vfs,ClassLoader parent) { + this.vfs = vfs; + this.parent = parent; + } + + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + Class c; + + c = findLoadedClass(name); + if (c != null) return c; + + try { + if (parent != null) return parent.loadClass(name); + } catch(ClassNotFoundException e) { + } + + java.io.InputStream in = vfs.open(name.replace('.','/')+".class"); + if (in == null) throw new ClassNotFoundException(name); + + try { + int av = in.available(); + byte[] buf = new byte[av]; + in.read(buf); + in.close(); + return loadClassFromBytes(name,buf); + } catch(java.io.IOException e) { + throw new ClassNotFoundException(name); + } + + } + + + private Class loadClassFromBytes(String name, byte[] data) { + Class c = defineClass(name, data, 0, data.length); + resolveClass(c); + if (c.isInterface()) interfaces.addElement(c); + if (!org.python.core.Options.skipCompile) { + Compiler.compileClass(c); + } + return c; + } + +} diff --git a/lib/jython/Lib/keyword.py b/lib/jython/Lib/keyword.py new file mode 100644 index 000000000..8102ec59f --- /dev/null +++ b/lib/jython/Lib/keyword.py @@ -0,0 +1,96 @@ +#! /usr/bin/env python
+
+"""Keywords (from "graminit.c")
+
+This file is automatically generated; please don't muck it up!
+
+To update the symbols in this file, 'cd' to the top directory of
+the python source tree after building the interpreter and run:
+
+ python Lib/keyword.py
+"""
+
+__all__ = ["iskeyword"]
+
+kwlist = [
+#--start keywords--
+ 'and',
+ 'assert',
+ 'break',
+ 'class',
+ 'continue',
+ 'def',
+ 'del',
+ 'elif',
+ 'else',
+ 'except',
+ 'exec',
+ 'finally',
+ 'for',
+ 'from',
+ 'global',
+ 'if',
+ 'import',
+ 'in',
+ 'is',
+ 'lambda',
+ 'not',
+ 'or',
+ 'pass',
+ 'print',
+ 'raise',
+ 'return',
+ 'try',
+ 'while',
+#--end keywords--
+ ]
+
+kwdict = {}
+for keyword in kwlist:
+ kwdict[keyword] = 1
+
+iskeyword = kwdict.has_key
+
+def main():
+ import sys, re
+
+ args = sys.argv[1:]
+ iptfile = args and args[0] or "Python/graminit.c"
+ if len(args) > 1: optfile = args[1]
+ else: optfile = "Lib/keyword.py"
+
+ # scan the source file for keywords
+ fp = open(iptfile)
+ strprog = re.compile('"([^"]+)"')
+ lines = []
+ while 1:
+ line = fp.readline()
+ if not line: break
+ if line.find('{1, "') > -1:
+ match = strprog.search(line)
+ if match:
+ lines.append(" '" + match.group(1) + "',\n")
+ fp.close()
+ lines.sort()
+
+ # load the output skeleton from the target
+ fp = open(optfile)
+ format = fp.readlines()
+ fp.close()
+
+ # insert the lines of keywords
+ try:
+ start = format.index("#--start keywords--\n") + 1
+ end = format.index("#--end keywords--\n")
+ format[start:end] = lines
+ except ValueError:
+ sys.stderr.write("target does not contain format markers\n")
+ sys.exit(1)
+
+ # write the output file
+ fp = open(optfile, 'w')
+ fp.write(''.join(format))
+ fp.close()
+
+if __name__ == "__main__":
+ main()
diff --git a/lib/jython/Lib/linecache.py b/lib/jython/Lib/linecache.py new file mode 100644 index 000000000..1c8eb9815 --- /dev/null +++ b/lib/jython/Lib/linecache.py @@ -0,0 +1,94 @@ +"""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 *
+
+__all__ = ["getline","clearcache","checkcache"]
+
+def getline(filename, lineno):
+ lines = getlines(filename)
+ if 1 <= lineno <= len(lines):
+ return lines[lineno-1]
+ else:
+ return ''
+
+
+# The cache
+
+cache = {} # The cache
+
+
+def clearcache():
+ """Clear the cache entirely."""
+
+ global cache
+ cache = {}
+
+
+def getlines(filename):
+ """Get the lines for a file from the cache.
+ Update the cache if it doesn't contain an entry for this file already."""
+
+ if cache.has_key(filename):
+ return cache[filename][2]
+ else:
+ return updatecache(filename)
+
+
+def checkcache():
+ """Discard cache entries that are out of date.
+ (This is not checked upon each call!)"""
+
+ 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]
+
+
+def updatecache(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."""
+
+ 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/jython/Lib/macpath.py b/lib/jython/Lib/macpath.py new file mode 100644 index 000000000..42fc6e89e --- /dev/null +++ b/lib/jython/Lib/macpath.py @@ -0,0 +1,227 @@ +"""Pathname and path-related operations for the Macintosh."""
+
+import os
+from stat import *
+
+__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
+ "basename","dirname","commonprefix","getsize","getmtime",
+ "getatime","islink","exists","isdir","isfile",
+ "walk","expanduser","expandvars","normpath","abspath"]
+
+# Normalize the case of a pathname. Dummy in Posix, but <s>.lower() here.
+
+def normcase(path):
+ return path.lower()
+
+
+def isabs(s):
+ """Return true if a path is absolute.
+ On the Mac, relative paths begin with a colon,
+ but as a special case, paths with no colons at all are also relative.
+ Anything else is absolute (the string up to the first colon is the
+ volume name)."""
+
+ return ':' in s and s[0] != ':'
+
+
+def join(s, *p):
+ path = s
+ for t in p:
+ if (not s) or isabs(t):
+ path = t
+ continue
+ if t[:1] == ':':
+ t = t[1:]
+ if ':' not in path:
+ path = ':' + path
+ if path[-1:] != ':':
+ path = path + ':'
+ path = path + t
+ return path
+
+
+def split(s):
+ """Split a pathname into two parts: the directory leading up to the final
+ bit, and the basename (the filename, without colons, in that directory).
+ The result (s, t) is such that join(s, t) yields the original argument."""
+
+ if ':' not in s: return '', s
+ colon = 0
+ for i in range(len(s)):
+ if s[i] == ':': colon = i + 1
+ path, file = s[:colon-1], s[colon:]
+ if path and not ':' in path:
+ path = path + ':'
+ return path, file
+
+
+def splitext(p):
+ """Split a path into root and extension.
+ The extension is everything starting at the last dot in the last
+ pathname component; the root is everything before that.
+ It is always true that root + ext == 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
+
+
+def splitdrive(p):
+ """Split a pathname into a drive specification and the rest of the
+ path. Useful on DOS/Windows/NT; on the Mac, the drive is always
+ empty (don't use the volume name -- it doesn't have the same
+ syntactic and semantic oddities as DOS drive letters, such as there
+ being a separate current directory per drive)."""
+
+ return '', p
+
+
+# Short interfaces to split()
+
+def dirname(s): return split(s)[0]
+def basename(s): return split(s)[1]
+
+
+def isdir(s):
+ """Return true if the pathname refers to an existing directory."""
+
+ try:
+ st = os.stat(s)
+ except os.error:
+ return 0
+ return S_ISDIR(st[ST_MODE])
+
+
+# Get size, mtime, atime of files.
+
+def getsize(filename):
+ """Return the size of a file, reported by os.stat()."""
+ st = os.stat(filename)
+ return st[ST_SIZE]
+
+def getmtime(filename):
+ """Return the last modification time of a file, reported by os.stat()."""
+ st = os.stat(filename)
+ return st[ST_MTIME]
+
+def getatime(filename):
+ """Return the last access time of a file, reported by os.stat()."""
+ st = os.stat(filename)
+ return st[ST_ATIME]
+
+
+def islink(s):
+ """Return true if the pathname refers to a symbolic link.
+ Always false on the Mac, until we understand Aliases.)"""
+
+ return 0
+
+
+def isfile(s):
+ """Return true if the pathname refers to an existing regular file."""
+
+ try:
+ st = os.stat(s)
+ except os.error:
+ return 0
+ return S_ISREG(st[ST_MODE])
+
+
+def exists(s):
+ """Return true if the pathname refers to an existing file or directory."""
+
+ try:
+ st = os.stat(s)
+ except os.error:
+ return 0
+ return 1
+
+# Return the longest prefix of all list elements.
+
+def commonprefix(m):
+ "Given a list of pathnames, returns the longest common leading component"
+ 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
+
+def expandvars(path):
+ """Dummy to retain interface-compatibility with other operating systems."""
+ return path
+
+
+def expanduser(path):
+ """Dummy to retain interface-compatibility with other operating systems."""
+ return path
+
+norm_error = 'macpath.norm_error: path cannot be normalized'
+
+def normpath(s):
+ """Normalize a pathname. Will return the same result for
+ equivalent paths."""
+
+ if ":" not in s:
+ return ":"+s
+
+ comps = s.split(":")
+ i = 1
+ while i < len(comps)-1:
+ if comps[i] == "" and comps[i-1] != "":
+ if i > 1:
+ del comps[i-1:i+1]
+ i = i - 1
+ else:
+ # best way to handle this is to raise an exception
+ raise norm_error, 'Cannot use :: immedeately after volume name'
+ else:
+ i = i + 1
+
+ s = ":".join(comps)
+
+ # remove trailing ":" except for ":" and "Volume:"
+ if s[-1] == ":" and len(comps) > 2 and s != ":"*len(s):
+ s = s[:-1]
+ return s
+
+
+def walk(top, func, arg):
+ """Directory tree walk.
+ For each directory under top (including top itself),
+ func(arg, dirname, filenames) is called, where
+ dirname is the name of the directory and filenames is the list
+ of 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."""
+
+ try:
+ names = os.listdir(top)
+ except os.error:
+ return
+ func(arg, top, names)
+ for name in names:
+ name = join(top, name)
+ if isdir(name):
+ walk(name, func, arg)
+
+
+def abspath(path):
+ """Return an absolute path."""
+ if not isabs(path):
+ path = join(os.getcwd(), path)
+ return normpath(path)
diff --git a/lib/jython/Lib/macurl2path.py b/lib/jython/Lib/macurl2path.py new file mode 100644 index 000000000..731fd5b3c --- /dev/null +++ b/lib/jython/Lib/macurl2path.py @@ -0,0 +1,95 @@ +"""Macintosh-specific module for conversion between pathnames and URLs.
+
+Do not import directly; use urllib instead."""
+
+import urllib
+import os
+
+__all__ = ["url2pathname","pathname2url"]
+
+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'
+ # Turn starting /// into /, an empty hostname means current host
+ if pathname[:3] == '///':
+ pathname = pathname[2:]
+ elif pathname[:2] == '//':
+ raise RuntimeError, 'Cannot convert non-local URL to pathname'
+ components = pathname.split('/')
+ # 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
+ rv = ':'.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
+ rv = ':' + ':'.join(components)
+ # and finally unquote slashes and other funny characters
+ return urllib.unquote(rv)
+
+def pathname2url(pathname):
+ "convert mac pathname to /-delimited pathname"
+ if '/' in pathname:
+ raise RuntimeError, "Cannot convert pathname containing slashes"
+ components = pathname.split(':')
+ # Remove empty first and/or last component
+ if components[0] == '':
+ del components[0]
+ if components[-1] == '':
+ del components[-1]
+ # Replace empty string ('::') by .. (will result in '/../' later)
+ for i in range(len(components)):
+ if components[i] == '':
+ components[i] = '..'
+ # Truncate names longer than 31 bytes
+ components = map(_pncomp2url, components)
+
+ if os.path.isabs(pathname):
+ return '/' + '/'.join(components)
+ else:
+ return '/'.join(components)
+
+def _pncomp2url(component):
+ component = urllib.quote(component[:31], safe='') # We want to quote slashes
+ return component
+
+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/jython/Lib/mailbox.py b/lib/jython/Lib/mailbox.py new file mode 100644 index 000000000..884e64471 --- /dev/null +++ b/lib/jython/Lib/mailbox.py @@ -0,0 +1,304 @@ +#! /usr/bin/env python
+
+"""Classes to handle Unix style, MMDF style, and MH style mailboxes."""
+
+
+import rfc822
+import os
+
+__all__ = ["UnixMailbox","MmdfMailbox","MHMailbox","Maildir","BabylMailbox"]
+
+class _Mailbox:
+ def __init__(self, fp, factory=rfc822.Message):
+ self.fp = fp
+ self.seekp = 0
+ self.factory = factory
+
+ def next(self):
+ while 1:
+ self.fp.seek(self.seekp)
+ try:
+ self._search_start()
+ except EOFError:
+ self.seekp = self.fp.tell()
+ return None
+ start = self.fp.tell()
+ self._search_end()
+ self.seekp = stop = self.fp.tell()
+ if start != stop:
+ break
+ return self.factory(_Subfile(self.fp, start, stop))
+
+
+class _Subfile:
+ def __init__(self, fp, start, stop):
+ self.fp = fp
+ self.start = start
+ self.stop = stop
+ self.pos = self.start
+
+ def read(self, length = None):
+ if self.pos >= self.stop:
+ return ''
+ remaining = self.stop - self.pos
+ if length is None or length < 0:
+ length = remaining
+ elif length > remaining:
+ length = remaining
+ self.fp.seek(self.pos)
+ data = self.fp.read(length)
+ self.pos = self.fp.tell()
+ return data
+
+ def readline(self, length = None):
+ if self.pos >= self.stop:
+ return ''
+ if length is None:
+ length = self.stop - self.pos
+ self.fp.seek(self.pos)
+ data = self.fp.readline(length)
+ self.pos = self.fp.tell()
+ return data
+
+ def readlines(self, sizehint = -1):
+ lines = []
+ while 1:
+ line = self.readline()
+ if not line:
+ break
+ lines.append(line)
+ if sizehint >= 0:
+ sizehint = sizehint - len(line)
+ if sizehint <= 0:
+ break
+ return lines
+
+ def tell(self):
+ return self.pos - self.start
+
+ def seek(self, pos, whence=0):
+ if whence == 0:
+ self.pos = self.start + pos
+ elif whence == 1:
+ self.pos = self.pos + pos
+ elif whence == 2:
+ self.pos = self.stop + pos
+
+ def close(self):
+ del self.fp
+
+
+class UnixMailbox(_Mailbox):
+ def _search_start(self):
+ while 1:
+ pos = self.fp.tell()
+ line = self.fp.readline()
+ if not line:
+ raise EOFError
+ if line[:5] == 'From ' and self._isrealfromline(line):
+ self.fp.seek(pos)
+ return
+
+ def _search_end(self):
+ self.fp.readline() # Throw away header line
+ while 1:
+ pos = self.fp.tell()
+ line = self.fp.readline()
+ if not line:
+ return
+ if line[:5] == 'From ' and self._isrealfromline(line):
+ self.fp.seek(pos)
+ return
+
+ # An overridable mechanism to test for From-line-ness. You can either
+ # specify a different regular expression or define a whole new
+ # _isrealfromline() method. Note that this only gets called for lines
+ # starting with the 5 characters "From ".
+ #
+ # BAW: According to
+ #http://home.netscape.com/eng/mozilla/2.0/relnotes/demo/content-length.html
+ # the only portable, reliable way to find message delimiters in a BSD (i.e
+ # Unix mailbox) style folder is to search for "\n\nFrom .*\n", or at the
+ # beginning of the file, "^From .*\n". While _fromlinepattern below seems
+ # like a good idea, in practice, there are too many variations for more
+ # strict parsing of the line to be completely accurate.
+ #
+ # _strict_isrealfromline() is the old version which tries to do stricter
+ # parsing of the From_ line. _portable_isrealfromline() simply returns
+ # true, since it's never called if the line doesn't already start with
+ # "From ".
+ #
+ # This algorithm, and the way it interacts with _search_start() and
+ # _search_end() may not be completely correct, because it doesn't check
+ # that the two characters preceding "From " are \n\n or the beginning of
+ # the file. Fixing this would require a more extensive rewrite than is
+ # necessary. For convenience, we've added a StrictUnixMailbox class which
+ # uses the older, more strict _fromlinepattern regular expression.
+
+ _fromlinepattern = r"From \s*[^\s]+\s+\w\w\w\s+\w\w\w\s+\d?\d\s+" \
+ r"\d?\d:\d\d(:\d\d)?(\s+[^\s]+)?\s+\d\d\d\d\s*$"
+ _regexp = None
+
+ def _strict_isrealfromline(self, line):
+ if not self._regexp:
+ import re
+ self._regexp = re.compile(self._fromlinepattern)
+ return self._regexp.match(line)
+
+ def _portable_isrealfromline(self, line):
+ return 1
+
+ _isrealfromline = _strict_isrealfromline
+
+
+class PortableUnixMailbox(UnixMailbox):
+ _isrealfromline = UnixMailbox._portable_isrealfromline
+
+
+class MmdfMailbox(_Mailbox):
+ def _search_start(self):
+ while 1:
+ line = self.fp.readline()
+ if not line:
+ raise EOFError
+ if line[:5] == '\001\001\001\001\n':
+ return
+
+ def _search_end(self):
+ while 1:
+ pos = self.fp.tell()
+ line = self.fp.readline()
+ if not line:
+ return
+ if line == '\001\001\001\001\n':
+ self.fp.seek(pos)
+ return
+
+
+class MHMailbox:
+ def __init__(self, dirname, factory=rfc822.Message):
+ import re
+ pat = re.compile('^[1-9][0-9]*$')
+ self.dirname = dirname
+ # the three following lines could be combined into:
+ # list = map(long, filter(pat.match, os.listdir(self.dirname)))
+ list = os.listdir(self.dirname)
+ list = filter(pat.match, list)
+ list = map(long, list)
+ list.sort()
+ # This only works in Python 1.6 or later;
+ # before that str() added 'L':
+ self.boxes = map(str, list)
+ self.factory = factory
+
+ def next(self):
+ if not self.boxes:
+ return None
+ fn = self.boxes[0]
+ del self.boxes[0]
+ fp = open(os.path.join(self.dirname, fn))
+ return self.factory(fp)
+
+
+class Maildir:
+ # Qmail directory mailbox
+
+ def __init__(self, dirname, factory=rfc822.Message):
+ self.dirname = dirname
+ self.factory = factory
+
+ # check for new mail
+ newdir = os.path.join(self.dirname, 'new')
+ boxes = [os.path.join(newdir, f)
+ for f in os.listdir(newdir) if f[0] != '.']
+
+ # Now check for current mail in this maildir
+ curdir = os.path.join(self.dirname, 'cur')
+ boxes += [os.path.join(curdir, f)
+ for f in os.listdir(curdir) if f[0] != '.']
+
+ self.boxes = boxes
+
+ def next(self):
+ if not self.boxes:
+ return None
+ fn = self.boxes[0]
+ del self.boxes[0]
+ fp = open(fn)
+ return self.factory(fp)
+
+
+class BabylMailbox(_Mailbox):
+ def _search_start(self):
+ while 1:
+ line = self.fp.readline()
+ if not line:
+ raise EOFError
+ if line == '*** EOOH ***\n':
+ return
+
+ def _search_end(self):
+ while 1:
+ pos = self.fp.tell()
+ line = self.fp.readline()
+ if not line:
+ return
+ if line == '\037\014\n':
+ self.fp.seek(pos)
+ return
+
+
+def _test():
+ import time
+ import sys
+ import os
+
+ args = sys.argv[1:]
+ if not args:
+ for key in 'MAILDIR', 'MAIL', 'LOGNAME', 'USER':
+ if os.environ.has_key(key):
+ mbox = os.environ[key]
+ break
+ else:
+ print "$MAIL, $LOGNAME nor $USER set -- who are you?"
+ return
+ else:
+ mbox = args[0]
+ if mbox[:1] == '+':
+ mbox = os.environ['HOME'] + '/Mail/' + mbox[1:]
+ elif not '/' in mbox:
+ mbox = '/usr/mail/' + mbox
+ if os.path.isdir(mbox):
+ if os.path.isdir(os.path.join(mbox, 'cur')):
+ mb = Maildir(mbox)
+ else:
+ mb = MHMailbox(mbox)
+ else:
+ fp = open(mbox, 'r')
+ mb = UnixMailbox(fp)
+
+ msgs = []
+ while 1:
+ msg = mb.next()
+ if msg is None:
+ break
+ msgs.append(msg)
+ if len(args) <= 1:
+ msg.fp = None
+ if len(args) > 1:
+ num = int(args[1])
+ print 'Message %d body:'%num
+ msg = msgs[num-1]
+ msg.rewindbody()
+ sys.stdout.write(msg.fp.read())
+ else:
+ print 'Mailbox',mbox,'has',len(msgs),'messages:'
+ for msg in msgs:
+ f = msg.getheader('from') or ""
+ s = msg.getheader('subject') or ""
+ d = msg.getheader('date') or ""
+ print '-%20.20s %20.20s %-30.30s'%(f, d[5:], s)
+
+
+if __name__ == '__main__':
+ _test()
diff --git a/lib/jython/Lib/mailcap.py b/lib/jython/Lib/mailcap.py new file mode 100644 index 000000000..701a7b30b --- /dev/null +++ b/lib/jython/Lib/mailcap.py @@ -0,0 +1,255 @@ +"""Mailcap file handling. See RFC 1524."""
+
+import os
+
+__all__ = ["getcaps","findmatch"]
+
+# Part 1: top-level interface.
+
+def getcaps():
+ """Return a dictionary containing the mailcap database.
+
+ The dictionary maps a MIME type (in all lowercase, e.g. 'text/plain')
+ to a list of dictionaries corresponding to mailcap entries. The list
+ collects all the entries for that MIME type from all available mailcap
+ files. Each dictionary contains key-value pairs for that MIME type,
+ where the viewing command is stored with the key "view".
+
+ """
+ caps = {}
+ for mailcap in listmailcapfiles():
+ try:
+ fp = open(mailcap, 'r')
+ except:
+ continue
+ morecaps = readmailcapfile(fp)
+ fp.close()
+ for key in morecaps.keys():
+ if not caps.has_key(key):
+ caps[key] = morecaps[key]
+ else:
+ caps[key] = caps[key] + morecaps[key]
+ return caps
+
+def listmailcapfiles():
+ """Return a list of all mailcap files found on the system."""
+ # XXX Actually, this is Unix-specific
+ if os.environ.has_key('MAILCAPS'):
+ str = os.environ['MAILCAPS']
+ mailcaps = str.split(':')
+ else:
+ if os.environ.has_key('HOME'):
+ home = os.environ['HOME']
+ else:
+ # Don't bother with getpwuid()
+ home = '.' # Last resort
+ mailcaps = [home + '/.mailcap', '/etc/mailcap',
+ '/usr/etc/mailcap', '/usr/local/etc/mailcap']
+ return mailcaps
+
+
+# Part 2: the parser.
+
+def readmailcapfile(fp):
+ """Read a mailcap file and return a dictionary keyed by MIME type.
+
+ Each MIME type is mapped to an entry consisting of a list of
+ dictionaries; the list will contain more than one such dictionary
+ if a given MIME type appears more than once in the mailcap file.
+ Each dictionary contains key-value pairs for that MIME type, where
+ the viewing command is stored with the key "view".
+ """
+ caps = {}
+ while 1:
+ line = fp.readline()
+ if not line: break
+ # Ignore comments and blank lines
+ if line[0] == '#' or line.strip() == '':
+ continue
+ nextline = line
+ # Join continuation lines
+ while nextline[-2:] == '\\\n':
+ nextline = fp.readline()
+ if not nextline: nextline = '\n'
+ line = line[:-2] + nextline
+ # Parse the line
+ key, fields = parseline(line)
+ if not (key and fields):
+ continue
+ # Normalize the key
+ types = key.split('/')
+ for j in range(len(types)):
+ types[j] = types[j].strip()
+ key = '/'.join(types).lower()
+ # Update the database
+ if caps.has_key(key):
+ caps[key].append(fields)
+ else:
+ caps[key] = [fields]
+ return caps
+
+def parseline(line):
+ """Parse one entry in a mailcap file and return a dictionary.
+
+ The viewing command is stored as the value with the key "view",
+ and the rest of the fields produce key-value pairs in the dict.
+ """
+ fields = []
+ i, n = 0, len(line)
+ while i < n:
+ field, i = parsefield(line, i, n)
+ fields.append(field)
+ i = i+1 # Skip semicolon
+ if len(fields) < 2:
+ return None, None
+ key, view, rest = fields[0], fields[1], fields[2:]
+ fields = {'view': view}
+ for field in rest:
+ i = field.find('=')
+ if i < 0:
+ fkey = field
+ fvalue = ""
+ else:
+ fkey = field[:i].strip()
+ fvalue = field[i+1:].strip()
+ if fields.has_key(fkey):
+ # Ignore it
+ pass
+ else:
+ fields[fkey] = fvalue
+ return key, fields
+
+def parsefield(line, i, n):
+ """Separate one key-value pair in a mailcap entry."""
+ start = i
+ while i < n:
+ c = line[i]
+ if c == ';':
+ break
+ elif c == '\\':
+ i = i+2
+ else:
+ i = i+1
+ return line[start:i].strip(), i
+
+
+# Part 3: using the database.
+
+def findmatch(caps, MIMEtype, key='view', filename="/dev/null", plist=[]):
+ """Find a match for a mailcap entry.
+
+ Return a tuple containing the command line, and the mailcap entry
+ used; (None, None) if no match is found. This may invoke the
+ 'test' command of several matching entries before deciding which
+ entry to use.
+
+ """
+ entries = lookup(caps, MIMEtype, key)
+ # XXX This code should somehow check for the needsterminal flag.
+ for e in entries:
+ if e.has_key('test'):
+ test = subst(e['test'], filename, plist)
+ if test and os.system(test) != 0:
+ continue
+ command = subst(e[key], MIMEtype, filename, plist)
+ return command, e
+ return None, None
+
+def lookup(caps, MIMEtype, key=None):
+ entries = []
+ if caps.has_key(MIMEtype):
+ entries = entries + caps[MIMEtype]
+ MIMEtypes = MIMEtype.split('/')
+ MIMEtype = MIMEtypes[0] + '/*'
+ if caps.has_key(MIMEtype):
+ entries = entries + caps[MIMEtype]
+ if key is not None:
+ entries = filter(lambda e, key=key: e.has_key(key), entries)
+ return entries
+
+def subst(field, MIMEtype, filename, plist=[]):
+ # XXX Actually, this is Unix-specific
+ res = ''
+ i, n = 0, len(field)
+ while i < n:
+ c = field[i]; i = i+1
+ if c != '%':
+ if c == '\\':
+ c = field[i:i+1]; i = i+1
+ res = res + c
+ else:
+ c = field[i]; i = i+1
+ if c == '%':
+ res = res + c
+ elif c == 's':
+ res = res + filename
+ elif c == 't':
+ res = res + MIMEtype
+ elif c == '{':
+ start = i
+ while i < n and field[i] != '}':
+ i = i+1
+ name = field[start:i]
+ i = i+1
+ res = res + findparam(name, plist)
+ # XXX To do:
+ # %n == number of parts if type is multipart/*
+ # %F == list of alternating type and filename for parts
+ else:
+ res = res + '%' + c
+ return res
+
+def findparam(name, plist):
+ name = name.lower() + '='
+ n = len(name)
+ for p in plist:
+ if p[:n].lower() == name:
+ return p[n:]
+ return ''
+
+
+# Part 4: test program.
+
+def test():
+ import sys
+ caps = getcaps()
+ if not sys.argv[1:]:
+ show(caps)
+ return
+ for i in range(1, len(sys.argv), 2):
+ args = sys.argv[i:i+2]
+ if len(args) < 2:
+ print "usage: mailcap [MIMEtype file] ..."
+ return
+ MIMEtype = args[0]
+ file = args[1]
+ command, e = findmatch(caps, MIMEtype, 'view', file)
+ if not command:
+ print "No viewer found for", type
+ else:
+ print "Executing:", command
+ sts = os.system(command)
+ if sts:
+ print "Exit status:", sts
+
+def show(caps):
+ print "Mailcap files:"
+ for fn in listmailcapfiles(): print "\t" + fn
+ print
+ if not caps: caps = getcaps()
+ print "Mailcap entries:"
+ print
+ ckeys = caps.keys()
+ ckeys.sort()
+ for type in ckeys:
+ print type
+ entries = caps[type]
+ for e in entries:
+ keys = e.keys()
+ keys.sort()
+ for k in keys:
+ print " %-15s" % k, e[k]
+ print
+
+if __name__ == '__main__':
+ test()
diff --git a/lib/jython/Lib/marshal.py b/lib/jython/Lib/marshal.py new file mode 100644 index 000000000..61bb59da5 --- /dev/null +++ b/lib/jython/Lib/marshal.py @@ -0,0 +1,315 @@ +"""Marshal module written in Python.
+
+This doesn't marshal code objects, but supports everything else.
+Performance or careful error checking is not an issue.
+
+"""
+
+import StringIO
+import string
+from types import *
+try:
+ import new
+except ImportError:
+ new = None
+
+TYPE_NULL = '0'
+TYPE_NONE = 'N'
+TYPE_ELLIPSIS = '.'
+TYPE_INT = 'i'
+TYPE_INT64 = 'I'
+TYPE_FLOAT = 'f'
+TYPE_COMPLEX = 'x'
+TYPE_LONG = 'l'
+TYPE_STRING = 's'
+TYPE_TUPLE = '('
+TYPE_LIST = '['
+TYPE_DICT = '{'
+TYPE_CODE = 'c'
+TYPE_UNKNOWN = '?'
+
+
+class Marshaller:
+
+ dispatch = {}
+
+ def __init__(self, f):
+ self.f = f
+
+ def dump(self, x):
+ self.dispatch[type(x)](self, x)
+
+ def w_long64(self, x):
+ self.w_long(x)
+ self.w_long(x>>32)
+
+ def w_long(self, x):
+ write = self.f.write
+ write(chr((x) & 0xff))
+ write(chr((x>> 8) & 0xff))
+ write(chr((x>>16) & 0xff))
+ write(chr((x>>24) & 0xff))
+
+ def w_short(self, x):
+ write = self.f.write
+ write(chr((x) & 0xff))
+ write(chr((x>> 8) & 0xff))
+
+ def dump_none(self, x):
+ self.f.write(TYPE_NONE)
+ dispatch[NoneType] = dump_none
+
+ def dump_ellipsis(self, x):
+ self.f.write(TYPE_ELLIPSIS)
+ try:
+ dispatch[EllipsisType] = dump_ellipsis
+ except NameError:
+ pass
+
+ def dump_int(self, x):
+ y = x>>31
+ if y and y != -1:
+ self.f.write(TYPE_INT64)
+ self.w_long64(x)
+ else:
+ self.f.write(TYPE_INT)
+ self.w_long(x)
+ dispatch[IntType] = dump_int
+
+ def dump_long(self, x):
+ self.f.write(TYPE_LONG)
+ sign = 1
+ if x < 0:
+ sign = -1
+ x = -x
+ digits = []
+ while x:
+ digits.append(x & 0x7FFF)
+ x = x>>15
+ self.w_long(len(digits) * sign)
+ for d in digits:
+ self.w_short(d)
+ dispatch[LongType] = dump_long
+
+ def dump_float(self, x):
+ write = self.f.write
+ write(TYPE_FLOAT)
+ s = `x`
+ write(chr(len(s)))
+ write(s)
+ dispatch[FloatType] = dump_float
+
+ def dump_complex(self, x):
+ write = self.f.write
+ write(TYPE_COMPLEX)
+ s = `x.real`
+ write(chr(len(s)))
+ write(s)
+ s = `x.imag`
+ write(chr(len(s)))
+ write(s)
+ try:
+ dispatch[ComplexType] = dump_complex
+ except NameError:
+ pass
+
+ def dump_string(self, x):
+ self.f.write(TYPE_STRING)
+ self.w_long(len(x))
+ self.f.write(x)
+ dispatch[StringType] = dump_string
+
+ def dump_tuple(self, x):
+ self.f.write(TYPE_TUPLE)
+ self.w_long(len(x))
+ for item in x:
+ self.dump(item)
+ dispatch[TupleType] = dump_tuple
+
+ def dump_list(self, x):
+ self.f.write(TYPE_LIST)
+ self.w_long(len(x))
+ for item in x:
+ self.dump(item)
+ dispatch[ListType] = dump_list
+
+ def dump_dict(self, x):
+ self.f.write(TYPE_DICT)
+ for key, value in x.items():
+ self.dump(key)
+ self.dump(value)
+ self.f.write(TYPE_NULL)
+ dispatch[DictionaryType] = dump_dict
+
+ def dump_code(self, x):
+ self.f.write(TYPE_CODE)
+ self.w_short(x.co_argcount)
+ self.w_short(x.co_nlocals)
+ self.w_short(x.co_stacksize)
+ self.w_short(x.co_flags)
+ self.dump(x.co_code)
+ self.dump(x.co_consts)
+ self.dump(x.co_names)
+ self.dump(x.co_varnames)
+ self.dump(x.co_filename)
+ self.dump(x.co_name)
+ self.w_short(x.co_firstlineno)
+ self.dump(x.co_lnotab)
+ try:
+ dispatch[CodeType] = dump_code
+ except NameError:
+ pass
+
+
+class NULL:
+ pass
+
+class Unmarshaller:
+
+ dispatch = {}
+
+ def __init__(self, f):
+ self.f = f
+
+ def load(self):
+ c = self.f.read(1)
+ if not c:
+ raise EOFError
+ return self.dispatch[c](self)
+
+ def r_short(self):
+ read = self.f.read
+ lo = ord(read(1))
+ hi = ord(read(1))
+ x = lo | (hi<<8)
+ if x & 0x8000:
+ x = x - 0x10000
+ return x
+
+ def r_long(self):
+ read = self.f.read
+ a = ord(read(1))
+ b = ord(read(1))
+ c = ord(read(1))
+ d = ord(read(1))
+ x = a | (b<<8) | (c<<16) | (d<<24)
+ if x & 0x80000000 and x > 0:
+ x = string.atoi(x - 0x100000000L)
+ return x
+
+ def r_long64(self):
+ a = self.r_long()
+ b = self.r_long()
+ return a | (b<<32)
+
+ def load_null(self):
+ return NULL
+ dispatch[TYPE_NULL] = load_null
+
+ def load_none(self):
+ return None
+ dispatch[TYPE_NONE] = load_none
+
+ def load_ellipsis(self):
+ return EllipsisType
+ dispatch[TYPE_ELLIPSIS] = load_ellipsis
+
+ def load_int(self):
+ return self.r_long()
+ dispatch[TYPE_INT] = load_int
+
+ def load_int64(self):
+ return self.r_long64()
+ dispatch[TYPE_INT64] = load_int64
+
+ def load_long(self):
+ size = self.r_long()
+ sign = 1
+ if size < 0:
+ sign = -1
+ size = -size
+ x = 0L
+ for i in range(size):
+ d = self.r_short()
+ x = x | (d<<(i*15L))
+ return x * sign
+ dispatch[TYPE_LONG] = load_long
+
+ def load_float(self):
+ n = ord(self.f.read(1))
+ s = self.f.read(n)
+ return string.atof(s)
+ dispatch[TYPE_FLOAT] = load_float
+
+ def load_complex(self):
+ n = ord(self.f.read(1))
+ s = self.f.read(n)
+ real = float(s)
+ n = ord(self.f.read(1))
+ s = self.f.read(n)
+ imag = float(s)
+ return complex(real, imag)
+ dispatch[TYPE_COMPLEX] = load_complex
+
+ def load_string(self):
+ n = self.r_long()
+ return self.f.read(n)
+ dispatch[TYPE_STRING] = load_string
+
+ def load_tuple(self):
+ return tuple(self.load_list())
+ dispatch[TYPE_TUPLE] = load_tuple
+
+ def load_list(self):
+ n = self.r_long()
+ list = []
+ for i in range(n):
+ list.append(self.load())
+ return list
+ dispatch[TYPE_LIST] = load_list
+
+ def load_dict(self):
+ d = {}
+ while 1:
+ key = self.load()
+ if key is NULL:
+ break
+ value = self.load()
+ d[key] = value
+ return d
+ dispatch[TYPE_DICT] = load_dict
+
+ def load_code(self):
+ argcount = self.r_short()
+ nlocals = self.r_short()
+ stacksize = self.r_short()
+ flags = self.r_short()
+ code = self.load()
+ consts = self.load()
+ names = self.load()
+ varnames = self.load()
+ filename = self.load()
+ name = self.load()
+ firstlineno = self.r_short()
+ lnotab = self.load()
+ if not new:
+ raise RuntimeError, "can't unmarshal code objects; no 'new' module"
+ return new.code(argcount, nlocals, stacksize, flags, code, consts,
+ names, varnames, filename, name, firstlineno, lnotab)
+ dispatch[TYPE_CODE] = load_code
+
+
+def dump(x, f):
+ Marshaller(f).dump(x)
+
+def load(f):
+ return Unmarshaller(f).load()
+
+def dumps(x):
+ f = StringIO.StringIO()
+ dump(x, f)
+ return f.getvalue()
+
+def loads(s):
+ f = StringIO.StringIO(s)
+ return load(f)
diff --git a/lib/jython/Lib/mhlib.py b/lib/jython/Lib/mhlib.py new file mode 100644 index 000000000..b4e154146 --- /dev/null +++ b/lib/jython/Lib/mhlib.py @@ -0,0 +1,1003 @@ +"""MH interface -- purely object-oriented (well, almost)
+
+Executive summary:
+
+import mhlib
+
+mh = mhlib.MH() # use default mailbox directory and profile
+mh = mhlib.MH(mailbox) # override mailbox location (default from profile)
+mh = mhlib.MH(mailbox, profile) # override mailbox and profile
+
+mh.error(format, ...) # print error message -- can be overridden
+s = mh.getprofile(key) # profile entry (None if not set)
+path = mh.getpath() # mailbox pathname
+name = mh.getcontext() # name of current folder
+mh.setcontext(name) # set name of current folder
+
+list = mh.listfolders() # names of top-level folders
+list = mh.listallfolders() # names of all folders, including subfolders
+list = mh.listsubfolders(name) # direct subfolders of given folder
+list = mh.listallsubfolders(name) # all subfolders of given folder
+
+mh.makefolder(name) # create new folder
+mh.deletefolder(name) # delete folder -- must have no subfolders
+
+f = mh.openfolder(name) # new open folder object
+
+f.error(format, ...) # same as mh.error(format, ...)
+path = f.getfullname() # folder's full pathname
+path = f.getsequencesfilename() # full pathname of folder's sequences file
+path = f.getmessagefilename(n) # full pathname of message n in folder
+
+list = f.listmessages() # list of messages in folder (as numbers)
+n = f.getcurrent() # get current message
+f.setcurrent(n) # set current message
+list = f.parsesequence(seq) # parse msgs syntax into list of messages
+n = f.getlast() # get last message (0 if no messagse)
+f.setlast(n) # set last message (internal use only)
+
+dict = f.getsequences() # dictionary of sequences in folder {name: list}
+f.putsequences(dict) # write sequences back to folder
+
+f.createmessage(n, fp) # add message from file f as number n
+f.removemessages(list) # remove messages in list from folder
+f.refilemessages(list, tofolder) # move messages in list to other folder
+f.movemessage(n, tofolder, ton) # move one message to a given destination
+f.copymessage(n, tofolder, ton) # copy one message to a given destination
+
+m = f.openmessage(n) # new open message object (costs a file descriptor)
+m is a derived class of mimetools.Message(rfc822.Message), with:
+s = m.getheadertext() # text of message's headers
+s = m.getheadertext(pred) # text of message's headers, filtered by pred
+s = m.getbodytext() # text of message's body, decoded
+s = m.getbodytext(0) # text of message's body, not decoded
+"""
+
+# XXX To do, functionality:
+# - annotate messages
+# - send messages
+#
+# XXX To do, organization:
+# - move IntSet to separate file
+# - move most Message functionality to module mimetools
+
+
+# Customizable defaults
+
+MH_PROFILE = '~/.mh_profile'
+PATH = '~/Mail'
+MH_SEQUENCES = '.mh_sequences'
+FOLDER_PROTECT = 0700
+
+
+# Imported modules
+
+import os
+import sys
+from stat import ST_NLINK
+import re
+import mimetools
+import multifile
+import shutil
+from bisect import bisect
+
+__all__ = ["MH","Error","Folder","Message"]
+
+# Exported constants
+
+class Error(Exception):
+ pass
+
+
+class MH:
+ """Class representing a particular collection of folders.
+ Optional constructor arguments are the pathname for the directory
+ containing the collection, and the MH profile to use.
+ If either is omitted or empty a default is used; the default
+ directory is taken from the MH profile if it is specified there."""
+
+ def __init__(self, path = None, profile = None):
+ """Constructor."""
+ if not profile: profile = MH_PROFILE
+ self.profile = os.path.expanduser(profile)
+ if not path: path = self.getprofile('Path')
+ if not path: path = PATH
+ if not os.path.isabs(path) and path[0] != '~':
+ path = os.path.join('~', path)
+ path = os.path.expanduser(path)
+ if not os.path.isdir(path): raise Error, 'MH() path not found'
+ self.path = path
+
+ def __repr__(self):
+ """String representation."""
+ return 'MH(%s, %s)' % (`self.path`, `self.profile`)
+
+ def error(self, msg, *args):
+ """Routine to print an error. May be overridden by a derived class."""
+ sys.stderr.write('MH error: %s\n' % (msg % args))
+
+ def getprofile(self, key):
+ """Return a profile entry, None if not found."""
+ return pickline(self.profile, key)
+
+ def getpath(self):
+ """Return the path (the name of the collection's directory)."""
+ return self.path
+
+ def getcontext(self):
+ """Return the name of the current folder."""
+ context = pickline(os.path.join(self.getpath(), 'context'),
+ 'Current-Folder')
+ if not context: context = 'inbox'
+ return context
+
+ def setcontext(self, context):
+ """Set the name of the current folder."""
+ fn = os.path.join(self.getpath(), 'context')
+ f = open(fn, "w")
+ f.write("Current-Folder: %s\n" % context)
+ f.close()
+
+ def listfolders(self):
+ """Return the names of the top-level folders."""
+ folders = []
+ path = self.getpath()
+ for name in os.listdir(path):
+ fullname = os.path.join(path, name)
+ if os.path.isdir(fullname):
+ folders.append(name)
+ folders.sort()
+ return folders
+
+ def listsubfolders(self, name):
+ """Return the names of the subfolders in a given folder
+ (prefixed with the given folder name)."""
+ fullname = os.path.join(self.path, name)
+ # Get the link count so we can avoid listing folders
+ # that have no subfolders.
+ st = os.stat(fullname)
+ nlinks = st[ST_NLINK]
+ if nlinks <= 2:
+ return []
+ subfolders = []
+ subnames = os.listdir(fullname)
+ for subname in subnames:
+ fullsubname = os.path.join(fullname, subname)
+ if os.path.isdir(fullsubname):
+ name_subname = os.path.join(name, subname)
+ subfolders.append(name_subname)
+ # Stop looking for subfolders when
+ # we've seen them all
+ nlinks = nlinks - 1
+ if nlinks <= 2:
+ break
+ subfolders.sort()
+ return subfolders
+
+ def listallfolders(self):
+ """Return the names of all folders and subfolders, recursively."""
+ return self.listallsubfolders('')
+
+ def listallsubfolders(self, name):
+ """Return the names of subfolders in a given folder, recursively."""
+ fullname = os.path.join(self.path, name)
+ # Get the link count so we can avoid listing folders
+ # that have no subfolders.
+ st = os.stat(fullname)
+ nlinks = st[ST_NLINK]
+ if nlinks <= 2:
+ return []
+ subfolders = []
+ subnames = os.listdir(fullname)
+ for subname in subnames:
+ if subname[0] == ',' or isnumeric(subname): continue
+ fullsubname = os.path.join(fullname, subname)
+ if os.path.isdir(fullsubname):
+ name_subname = os.path.join(name, subname)
+ subfolders.append(name_subname)
+ if not os.path.islink(fullsubname):
+ subsubfolders = self.listallsubfolders(
+ name_subname)
+ subfolders = subfolders + subsubfolders
+ # Stop looking for subfolders when
+ # we've seen them all
+ nlinks = nlinks - 1
+ if nlinks <= 2:
+ break
+ subfolders.sort()
+ return subfolders
+
+ def openfolder(self, name):
+ """Return a new Folder object for the named folder."""
+ return Folder(self, name)
+
+ def makefolder(self, name):
+ """Create a new folder (or raise os.error if it cannot be created)."""
+ protect = pickline(self.profile, 'Folder-Protect')
+ if protect and isnumeric(protect):
+ mode = int(protect, 8)
+ else:
+ mode = FOLDER_PROTECT
+ os.mkdir(os.path.join(self.getpath(), name), mode)
+
+ def deletefolder(self, name):
+ """Delete a folder. This removes files in the folder but not
+ subdirectories. Raise os.error if deleting the folder itself fails."""
+ fullname = os.path.join(self.getpath(), name)
+ for subname in os.listdir(fullname):
+ fullsubname = os.path.join(fullname, subname)
+ try:
+ os.unlink(fullsubname)
+ except os.error:
+ self.error('%s not deleted, continuing...' %
+ fullsubname)
+ os.rmdir(fullname)
+
+
+numericprog = re.compile('^[1-9][0-9]*$')
+def isnumeric(str):
+ return numericprog.match(str) is not None
+
+class Folder:
+ """Class representing a particular folder."""
+
+ def __init__(self, mh, name):
+ """Constructor."""
+ self.mh = mh
+ self.name = name
+ if not os.path.isdir(self.getfullname()):
+ raise Error, 'no folder %s' % name
+
+ def __repr__(self):
+ """String representation."""
+ return 'Folder(%s, %s)' % (`self.mh`, `self.name`)
+
+ def error(self, *args):
+ """Error message handler."""
+ apply(self.mh.error, args)
+
+ def getfullname(self):
+ """Return the full pathname of the folder."""
+ return os.path.join(self.mh.path, self.name)
+
+ def getsequencesfilename(self):
+ """Return the full pathname of the folder's sequences file."""
+ return os.path.join(self.getfullname(), MH_SEQUENCES)
+
+ def getmessagefilename(self, n):
+ """Return the full pathname of a message in the folder."""
+ return os.path.join(self.getfullname(), str(n))
+
+ def listsubfolders(self):
+ """Return list of direct subfolders."""
+ return self.mh.listsubfolders(self.name)
+
+ def listallsubfolders(self):
+ """Return list of all subfolders."""
+ return self.mh.listallsubfolders(self.name)
+
+ def listmessages(self):
+ """Return the list of messages currently present in the folder.
+ As a side effect, set self.last to the last message (or 0)."""
+ messages = []
+ match = numericprog.match
+ append = messages.append
+ for name in os.listdir(self.getfullname()):
+ if match(name):
+ append(name)
+ messages = map(int, messages)
+ messages.sort()
+ if messages:
+ self.last = messages[-1]
+ else:
+ self.last = 0
+ return messages
+
+ def getsequences(self):
+ """Return the set of sequences for the folder."""
+ sequences = {}
+ fullname = self.getsequencesfilename()
+ try:
+ f = open(fullname, 'r')
+ except IOError:
+ return sequences
+ while 1:
+ line = f.readline()
+ if not line: break
+ fields = line.split(':')
+ if len(fields) != 2:
+ self.error('bad sequence in %s: %s' %
+ (fullname, line.strip()))
+ key = fields[0].strip()
+ value = IntSet(fields[1].strip(), ' ').tolist()
+ sequences[key] = value
+ return sequences
+
+ def putsequences(self, sequences):
+ """Write the set of sequences back to the folder."""
+ fullname = self.getsequencesfilename()
+ f = None
+ for key in sequences.keys():
+ s = IntSet('', ' ')
+ s.fromlist(sequences[key])
+ if not f: f = open(fullname, 'w')
+ f.write('%s: %s\n' % (key, s.tostring()))
+ if not f:
+ try:
+ os.unlink(fullname)
+ except os.error:
+ pass
+ else:
+ f.close()
+
+ def getcurrent(self):
+ """Return the current message. Raise Error when there is none."""
+ seqs = self.getsequences()
+ try:
+ return max(seqs['cur'])
+ except (ValueError, KeyError):
+ raise Error, "no cur message"
+
+ def setcurrent(self, n):
+ """Set the current message."""
+ updateline(self.getsequencesfilename(), 'cur', str(n), 0)
+
+ def parsesequence(self, seq):
+ """Parse an MH sequence specification into a message list.
+ Attempt to mimic mh-sequence(5) as close as possible.
+ Also attempt to mimic observed behavior regarding which
+ conditions cause which error messages."""
+ # XXX Still not complete (see mh-format(5)).
+ # Missing are:
+ # - 'prev', 'next' as count
+ # - Sequence-Negation option
+ all = self.listmessages()
+ # Observed behavior: test for empty folder is done first
+ if not all:
+ raise Error, "no messages in %s" % self.name
+ # Common case first: all is frequently the default
+ if seq == 'all':
+ return all
+ # Test for X:Y before X-Y because 'seq:-n' matches both
+ i = seq.find(':')
+ if i >= 0:
+ head, dir, tail = seq[:i], '', seq[i+1:]
+ if tail[:1] in '-+':
+ dir, tail = tail[:1], tail[1:]
+ if not isnumeric(tail):
+ raise Error, "bad message list %s" % seq
+ try:
+ count = int(tail)
+ except (ValueError, OverflowError):
+ # Can't use sys.maxint because of i+count below
+ count = len(all)
+ try:
+ anchor = self._parseindex(head, all)
+ except Error, msg:
+ seqs = self.getsequences()
+ if not seqs.has_key(head):
+ if not msg:
+ msg = "bad message list %s" % seq
+ raise Error, msg, sys.exc_info()[2]
+ msgs = seqs[head]
+ if not msgs:
+ raise Error, "sequence %s empty" % head
+ if dir == '-':
+ return msgs[-count:]
+ else:
+ return msgs[:count]
+ else:
+ if not dir:
+ if head in ('prev', 'last'):
+ dir = '-'
+ if dir == '-':
+ i = bisect(all, anchor)
+ return all[max(0, i-count):i]
+ else:
+ i = bisect(all, anchor-1)
+ return all[i:i+count]
+ # Test for X-Y next
+ i = seq.find('-')
+ if i >= 0:
+ begin = self._parseindex(seq[:i], all)
+ end = self._parseindex(seq[i+1:], all)
+ i = bisect(all, begin-1)
+ j = bisect(all, end)
+ r = all[i:j]
+ if not r:
+ raise Error, "bad message list %s" % seq
+ return r
+ # Neither X:Y nor X-Y; must be a number or a (pseudo-)sequence
+ try:
+ n = self._parseindex(seq, all)
+ except Error, msg:
+ seqs = self.getsequences()
+ if not seqs.has_key(seq):
+ if not msg:
+ msg = "bad message list %s" % seq
+ raise Error, msg
+ return seqs[seq]
+ else:
+ if n not in all:
+ if isnumeric(seq):
+ raise Error, "message %d doesn't exist" % n
+ else:
+ raise Error, "no %s message" % seq
+ else:
+ return [n]
+
+ def _parseindex(self, seq, all):
+ """Internal: parse a message number (or cur, first, etc.)."""
+ if isnumeric(seq):
+ try:
+ return int(seq)
+ except (OverflowError, ValueError):
+ return sys.maxint
+ if seq in ('cur', '.'):
+ return self.getcurrent()
+ if seq == 'first':
+ return all[0]
+ if seq == 'last':
+ return all[-1]
+ if seq == 'next':
+ n = self.getcurrent()
+ i = bisect(all, n)
+ try:
+ return all[i]
+ except IndexError:
+ raise Error, "no next message"
+ if seq == 'prev':
+ n = self.getcurrent()
+ i = bisect(all, n-1)
+ if i == 0:
+ raise Error, "no prev message"
+ try:
+ return all[i-1]
+ except IndexError:
+ raise Error, "no prev message"
+ raise Error, None
+
+ def openmessage(self, n):
+ """Open a message -- returns a Message object."""
+ return Message(self, n)
+
+ def removemessages(self, list):
+ """Remove one or more messages -- may raise os.error."""
+ errors = []
+ deleted = []
+ for n in list:
+ path = self.getmessagefilename(n)
+ commapath = self.getmessagefilename(',' + str(n))
+ try:
+ os.unlink(commapath)
+ except os.error:
+ pass
+ try:
+ os.rename(path, commapath)
+ except os.error, msg:
+ errors.append(msg)
+ else:
+ deleted.append(n)
+ if deleted:
+ self.removefromallsequences(deleted)
+ if errors:
+ if len(errors) == 1:
+ raise os.error, errors[0]
+ else:
+ raise os.error, ('multiple errors:', errors)
+
+ def refilemessages(self, list, tofolder, keepsequences=0):
+ """Refile one or more messages -- may raise os.error.
+ 'tofolder' is an open folder object."""
+ errors = []
+ refiled = {}
+ for n in list:
+ ton = tofolder.getlast() + 1
+ path = self.getmessagefilename(n)
+ topath = tofolder.getmessagefilename(ton)
+ try:
+ os.rename(path, topath)
+ except os.error:
+ # Try copying
+ try:
+ shutil.copy2(path, topath)
+ os.unlink(path)
+ except (IOError, os.error), msg:
+ errors.append(msg)
+ try:
+ os.unlink(topath)
+ except os.error:
+ pass
+ continue
+ tofolder.setlast(ton)
+ refiled[n] = ton
+ if refiled:
+ if keepsequences:
+ tofolder._copysequences(self, refiled.items())
+ self.removefromallsequences(refiled.keys())
+ if errors:
+ if len(errors) == 1:
+ raise os.error, errors[0]
+ else:
+ raise os.error, ('multiple errors:', errors)
+
+ def _copysequences(self, fromfolder, refileditems):
+ """Helper for refilemessages() to copy sequences."""
+ fromsequences = fromfolder.getsequences()
+ tosequences = self.getsequences()
+ changed = 0
+ for name, seq in fromsequences.items():
+ try:
+ toseq = tosequences[name]
+ new = 0
+ except:
+ toseq = []
+ new = 1
+ for fromn, ton in refileditems:
+ if fromn in seq:
+ toseq.append(ton)
+ changed = 1
+ if new and toseq:
+ tosequences[name] = toseq
+ if changed:
+ self.putsequences(tosequences)
+
+ def movemessage(self, n, tofolder, ton):
+ """Move one message over a specific destination message,
+ which may or may not already exist."""
+ path = self.getmessagefilename(n)
+ # Open it to check that it exists
+ f = open(path)
+ f.close()
+ del f
+ topath = tofolder.getmessagefilename(ton)
+ backuptopath = tofolder.getmessagefilename(',%d' % ton)
+ try:
+ os.rename(topath, backuptopath)
+ except os.error:
+ pass
+ try:
+ os.rename(path, topath)
+ except os.error:
+ # Try copying
+ ok = 0
+ try:
+ tofolder.setlast(None)
+ shutil.copy2(path, topath)
+ ok = 1
+ finally:
+ if not ok:
+ try:
+ os.unlink(topath)
+ except os.error:
+ pass
+ os.unlink(path)
+ self.removefromallsequences([n])
+
+ def copymessage(self, n, tofolder, ton):
+ """Copy one message over a specific destination message,
+ which may or may not already exist."""
+ path = self.getmessagefilename(n)
+ # Open it to check that it exists
+ f = open(path)
+ f.close()
+ del f
+ topath = tofolder.getmessagefilename(ton)
+ backuptopath = tofolder.getmessagefilename(',%d' % ton)
+ try:
+ os.rename(topath, backuptopath)
+ except os.error:
+ pass
+ ok = 0
+ try:
+ tofolder.setlast(None)
+ shutil.copy2(path, topath)
+ ok = 1
+ finally:
+ if not ok:
+ try:
+ os.unlink(topath)
+ except os.error:
+ pass
+
+ def createmessage(self, n, txt):
+ """Create a message, with text from the open file txt."""
+ path = self.getmessagefilename(n)
+ backuppath = self.getmessagefilename(',%d' % n)
+ try:
+ os.rename(path, backuppath)
+ except os.error:
+ pass
+ ok = 0
+ BUFSIZE = 16*1024
+ try:
+ f = open(path, "w")
+ while 1:
+ buf = txt.read(BUFSIZE)
+ if not buf:
+ break
+ f.write(buf)
+ f.close()
+ ok = 1
+ finally:
+ if not ok:
+ try:
+ os.unlink(path)
+ except os.error:
+ pass
+
+ def removefromallsequences(self, list):
+ """Remove one or more messages from all sequences (including last)
+ -- but not from 'cur'!!!"""
+ if hasattr(self, 'last') and self.last in list:
+ del self.last
+ sequences = self.getsequences()
+ changed = 0
+ for name, seq in sequences.items():
+ if name == 'cur':
+ continue
+ for n in list:
+ if n in seq:
+ seq.remove(n)
+ changed = 1
+ if not seq:
+ del sequences[name]
+ if changed:
+ self.putsequences(sequences)
+
+ def getlast(self):
+ """Return the last message number."""
+ if not hasattr(self, 'last'):
+ messages = self.listmessages()
+ return self.last
+
+ def setlast(self, last):
+ """Set the last message number."""
+ if last is None:
+ if hasattr(self, 'last'):
+ del self.last
+ else:
+ self.last = last
+
+class Message(mimetools.Message):
+
+ def __init__(self, f, n, fp = None):
+ """Constructor."""
+ self.folder = f
+ self.number = n
+ if not fp:
+ path = f.getmessagefilename(n)
+ fp = open(path, 'r')
+ mimetools.Message.__init__(self, fp)
+
+ def __repr__(self):
+ """String representation."""
+ return 'Message(%s, %s)' % (repr(self.folder), self.number)
+
+ def getheadertext(self, pred = None):
+ """Return the message's header text as a string. If an
+ argument is specified, it is used as a filter predicate to
+ decide which headers to return (its argument is the header
+ name converted to lower case)."""
+ if not pred:
+ return ''.join(self.headers)
+ headers = []
+ hit = 0
+ for line in self.headers:
+ if not line[0].isspace():
+ i = line.find(':')
+ if i > 0:
+ hit = pred(line[:i].lower())
+ if hit: headers.append(line)
+ return ''.join(headers)
+
+ def getbodytext(self, decode = 1):
+ """Return the message's body text as string. This undoes a
+ Content-Transfer-Encoding, but does not interpret other MIME
+ features (e.g. multipart messages). To suppress decoding,
+ pass 0 as an argument."""
+ self.fp.seek(self.startofbody)
+ encoding = self.getencoding()
+ if not decode or encoding in ('', '7bit', '8bit', 'binary'):
+ return self.fp.read()
+ from StringIO import StringIO
+ output = StringIO()
+ mimetools.decode(self.fp, output, encoding)
+ return output.getvalue()
+
+ def getbodyparts(self):
+ """Only for multipart messages: return the message's body as a
+ list of SubMessage objects. Each submessage object behaves
+ (almost) as a Message object."""
+ if self.getmaintype() != 'multipart':
+ raise Error, 'Content-Type is not multipart/*'
+ bdry = self.getparam('boundary')
+ if not bdry:
+ raise Error, 'multipart/* without boundary param'
+ self.fp.seek(self.startofbody)
+ mf = multifile.MultiFile(self.fp)
+ mf.push(bdry)
+ parts = []
+ while mf.next():
+ n = str(self.number) + '.' + `1 + len(parts)`
+ part = SubMessage(self.folder, n, mf)
+ parts.append(part)
+ mf.pop()
+ return parts
+
+ def getbody(self):
+ """Return body, either a string or a list of messages."""
+ if self.getmaintype() == 'multipart':
+ return self.getbodyparts()
+ else:
+ return self.getbodytext()
+
+
+class SubMessage(Message):
+
+ def __init__(self, f, n, fp):
+ """Constructor."""
+ Message.__init__(self, f, n, fp)
+ if self.getmaintype() == 'multipart':
+ self.body = Message.getbodyparts(self)
+ else:
+ self.body = Message.getbodytext(self)
+ self.bodyencoded = Message.getbodytext(self, decode=0)
+ # XXX If this is big, should remember file pointers
+
+ def __repr__(self):
+ """String representation."""
+ f, n, fp = self.folder, self.number, self.fp
+ return 'SubMessage(%s, %s, %s)' % (f, n, fp)
+
+ def getbodytext(self, decode = 1):
+ if not decode:
+ return self.bodyencoded
+ if type(self.body) == type(''):
+ return self.body
+
+ def getbodyparts(self):
+ if type(self.body) == type([]):
+ return self.body
+
+ def getbody(self):
+ return self.body
+
+
+class IntSet:
+ """Class implementing sets of integers.
+
+ This is an efficient representation for sets consisting of several
+ continuous ranges, e.g. 1-100,200-400,402-1000 is represented
+ internally as a list of three pairs: [(1,100), (200,400),
+ (402,1000)]. The internal representation is always kept normalized.
+
+ The constructor has up to three arguments:
+ - the string used to initialize the set (default ''),
+ - the separator between ranges (default ',')
+ - the separator between begin and end of a range (default '-')
+ The separators must be strings (not regexprs) and should be different.
+
+ The tostring() function yields a string that can be passed to another
+ IntSet constructor; __repr__() is a valid IntSet constructor itself.
+ """
+
+ # XXX The default begin/end separator means that negative numbers are
+ # not supported very well.
+ #
+ # XXX There are currently no operations to remove set elements.
+
+ def __init__(self, data = None, sep = ',', rng = '-'):
+ self.pairs = []
+ self.sep = sep
+ self.rng = rng
+ if data: self.fromstring(data)
+
+ def reset(self):
+ self.pairs = []
+
+ def __cmp__(self, other):
+ return cmp(self.pairs, other.pairs)
+
+ def __hash__(self):
+ return hash(self.pairs)
+
+ def __repr__(self):
+ return 'IntSet(%s, %s, %s)' % (`self.tostring()`,
+ `self.sep`, `self.rng`)
+
+ def normalize(self):
+ self.pairs.sort()
+ i = 1
+ while i < len(self.pairs):
+ alo, ahi = self.pairs[i-1]
+ blo, bhi = self.pairs[i]
+ if ahi >= blo-1:
+ self.pairs[i-1:i+1] = [(alo, max(ahi, bhi))]
+ else:
+ i = i+1
+
+ def tostring(self):
+ s = ''
+ for lo, hi in self.pairs:
+ if lo == hi: t = `lo`
+ else: t = `lo` + self.rng + `hi`
+ if s: s = s + (self.sep + t)
+ else: s = t
+ return s
+
+ def tolist(self):
+ l = []
+ for lo, hi in self.pairs:
+ m = range(lo, hi+1)
+ l = l + m
+ return l
+
+ def fromlist(self, list):
+ for i in list:
+ self.append(i)
+
+ def clone(self):
+ new = IntSet()
+ new.pairs = self.pairs[:]
+ return new
+
+ def min(self):
+ return self.pairs[0][0]
+
+ def max(self):
+ return self.pairs[-1][-1]
+
+ def contains(self, x):
+ for lo, hi in self.pairs:
+ if lo <= x <= hi: return 1
+ return 0
+
+ def append(self, x):
+ for i in range(len(self.pairs)):
+ lo, hi = self.pairs[i]
+ if x < lo: # Need to insert before
+ if x+1 == lo:
+ self.pairs[i] = (x, hi)
+ else:
+ self.pairs.insert(i, (x, x))
+ if i > 0 and x-1 == self.pairs[i-1][1]:
+ # Merge with previous
+ self.pairs[i-1:i+1] = [
+ (self.pairs[i-1][0],
+ self.pairs[i][1])
+ ]
+ return
+ if x <= hi: # Already in set
+ return
+ i = len(self.pairs) - 1
+ if i >= 0:
+ lo, hi = self.pairs[i]
+ if x-1 == hi:
+ self.pairs[i] = lo, x
+ return
+ self.pairs.append((x, x))
+
+ def addpair(self, xlo, xhi):
+ if xlo > xhi: return
+ self.pairs.append((xlo, xhi))
+ self.normalize()
+
+ def fromstring(self, data):
+ new = []
+ for part in data.split(self.sep):
+ list = []
+ for subp in part.split(self.rng):
+ s = subp.strip()
+ list.append(int(s))
+ if len(list) == 1:
+ new.append((list[0], list[0]))
+ elif len(list) == 2 and list[0] <= list[1]:
+ new.append((list[0], list[1]))
+ else:
+ raise ValueError, 'bad data passed to IntSet'
+ self.pairs = self.pairs + new
+ self.normalize()
+
+
+# Subroutines to read/write entries in .mh_profile and .mh_sequences
+
+def pickline(file, key, casefold = 1):
+ try:
+ f = open(file, 'r')
+ except IOError:
+ return None
+ pat = re.escape(key) + ':'
+ prog = re.compile(pat, casefold and re.IGNORECASE)
+ while 1:
+ line = f.readline()
+ if not line: break
+ if prog.match(line):
+ text = line[len(key)+1:]
+ while 1:
+ line = f.readline()
+ if not line or not line[0].isspace():
+ break
+ text = text + line
+ return text.strip()
+ return None
+
+def updateline(file, key, value, casefold = 1):
+ try:
+ f = open(file, 'r')
+ lines = f.readlines()
+ f.close()
+ except IOError:
+ lines = []
+ pat = re.escape(key) + ':(.*)\n'
+ prog = re.compile(pat, casefold and re.IGNORECASE)
+ if value is None:
+ newline = None
+ else:
+ newline = '%s: %s\n' % (key, value)
+ for i in range(len(lines)):
+ line = lines[i]
+ if prog.match(line):
+ if newline is None:
+ del lines[i]
+ else:
+ lines[i] = newline
+ break
+ else:
+ if newline is not None:
+ lines.append(newline)
+ tempfile = file + "~"
+ f = open(tempfile, 'w')
+ for line in lines:
+ f.write(line)
+ f.close()
+ os.rename(tempfile, file)
+
+
+# Test program
+
+def test():
+ global mh, f
+ os.system('rm -rf $HOME/Mail/@test')
+ mh = MH()
+ def do(s): print s; print eval(s)
+ do('mh.listfolders()')
+ do('mh.listallfolders()')
+ testfolders = ['@test', '@test/test1', '@test/test2',
+ '@test/test1/test11', '@test/test1/test12',
+ '@test/test1/test11/test111']
+ for t in testfolders: do('mh.makefolder(%s)' % `t`)
+ do('mh.listsubfolders(\'@test\')')
+ do('mh.listallsubfolders(\'@test\')')
+ f = mh.openfolder('@test')
+ do('f.listsubfolders()')
+ do('f.listallsubfolders()')
+ do('f.getsequences()')
+ seqs = f.getsequences()
+ seqs['foo'] = IntSet('1-10 12-20', ' ').tolist()
+ print seqs
+ f.putsequences(seqs)
+ do('f.getsequences()')
+ testfolders.reverse()
+ for t in testfolders: do('mh.deletefolder(%s)' % `t`)
+ do('mh.getcontext()')
+ context = mh.getcontext()
+ f = mh.openfolder(context)
+ do('f.getcurrent()')
+ for seq in ['first', 'last', 'cur', '.', 'prev', 'next',
+ 'first:3', 'last:3', 'cur:3', 'cur:-3',
+ 'prev:3', 'next:3',
+ '1:3', '1:-3', '100:3', '100:-3', '10000:3', '10000:-3',
+ 'all']:
+ try:
+ do('f.parsesequence(%s)' % `seq`)
+ except Error, msg:
+ print "Error:", msg
+ stuff = os.popen("pick %s 2>/dev/null" % `seq`).read()
+ list = map(int, stuff.split())
+ print list, "<-- pick"
+ do('f.listmessages()')
+
+
+if __name__ == '__main__':
+ test()
diff --git a/lib/jython/Lib/mimetools.py b/lib/jython/Lib/mimetools.py new file mode 100644 index 000000000..da26847b4 --- /dev/null +++ b/lib/jython/Lib/mimetools.py @@ -0,0 +1,226 @@ +"""Various tools used by MIME-reading or MIME-writing programs."""
+
+
+import os
+import rfc822
+import tempfile
+
+__all__ = ["Message","choose_boundary","encode","decode","copyliteral",
+ "copybinary"]
+
+class Message(rfc822.Message):
+ """A derived class of rfc822.Message that knows about MIME headers and
+ contains some hooks for decoding encoded and multipart messages."""
+
+ 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 is None:
+ str = 'text/plain'
+ if ';' in str:
+ i = str.index(';')
+ self.plisttext = str[i:]
+ str = str[:i]
+ else:
+ self.plisttext = ''
+ fields = str.split('/')
+ for i in range(len(fields)):
+ fields[i] = fields[i].strip().lower()
+ self.type = '/'.join(fields)
+ self.maintype = fields[0]
+ self.subtype = '/'.join(fields[1:])
+
+ def parseplist(self):
+ str = self.plisttext
+ self.plist = []
+ while str[:1] == ';':
+ str = str[1:]
+ if ';' in str:
+ # XXX Should parse quotes!
+ end = str.index(';')
+ else:
+ end = len(str)
+ f = str[:end]
+ if '=' in f:
+ i = f.index('=')
+ f = f[:i].strip().lower() + \
+ '=' + f[i+1:].strip()
+ self.plist.append(f.strip())
+ str = str[end:]
+
+ def getplist(self):
+ return self.plist
+
+ def getparam(self, name):
+ name = name.lower() + '='
+ n = len(name)
+ for p in self.plist:
+ if p[:n] == name:
+ return rfc822.unquote(p[n:])
+ return None
+
+ def getparamnames(self):
+ result = []
+ for p in self.plist:
+ i = p.find('=')
+ if i >= 0:
+ result.append(p[:i].lower())
+ return result
+
+ def getencoding(self):
+ if self.encodingheader is None:
+ return '7bit'
+ return self.encodingheader.lower()
+
+ def gettype(self):
+ return self.type
+
+ def getmaintype(self):
+ return self.maintype
+
+ def getsubtype(self):
+ return self.subtype
+
+
+
+
+# Utility functions
+# -----------------
+
+
+_prefix = None
+
+def choose_boundary():
+ """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."""
+
+ global _prefix
+ import time
+ import random
+ if _prefix is None:
+ import socket
+ import os
+ hostid = socket.gethostbyname(socket.gethostname())
+ try:
+ uid = `os.getuid()`
+ except:
+ uid = '1'
+ try:
+ pid = `os.getpid()`
+ except:
+ pid = '1'
+ _prefix = hostid + '.' + uid + '.' + pid
+ timestamp = '%.3f' % time.time()
+ seed = `random.randint(0, 32767)`
+ return _prefix + '.' + timestamp + '.' + seed
+
+
+# Subroutines for decoding some common content-transfer-types
+
+def decode(input, output, encoding):
+ """Decode common content-transfer-encodings (base64, quopri, uuencode)."""
+ if encoding == 'base64':
+ import base64
+ return base64.decode(input, output)
+ if encoding == 'quoted-printable':
+ import quopri
+ return quopri.decode(input, output)
+ if encoding in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
+ import uu
+ return uu.decode(input, output)
+ if encoding in ('7bit', '8bit'):
+ return output.write(input.read())
+ if decodetab.has_key(encoding):
+ pipethrough(input, decodetab[encoding], output)
+ else:
+ raise ValueError, \
+ 'unknown Content-Transfer-Encoding: %s' % encoding
+
+def encode(input, output, encoding):
+ """Encode common content-transfer-encodings (base64, quopri, uuencode)."""
+ if encoding == 'base64':
+ import base64
+ return base64.encode(input, output)
+ if encoding == 'quoted-printable':
+ import quopri
+ return quopri.encode(input, output, 0)
+ if encoding in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
+ import uu
+ return uu.encode(input, output)
+ if encoding in ('7bit', '8bit'):
+ return output.write(input.read())
+ if encodetab.has_key(encoding):
+ pipethrough(input, encodetab[encoding], output)
+ else:
+ raise ValueError, \
+ 'unknown Content-Transfer-Encoding: %s' % encoding
+
+# The following is no longer used for standard encodings
+
+# XXX This requires that uudecode and mmencode are in $PATH
+
+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,
+ 'uue': uudecode_pipe,
+ 'x-uue': uudecode_pipe,
+ 'quoted-printable': 'mmencode -u -q',
+ 'base64': 'mmencode -u -b',
+}
+
+encodetab = {
+ 'x-uuencode': 'uuencode tempfile',
+ 'uuencode': 'uuencode tempfile',
+ 'x-uue': 'uuencode tempfile',
+ 'uue': '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()
+ temp = open(tempname, 'w')
+ 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/jython/Lib/mimetypes.py b/lib/jython/Lib/mimetypes.py new file mode 100644 index 000000000..31e0b33f6 --- /dev/null +++ b/lib/jython/Lib/mimetypes.py @@ -0,0 +1,242 @@ +"""Guess the MIME type of a file.
+
+This module defines two useful functions:
+
+guess_type(url) -- guess the MIME type and encoding of a URL.
+
+guess_extension(type) -- guess the extension for a given MIME type.
+
+It also contains the following, for tuning the behavior:
+
+Data:
+
+knownfiles -- list of files to parse
+inited -- flag set when init() has been called
+suffixes_map -- dictionary mapping suffixes to suffixes
+encodings_map -- dictionary mapping suffixes to encodings
+types_map -- dictionary mapping suffixes to types
+
+Functions:
+
+init([files]) -- parse a list of files, default knownfiles
+read_mime_types(file) -- parse one file, return a dictionary or None
+
+"""
+
+import posixpath
+import urllib
+
+__all__ = ["guess_type","guess_extension","read_mime_types","init"]
+
+knownfiles = [
+ "/usr/local/etc/httpd/conf/mime.types",
+ "/usr/local/lib/netscape/mime.types",
+ "/usr/local/etc/httpd/conf/mime.types", # Apache 1.2
+ "/usr/local/etc/mime.types", # Apache 1.3
+ ]
+
+inited = 0
+
+def guess_type(url):
+ """Guess the type of a file based on its URL.
+
+ Return value is a tuple (type, encoding) where type is None if the
+ type can't be guessed (no or unknown suffix) or a string of the
+ form type/subtype, usable for a MIME Content-type header; and
+ encoding is None for no encoding or the name of the program used
+ to encode (e.g. compress or gzip). The mappings are table
+ driven. Encoding suffixes are case sensitive; type suffixes are
+ first tried case sensitive, then case insensitive.
+
+ The suffixes .tgz, .taz and .tz (case sensitive!) are all mapped
+ to ".tar.gz". (This is table-driven too, using the dictionary
+ suffix_map).
+
+ """
+ if not inited:
+ init()
+ scheme, url = urllib.splittype(url)
+ if scheme == 'data':
+ # syntax of data URLs:
+ # dataurl := "data:" [ mediatype ] [ ";base64" ] "," data
+ # mediatype := [ type "/" subtype ] *( ";" parameter )
+ # data := *urlchar
+ # parameter := attribute "=" value
+ # type/subtype defaults to "text/plain"
+ comma = url.find(',')
+ if comma < 0:
+ # bad data URL
+ return None, None
+ semi = url.find(';', 0, comma)
+ if semi >= 0:
+ type = url[:semi]
+ else:
+ type = url[:comma]
+ if '=' in type or '/' not in type:
+ type = 'text/plain'
+ return type, None # never compressed, so encoding is None
+ base, ext = posixpath.splitext(url)
+ while suffix_map.has_key(ext):
+ base, ext = posixpath.splitext(base + suffix_map[ext])
+ if encodings_map.has_key(ext):
+ encoding = encodings_map[ext]
+ base, ext = posixpath.splitext(base)
+ else:
+ encoding = None
+ if types_map.has_key(ext):
+ return types_map[ext], encoding
+ elif types_map.has_key(ext.lower()):
+ return types_map[ext.lower()], encoding
+ else:
+ return None, encoding
+
+def guess_extension(type):
+ """Guess the extension for a file based on its MIME type.
+
+ Return value is a string giving a filename extension, including the
+ leading dot ('.'). The extension is not guaranteed to have been
+ associated with any particular data stream, but would be mapped to the
+ MIME type `type' by guess_type(). If no extension can be guessed for
+ `type', None is returned.
+ """
+ global inited
+ if not inited:
+ init()
+ type = type.lower()
+ for ext, stype in types_map.items():
+ if type == stype:
+ return ext
+ return None
+
+def init(files=None):
+ global inited
+ for file in files or knownfiles:
+ s = read_mime_types(file)
+ if s:
+ for key, value in s.items():
+ types_map[key] = value
+ inited = 1
+
+def read_mime_types(file):
+ try:
+ f = open(file)
+ except IOError:
+ return None
+ map = {}
+ while 1:
+ line = f.readline()
+ if not line: break
+ words = line.split()
+ for i in range(len(words)):
+ if words[i][0] == '#':
+ del words[i:]
+ break
+ if not words: continue
+ type, suffixes = words[0], words[1:]
+ for suff in suffixes:
+ map['.'+suff] = type
+ f.close()
+ return map
+
+suffix_map = {
+ '.tgz': '.tar.gz',
+ '.taz': '.tar.gz',
+ '.tz': '.tar.gz',
+}
+
+encodings_map = {
+ '.gz': 'gzip',
+ '.Z': 'compress',
+ }
+
+types_map = {
+ '.a': 'application/octet-stream',
+ '.ai': 'application/postscript',
+ '.aif': 'audio/x-aiff',
+ '.aifc': 'audio/x-aiff',
+ '.aiff': 'audio/x-aiff',
+ '.au': 'audio/basic',
+ '.avi': 'video/x-msvideo',
+ '.bcpio': 'application/x-bcpio',
+ '.bin': 'application/octet-stream',
+ '.cdf': 'application/x-netcdf',
+ '.cpio': 'application/x-cpio',
+ '.csh': 'application/x-csh',
+ '.dll': 'application/octet-stream',
+ '.dvi': 'application/x-dvi',
+ '.exe': 'application/octet-stream',
+ '.eps': 'application/postscript',
+ '.etx': 'text/x-setext',
+ '.gif': 'image/gif',
+ '.gtar': 'application/x-gtar',
+ '.hdf': 'application/x-hdf',
+ '.htm': 'text/html',
+ '.html': 'text/html',
+ '.ief': 'image/ief',
+ '.jpe': 'image/jpeg',
+ '.jpeg': 'image/jpeg',
+ '.jpg': 'image/jpeg',
+ '.js': 'application/x-javascript',
+ '.latex': 'application/x-latex',
+ '.man': 'application/x-troff-man',
+ '.me': 'application/x-troff-me',
+ '.mif': 'application/x-mif',
+ '.mov': 'video/quicktime',
+ '.movie': 'video/x-sgi-movie',
+ '.mpe': 'video/mpeg',
+ '.mpeg': 'video/mpeg',
+ '.mpg': 'video/mpeg',
+ '.ms': 'application/x-troff-ms',
+ '.nc': 'application/x-netcdf',
+ '.o': 'application/octet-stream',
+ '.obj': 'application/octet-stream',
+ '.oda': 'application/oda',
+ '.pbm': 'image/x-portable-bitmap',
+ '.pdf': 'application/pdf',
+ '.pgm': 'image/x-portable-graymap',
+ '.pnm': 'image/x-portable-anymap',
+ '.png': 'image/png',
+ '.ppm': 'image/x-portable-pixmap',
+ '.py': 'text/x-python',
+ '.pyc': 'application/x-python-code',
+ '.ps': 'application/postscript',
+ '.qt': 'video/quicktime',
+ '.ras': 'image/x-cmu-raster',
+ '.rgb': 'image/x-rgb',
+ '.rdf': 'application/xml',
+ '.roff': 'application/x-troff',
+ '.rtf': 'application/rtf',
+ '.rtx': 'text/richtext',
+ '.sgm': 'text/x-sgml',
+ '.sgml': 'text/x-sgml',
+ '.sh': 'application/x-sh',
+ '.shar': 'application/x-shar',
+ '.snd': 'audio/basic',
+ '.so': 'application/octet-stream',
+ '.src': 'application/x-wais-source',
+ '.sv4cpio': 'application/x-sv4cpio',
+ '.sv4crc': 'application/x-sv4crc',
+ '.t': 'application/x-troff',
+ '.tar': 'application/x-tar',
+ '.tcl': 'application/x-tcl',
+ '.tex': 'application/x-tex',
+ '.texi': 'application/x-texinfo',
+ '.texinfo': 'application/x-texinfo',
+ '.tif': 'image/tiff',
+ '.tiff': 'image/tiff',
+ '.tr': 'application/x-troff',
+ '.tsv': 'text/tab-separated-values',
+ '.txt': 'text/plain',
+ '.ustar': 'application/x-ustar',
+ '.wav': 'audio/x-wav',
+ '.xbm': 'image/x-xbitmap',
+ '.xml': 'text/xml',
+ '.xsl': 'application/xml',
+ '.xpm': 'image/x-xpixmap',
+ '.xwd': 'image/x-xwindowdump',
+ '.zip': 'application/zip',
+ }
+
+if __name__ == '__main__':
+ import sys
+ print guess_type(sys.argv[1])
diff --git a/lib/jython/Lib/mimify.py b/lib/jython/Lib/mimify.py new file mode 100644 index 000000000..9bcda2450 --- /dev/null +++ b/lib/jython/Lib/mimify.py @@ -0,0 +1,464 @@ +#! /usr/bin/env python
+
+"""Mimification and unmimification of mail messages.
+
+Decode quoted-printable parts of a mail message or encode using
+quoted-printable.
+
+Usage:
+ mimify(input, output)
+ unmimify(input, output, decode_base64 = 0)
+to encode and decode respectively. Input and output may be the name
+of a file or an open file object. Only a readline() method is used
+on the input file, only a write() method is used on the output file.
+When using file names, the input and output file names may be the
+same.
+
+Interactive usage:
+ mimify.py -e [infile [outfile]]
+ mimify.py -d [infile [outfile]]
+to encode and decode respectively. Infile defaults to standard
+input and outfile to standard output.
+"""
+
+# Configure
+MAXLEN = 200 # if lines longer than this, encode as quoted-printable
+CHARSET = 'ISO-8859-1' # default charset for non-US-ASCII mail
+QUOTE = '> ' # string replies are quoted with
+# End configure
+
+import re
+
+__all__ = ["mimify","unmimify","mime_encode_header","mime_decode_header"]
+
+qp = re.compile('^content-transfer-encoding:\\s*quoted-printable', re.I)
+base64_re = re.compile('^content-transfer-encoding:\\s*base64', re.I)
+mp = re.compile('^content-type:.*multipart/.*boundary="?([^;"\n]*)', re.I|re.S)
+chrset = re.compile('^(content-type:.*charset=")(us-ascii|iso-8859-[0-9]+)(".*)', re.I|re.S)
+he = re.compile('^-*\n')
+mime_code = re.compile('=([0-9a-f][0-9a-f])', re.I)
+mime_head = re.compile('=\\?iso-8859-1\\?q\\?([^? \t\n]+)\\?=', re.I)
+repl = re.compile('^subject:\\s+re: ', re.I)
+
+class File:
+ """A simple fake file object that knows about limited read-ahead and
+ boundaries. The only supported method is readline()."""
+
+ def __init__(self, file, boundary):
+ self.file = file
+ self.boundary = boundary
+ self.peek = None
+
+ def readline(self):
+ if self.peek is not None:
+ return ''
+ line = self.file.readline()
+ if not line:
+ return line
+ if self.boundary:
+ if line == self.boundary + '\n':
+ self.peek = line
+ return ''
+ if line == self.boundary + '--\n':
+ self.peek = line
+ return ''
+ return line
+
+class HeaderFile:
+ def __init__(self, file):
+ self.file = file
+ self.peek = None
+
+ def readline(self):
+ if self.peek is not None:
+ line = self.peek
+ self.peek = None
+ else:
+ line = self.file.readline()
+ if not line:
+ return line
+ if he.match(line):
+ return line
+ while 1:
+ self.peek = self.file.readline()
+ if len(self.peek) == 0 or \
+ (self.peek[0] != ' ' and self.peek[0] != '\t'):
+ return line
+ line = line + self.peek
+ self.peek = None
+
+def mime_decode(line):
+ """Decode a single line of quoted-printable text to 8bit."""
+ newline = ''
+ pos = 0
+ while 1:
+ res = mime_code.search(line, pos)
+ if res is None:
+ break
+ newline = newline + line[pos:res.start(0)] + \
+ chr(int(res.group(1), 16))
+ pos = res.end(0)
+ return newline + line[pos:]
+
+def mime_decode_header(line):
+ """Decode a header line to 8bit."""
+ newline = ''
+ pos = 0
+ while 1:
+ res = mime_head.search(line, pos)
+ if res is None:
+ break
+ match = res.group(1)
+ # convert underscores to spaces (before =XX conversion!)
+ match = ' '.join(match.split('_'))
+ newline = newline + line[pos:res.start(0)] + mime_decode(match)
+ pos = res.end(0)
+ return newline + line[pos:]
+
+def unmimify_part(ifile, ofile, decode_base64 = 0):
+ """Convert a quoted-printable part of a MIME mail message to 8bit."""
+ multipart = None
+ quoted_printable = 0
+ is_base64 = 0
+ is_repl = 0
+ if ifile.boundary and ifile.boundary[:2] == QUOTE:
+ prefix = QUOTE
+ else:
+ prefix = ''
+
+ # read header
+ hfile = HeaderFile(ifile)
+ while 1:
+ line = hfile.readline()
+ if not line:
+ return
+ if prefix and line[:len(prefix)] == prefix:
+ line = line[len(prefix):]
+ pref = prefix
+ else:
+ pref = ''
+ line = mime_decode_header(line)
+ if qp.match(line):
+ quoted_printable = 1
+ continue # skip this header
+ if decode_base64 and base64_re.match(line):
+ is_base64 = 1
+ continue
+ ofile.write(pref + line)
+ if not prefix and repl.match(line):
+ # we're dealing with a reply message
+ is_repl = 1
+ mp_res = mp.match(line)
+ if mp_res:
+ multipart = '--' + mp_res.group(1)
+ if he.match(line):
+ break
+ if is_repl and (quoted_printable or multipart):
+ is_repl = 0
+
+ # read body
+ while 1:
+ line = ifile.readline()
+ if not line:
+ return
+ line = re.sub(mime_head, '\\1', line)
+ if prefix and line[:len(prefix)] == prefix:
+ line = line[len(prefix):]
+ pref = prefix
+ else:
+ pref = ''
+## if is_repl and len(line) >= 4 and line[:4] == QUOTE+'--' and line[-3:] != '--\n':
+## multipart = line[:-1]
+ while multipart:
+ if line == multipart + '--\n':
+ ofile.write(pref + line)
+ multipart = None
+ line = None
+ break
+ if line == multipart + '\n':
+ ofile.write(pref + line)
+ nifile = File(ifile, multipart)
+ unmimify_part(nifile, ofile, decode_base64)
+ line = nifile.peek
+ if not line:
+ # premature end of file
+ break
+ continue
+ # not a boundary between parts
+ break
+ if line and quoted_printable:
+ while line[-2:] == '=\n':
+ line = line[:-2]
+ newline = ifile.readline()
+ if newline[:len(QUOTE)] == QUOTE:
+ newline = newline[len(QUOTE):]
+ line = line + newline
+ line = mime_decode(line)
+ if line and is_base64 and not pref:
+ import base64
+ line = base64.decodestring(line)
+ if line:
+ ofile.write(pref + line)
+
+def unmimify(infile, outfile, decode_base64 = 0):
+ """Convert quoted-printable parts of a MIME mail message to 8bit."""
+ if type(infile) == type(''):
+ ifile = open(infile)
+ if type(outfile) == type('') and infile == outfile:
+ import os
+ d, f = os.path.split(infile)
+ os.rename(infile, os.path.join(d, ',' + f))
+ else:
+ ifile = infile
+ if type(outfile) == type(''):
+ ofile = open(outfile, 'w')
+ else:
+ ofile = outfile
+ nifile = File(ifile, None)
+ unmimify_part(nifile, ofile, decode_base64)
+ ofile.flush()
+
+mime_char = re.compile('[=\177-\377]') # quote these chars in body
+mime_header_char = re.compile('[=?\177-\377]') # quote these in header
+
+def mime_encode(line, header):
+ """Code a single line as quoted-printable.
+ If header is set, quote some extra characters."""
+ if header:
+ reg = mime_header_char
+ else:
+ reg = mime_char
+ newline = ''
+ pos = 0
+ if len(line) >= 5 and line[:5] == 'From ':
+ # quote 'From ' at the start of a line for stupid mailers
+ newline = ('=%02x' % ord('F')).upper()
+ pos = 1
+ while 1:
+ res = reg.search(line, pos)
+ if res is None:
+ break
+ newline = newline + line[pos:res.start(0)] + \
+ ('=%02x' % ord(res.group(0))).upper()
+ pos = res.end(0)
+ line = newline + line[pos:]
+
+ newline = ''
+ while len(line) >= 75:
+ i = 73
+ while line[i] == '=' or line[i-1] == '=':
+ i = i - 1
+ i = i + 1
+ newline = newline + line[:i] + '=\n'
+ line = line[i:]
+ return newline + line
+
+mime_header = re.compile('([ \t(]|^)([-a-zA-Z0-9_+]*[\177-\377][-a-zA-Z0-9_+\177-\377]*)([ \t)]|\n)')
+
+def mime_encode_header(line):
+ """Code a single header line as quoted-printable."""
+ newline = ''
+ pos = 0
+ while 1:
+ res = mime_header.search(line, pos)
+ if res is None:
+ break
+ newline = '%s%s%s=?%s?Q?%s?=%s' % \
+ (newline, line[pos:res.start(0)], res.group(1),
+ CHARSET, mime_encode(res.group(2), 1), res.group(3))
+ pos = res.end(0)
+ return newline + line[pos:]
+
+mv = re.compile('^mime-version:', re.I)
+cte = re.compile('^content-transfer-encoding:', re.I)
+iso_char = re.compile('[\177-\377]')
+
+def mimify_part(ifile, ofile, is_mime):
+ """Convert an 8bit part of a MIME mail message to quoted-printable."""
+ has_cte = is_qp = is_base64 = 0
+ multipart = None
+ must_quote_body = must_quote_header = has_iso_chars = 0
+
+ header = []
+ header_end = ''
+ message = []
+ message_end = ''
+ # read header
+ hfile = HeaderFile(ifile)
+ while 1:
+ line = hfile.readline()
+ if not line:
+ break
+ if not must_quote_header and iso_char.search(line):
+ must_quote_header = 1
+ if mv.match(line):
+ is_mime = 1
+ if cte.match(line):
+ has_cte = 1
+ if qp.match(line):
+ is_qp = 1
+ elif base64_re.match(line):
+ is_base64 = 1
+ mp_res = mp.match(line)
+ if mp_res:
+ multipart = '--' + mp_res.group(1)
+ if he.match(line):
+ header_end = line
+ break
+ header.append(line)
+
+ # read body
+ while 1:
+ line = ifile.readline()
+ if not line:
+ break
+ if multipart:
+ if line == multipart + '--\n':
+ message_end = line
+ break
+ if line == multipart + '\n':
+ message_end = line
+ break
+ if is_base64:
+ message.append(line)
+ continue
+ if is_qp:
+ while line[-2:] == '=\n':
+ line = line[:-2]
+ newline = ifile.readline()
+ if newline[:len(QUOTE)] == QUOTE:
+ newline = newline[len(QUOTE):]
+ line = line + newline
+ line = mime_decode(line)
+ message.append(line)
+ if not has_iso_chars:
+ if iso_char.search(line):
+ has_iso_chars = must_quote_body = 1
+ if not must_quote_body:
+ if len(line) > MAXLEN:
+ must_quote_body = 1
+
+ # convert and output header and body
+ for line in header:
+ if must_quote_header:
+ line = mime_encode_header(line)
+ chrset_res = chrset.match(line)
+ if chrset_res:
+ if has_iso_chars:
+ # change us-ascii into iso-8859-1
+ if chrset_res.group(2).lower() == 'us-ascii':
+ line = '%s%s%s' % (chrset_res.group(1),
+ CHARSET,
+ chrset_res.group(3))
+ else:
+ # change iso-8859-* into us-ascii
+ line = '%sus-ascii%s' % chrset_res.group(1, 3)
+ if has_cte and cte.match(line):
+ line = 'Content-Transfer-Encoding: '
+ if is_base64:
+ line = line + 'base64\n'
+ elif must_quote_body:
+ line = line + 'quoted-printable\n'
+ else:
+ line = line + '7bit\n'
+ ofile.write(line)
+ if (must_quote_header or must_quote_body) and not is_mime:
+ ofile.write('Mime-Version: 1.0\n')
+ ofile.write('Content-Type: text/plain; ')
+ if has_iso_chars:
+ ofile.write('charset="%s"\n' % CHARSET)
+ else:
+ ofile.write('charset="us-ascii"\n')
+ if must_quote_body and not has_cte:
+ ofile.write('Content-Transfer-Encoding: quoted-printable\n')
+ ofile.write(header_end)
+
+ for line in message:
+ if must_quote_body:
+ line = mime_encode(line, 0)
+ ofile.write(line)
+ ofile.write(message_end)
+
+ line = message_end
+ while multipart:
+ if line == multipart + '--\n':
+ # read bit after the end of the last part
+ while 1:
+ line = ifile.readline()
+ if not line:
+ return
+ if must_quote_body:
+ line = mime_encode(line, 0)
+ ofile.write(line)
+ if line == multipart + '\n':
+ nifile = File(ifile, multipart)
+ mimify_part(nifile, ofile, 1)
+ line = nifile.peek
+ if not line:
+ # premature end of file
+ break
+ ofile.write(line)
+ continue
+ # unexpectedly no multipart separator--copy rest of file
+ while 1:
+ line = ifile.readline()
+ if not line:
+ return
+ if must_quote_body:
+ line = mime_encode(line, 0)
+ ofile.write(line)
+
+def mimify(infile, outfile):
+ """Convert 8bit parts of a MIME mail message to quoted-printable."""
+ if type(infile) == type(''):
+ ifile = open(infile)
+ if type(outfile) == type('') and infile == outfile:
+ import os
+ d, f = os.path.split(infile)
+ os.rename(infile, os.path.join(d, ',' + f))
+ else:
+ ifile = infile
+ if type(outfile) == type(''):
+ ofile = open(outfile, 'w')
+ else:
+ ofile = outfile
+ nifile = File(ifile, None)
+ mimify_part(nifile, ofile, 0)
+ ofile.flush()
+
+import sys
+if __name__ == '__main__' or (len(sys.argv) > 0 and sys.argv[0] == 'mimify'):
+ import getopt
+ usage = 'Usage: mimify [-l len] -[ed] [infile [outfile]]'
+
+ decode_base64 = 0
+ opts, args = getopt.getopt(sys.argv[1:], 'l:edb')
+ if len(args) not in (0, 1, 2):
+ print usage
+ sys.exit(1)
+ if (('-e', '') in opts) == (('-d', '') in opts) or \
+ ((('-b', '') in opts) and (('-d', '') not in opts)):
+ print usage
+ sys.exit(1)
+ for o, a in opts:
+ if o == '-e':
+ encode = mimify
+ elif o == '-d':
+ encode = unmimify
+ elif o == '-l':
+ try:
+ MAXLEN = int(a)
+ except (ValueError, OverflowError):
+ print usage
+ sys.exit(1)
+ elif o == '-b':
+ decode_base64 = 1
+ if len(args) == 0:
+ encode_args = (sys.stdin, sys.stdout)
+ elif len(args) == 1:
+ encode_args = (args[0], sys.stdout)
+ else:
+ encode_args = (args[0], args[1])
+ if decode_base64:
+ encode_args = encode_args + (decode_base64,)
+ apply(encode, encode_args)
diff --git a/lib/jython/Lib/multifile.py b/lib/jython/Lib/multifile.py new file mode 100644 index 000000000..c7092cb06 --- /dev/null +++ b/lib/jython/Lib/multifile.py @@ -0,0 +1,162 @@ +"""A readline()-style interface to the parts of a multipart message.
+
+The MultiFile class 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.
+
+If seekable is given as 0, the class code will not do the bookkeeping
+it normally attempts in order to make seeks relative to the beginning of the
+current file part. This may be useful when using MultiFile with a non-
+seekable stream object.
+"""
+
+import sys
+
+__all__ = ["MultiFile","Error"]
+
+class Error(Exception):
+ pass
+
+class MultiFile:
+
+ seekable = 0
+
+ def __init__(self, fp, seekable=1):
+ self.fp = fp
+ self.stack = [] # Grows down
+ self.level = 0
+ self.last = 0
+ if seekable:
+ self.seekable = 1
+ 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, whence=0):
+ here = self.tell()
+ if whence:
+ if whence == 1:
+ pos = pos + here
+ elif whence == 2:
+ if self.level > 0:
+ pos = pos + self.lastpos
+ else:
+ raise Error, "can't use whence=2 yet"
+ if not 0 <= pos <= here 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()
+ # Real EOF?
+ if not line:
+ self.level = len(self.stack)
+ self.last = (self.level > 0)
+ if self.last:
+ raise Error, 'sudden EOF in MultiFile.readline()'
+ return ''
+ assert self.level == 0
+ # Fast check to see if this is just data
+ if self.is_data(line):
+ return line
+ else:
+ # Ignore trailing whitespace on marker lines
+ marker = line.rstrip()
+ # No? OK, try to match a boundary.
+ # Return the line (unstripped) if we don't.
+ for i in range(len(self.stack)):
+ sep = self.stack[i]
+ if marker == self.section_divider(sep):
+ self.last = 0
+ break
+ elif marker == self.end_marker(sep):
+ self.last = 1
+ break
+ else:
+ return line
+ # We only get here if we see a section divider or EOM line
+ if self.seekable:
+ self.lastpos = self.tell() - len(line)
+ self.level = i+1
+ if self.level > 1:
+ raise Error,'Missing endmarker in MultiFile.readline()'
+ 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 ''.join(self.readlines())
+
+ def next(self):
+ while self.readline(): pass
+ if self.level > 1 or self.last:
+ return 0
+ self.level = 0
+ self.last = 0
+ if self.seekable:
+ 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)
+ if self.seekable:
+ 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]
+ if self.seekable:
+ self.start = self.posstack[0]
+ del self.posstack[0]
+ if self.level > 0:
+ self.lastpos = abslastpos - self.start
+
+ def is_data(self, line):
+ return line[:2] != '--'
+
+ def section_divider(self, str):
+ return "--" + str
+
+ def end_marker(self, str):
+ return "--" + str + "--"
diff --git a/lib/jython/Lib/mutex.py b/lib/jython/Lib/mutex.py new file mode 100644 index 000000000..9b8b1a0cb --- /dev/null +++ b/lib/jython/Lib/mutex.py @@ -0,0 +1,51 @@ +"""Mutual exclusion -- for use with module sched
+
+A mutex has two pieces of state -- a 'locked' bit and a queue.
+When the mutex is not locked, the queue is empty.
+Otherwise, the queue contains 0 or more (function, argument) pairs
+representing functions (or methods) waiting to acquire the lock.
+When the mutex is unlocked while the queue is not empty,
+the first queue entry is removed and its function(argument) pair called,
+implying it now has the lock.
+
+Of course, no multi-threading is implied -- hence the funny interface
+for lock, where a function is called once the lock is aquired.
+"""
+
+class mutex:
+ def __init__(self):
+ """Create a new mutex -- initially unlocked."""
+ self.locked = 0
+ self.queue = []
+
+ def test(self):
+ """Test the locked bit of the mutex."""
+ return self.locked
+
+ def testandset(self):
+ """Atomic test-and-set -- grab the lock if it is not set,
+ return true if it succeeded."""
+ if not self.locked:
+ self.locked = 1
+ return 1
+ else:
+ return 0
+
+ def lock(self, function, argument):
+ """Lock a mutex, call the function with supplied argument
+ when it is acquired. If the mutex is already locked, place
+ function and argument in the queue."""
+ if self.testandset():
+ function(argument)
+ else:
+ self.queue.append((function, argument))
+
+ def unlock(self):
+ """Unlock a mutex. If the queue is not empty, call the next
+ function with its argument."""
+ if self.queue:
+ function, argument = self.queue[0]
+ del self.queue[0]
+ function(argument)
+ else:
+ self.locked = 0
diff --git a/lib/jython/Lib/nntplib.py b/lib/jython/Lib/nntplib.py new file mode 100644 index 000000000..683f9245c --- /dev/null +++ b/lib/jython/Lib/nntplib.py @@ -0,0 +1,557 @@ +"""An NNTP client class based on RFC 977: Network News Transfer Protocol.
+
+Example:
+
+>>> from nntplib import NNTP
+>>> s = NNTP('news')
+>>> resp, count, first, last, name = s.group('comp.lang.python')
+>>> print 'Group', name, 'has', count, 'articles, range', first, 'to', last
+Group comp.lang.python has 51 articles, range 5770 to 5821
+>>> resp, subs = s.xhdr('subject', first + '-' + last)
+>>> resp = s.quit()
+>>>
+
+Here 'resp' is the server response line.
+Error responses are turned into exceptions.
+
+To post an article from a file:
+>>> f = open(filename, 'r') # file containing article, including header
+>>> resp = s.post(f)
+>>>
+
+For descriptions of all methods, read the comments in the code below.
+Note that all arguments and return values representing article numbers
+are strings, not numbers, since they are rarely used for calculations.
+"""
+
+# RFC 977 by Brian Kantor and Phil Lapsley.
+# xover, xgtitle, xpath, date methods by Kevan Heydon
+
+
+# Imports
+import re
+import socket
+
+__all__ = ["NNTP","NNTPReplyError","NNTPTemporaryError",
+ "NNTPPermanentError","NNTPProtocolError","NNTPDataError",
+ "error_reply","error_temp","error_perm","error_proto",
+ "error_data",]
+
+# Exceptions raised when an error or invalid response is received
+class NNTPError(Exception):
+ """Base class for all nntplib exceptions"""
+ def __init__(self, *args):
+ apply(Exception.__init__, (self,)+args)
+ try:
+ self.response = args[0]
+ except IndexError:
+ self.response = 'No response given'
+
+class NNTPReplyError(NNTPError):
+ """Unexpected [123]xx reply"""
+ pass
+
+class NNTPTemporaryError(NNTPError):
+ """4xx errors"""
+ pass
+
+class NNTPPermanentError(NNTPError):
+ """5xx errors"""
+ pass
+
+class NNTPProtocolError(NNTPError):
+ """Response does not begin with [1-5]"""
+ pass
+
+class NNTPDataError(NNTPError):
+ """Error in response data"""
+ pass
+
+# for backwards compatibility
+error_reply = NNTPReplyError
+error_temp = NNTPTemporaryError
+error_perm = NNTPPermanentError
+error_proto = NNTPProtocolError
+error_data = NNTPDataError
+
+
+
+# Standard port used by NNTP servers
+NNTP_PORT = 119
+
+
+# Response numbers that are followed by additional text (e.g. article)
+LONGRESP = ['100', '215', '220', '221', '222', '224', '230', '231', '282']
+
+
+# Line terminators (we always output CRLF, but accept any of CRLF, CR, LF)
+CRLF = '\r\n'
+
+
+
+# The class itself
+class NNTP:
+ def __init__(self, host, port=NNTP_PORT, user=None, password=None,
+ readermode=None):
+ """Initialize an instance. Arguments:
+ - host: hostname to connect to
+ - port: port to connect to (default the standard NNTP port)
+ - user: username to authenticate with
+ - password: password to use with username
+ - readermode: if true, send 'mode reader' command after
+ connecting.
+
+ readermode is sometimes necessary if you are connecting to an
+ NNTP server on the local machine and intend to call
+ reader-specific comamnds, such as `group'. If you get
+ unexpected NNTPPermanentErrors, you might need to set
+ readermode.
+ """
+ self.host = host
+ self.port = port
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.sock.connect((self.host, self.port))
+ self.file = self.sock.makefile('rb')
+ self.debugging = 0
+ self.welcome = self.getresp()
+
+ # 'mode reader' is sometimes necessary to enable 'reader' mode.
+ # However, the order in which 'mode reader' and 'authinfo' need to
+ # arrive differs between some NNTP servers. Try to send
+ # 'mode reader', and if it fails with an authorization failed
+ # error, try again after sending authinfo.
+ readermode_afterauth = 0
+ if readermode:
+ try:
+ self.welcome = self.shortcmd('mode reader')
+ except NNTPPermanentError:
+ # error 500, probably 'not implemented'
+ pass
+ except NNTPTemporaryError, e:
+ if user and e.response[:3] == '480':
+ # Need authorization before 'mode reader'
+ readermode_afterauth = 1
+ else:
+ raise
+ if user:
+ resp = self.shortcmd('authinfo user '+user)
+ if resp[:3] == '381':
+ if not password:
+ raise NNTPReplyError(resp)
+ else:
+ resp = self.shortcmd(
+ 'authinfo pass '+password)
+ if resp[:3] != '281':
+ raise NNTPPermanentError(resp)
+ if readermode_afterauth:
+ try:
+ self.welcome = self.shortcmd('mode reader')
+ except NNTPPermanentError:
+ # error 500, probably 'not implemented'
+ pass
+
+
+ # Get the welcome message from the server
+ # (this is read and squirreled away by __init__()).
+ # If the response code is 200, posting is allowed;
+ # if it 201, posting is not allowed
+
+ def getwelcome(self):
+ """Get the welcome message from the server
+ (this is read and squirreled away by __init__()).
+ If the response code is 200, posting is allowed;
+ if it 201, posting is not allowed."""
+
+ if self.debugging: print '*welcome*', `self.welcome`
+ return self.welcome
+
+ def set_debuglevel(self, level):
+ """Set the debugging level. Argument 'level' means:
+ 0: no debugging output (default)
+ 1: print commands and responses but not body text etc.
+ 2: also print raw lines read and sent before stripping CR/LF"""
+
+ self.debugging = level
+ debug = set_debuglevel
+
+ def putline(self, line):
+ """Internal: send one line to the server, appending CRLF."""
+ line = line + CRLF
+ if self.debugging > 1: print '*put*', `line`
+ self.sock.send(line)
+
+ def putcmd(self, line):
+ """Internal: send one command to the server (through putline())."""
+ if self.debugging: print '*cmd*', `line`
+ self.putline(line)
+
+ def getline(self):
+ """Internal: return one line from the server, stripping CRLF.
+ Raise EOFError if the connection is closed."""
+ line = self.file.readline()
+ if self.debugging > 1:
+ print '*get*', `line`
+ if not line: raise EOFError
+ if line[-2:] == CRLF: line = line[:-2]
+ elif line[-1:] in CRLF: line = line[:-1]
+ return line
+
+ def getresp(self):
+ """Internal: get a response from the server.
+ Raise various errors if the response indicates an error."""
+ resp = self.getline()
+ if self.debugging: print '*resp*', `resp`
+ c = resp[:1]
+ if c == '4':
+ raise NNTPTemporaryError(resp)
+ if c == '5':
+ raise NNTPPermanentError(resp)
+ if c not in '123':
+ raise NNTPProtocolError(resp)
+ return resp
+
+ def getlongresp(self):
+ """Internal: get a response plus following text from the server.
+ Raise various errors if the response indicates an error."""
+ resp = self.getresp()
+ if resp[:3] not in LONGRESP:
+ raise NNTPReplyError(resp)
+ list = []
+ while 1:
+ line = self.getline()
+ if line == '.':
+ break
+ if line[:2] == '..':
+ line = line[1:]
+ list.append(line)
+ return resp, list
+
+ def shortcmd(self, line):
+ """Internal: send a command and get the response."""
+ self.putcmd(line)
+ return self.getresp()
+
+ def longcmd(self, line):
+ """Internal: send a command and get the response plus following text."""
+ self.putcmd(line)
+ return self.getlongresp()
+
+ def newgroups(self, date, time):
+ """Process a NEWGROUPS command. Arguments:
+ - date: string 'yymmdd' indicating the date
+ - time: string 'hhmmss' indicating the time
+ Return:
+ - resp: server response if successful
+ - list: list of newsgroup names"""
+
+ return self.longcmd('NEWGROUPS ' + date + ' ' + time)
+
+ def newnews(self, group, date, time):
+ """Process a NEWNEWS command. Arguments:
+ - group: group name or '*'
+ - date: string 'yymmdd' indicating the date
+ - time: string 'hhmmss' indicating the time
+ Return:
+ - resp: server response if successful
+ - list: list of article ids"""
+
+ cmd = 'NEWNEWS ' + group + ' ' + date + ' ' + time
+ return self.longcmd(cmd)
+
+ def list(self):
+ """Process a LIST command. Return:
+ - resp: server response if successful
+ - list: list of (group, last, first, flag) (strings)"""
+
+ resp, list = self.longcmd('LIST')
+ for i in range(len(list)):
+ # Parse lines into "group last first flag"
+ list[i] = tuple(list[i].split())
+ return resp, list
+
+ def group(self, name):
+ """Process a GROUP command. Argument:
+ - group: the group name
+ Returns:
+ - resp: server response if successful
+ - count: number of articles (string)
+ - first: first article number (string)
+ - last: last article number (string)
+ - name: the group name"""
+
+ resp = self.shortcmd('GROUP ' + name)
+ if resp[:3] != '211':
+ raise NNTPReplyError(resp)
+ words = resp.split()
+ count = first = last = 0
+ n = len(words)
+ if n > 1:
+ count = words[1]
+ if n > 2:
+ first = words[2]
+ if n > 3:
+ last = words[3]
+ if n > 4:
+ name = words[4].lower()
+ return resp, count, first, last, name
+
+ def help(self):
+ """Process a HELP command. Returns:
+ - resp: server response if successful
+ - list: list of strings"""
+
+ return self.longcmd('HELP')
+
+ def statparse(self, resp):
+ """Internal: parse the response of a STAT, NEXT or LAST command."""
+ if resp[:2] != '22':
+ raise NNTPReplyError(resp)
+ words = resp.split()
+ nr = 0
+ id = ''
+ n = len(words)
+ if n > 1:
+ nr = words[1]
+ if n > 2:
+ id = words[2]
+ return resp, nr, id
+
+ def statcmd(self, line):
+ """Internal: process a STAT, NEXT or LAST command."""
+ resp = self.shortcmd(line)
+ return self.statparse(resp)
+
+ def stat(self, id):
+ """Process a STAT command. Argument:
+ - id: article number or message id
+ Returns:
+ - resp: server response if successful
+ - nr: the article number
+ - id: the article id"""
+
+ return self.statcmd('STAT ' + id)
+
+ def next(self):
+ """Process a NEXT command. No arguments. Return as for STAT."""
+ return self.statcmd('NEXT')
+
+ def last(self):
+ """Process a LAST command. No arguments. Return as for STAT."""
+ return self.statcmd('LAST')
+
+ def artcmd(self, line):
+ """Internal: process a HEAD, BODY or ARTICLE command."""
+ resp, list = self.longcmd(line)
+ resp, nr, id = self.statparse(resp)
+ return resp, nr, id, list
+
+ def head(self, id):
+ """Process a HEAD command. Argument:
+ - id: article number or message id
+ Returns:
+ - resp: server response if successful
+ - nr: article number
+ - id: message id
+ - list: the lines of the article's header"""
+
+ return self.artcmd('HEAD ' + id)
+
+ def body(self, id):
+ """Process a BODY command. Argument:
+ - id: article number or message id
+ Returns:
+ - resp: server response if successful
+ - nr: article number
+ - id: message id
+ - list: the lines of the article's body"""
+
+ return self.artcmd('BODY ' + id)
+
+ def article(self, id):
+ """Process an ARTICLE command. Argument:
+ - id: article number or message id
+ Returns:
+ - resp: server response if successful
+ - nr: article number
+ - id: message id
+ - list: the lines of the article"""
+
+ return self.artcmd('ARTICLE ' + id)
+
+ def slave(self):
+ """Process a SLAVE command. Returns:
+ - resp: server response if successful"""
+
+ return self.shortcmd('SLAVE')
+
+ def xhdr(self, hdr, str):
+ """Process an XHDR command (optional server extension). Arguments:
+ - hdr: the header type (e.g. 'subject')
+ - str: an article nr, a message id, or a range nr1-nr2
+ Returns:
+ - resp: server response if successful
+ - list: list of (nr, value) strings"""
+
+ pat = re.compile('^([0-9]+) ?(.*)\n?')
+ resp, lines = self.longcmd('XHDR ' + hdr + ' ' + str)
+ for i in range(len(lines)):
+ line = lines[i]
+ m = pat.match(line)
+ if m:
+ lines[i] = m.group(1, 2)
+ return resp, lines
+
+ def xover(self,start,end):
+ """Process an XOVER command (optional server extension) Arguments:
+ - start: start of range
+ - end: end of range
+ Returns:
+ - resp: server response if successful
+ - list: list of (art-nr, subject, poster, date,
+ id, references, size, lines)"""
+
+ resp, lines = self.longcmd('XOVER ' + start + '-' + end)
+ xover_lines = []
+ for line in lines:
+ elem = line.split("\t")
+ try:
+ xover_lines.append((elem[0],
+ elem[1],
+ elem[2],
+ elem[3],
+ elem[4],
+ elem[5].split(),
+ elem[6],
+ elem[7]))
+ except IndexError:
+ raise NNTPDataError(line)
+ return resp,xover_lines
+
+ def xgtitle(self, group):
+ """Process an XGTITLE command (optional server extension) Arguments:
+ - group: group name wildcard (i.e. news.*)
+ Returns:
+ - resp: server response if successful
+ - list: list of (name,title) strings"""
+
+ line_pat = re.compile("^([^ \t]+)[ \t]+(.*)$")
+ resp, raw_lines = self.longcmd('XGTITLE ' + group)
+ lines = []
+ for raw_line in raw_lines:
+ match = line_pat.search(raw_line.strip())
+ if match:
+ lines.append(match.group(1, 2))
+ return resp, lines
+
+ def xpath(self,id):
+ """Process an XPATH command (optional server extension) Arguments:
+ - id: Message id of article
+ Returns:
+ resp: server response if successful
+ path: directory path to article"""
+
+ resp = self.shortcmd("XPATH " + id)
+ if resp[:3] != '223':
+ raise NNTPReplyError(resp)
+ try:
+ [resp_num, path] = resp.split()
+ except ValueError:
+ raise NNTPReplyError(resp)
+ else:
+ return resp, path
+
+ def date (self):
+ """Process the DATE command. Arguments:
+ None
+ Returns:
+ resp: server response if successful
+ date: Date suitable for newnews/newgroups commands etc.
+ time: Time suitable for newnews/newgroups commands etc."""
+
+ resp = self.shortcmd("DATE")
+ if resp[:3] != '111':
+ raise NNTPReplyError(resp)
+ elem = resp.split()
+ if len(elem) != 2:
+ raise NNTPDataError(resp)
+ date = elem[1][2:8]
+ time = elem[1][-6:]
+ if len(date) != 6 or len(time) != 6:
+ raise NNTPDataError(resp)
+ return resp, date, time
+
+
+ def post(self, f):
+ """Process a POST command. Arguments:
+ - f: file containing the article
+ Returns:
+ - resp: server response if successful"""
+
+ resp = self.shortcmd('POST')
+ # Raises error_??? if posting is not allowed
+ if resp[0] != '3':
+ raise NNTPReplyError(resp)
+ while 1:
+ line = f.readline()
+ if not line:
+ break
+ if line[-1] == '\n':
+ line = line[:-1]
+ if line[:1] == '.':
+ line = '.' + line
+ self.putline(line)
+ self.putline('.')
+ return self.getresp()
+
+ def ihave(self, id, f):
+ """Process an IHAVE command. Arguments:
+ - id: message-id of the article
+ - f: file containing the article
+ Returns:
+ - resp: server response if successful
+ Note that if the server refuses the article an exception is raised."""
+
+ resp = self.shortcmd('IHAVE ' + id)
+ # Raises error_??? if the server already has it
+ if resp[0] != '3':
+ raise NNTPReplyError(resp)
+ while 1:
+ line = f.readline()
+ if not line:
+ break
+ if line[-1] == '\n':
+ line = line[:-1]
+ if line[:1] == '.':
+ line = '.' + line
+ self.putline(line)
+ self.putline('.')
+ return self.getresp()
+
+ def quit(self):
+ """Process a QUIT command and close the socket. Returns:
+ - resp: server response if successful"""
+
+ resp = self.shortcmd('QUIT')
+ self.file.close()
+ self.sock.close()
+ del self.file, self.sock
+ return resp
+
+
+def _test():
+ """Minimal test function."""
+ s = NNTP('news', readermode='reader')
+ resp, count, first, last, name = s.group('comp.lang.python')
+ print resp
+ print 'Group', name, 'has', count, 'articles, range', first, 'to', last
+ resp, subs = s.xhdr('subject', first + '-' + last)
+ print resp
+ for item in subs:
+ print "%7s %s" % item
+ resp = s.quit()
+ print resp
+
+
+# Run the test when run as a script
+if __name__ == '__main__':
+ _test()
diff --git a/lib/jython/Lib/ntpath.py b/lib/jython/Lib/ntpath.py new file mode 100644 index 000000000..989fd0a99 --- /dev/null +++ b/lib/jython/Lib/ntpath.py @@ -0,0 +1,424 @@ +# Module 'ntpath' -- common operations on WinNT/Win95 pathnames
+"""Common pathname manipulations, WindowsNT/95 version.
+
+Instead of importing this module directly, import os and refer to this
+module as os.path.
+"""
+
+import os
+import stat
+
+__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
+ "basename","dirname","commonprefix","getsize","getmtime",
+ "getatime","islink","exists","isdir","isfile","ismount",
+ "walk","expanduser","expandvars","normpath","abspath","splitunc"]
+
+# Normalize the case of a pathname and map slashes to backslashes.
+# Other normalizations (such as optimizing '../' away) are not done
+# (this is done by normpath).
+
+def normcase(s):
+ """Normalize case of pathname.
+
+ Makes all characters lowercase and all slashes into backslashes."""
+ return s.replace("/", "\\").lower()
+
+
+# Return whether a path is absolute.
+# Trivial in Posix, harder on the Mac or MS-DOS.
+# For DOS it is absolute if it starts with a slash or backslash (current
+# volume), or if a pathname after the volume letter and colon / UNC resource
+# starts with a slash or backslash.
+
+def isabs(s):
+ """Test whether a path is absolute"""
+ s = splitdrive(s)[1]
+ return s != '' and s[:1] in '/\\'
+
+
+# Join two (or more) paths.
+
+def join(a, *p):
+ """Join two or more pathname components, inserting "\\" as needed"""
+ path = a
+ for b in p:
+ if isabs(b):
+ path = b
+ elif path == '' or path[-1:] in '/\\:':
+ path = path + b
+ else:
+ path = path + "\\" + b
+ return path
+
+
+# Split a path in a drive specification (a drive letter followed by a
+# colon) and the path specification.
+# It is always true that drivespec + pathspec == p
+def splitdrive(p):
+ """Split a pathname into drive and path specifiers. Returns a 2-tuple
+"(drive,path)"; either part may be empty"""
+ if p[1:2] == ':':
+ return p[0:2], p[2:]
+ return '', p
+
+
+# Parse UNC paths
+def splitunc(p):
+ """Split a pathname into UNC mount point and relative path specifiers.
+
+ Return a 2-tuple (unc, rest); either part may be empty.
+ If unc is not empty, it has the form '//host/mount' (or similar
+ using backslashes). unc+rest is always the input path.
+ Paths containing drive letters never have an UNC part.
+ """
+ if p[1:2] == ':':
+ return '', p # Drive letter present
+ firstTwo = p[0:2]
+ if firstTwo == '//' or firstTwo == '\\\\':
+ # is a UNC path:
+ # vvvvvvvvvvvvvvvvvvvv equivalent to drive letter
+ # \\machine\mountpoint\directories...
+ # directory ^^^^^^^^^^^^^^^
+ normp = normcase(p)
+ index = normp.find('\\', 2)
+ if index == -1:
+ ##raise RuntimeError, 'illegal UNC path: "' + p + '"'
+ return ("", p)
+ index = normp.find('\\', index + 1)
+ if index == -1:
+ index = len(p)
+ return p[:index], p[index:]
+ return '', p
+
+
+# Split a path in head (everything up to the last '/') and tail (the
+# rest). After the trailing '/' is stripped, the invariant
+# join(head, tail) == p holds.
+# The resulting head won't end in '/' unless it is the root.
+
+def split(p):
+ """Split a pathname.
+
+ Return tuple (head, tail) where tail is everything after the final slash.
+ Either part may be empty."""
+
+ d, p = splitdrive(p)
+ # set i to index beyond p's last slash
+ i = len(p)
+ while i and p[i-1] not in '/\\':
+ i = i - 1
+ head, tail = p[:i], p[i:] # now tail has no slashes
+ # remove trailing slashes from head, unless it's all slashes
+ head2 = head
+ while head2 and head2[-1] in '/\\':
+ head2 = head2[:-1]
+ head = head2 or head
+ return d + head, tail
+
+
+# Split a path in root and extension.
+# The extension is everything starting at the last dot in the last
+# pathname component; the root is everything before that.
+# It is always true that root + ext == p.
+
+def splitext(p):
+ """Split the extension from a pathname.
+
+ Extension is everything from the last dot to the end.
+ Return (root, ext), either part may be empty."""
+ root, ext = '', ''
+ for c in p:
+ if c in ['/','\\']:
+ 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
+
+
+# Return the tail (basename) part of a path.
+
+def basename(p):
+ """Returns the final component of a pathname"""
+ return split(p)[1]
+
+
+# Return the head (dirname) part of a path.
+
+def dirname(p):
+ """Returns the directory component of a pathname"""
+ return split(p)[0]
+
+
+# Return the longest prefix of all list elements.
+
+def commonprefix(m):
+ "Given a list of pathnames, returns the longest common leading component"
+ 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
+
+
+# Get size, mtime, atime of files.
+
+def getsize(filename):
+ """Return the size of a file, reported by os.stat()"""
+ st = os.stat(filename)
+ return st[stat.ST_SIZE]
+
+def getmtime(filename):
+ """Return the last modification time of a file, reported by os.stat()"""
+ st = os.stat(filename)
+ return st[stat.ST_MTIME]
+
+def getatime(filename):
+ """Return the last access time of a file, reported by os.stat()"""
+ st = os.stat(filename)
+ return st[stat.ST_ATIME]
+
+
+# Is a path a symbolic link?
+# This will always return false on systems where posix.lstat doesn't exist.
+
+def islink(path):
+ """Test for symbolic link. On WindowsNT/95 always returns false"""
+ return 0
+
+
+# Does a path exist?
+# This is false for dangling symbolic links.
+
+def exists(path):
+ """Test whether a path exists"""
+ try:
+ st = os.stat(path)
+ except os.error:
+ return 0
+ return 1
+
+
+# Is a path a dos directory?
+# This follows symbolic links, so both islink() and isdir() can be true
+# for the same path.
+
+def isdir(path):
+ """Test whether a path is a directory"""
+ try:
+ st = os.stat(path)
+ except os.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 isdir() can be true
+# for the same path.
+
+def isfile(path):
+ """Test whether a path is a regular file"""
+ try:
+ st = os.stat(path)
+ except os.error:
+ return 0
+ return stat.S_ISREG(st[stat.ST_MODE])
+
+
+# Is a path a mount point? Either a root (with or without drive letter)
+# or an UNC path with at most a / or \ after the mount point.
+
+def ismount(path):
+ """Test whether a path is a mount point (defined as root of drive)"""
+ unc, rest = splitunc(path)
+ if unc:
+ return rest in ("", "/", "\\")
+ p = splitdrive(path)[1]
+ return len(p) == 1 and p[0] in '/\\'
+
+
+# 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):
+ """Directory tree walk whth callback function.
+
+ walk(top, func, arg) calls func(arg, d, files) for each directory d
+ in the tree rooted at top (including top itself); files is a list
+ of all the files and subdirs in directory d."""
+ try:
+ names = os.listdir(top)
+ except os.error:
+ return
+ func(arg, top, names)
+ exceptions = ('.', '..')
+ for name in names:
+ if name not in exceptions:
+ name = join(top, name)
+ if isdir(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):
+ """Expand ~ and ~user constructs.
+
+ If user or $HOME is unknown, do nothing."""
+ if path[:1] != '~':
+ return path
+ i, n = 1, len(path)
+ while i < n and path[i] not in '/\\':
+ i = i + 1
+ if i == 1:
+ if os.environ.has_key('HOME'):
+ userhome = os.environ['HOME']
+ elif not os.environ.has_key('HOMEPATH'):
+ return path
+ else:
+ try:
+ drive = os.environ['HOMEDRIVE']
+ except KeyError:
+ drive = ''
+ userhome = join(drive, os.environ['HOMEPATH'])
+ else:
+ return path
+ return userhome + path[i:]
+
+
+# Expand paths containing shell variable substitutions.
+# The following rules apply:
+# - no expansion within single quotes
+# - no escape character, except for '$$' which is translated into '$'
+# - ${varname} is accepted.
+# - varnames can be made out of letters, digits and the character '_'
+# XXX With COMMAND.COM you can use any characters in a variable name,
+# XXX except '^|<>='.
+
+def expandvars(path):
+ """Expand shell variables of form $var and ${var}.
+
+ Unknown variables are left unchanged."""
+ if '$' not in path:
+ return path
+ import string
+ varchars = string.letters + string.digits + '_-'
+ res = ''
+ index = 0
+ pathlen = len(path)
+ while index < pathlen:
+ c = path[index]
+ if c == '\'': # no expansion within single quotes
+ path = path[index + 1:]
+ pathlen = len(path)
+ try:
+ index = path.index('\'')
+ res = res + '\'' + path[:index + 1]
+ except ValueError:
+ res = res + path
+ index = pathlen - 1
+ elif c == '$': # variable or '$$'
+ if path[index + 1:index + 2] == '$':
+ res = res + c
+ index = index + 1
+ elif path[index + 1:index + 2] == '{':
+ path = path[index+2:]
+ pathlen = len(path)
+ try:
+ index = path.index('}')
+ var = path[:index]
+ if os.environ.has_key(var):
+ res = res + os.environ[var]
+ except ValueError:
+ res = res + path
+ index = pathlen - 1
+ else:
+ var = ''
+ index = index + 1
+ c = path[index:index + 1]
+ while c != '' and c in varchars:
+ var = var + c
+ index = index + 1
+ c = path[index:index + 1]
+ if os.environ.has_key(var):
+ res = res + os.environ[var]
+ if c != '':
+ res = res + c
+ else:
+ res = res + c
+ index = index + 1
+ return res
+
+
+# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
+# Previously, this function also truncated pathnames to 8+3 format,
+# but as this module is called "ntpath", that's obviously wrong!
+
+def normpath(path):
+ """Normalize path, eliminating double slashes, etc."""
+ path = path.replace("/", "\\")
+ prefix, path = splitdrive(path)
+ while path[:1] == "\\":
+ prefix = prefix + "\\"
+ path = path[1:]
+ comps = path.split("\\")
+ 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 prefix and not comps:
+ comps.append('.')
+ return prefix + "\\".join(comps)
+
+
+# Return an absolute path.
+def abspath(path):
+ """Return the absolute version of a path"""
+ try:
+ import win32api
+ except ImportError:
+ global abspath
+ def _abspath(path):
+ if not isabs(path):
+ path = join(os.getcwd(), path)
+ return normpath(path)
+ abspath = _abspath
+ return _abspath(path)
+ if path: # Empty path must return current working directory.
+ try:
+ path = win32api.GetFullPathName(path)
+ except win32api.error:
+ pass # Bad path - return unchanged.
+ else:
+ path = os.getcwd()
+ return normpath(path)
diff --git a/lib/jython/Lib/nturl2path.py b/lib/jython/Lib/nturl2path.py new file mode 100644 index 000000000..6de9b8566 --- /dev/null +++ b/lib/jython/Lib/nturl2path.py @@ -0,0 +1,66 @@ +"""Convert a NT pathname to a file URL and vice versa."""
+
+def url2pathname(url):
+ r"""Convert a URL to a DOS path.
+
+ ///C|/foo/bar/spam.foo
+
+ becomes
+
+ C:\foo\bar\spam.foo
+ """
+ import string, urllib
+ if not '|' in url:
+ # No drive specifier, just convert slashes
+ if url[:4] == '////':
+ # path is something like ////host/path/on/remote/host
+ # convert this to \\host\path\on\remote\host
+ # (notice halving of slashes at the start of the path)
+ url = url[2:]
+ components = url.split('/')
+ # make sure not to convert quoted slashes :-)
+ return urllib.unquote('\\'.join(components))
+ comp = url.split('|')
+ if len(comp) != 2 or comp[0][-1] not in string.letters:
+ error = 'Bad URL: ' + url
+ raise IOError, error
+ drive = comp[0][-1].upper()
+ components = comp[1].split('/')
+ path = drive + ':'
+ for comp in components:
+ if comp:
+ path = path + '\\' + urllib.unquote(comp)
+ return path
+
+def pathname2url(p):
+ r"""Convert a DOS path name to a file url.
+
+ C:\foo\bar\spam.foo
+
+ becomes
+
+ ///C|/foo/bar/spam.foo
+ """
+
+ import string, urllib
+ if not ':' in p:
+ # No drive specifier, just convert slashes and quote the name
+ if p[:2] == '\\\\':
+ # path is something like \\host\path\on\remote\host
+ # convert this to ////host/path/on/remote/host
+ # (notice doubling of slashes at the start of the path)
+ p = '\\\\' + p
+ components = p.split('\\')
+ return urllib.quote('/'.join(components))
+ comp = p.split(':')
+ if len(comp) != 2 or len(comp[0]) > 1:
+ error = 'Bad path: ' + p
+ raise IOError, error
+
+ drive = urllib.quote(comp[0].upper())
+ components = comp[1].split('\\')
+ path = '///' + drive + '|'
+ for comp in components:
+ if comp:
+ path = path + '/' + urllib.quote(comp)
+ return path
diff --git a/lib/jython/Lib/pawt/__init__.py b/lib/jython/Lib/pawt/__init__.py new file mode 100644 index 000000000..5f37e6c76 --- /dev/null +++ b/lib/jython/Lib/pawt/__init__.py @@ -0,0 +1,35 @@ +import sys
+from java import awt
+
+def test(panel, size=None, name='AWT Tester'):
+ f = awt.Frame(name, windowClosing=lambda event: sys.exit(0))
+ if hasattr(panel, 'init'):
+ panel.init()
+
+ f.add('Center', panel)
+ f.pack()
+ if size is not None:
+ f.setSize(apply(awt.Dimension, size))
+ f.setVisible(1)
+ return f
+
+class GridBag:
+ def __init__(self, frame, **defaults):
+ self.frame = frame
+ self.gridbag = awt.GridBagLayout()
+ self.defaults = defaults
+ frame.setLayout(self.gridbag)
+
+ def addRow(self, widget, **kw):
+ kw['gridwidth'] = 'REMAINDER'
+ apply(self.add, (widget, ), kw)
+
+ def add(self, widget, **kw):
+ constraints = awt.GridBagConstraints()
+
+ for key, value in self.defaults.items()+kw.items():
+ if isinstance(value, type('')):
+ value = getattr(awt.GridBagConstraints, value)
+ setattr(constraints, key, value)
+ self.gridbag.setConstraints(widget, constraints)
+ self.frame.add(widget)
diff --git a/lib/jython/Lib/pawt/colors.py b/lib/jython/Lib/pawt/colors.py new file mode 100644 index 000000000..36ae53d9f --- /dev/null +++ b/lib/jython/Lib/pawt/colors.py @@ -0,0 +1,144 @@ +from java.awt import Color
+
+aliceblue = Color(240, 248, 255)
+antiquewhite = Color(250, 235, 215)
+aqua = Color(0, 255, 255)
+aquamarine = Color(127, 255, 212)
+azure = Color(240, 255, 255)
+beige = Color(245, 245, 220)
+bisque = Color(255, 228, 196)
+black = Color(0, 0, 0)
+blanchedalmond = Color(255, 235, 205)
+blue = Color(0, 0, 255)
+blueviolet = Color(138, 43, 226)
+brown = Color(165, 42, 42)
+burlywood = Color(222, 184, 135)
+cadetblue = Color(95, 158, 160)
+chartreuse = Color(127, 255, 0)
+chocolate = Color(210, 105, 30)
+coral = Color(255, 127, 80)
+cornflowerblue = Color(100, 149, 237)
+cornsilk = Color(255, 248, 220)
+crimson = Color(220, 20, 60)
+cyan = Color(0, 255, 255)
+darkblue = Color(0, 0, 139)
+darkcyan = Color(0, 139, 139)
+darkgoldenrod = Color(184, 134, 11)
+darkgray = Color(169, 169, 169)
+darkgreen = Color(0, 100, 0)
+darkkhaki = Color(189, 183, 107)
+darkmagenta = Color(139, 0, 139)
+darkolivegreen = Color(85, 107, 47)
+darkorange = Color(255, 140, 0)
+darkorchid = Color(153, 50, 204)
+darkred = Color(139, 0, 0)
+darksalmon = Color(233, 150, 122)
+darkseagreen = Color(143, 188, 143)
+darkslateblue = Color(72, 61, 139)
+darkslategray = Color(47, 79, 79)
+darkturquoise = Color(0, 206, 209)
+darkviolet = Color(148, 0, 211)
+deeppink = Color(255, 20, 147)
+deepskyblue = Color(0, 191, 255)
+dimgray = Color(105, 105, 105)
+dodgerblue = Color(30, 144, 255)
+firebrick = Color(178, 34, 34)
+floralwhite = Color(255, 250, 240)
+forestgreen = Color(34, 139, 34)
+fuchsia = Color(255, 0, 255)
+gainsboro = Color(220, 220, 220)
+ghostwhite = Color(248, 248, 255)
+gold = Color(255, 215, 0)
+goldenrod = Color(218, 165, 32)
+gray = Color(128, 128, 128)
+green = Color(0, 128, 0)
+greenyellow = Color(173, 255, 47)
+honeydew = Color(240, 255, 240)
+hotpink = Color(255, 105, 180)
+indianred = Color(205, 92, 92)
+indigo = Color(75, 0, 130)
+ivory = Color(255, 255, 240)
+khaki = Color(240, 230, 140)
+lavender = Color(230, 230, 250)
+lavenderblush = Color(255, 240, 245)
+lawngreen = Color(124, 252, 0)
+lemonchiffon = Color(255, 250, 205)
+lightblue = Color(173, 216, 230)
+lightcoral = Color(240, 128, 128)
+lightcyan = Color(224, 255, 255)
+lightgoldenrodyellow = Color(250, 250, 210)
+lightgreen = Color(144, 238, 144)
+lightgrey = Color(211, 211, 211)
+lightpink = Color(255, 182, 193)
+lightsalmon = Color(255, 160, 122)
+lightseagreen = Color(32, 178, 170)
+lightskyblue = Color(135, 206, 250)
+lightslategray = Color(119, 136, 153)
+lightsteelblue = Color(176, 196, 222)
+lightyellow = Color(255, 255, 224)
+lime = Color(0, 255, 0)
+limegreen = Color(50, 205, 50)
+linen = Color(250, 240, 230)
+magenta = Color(255, 0, 255)
+maroon = Color(128, 0, 0)
+mediumaquamarine = Color(102, 205, 170)
+mediumblue = Color(0, 0, 205)
+mediumorchid = Color(186, 85, 211)
+mediumpurple = Color(147, 112, 219)
+mediumseagreen = Color(60, 179, 113)
+mediumslateblue = Color(123, 104, 238)
+mediumspringgreen = Color(0, 250, 154)
+mediumturquoise = Color(72, 209, 204)
+mediumvioletred = Color(199, 21, 133)
+midnightblue = Color(25, 25, 112)
+mintcream = Color(245, 255, 250)
+mistyrose = Color(255, 228, 225)
+moccasin = Color(255, 228, 181)
+navajowhite = Color(255, 222, 173)
+navy = Color(0, 0, 128)
+oldlace = Color(253, 245, 230)
+olive = Color(128, 128, 0)
+olivedrab = Color(107, 142, 35)
+orange = Color(255, 165, 0)
+orangered = Color(255, 69, 0)
+orchid = Color(218, 112, 214)
+palegoldenrod = Color(238, 232, 170)
+palegreen = Color(152, 251, 152)
+paleturquoise = Color(175, 238, 238)
+palevioletred = Color(219, 112, 147)
+papayawhip = Color(255, 239, 213)
+peachpuff = Color(255, 218, 185)
+peru = Color(205, 133, 63)
+pink = Color(255, 192, 203)
+plum = Color(221, 160, 221)
+powderblue = Color(176, 224, 230)
+purple = Color(128, 0, 128)
+red = Color(255, 0, 0)
+rosybrown = Color(188, 143, 143)
+royalblue = Color(65, 105, 225)
+saddlebrown = Color(139, 69, 19)
+salmon = Color(250, 128, 114)
+sandybrown = Color(244, 164, 96)
+seagreen = Color(46, 139, 87)
+seashell = Color(255, 245, 238)
+sienna = Color(160, 82, 45)
+silver = Color(192, 192, 192)
+skyblue = Color(135, 206, 235)
+slateblue = Color(106, 90, 205)
+slategray = Color(112, 128, 144)
+snow = Color(255, 250, 250)
+springgreen = Color(0, 255, 127)
+steelblue = Color(70, 130, 180)
+tan = Color(210, 180, 140)
+teal = Color(0, 128, 128)
+thistle = Color(216, 191, 216)
+tomato = Color(255, 99, 71)
+turquoise = Color(64, 224, 208)
+violet = Color(238, 130, 238)
+wheat = Color(245, 222, 179)
+white = Color(255, 255, 255)
+whitesmoke = Color(245, 245, 245)
+yellow = Color(255, 255, 0)
+yellowgreen = Color(154, 205, 50)
+
+del Color
diff --git a/lib/jython/Lib/pawt/swing.py b/lib/jython/Lib/pawt/swing.py new file mode 100644 index 000000000..debe9b975 --- /dev/null +++ b/lib/jython/Lib/pawt/swing.py @@ -0,0 +1,42 @@ +"""
+A hack to make pawt.swing point to the java swing library.
+This allows code which imports pawt.swing to work on both JDK1.1 and 1.2
+"""
+swing = None
+
+try:
+ import javax.swing.Icon
+ from javax import swing
+except (ImportError, AttributeError):
+ try:
+ import java.awt.swing.Icon
+ from java.awt import swing
+ except (ImportError, AttributeError):
+ try:
+ import com.sun.java.swing.Icon
+ from com.sun.java import swing
+ except (ImportError, AttributeError):
+ raise ImportError, 'swing not defined in javax.swing or java.awt.swing or com.sun.java.swing'
+import sys
+def test(panel, size=None, name='Swing Tester'):
+ f = swing.JFrame(name, windowClosing=lambda event: sys.exit(0))
+ if hasattr(panel, 'init'):
+ panel.init()
+
+ f.contentPane.add(panel)
+ f.pack()
+ if size is not None:
+ from java import awt
+ f.setSize(apply(awt.Dimension, size))
+ f.setVisible(1)
+ return f
+
+if swing is not None:
+ import pawt, sys
+ pawt.swing = swing
+ sys.modules['pawt.swing'] = swing
+ swing.__dict__['test'] = test
+
+ #These two lines help out jpythonc to figure out this very strange module
+ swing.__dict__['__file__'] = __file__
+ swing.__dict__['__jpythonc_name__'] = 'pawt.swing'
diff --git a/lib/jython/Lib/pdb.py b/lib/jython/Lib/pdb.py new file mode 100644 index 000000000..b6479d3f8 --- /dev/null +++ b/lib/jython/Lib/pdb.py @@ -0,0 +1,948 @@ +#! /usr/bin/env python
+
+"""A Python debugger."""
+
+# (See pdb.doc for documentation.)
+
+import sys
+import linecache
+import cmd
+import bdb
+from repr import repr as _saferepr
+import os
+import re
+
+__all__ = ["run", "pm", "Pdb", "runeval", "runctx", "runcall", "set_trace",
+ "post_mortem", "help"]
+
+def find_function(funcname, filename):
+ cre = re.compile(r'def\s+%s\s*[(]' % funcname)
+ try:
+ fp = open(filename)
+ except IOError:
+ return None
+ # consumer of this info expects the first line to be 1
+ lineno = 1
+ answer = None
+ while 1:
+ line = fp.readline()
+ if line == '':
+ break
+ if cre.match(line):
+ answer = funcname, filename, lineno
+ break
+ lineno = lineno + 1
+ fp.close()
+ return answer
+
+
+# Interaction prompt line will separate file and call info from code
+# text using value of line_prefix string. A newline and arrow may
+# be to your liking. You can set it once pdb is imported using the
+# command "pdb.line_prefix = '\n% '".
+# line_prefix = ': ' # Use this to get the old situation back
+line_prefix = '\n-> ' # Probably a better default
+
+class Pdb(bdb.Bdb, cmd.Cmd):
+
+ def __init__(self):
+ bdb.Bdb.__init__(self)
+ cmd.Cmd.__init__(self)
+ self.prompt = '(Pdb) '
+ self.aliases = {}
+ # Try to load readline if it exists
+ try:
+ import readline
+ except ImportError:
+ pass
+
+ # Read $HOME/.pdbrc and ./.pdbrc
+ self.rcLines = []
+ if os.environ.has_key('HOME'):
+ envHome = os.environ['HOME']
+ try:
+ rcFile = open(os.path.join(envHome, ".pdbrc"))
+ except IOError:
+ pass
+ else:
+ for line in rcFile.readlines():
+ self.rcLines.append(line)
+ rcFile.close()
+ try:
+ rcFile = open(".pdbrc")
+ except IOError:
+ pass
+ else:
+ for line in rcFile.readlines():
+ self.rcLines.append(line)
+ rcFile.close()
+
+ def reset(self):
+ bdb.Bdb.reset(self)
+ self.forget()
+
+ def forget(self):
+ self.lineno = None
+ self.stack = []
+ self.curindex = 0
+ self.curframe = None
+
+ def setup(self, f, t):
+ self.forget()
+ self.stack, self.curindex = self.get_stack(f, t)
+ self.curframe = self.stack[self.curindex][0]
+ self.execRcLines()
+
+ # Can be executed earlier than 'setup' if desired
+ def execRcLines(self):
+ if self.rcLines:
+ # Make local copy because of recursion
+ rcLines = self.rcLines
+ # executed only once
+ self.rcLines = []
+ for line in rcLines:
+ line = line[:-1]
+ if len (line) > 0 and line[0] != '#':
+ self.onecmd (line)
+
+ # Override Bdb methods (except user_call, for now)
+
+ def user_line(self, frame):
+ """This function is called when we stop or break at this line."""
+ self.interaction(frame, None)
+
+ def user_return(self, frame, return_value):
+ """This function is called when a return trap is set here."""
+ frame.f_locals['__return__'] = return_value
+ print '--Return--'
+ self.interaction(frame, None)
+
+ def user_exception(self, frame, (exc_type, exc_value, exc_traceback)):
+ """This function is called if an exception occurs,
+ but only if we are to stop at or just below this level."""
+ frame.f_locals['__exception__'] = exc_type, exc_value
+ if type(exc_type) == type(''):
+ exc_type_name = exc_type
+ else: exc_type_name = exc_type.__name__
+ print exc_type_name + ':', _saferepr(exc_value)
+ self.interaction(frame, exc_traceback)
+
+ # General interaction function
+
+ def interaction(self, frame, traceback):
+ self.setup(frame, traceback)
+ self.print_stack_entry(self.stack[self.curindex])
+ self.cmdloop()
+ self.forget()
+
+ def default(self, line):
+ if line[:1] == '!': line = line[1:]
+ locals = self.curframe.f_locals
+ globals = self.curframe.f_globals
+ try:
+ code = compile(line + '\n', '<stdin>', 'single')
+ exec code in globals, locals
+ except:
+ t, v = sys.exc_info()[:2]
+ if type(t) == type(''):
+ exc_type_name = t
+ else: exc_type_name = t.__name__
+ print '***', exc_type_name + ':', v
+
+ def precmd(self, line):
+ """Handle alias expansion and ';;' separator."""
+ if not line:
+ return line
+ args = line.split()
+ while self.aliases.has_key(args[0]):
+ line = self.aliases[args[0]]
+ ii = 1
+ for tmpArg in args[1:]:
+ line = line.replace("%" + str(ii),
+ tmpArg)
+ ii = ii + 1
+ line = line.replace("%*", ' '.join(args[1:]))
+ args = line.split()
+ # split into ';;' separated commands
+ # unless it's an alias command
+ if args[0] != 'alias':
+ marker = line.find(';;')
+ if marker >= 0:
+ # queue up everything after marker
+ next = line[marker+2:].lstrip()
+ self.cmdqueue.append(next)
+ line = line[:marker].rstrip()
+ return line
+
+ # Command definitions, called by cmdloop()
+ # The argument is the remaining string on the command line
+ # Return true to exit from the command loop
+
+ do_h = cmd.Cmd.do_help
+
+ def do_EOF(self, arg):
+ return 0 # Don't die on EOF
+
+ def do_break(self, arg, temporary = 0):
+ # break [ ([filename:]lineno | function) [, "condition"] ]
+ if not arg:
+ if self.breaks: # There's at least one
+ print "Num Type Disp Enb Where"
+ for bp in bdb.Breakpoint.bpbynumber:
+ if bp:
+ bp.bpprint()
+ return
+ # parse arguments; comma has lowest precedence
+ # and cannot occur in filename
+ filename = None
+ lineno = None
+ cond = None
+ comma = arg.find(',')
+ if comma > 0:
+ # parse stuff after comma: "condition"
+ cond = arg[comma+1:].lstrip()
+ arg = arg[:comma].rstrip()
+ # parse stuff before comma: [filename:]lineno | function
+ colon = arg.rfind(':')
+ if colon >= 0:
+ filename = arg[:colon].rstrip()
+ f = self.lookupmodule(filename)
+ if not f:
+ print '*** ', `filename`,
+ print 'not found from sys.path'
+ return
+ else:
+ filename = f
+ arg = arg[colon+1:].lstrip()
+ try:
+ lineno = int(arg)
+ except ValueError, msg:
+ print '*** Bad lineno:', arg
+ return
+ else:
+ # no colon; can be lineno or function
+ try:
+ lineno = int(arg)
+ except ValueError:
+ try:
+ func = eval(arg,
+ self.curframe.f_globals,
+ self.curframe.f_locals)
+ except:
+ func = arg
+ try:
+ if hasattr(func, 'im_func'):
+ func = func.im_func
+ code = func.func_code
+ lineno = code.co_firstlineno
+ filename = code.co_filename
+ except:
+ # last thing to try
+ (ok, filename, ln) = self.lineinfo(arg)
+ if not ok:
+ print '*** The specified object',
+ print `arg`,
+ print 'is not a function'
+ print ('or was not found '
+ 'along sys.path.')
+ return
+ lineno = int(ln)
+ if not filename:
+ filename = self.defaultFile()
+ # Check for reasonable breakpoint
+ line = self.checkline(filename, lineno)
+ if line:
+ # now set the break point
+ err = self.set_break(filename, line, temporary, cond)
+ if err: print '***', err
+ else:
+ bp = self.get_breaks(filename, line)[-1]
+ print "Breakpoint %d at %s:%d" % (bp.number,
+ bp.file,
+ bp.line)
+
+ # To be overridden in derived debuggers
+ def defaultFile(self):
+ """Produce a reasonable default."""
+ filename = self.curframe.f_code.co_filename
+ if filename == '<string>' and mainpyfile:
+ filename = mainpyfile
+ return filename
+
+ do_b = do_break
+
+ def do_tbreak(self, arg):
+ self.do_break(arg, 1)
+
+ def lineinfo(self, identifier):
+ failed = (None, None, None)
+ # Input is identifier, may be in single quotes
+ idstring = identifier.split("'")
+ if len(idstring) == 1:
+ # not in single quotes
+ id = idstring[0].strip()
+ elif len(idstring) == 3:
+ # quoted
+ id = idstring[1].strip()
+ else:
+ return failed
+ if id == '': return failed
+ parts = id.split('.')
+ # Protection for derived debuggers
+ if parts[0] == 'self':
+ del parts[0]
+ if len(parts) == 0:
+ return failed
+ # Best first guess at file to look at
+ fname = self.defaultFile()
+ if len(parts) == 1:
+ item = parts[0]
+ else:
+ # More than one part.
+ # First is module, second is method/class
+ f = self.lookupmodule(parts[0])
+ if f:
+ fname = f
+ item = parts[1]
+ answer = find_function(item, fname)
+ return answer or failed
+
+ def checkline(self, filename, lineno):
+ """Return line number of first line at or after input
+ argument such that if the input points to a 'def', the
+ returned line number is the first
+ non-blank/non-comment line to follow. If the input
+ points to a blank or comment line, return 0. At end
+ of file, also return 0."""
+
+ line = linecache.getline(filename, lineno)
+ if not line:
+ print 'End of file'
+ return 0
+ line = line.strip()
+ # Don't allow setting breakpoint at a blank line
+ if ( not line or (line[0] == '#') or
+ (line[:3] == '"""') or line[:3] == "'''" ):
+ print '*** Blank or comment'
+ return 0
+ # When a file is read in and a breakpoint is at
+ # the 'def' statement, the system stops there at
+ # code parse time. We don't want that, so all breakpoints
+ # set at 'def' statements are moved one line onward
+ if line[:3] == 'def':
+ instr = ''
+ brackets = 0
+ while 1:
+ skipone = 0
+ for c in line:
+ if instr:
+ if skipone:
+ skipone = 0
+ elif c == '\\':
+ skipone = 1
+ elif c == instr:
+ instr = ''
+ elif c == '#':
+ break
+ elif c in ('"',"'"):
+ instr = c
+ elif c in ('(','{','['):
+ brackets = brackets + 1
+ elif c in (')','}',']'):
+ brackets = brackets - 1
+ lineno = lineno+1
+ line = linecache.getline(filename, lineno)
+ if not line:
+ print 'end of file'
+ return 0
+ line = line.strip()
+ if not line: continue # Blank line
+ if brackets <= 0 and line[0] not in ('#','"',"'"):
+ break
+ return lineno
+
+ def do_enable(self, arg):
+ args = arg.split()
+ for i in args:
+ bp = bdb.Breakpoint.bpbynumber[int(i)]
+ if bp:
+ bp.enable()
+
+ def do_disable(self, arg):
+ args = arg.split()
+ for i in args:
+ bp = bdb.Breakpoint.bpbynumber[int(i)]
+ if bp:
+ bp.disable()
+
+ def do_condition(self, arg):
+ # arg is breakpoint number and condition
+ args = arg.split(' ', 1)
+ bpnum = int(args[0].strip())
+ try:
+ cond = args[1]
+ except:
+ cond = None
+ bp = bdb.Breakpoint.bpbynumber[bpnum]
+ if bp:
+ bp.cond = cond
+ if not cond:
+ print 'Breakpoint', bpnum,
+ print 'is now unconditional.'
+
+ def do_ignore(self,arg):
+ """arg is bp number followed by ignore count."""
+ args = arg.split()
+ bpnum = int(args[0].strip())
+ try:
+ count = int(args[1].strip())
+ except:
+ count = 0
+ bp = bdb.Breakpoint.bpbynumber[bpnum]
+ if bp:
+ bp.ignore = count
+ if (count > 0):
+ reply = 'Will ignore next '
+ if (count > 1):
+ reply = reply + '%d crossings' % count
+ else:
+ reply = reply + '1 crossing'
+ print reply + ' of breakpoint %d.' % bpnum
+ else:
+ print 'Will stop next time breakpoint',
+ print bpnum, 'is reached.'
+
+ def do_clear(self, arg):
+ """Three possibilities, tried in this order:
+ clear -> clear all breaks, ask for confirmation
+ clear file:lineno -> clear all breaks at file:lineno
+ clear bpno bpno ... -> clear breakpoints by number"""
+ if not arg:
+ try:
+ reply = raw_input('Clear all breaks? ')
+ except EOFError:
+ reply = 'no'
+ reply = reply.strip().lower()
+ if reply in ('y', 'yes'):
+ self.clear_all_breaks()
+ return
+ if ':' in arg:
+ # Make sure it works for "clear C:\foo\bar.py:12"
+ i = arg.rfind(':')
+ filename = arg[:i]
+ arg = arg[i+1:]
+ try:
+ lineno = int(arg)
+ except:
+ err = "Invalid line number (%s)" % arg
+ else:
+ err = self.clear_break(filename, lineno)
+ if err: print '***', err
+ return
+ numberlist = arg.split()
+ for i in numberlist:
+ err = self.clear_bpbynumber(i)
+ if err:
+ print '***', err
+ else:
+ print 'Deleted breakpoint %s ' % (i,)
+ do_cl = do_clear # 'c' is already an abbreviation for 'continue'
+
+ def do_where(self, arg):
+ self.print_stack_trace()
+ do_w = do_where
+ do_bt = do_where
+
+ def do_up(self, arg):
+ if self.curindex == 0:
+ print '*** Oldest frame'
+ else:
+ self.curindex = self.curindex - 1
+ self.curframe = self.stack[self.curindex][0]
+ self.print_stack_entry(self.stack[self.curindex])
+ self.lineno = None
+ do_u = do_up
+
+ def do_down(self, arg):
+ if self.curindex + 1 == len(self.stack):
+ print '*** Newest frame'
+ else:
+ self.curindex = self.curindex + 1
+ self.curframe = self.stack[self.curindex][0]
+ self.print_stack_entry(self.stack[self.curindex])
+ self.lineno = None
+ do_d = do_down
+
+ def do_step(self, arg):
+ self.set_step()
+ return 1
+ do_s = do_step
+
+ def do_next(self, arg):
+ self.set_next(self.curframe)
+ return 1
+ do_n = do_next
+
+ def do_return(self, arg):
+ self.set_return(self.curframe)
+ return 1
+ do_r = do_return
+
+ def do_continue(self, arg):
+ self.set_continue()
+ return 1
+ do_c = do_cont = do_continue
+
+ def do_quit(self, arg):
+ self.set_quit()
+ return 1
+ do_q = do_quit
+
+ def do_args(self, arg):
+ f = self.curframe
+ co = f.f_code
+ dict = f.f_locals
+ n = co.co_argcount
+ if co.co_flags & 4: n = n+1
+ if co.co_flags & 8: n = n+1
+ for i in range(n):
+ name = co.co_varnames[i]
+ print name, '=',
+ if dict.has_key(name): print dict[name]
+ else: print "*** undefined ***"
+ do_a = do_args
+
+ def do_retval(self, arg):
+ if self.curframe.f_locals.has_key('__return__'):
+ print self.curframe.f_locals['__return__']
+ else:
+ print '*** Not yet returned!'
+ do_rv = do_retval
+
+ def do_p(self, arg):
+ try:
+ value = eval(arg, self.curframe.f_globals,
+ self.curframe.f_locals)
+ except:
+ t, v = sys.exc_info()[:2]
+ if type(t) == type(''):
+ exc_type_name = t
+ else: exc_type_name = t.__name__
+ print '***', exc_type_name + ':', `v`
+ return
+
+ print `value`
+
+ def do_list(self, arg):
+ self.lastcmd = 'list'
+ last = None
+ if arg:
+ try:
+ x = eval(arg, {}, {})
+ if type(x) == type(()):
+ first, last = x
+ first = int(first)
+ last = int(last)
+ if last < first:
+ # Assume it's a count
+ last = first + last
+ else:
+ first = max(1, int(x) - 5)
+ except:
+ print '*** Error in argument:', `arg`
+ return
+ elif self.lineno is None:
+ first = max(1, self.curframe.f_lineno - 5)
+ else:
+ first = self.lineno + 1
+ if last is None:
+ last = first + 10
+ filename = self.curframe.f_code.co_filename
+ breaklist = self.get_file_breaks(filename)
+ try:
+ for lineno in range(first, last+1):
+ line = linecache.getline(filename, lineno)
+ if not line:
+ print '[EOF]'
+ break
+ else:
+ s = `lineno`.rjust(3)
+ if len(s) < 4: s = s + ' '
+ if lineno in breaklist: s = s + 'B'
+ else: s = s + ' '
+ if lineno == self.curframe.f_lineno:
+ s = s + '->'
+ print s + '\t' + line,
+ self.lineno = lineno
+ except KeyboardInterrupt:
+ pass
+ do_l = do_list
+
+ def do_whatis(self, arg):
+ try:
+ value = eval(arg, self.curframe.f_globals,
+ self.curframe.f_locals)
+ except:
+ t, v = sys.exc_info()[:2]
+ if type(t) == type(''):
+ exc_type_name = t
+ else: exc_type_name = t.__name__
+ print '***', exc_type_name + ':', `v`
+ return
+ code = None
+ # Is it a function?
+ try: code = value.func_code
+ except: pass
+ if code:
+ print 'Function', code.co_name
+ return
+ # Is it an instance method?
+ try: code = value.im_func.func_code
+ except: pass
+ if code:
+ print 'Method', code.co_name
+ return
+ # None of the above...
+ print type(value)
+
+ def do_alias(self, arg):
+ args = arg.split()
+ if len(args) == 0:
+ keys = self.aliases.keys()
+ keys.sort()
+ for alias in keys:
+ print "%s = %s" % (alias, self.aliases[alias])
+ return
+ if self.aliases.has_key(args[0]) and len (args) == 1:
+ print "%s = %s" % (args[0], self.aliases[args[0]])
+ else:
+ self.aliases[args[0]] = ' '.join(args[1:])
+
+ def do_unalias(self, arg):
+ args = arg.split()
+ if len(args) == 0: return
+ if self.aliases.has_key(args[0]):
+ del self.aliases[args[0]]
+
+ # Print a traceback starting at the top stack frame.
+ # The most recently entered frame is printed last;
+ # this is different from dbx and gdb, but consistent with
+ # the Python interpreter's stack trace.
+ # It is also consistent with the up/down commands (which are
+ # compatible with dbx and gdb: up moves towards 'main()'
+ # and down moves towards the most recent stack frame).
+
+ def print_stack_trace(self):
+ try:
+ for frame_lineno in self.stack:
+ self.print_stack_entry(frame_lineno)
+ except KeyboardInterrupt:
+ pass
+
+ def print_stack_entry(self, frame_lineno, prompt_prefix=line_prefix):
+ frame, lineno = frame_lineno
+ if frame is self.curframe:
+ print '>',
+ else:
+ print ' ',
+ print self.format_stack_entry(frame_lineno, prompt_prefix)
+
+
+ # Help methods (derived from pdb.doc)
+
+ def help_help(self):
+ self.help_h()
+
+ def help_h(self):
+ print """h(elp)
+Without argument, print the list of available commands.
+With a command name as argument, print help about that command
+"help pdb" pipes the full documentation file to the $PAGER
+"help exec" gives help on the ! command"""
+
+ def help_where(self):
+ self.help_w()
+
+ def help_w(self):
+ print """w(here)
+Print a stack trace, with the most recent frame at the bottom.
+An arrow indicates the "current frame", which determines the
+context of most commands. 'bt' is an alias for this command."""
+
+ help_bt = help_w
+
+ def help_down(self):
+ self.help_d()
+
+ def help_d(self):
+ print """d(own)
+Move the current frame one level down in the stack trace
+(to an older frame)."""
+
+ def help_up(self):
+ self.help_u()
+
+ def help_u(self):
+ print """u(p)
+Move the current frame one level up in the stack trace
+(to a newer frame)."""
+
+ def help_break(self):
+ self.help_b()
+
+ def help_b(self):
+ print """b(reak) ([file:]lineno | function) [, condition]
+With a line number argument, set a break there in the current
+file. With a function name, set a break at first executable line
+of that function. Without argument, list all breaks. If a second
+argument is present, it is a string specifying an expression
+which must evaluate to true before the breakpoint is honored.
+
+The line number may be prefixed with a filename and a colon,
+to specify a breakpoint in another file (probably one that
+hasn't been loaded yet). The file is searched for on sys.path;
+the .py suffix may be omitted."""
+
+ def help_clear(self):
+ self.help_cl()
+
+ def help_cl(self):
+ print "cl(ear) filename:lineno"
+ print """cl(ear) [bpnumber [bpnumber...]]
+With a space separated list of breakpoint numbers, clear
+those breakpoints. Without argument, clear all breaks (but
+first ask confirmation). With a filename:lineno argument,
+clear all breaks at that line in that file.
+
+Note that the argument is different from previous versions of
+the debugger (in python distributions 1.5.1 and before) where
+a linenumber was used instead of either filename:lineno or
+breakpoint numbers."""
+
+ def help_tbreak(self):
+ print """tbreak same arguments as break, but breakpoint is
+removed when first hit."""
+
+ def help_enable(self):
+ print """enable bpnumber [bpnumber ...]
+Enables the breakpoints given as a space separated list of
+bp numbers."""
+
+ def help_disable(self):
+ print """disable bpnumber [bpnumber ...]
+Disables the breakpoints given as a space separated list of
+bp numbers."""
+
+ def help_ignore(self):
+ print """ignore bpnumber count
+Sets the ignore count for the given breakpoint number. A breakpoint
+becomes active when the ignore count is zero. When non-zero, the
+count is decremented each time the breakpoint is reached and the
+breakpoint is not disabled and any associated condition evaluates
+to true."""
+
+ def help_condition(self):
+ print """condition bpnumber str_condition
+str_condition is a string specifying an expression which
+must evaluate to true before the breakpoint is honored.
+If str_condition is absent, any existing condition is removed;
+i.e., the breakpoint is made unconditional."""
+
+ def help_step(self):
+ self.help_s()
+
+ def help_s(self):
+ print """s(tep)
+Execute the current line, stop at the first possible occasion
+(either in a function that is called or in the current function)."""
+
+ def help_next(self):
+ self.help_n()
+
+ def help_n(self):
+ print """n(ext)
+Continue execution until the next line in the current function
+is reached or it returns."""
+
+ def help_return(self):
+ self.help_r()
+
+ def help_r(self):
+ print """r(eturn)
+Continue execution until the current function returns."""
+
+ def help_continue(self):
+ self.help_c()
+
+ def help_cont(self):
+ self.help_c()
+
+ def help_c(self):
+ print """c(ont(inue))
+Continue execution, only stop when a breakpoint is encountered."""
+
+ def help_list(self):
+ self.help_l()
+
+ def help_l(self):
+ print """l(ist) [first [,last]]
+List source code for the current file.
+Without arguments, list 11 lines around the current line
+or continue the previous listing.
+With one argument, list 11 lines starting at that line.
+With two arguments, list the given range;
+if the second argument is less than the first, it is a count."""
+
+ def help_args(self):
+ self.help_a()
+
+ def help_a(self):
+ print """a(rgs)
+Print the arguments of the current function."""
+
+ def help_p(self):
+ print """p expression
+Print the value of the expression."""
+
+ def help_exec(self):
+ print """(!) statement
+Execute the (one-line) statement in the context of
+the current stack frame.
+The exclamation point can be omitted unless the first word
+of the statement resembles a debugger command.
+To assign to a global variable you must always prefix the
+command with a 'global' command, e.g.:
+(Pdb) global list_options; list_options = ['-l']
+(Pdb)"""
+
+ def help_quit(self):
+ self.help_q()
+
+ def help_q(self):
+ print """q(uit) Quit from the debugger.
+The program being executed is aborted."""
+
+ def help_whatis(self):
+ print """whatis arg
+Prints the type of the argument."""
+
+ def help_EOF(self):
+ print """EOF
+Handles the receipt of EOF as a command."""
+
+ def help_alias(self):
+ print """alias [name [command [parameter parameter ...] ]]
+Creates an alias called 'name' the executes 'command'. The command
+must *not* be enclosed in quotes. Replaceable parameters are
+indicated by %1, %2, and so on, while %* is replaced by all the
+parameters. If no command is given, the current alias for name
+is shown. If no name is given, all aliases are listed.
+
+Aliases may be nested and can contain anything that can be
+legally typed at the pdb prompt. Note! You *can* override
+internal pdb commands with aliases! Those internal commands
+are then hidden until the alias is removed. Aliasing is recursively
+applied to the first word of the command line; all other words
+in the line are left alone.
+
+Some useful aliases (especially when placed in the .pdbrc file) are:
+
+#Print instance variables (usage "pi classInst")
+alias pi for k in %1.__dict__.keys(): print "%1.",k,"=",%1.__dict__[k]
+
+#Print instance variables in self
+alias ps pi self
+"""
+
+ def help_unalias(self):
+ print """unalias name
+Deletes the specified alias."""
+
+ def help_pdb(self):
+ help()
+
+ def lookupmodule(self, filename):
+ """Helper function for break/clear parsing -- may be overridden."""
+ root, ext = os.path.splitext(filename)
+ if ext == '':
+ filename = filename + '.py'
+ if os.path.isabs(filename):
+ return filename
+ for dirname in sys.path:
+ while os.path.islink(dirname):
+ dirname = os.readlink(dirname)
+ fullname = os.path.join(dirname, filename)
+ if os.path.exists(fullname):
+ return fullname
+ return None
+
+# Simplified interface
+
+def run(statement, globals=None, locals=None):
+ Pdb().run(statement, globals, locals)
+
+def runeval(expression, globals=None, locals=None):
+ return Pdb().runeval(expression, globals, locals)
+
+def runctx(statement, globals, locals):
+ # B/W compatibility
+ run(statement, globals, locals)
+
+def runcall(*args):
+ return apply(Pdb().runcall, args)
+
+def set_trace():
+ Pdb().set_trace()
+
+# Post-Mortem interface
+
+def post_mortem(t):
+ p = Pdb()
+ p.reset()
+ while t.tb_next is not None:
+ t = t.tb_next
+ p.interaction(t.tb_frame, t)
+
+def pm():
+ post_mortem(sys.last_traceback)
+
+
+# Main program for testing
+
+TESTCMD = 'import x; x.main()'
+
+def test():
+ run(TESTCMD)
+
+# print help
+def help():
+ for dirname in sys.path:
+ fullname = os.path.join(dirname, 'pdb.doc')
+ if os.path.exists(fullname):
+ sts = os.system('${PAGER-more} '+fullname)
+ if sts: print '*** Pager exit status:', sts
+ break
+ else:
+ print 'Sorry, can\'t find the help file "pdb.doc"',
+ print 'along the Python search path'
+
+mainmodule = ''
+mainpyfile = ''
+
+# When invoked as main program, invoke the debugger on a script
+if __name__=='__main__':
+ if not sys.argv[1:]:
+ print "usage: pdb.py scriptfile [arg] ..."
+ sys.exit(2)
+
+ mainpyfile = filename = sys.argv[1] # Get script filename
+ if not os.path.exists(filename):
+ print 'Error:', `filename`, 'does not exist'
+ sys.exit(1)
+ mainmodule = os.path.basename(filename)
+ del sys.argv[0] # Hide "pdb.py" from argument list
+
+ # Insert script directory in front of module search path
+ sys.path.insert(0, os.path.dirname(filename))
+
+ run('execfile(' + `filename` + ')')
diff --git a/lib/jython/Lib/pickle.py b/lib/jython/Lib/pickle.py new file mode 100644 index 000000000..beefac9ce --- /dev/null +++ b/lib/jython/Lib/pickle.py @@ -0,0 +1,986 @@ +"""Create portable serialized representations of Python objects.
+
+See module cPickle for a (much) faster implementation.
+See module copy_reg for a mechanism for registering custom picklers.
+
+Classes:
+
+ Pickler
+ Unpickler
+
+Functions:
+
+ dump(object, file)
+ dumps(object) -> string
+ load(file) -> object
+ loads(string) -> object
+
+Misc variables:
+
+ __version__
+ format_version
+ compatible_formats
+
+"""
+
+__version__ = "$Revision: 1.48 $" # Code version
+
+from types import *
+from copy_reg import dispatch_table, safe_constructors
+import marshal
+import sys
+import struct
+import re
+
+__all__ = ["PickleError", "PicklingError", "UnpicklingError", "Pickler",
+ "Unpickler", "dump", "dumps", "load", "loads"]
+
+format_version = "1.3" # File format version we write
+compatible_formats = ["1.0", "1.1", "1.2"] # Old format versions we can read
+
+mdumps = marshal.dumps
+mloads = marshal.loads
+
+class PickleError(Exception): pass
+class PicklingError(PickleError): pass
+class UnpicklingError(PickleError): pass
+
+class _Stop(Exception):
+ def __init__(self, value):
+ self.value = value
+
+try:
+ from org.python.core import PyStringMap
+except ImportError:
+ PyStringMap = None
+
+MARK = '('
+STOP = '.'
+POP = '0'
+POP_MARK = '1'
+DUP = '2'
+FLOAT = 'F'
+INT = 'I'
+BININT = 'J'
+BININT1 = 'K'
+LONG = 'L'
+BININT2 = 'M'
+NONE = 'N'
+PERSID = 'P'
+BINPERSID = 'Q'
+REDUCE = 'R'
+STRING = 'S'
+BINSTRING = 'T'
+SHORT_BINSTRING = 'U'
+UNICODE = 'V'
+BINUNICODE = 'X'
+APPEND = 'a'
+BUILD = 'b'
+GLOBAL = 'c'
+DICT = 'd'
+EMPTY_DICT = '}'
+APPENDS = 'e'
+GET = 'g'
+BINGET = 'h'
+INST = 'i'
+LONG_BINGET = 'j'
+LIST = 'l'
+EMPTY_LIST = ']'
+OBJ = 'o'
+PUT = 'p'
+BINPUT = 'q'
+LONG_BINPUT = 'r'
+SETITEM = 's'
+TUPLE = 't'
+EMPTY_TUPLE = ')'
+SETITEMS = 'u'
+BINFLOAT = 'G'
+
+__all__.extend([x for x in dir() if re.match("[A-Z][A-Z0-9_]+$",x)])
+
+class Pickler:
+
+ def __init__(self, file, bin = 0):
+ self.write = file.write
+ self.memo = {}
+ self.bin = bin
+
+ def dump(self, object):
+ self.save(object)
+ self.write(STOP)
+
+ def put(self, i):
+ if self.bin:
+ s = mdumps(i)[1:]
+ if i < 256:
+ return BINPUT + s[0]
+
+ return LONG_BINPUT + s
+
+ return PUT + `i` + '\n'
+
+ def get(self, i):
+ if self.bin:
+ s = mdumps(i)[1:]
+
+ if i < 256:
+ return BINGET + s[0]
+
+ return LONG_BINGET + s
+
+ return GET + `i` + '\n'
+
+ def save(self, object, pers_save = 0):
+ memo = self.memo
+
+ if not pers_save:
+ pid = self.persistent_id(object)
+ if pid is not None:
+ self.save_pers(pid)
+ return
+
+ d = id(object)
+
+ t = type(object)
+
+ if (t is TupleType) and (len(object) == 0):
+ if self.bin:
+ self.save_empty_tuple(object)
+ else:
+ self.save_tuple(object)
+ return
+
+ if memo.has_key(d):
+ self.write(self.get(memo[d][0]))
+ return
+
+ try:
+ f = self.dispatch[t]
+ except KeyError:
+ pid = self.inst_persistent_id(object)
+ if pid is not None:
+ self.save_pers(pid)
+ return
+
+ try:
+ reduce = dispatch_table[t]
+ except KeyError:
+ try:
+ reduce = object.__reduce__
+ except AttributeError:
+ raise PicklingError, \
+ "can't pickle %s object: %s" % (`t.__name__`,
+ `object`)
+ else:
+ tup = reduce()
+ else:
+ tup = reduce(object)
+
+ if type(tup) is StringType:
+ self.save_global(object, tup)
+ return
+
+ if type(tup) is not TupleType:
+ raise PicklingError, "Value returned by %s must be a " \
+ "tuple" % reduce
+
+ l = len(tup)
+
+ if (l != 2) and (l != 3):
+ raise PicklingError, "tuple returned by %s must contain " \
+ "only two or three elements" % reduce
+
+ callable = tup[0]
+ arg_tup = tup[1]
+
+ if l > 2:
+ state = tup[2]
+ else:
+ state = None
+
+ if type(arg_tup) is not TupleType and arg_tup is not None:
+ raise PicklingError, "Second element of tuple returned " \
+ "by %s must be a tuple" % reduce
+
+ self.save_reduce(callable, arg_tup, state)
+ memo_len = len(memo)
+ self.write(self.put(memo_len))
+ memo[d] = (memo_len, object)
+ return
+
+ f(self, object)
+
+ def persistent_id(self, object):
+ return None
+
+ def inst_persistent_id(self, object):
+ return None
+
+ def save_pers(self, pid):
+ if not self.bin:
+ self.write(PERSID + str(pid) + '\n')
+ else:
+ self.save(pid, 1)
+ self.write(BINPERSID)
+
+ def save_reduce(self, callable, arg_tup, state = None):
+ write = self.write
+ save = self.save
+
+ save(callable)
+ save(arg_tup)
+ write(REDUCE)
+
+ if state is not None:
+ save(state)
+ write(BUILD)
+
+ dispatch = {}
+
+ def save_none(self, object):
+ self.write(NONE)
+ dispatch[NoneType] = save_none
+
+ def save_int(self, object):
+ if self.bin:
+ # If the int is small enough to fit in a signed 4-byte 2's-comp
+ # format, we can store it more efficiently than the general
+ # case.
+ high_bits = object >> 31 # note that Python shift sign-extends
+ if high_bits == 0 or high_bits == -1:
+ # All high bits are copies of bit 2**31, so the value
+ # fits in a 4-byte signed int.
+ i = mdumps(object)[1:]
+ assert len(i) == 4
+ if i[-2:] == '\000\000': # fits in 2-byte unsigned int
+ if i[-3] == '\000': # fits in 1-byte unsigned int
+ self.write(BININT1 + i[0])
+ else:
+ self.write(BININT2 + i[:2])
+ else:
+ self.write(BININT + i)
+ return
+ # Text pickle, or int too big to fit in signed 4-byte format.
+ self.write(INT + `object` + '\n')
+ dispatch[IntType] = save_int
+
+ def save_long(self, object):
+ self.write(LONG + `object` + '\n')
+ dispatch[LongType] = save_long
+
+ def save_float(self, object, pack=struct.pack):
+ if self.bin:
+ self.write(BINFLOAT + pack('>d', object))
+ else:
+ self.write(FLOAT + `object` + '\n')
+ dispatch[FloatType] = save_float
+
+ def save_string(self, object):
+ d = id(object)
+ memo = self.memo
+
+ if self.bin:
+ l = len(object)
+ s = mdumps(l)[1:]
+ if l < 256:
+ self.write(SHORT_BINSTRING + s[0] + object)
+ else:
+ self.write(BINSTRING + s + object)
+ else:
+ self.write(STRING + `object` + '\n')
+
+ memo_len = len(memo)
+ self.write(self.put(memo_len))
+ memo[d] = (memo_len, object)
+ dispatch[StringType] = save_string
+
+ def save_unicode(self, object):
+ d = id(object)
+ memo = self.memo
+
+ if self.bin:
+ encoding = object.encode('utf-8')
+ l = len(encoding)
+ s = mdumps(l)[1:]
+ self.write(BINUNICODE + s + encoding)
+ else:
+ object = object.replace(u"\\", u"\\u005c")
+ object = object.replace(u"\n", u"\\u000a")
+ self.write(UNICODE + object.encode('raw-unicode-escape') + '\n')
+
+ memo_len = len(memo)
+ self.write(self.put(memo_len))
+ memo[d] = (memo_len, object)
+ dispatch[UnicodeType] = save_unicode
+
+ if StringType == UnicodeType:
+ # This is true for Jython
+ def save_string(self, object):
+ d = id(object)
+ memo = self.memo
+ unicode = object.isunicode()
+
+ if self.bin:
+ if unicode:
+ object = object.encode("utf-8")
+ l = len(object)
+ s = mdumps(l)[1:]
+ if l < 256 and not unicode:
+ self.write(SHORT_BINSTRING + s[0] + object)
+ else:
+ if unicode:
+ self.write(BINUNICODE + s + object)
+ else:
+ self.write(BINSTRING + s + object)
+ else:
+ if unicode:
+ object = object.replace(u"\\", u"\\u005c")
+ object = object.replace(u"\n", u"\\u000a")
+ object = object.encode('raw-unicode-escape')
+ self.write(UNICODE + object + '\n')
+ else:
+ self.write(STRING + `object` + '\n')
+
+ memo_len = len(memo)
+ self.write(self.put(memo_len))
+ memo[d] = (memo_len, object)
+ dispatch[StringType] = save_string
+
+ def save_tuple(self, object):
+
+ write = self.write
+ save = self.save
+ memo = self.memo
+
+ d = id(object)
+
+ write(MARK)
+
+ for element in object:
+ save(element)
+
+ if len(object) and memo.has_key(d):
+ if self.bin:
+ write(POP_MARK + self.get(memo[d][0]))
+ return
+
+ write(POP * (len(object) + 1) + self.get(memo[d][0]))
+ return
+
+ memo_len = len(memo)
+ self.write(TUPLE + self.put(memo_len))
+ memo[d] = (memo_len, object)
+ dispatch[TupleType] = save_tuple
+
+ def save_empty_tuple(self, object):
+ self.write(EMPTY_TUPLE)
+
+ def save_list(self, object):
+ d = id(object)
+
+ write = self.write
+ save = self.save
+ memo = self.memo
+
+ if self.bin:
+ write(EMPTY_LIST)
+ else:
+ write(MARK + LIST)
+
+ memo_len = len(memo)
+ write(self.put(memo_len))
+ memo[d] = (memo_len, object)
+
+ using_appends = (self.bin and (len(object) > 1))
+
+ if using_appends:
+ write(MARK)
+
+ for element in object:
+ save(element)
+
+ if not using_appends:
+ write(APPEND)
+
+ if using_appends:
+ write(APPENDS)
+ dispatch[ListType] = save_list
+
+ def save_dict(self, object):
+ d = id(object)
+
+ write = self.write
+ save = self.save
+ memo = self.memo
+
+ if self.bin:
+ write(EMPTY_DICT)
+ else:
+ write(MARK + DICT)
+
+ memo_len = len(memo)
+ self.write(self.put(memo_len))
+ memo[d] = (memo_len, object)
+
+ using_setitems = (self.bin and (len(object) > 1))
+
+ if using_setitems:
+ write(MARK)
+
+ items = object.items()
+ for key, value in items:
+ save(key)
+ save(value)
+
+ if not using_setitems:
+ write(SETITEM)
+
+ if using_setitems:
+ write(SETITEMS)
+
+ dispatch[DictionaryType] = save_dict
+ if not PyStringMap is None:
+ dispatch[PyStringMap] = save_dict
+
+ def save_inst(self, object):
+ d = id(object)
+ cls = object.__class__
+
+ memo = self.memo
+ write = self.write
+ save = self.save
+
+ if hasattr(object, '__getinitargs__'):
+ args = object.__getinitargs__()
+ len(args) # XXX Assert it's a sequence
+ _keep_alive(args, memo)
+ else:
+ args = ()
+
+ write(MARK)
+
+ if self.bin:
+ save(cls)
+
+ for arg in args:
+ save(arg)
+
+ memo_len = len(memo)
+ if self.bin:
+ write(OBJ + self.put(memo_len))
+ else:
+ write(INST + cls.__module__ + '\n' + cls.__name__ + '\n' +
+ self.put(memo_len))
+
+ memo[d] = (memo_len, object)
+
+ try:
+ getstate = object.__getstate__
+ except AttributeError:
+ stuff = object.__dict__
+ else:
+ stuff = getstate()
+ _keep_alive(stuff, memo)
+ save(stuff)
+ write(BUILD)
+ dispatch[InstanceType] = save_inst
+
+ def save_global(self, object, name = None):
+ write = self.write
+ memo = self.memo
+
+ if name is None:
+ name = object.__name__
+
+ try:
+ module = object.__module__
+ except AttributeError:
+ module = whichmodule(object, name)
+
+ memo_len = len(memo)
+ write(GLOBAL + module + '\n' + name + '\n' +
+ self.put(memo_len))
+ memo[id(object)] = (memo_len, object)
+ dispatch[ClassType] = save_global
+ dispatch[FunctionType] = save_global
+ dispatch[BuiltinFunctionType] = save_global
+
+
+def _keep_alive(x, memo):
+ """Keeps a reference to the object x in the memo.
+
+ Because we remember objects by their id, we have
+ to assure that possibly temporary objects are kept
+ alive by referencing them.
+ We store a reference at the id of the memo, which should
+ normally not be used unless someone tries to deepcopy
+ the memo itself...
+ """
+ try:
+ memo[id(memo)].append(x)
+ except KeyError:
+ # aha, this is the first one :-)
+ memo[id(memo)]=[x]
+
+
+classmap = {}
+
+# This is no longer used to find classes, but still for functions
+def whichmodule(cls, clsname):
+ """Figure out the module in which a class occurs.
+
+ Search sys.modules for the module.
+ Cache in classmap.
+ Return a module name.
+ If the class cannot be found, return __main__.
+ """
+ if classmap.has_key(cls):
+ return classmap[cls]
+
+ for name, module in sys.modules.items():
+ if name != '__main__' and \
+ hasattr(module, clsname) and \
+ getattr(module, clsname) is cls:
+ break
+ else:
+ name = '__main__'
+ classmap[cls] = name
+ return name
+
+
+class Unpickler:
+
+ def __init__(self, file):
+ self.readline = file.readline
+ self.read = file.read
+ self.memo = {}
+
+ def load(self):
+ self.mark = ['spam'] # Any new unique object
+ self.stack = []
+ self.append = self.stack.append
+ read = self.read
+ dispatch = self.dispatch
+ try:
+ while 1:
+ key = read(1)
+ dispatch[key](self)
+ except _Stop, stopinst:
+ return stopinst.value
+
+ def marker(self):
+ stack = self.stack
+ mark = self.mark
+ k = len(stack)-1
+ while stack[k] is not mark: k = k-1
+ return k
+
+ dispatch = {}
+
+ def load_eof(self):
+ raise EOFError
+ dispatch[''] = load_eof
+
+ def load_persid(self):
+ pid = self.readline()[:-1]
+ self.append(self.persistent_load(pid))
+ dispatch[PERSID] = load_persid
+
+ def load_binpersid(self):
+ stack = self.stack
+
+ pid = stack[-1]
+ del stack[-1]
+
+ self.append(self.persistent_load(pid))
+ dispatch[BINPERSID] = load_binpersid
+
+ def load_none(self):
+ self.append(None)
+ dispatch[NONE] = load_none
+
+ def load_int(self):
+ self.append(int(self.readline()[:-1]))
+ dispatch[INT] = load_int
+
+ def load_binint(self):
+ self.append(mloads('i' + self.read(4)))
+ dispatch[BININT] = load_binint
+
+ def load_binint1(self):
+ self.append(mloads('i' + self.read(1) + '\000\000\000'))
+ dispatch[BININT1] = load_binint1
+
+ def load_binint2(self):
+ self.append(mloads('i' + self.read(2) + '\000\000'))
+ dispatch[BININT2] = load_binint2
+
+ def load_long(self):
+ self.append(long(self.readline()[:-1], 0))
+ dispatch[LONG] = load_long
+
+ def load_float(self):
+ self.append(float(self.readline()[:-1]))
+ dispatch[FLOAT] = load_float
+
+ def load_binfloat(self, unpack=struct.unpack):
+ self.append(unpack('>d', self.read(8))[0])
+ dispatch[BINFLOAT] = load_binfloat
+
+ def load_string(self):
+ rep = self.readline()[:-1]
+ if not self._is_string_secure(rep):
+ raise ValueError, "insecure string pickle"
+ self.append(eval(rep,
+ {'__builtins__': {}})) # Let's be careful
+ dispatch[STRING] = load_string
+
+ def _is_string_secure(self, s):
+ """Return true if s contains a string that is safe to eval
+
+ The definition of secure string is based on the implementation
+ in cPickle. s is secure as long as it only contains a quoted
+ string and optional trailing whitespace.
+ """
+ q = s[0]
+ if q not in ("'", '"'):
+ return 0
+ # find the closing quote
+ offset = 1
+ i = None
+ while 1:
+ try:
+ i = s.index(q, offset)
+ except ValueError:
+ # if there is an error the first time, there is no
+ # close quote
+ if offset == 1:
+ return 0
+ if s[i-1] != '\\':
+ break
+ # check to see if this one is escaped
+ nslash = 0
+ j = i - 1
+ while j >= offset and s[j] == '\\':
+ j = j - 1
+ nslash = nslash + 1
+ if nslash % 2 == 0:
+ break
+ offset = i + 1
+ for c in s[i+1:]:
+ if ord(c) > 32:
+ return 0
+ return 1
+
+ def load_binstring(self):
+ len = mloads('i' + self.read(4))
+ self.append(self.read(len))
+ dispatch[BINSTRING] = load_binstring
+
+ def load_unicode(self):
+ self.append(unicode(self.readline()[:-1],'raw-unicode-escape'))
+ dispatch[UNICODE] = load_unicode
+
+ def load_binunicode(self):
+ len = mloads('i' + self.read(4))
+ self.append(unicode(self.read(len),'utf-8'))
+ dispatch[BINUNICODE] = load_binunicode
+
+ def load_short_binstring(self):
+ len = mloads('i' + self.read(1) + '\000\000\000')
+ self.append(self.read(len))
+ dispatch[SHORT_BINSTRING] = load_short_binstring
+
+ def load_tuple(self):
+ k = self.marker()
+ self.stack[k:] = [tuple(self.stack[k+1:])]
+ dispatch[TUPLE] = load_tuple
+
+ def load_empty_tuple(self):
+ self.stack.append(())
+ dispatch[EMPTY_TUPLE] = load_empty_tuple
+
+ def load_empty_list(self):
+ self.stack.append([])
+ dispatch[EMPTY_LIST] = load_empty_list
+
+ def load_empty_dictionary(self):
+ self.stack.append({})
+ dispatch[EMPTY_DICT] = load_empty_dictionary
+
+ def load_list(self):
+ k = self.marker()
+ self.stack[k:] = [self.stack[k+1:]]
+ dispatch[LIST] = load_list
+
+ def load_dict(self):
+ k = self.marker()
+ d = {}
+ items = self.stack[k+1:]
+ for i in range(0, len(items), 2):
+ key = items[i]
+ value = items[i+1]
+ d[key] = value
+ self.stack[k:] = [d]
+ dispatch[DICT] = load_dict
+
+ def load_inst(self):
+ k = self.marker()
+ args = tuple(self.stack[k+1:])
+ del self.stack[k:]
+ module = self.readline()[:-1]
+ name = self.readline()[:-1]
+ klass = self.find_class(module, name)
+ instantiated = 0
+ if (not args and type(klass) is ClassType and
+ not hasattr(klass, "__getinitargs__")):
+ try:
+ value = _EmptyClass()
+ value.__class__ = klass
+ instantiated = 1
+ except RuntimeError:
+ # In restricted execution, assignment to inst.__class__ is
+ # prohibited
+ pass
+ if not instantiated:
+ try:
+ value = apply(klass, args)
+ except TypeError, err:
+ raise TypeError, "in constructor for %s: %s" % (
+ klass.__name__, str(err)), sys.exc_info()[2]
+ self.append(value)
+ dispatch[INST] = load_inst
+
+ def load_obj(self):
+ stack = self.stack
+ k = self.marker()
+ klass = stack[k + 1]
+ del stack[k + 1]
+ args = tuple(stack[k + 1:])
+ del stack[k:]
+ instantiated = 0
+ if (not args and type(klass) is ClassType and
+ not hasattr(klass, "__getinitargs__")):
+ try:
+ value = _EmptyClass()
+ value.__class__ = klass
+ instantiated = 1
+ except RuntimeError:
+ # In restricted execution, assignment to inst.__class__ is
+ # prohibited
+ pass
+ if not instantiated:
+ value = apply(klass, args)
+ self.append(value)
+ dispatch[OBJ] = load_obj
+
+ def load_global(self):
+ module = self.readline()[:-1]
+ name = self.readline()[:-1]
+ klass = self.find_class(module, name)
+ self.append(klass)
+ dispatch[GLOBAL] = load_global
+
+ def find_class(self, module, name):
+ try:
+ __import__(module)
+ mod = sys.modules[module]
+ klass = getattr(mod, name)
+ except (ImportError, KeyError, AttributeError):
+ raise SystemError, \
+ "Failed to import class %s from module %s" % \
+ (name, module)
+ return klass
+
+ def load_reduce(self):
+ stack = self.stack
+
+ callable = stack[-2]
+ arg_tup = stack[-1]
+ del stack[-2:]
+
+ if type(callable) is not ClassType:
+ if not safe_constructors.has_key(callable):
+ try:
+ safe = callable.__safe_for_unpickling__
+ except AttributeError:
+ safe = None
+
+ if not safe:
+ raise UnpicklingError, "%s is not safe for " \
+ "unpickling" % callable
+
+ if arg_tup is None:
+ value = callable.__basicnew__()
+ else:
+ value = apply(callable, arg_tup)
+ self.append(value)
+ dispatch[REDUCE] = load_reduce
+
+ def load_pop(self):
+ del self.stack[-1]
+ dispatch[POP] = load_pop
+
+ def load_pop_mark(self):
+ k = self.marker()
+ del self.stack[k:]
+ dispatch[POP_MARK] = load_pop_mark
+
+ def load_dup(self):
+ self.append(self.stack[-1])
+ dispatch[DUP] = load_dup
+
+ def load_get(self):
+ self.append(self.memo[self.readline()[:-1]])
+ dispatch[GET] = load_get
+
+ def load_binget(self):
+ i = mloads('i' + self.read(1) + '\000\000\000')
+ self.append(self.memo[`i`])
+ dispatch[BINGET] = load_binget
+
+ def load_long_binget(self):
+ i = mloads('i' + self.read(4))
+ self.append(self.memo[`i`])
+ dispatch[LONG_BINGET] = load_long_binget
+
+ def load_put(self):
+ self.memo[self.readline()[:-1]] = self.stack[-1]
+ dispatch[PUT] = load_put
+
+ def load_binput(self):
+ i = mloads('i' + self.read(1) + '\000\000\000')
+ self.memo[`i`] = self.stack[-1]
+ dispatch[BINPUT] = load_binput
+
+ def load_long_binput(self):
+ i = mloads('i' + self.read(4))
+ self.memo[`i`] = self.stack[-1]
+ dispatch[LONG_BINPUT] = load_long_binput
+
+ def load_append(self):
+ stack = self.stack
+ value = stack[-1]
+ del stack[-1]
+ list = stack[-1]
+ list.append(value)
+ dispatch[APPEND] = load_append
+
+ def load_appends(self):
+ stack = self.stack
+ mark = self.marker()
+ list = stack[mark - 1]
+ for i in range(mark + 1, len(stack)):
+ list.append(stack[i])
+
+ del stack[mark:]
+ dispatch[APPENDS] = load_appends
+
+ def load_setitem(self):
+ stack = self.stack
+ value = stack[-1]
+ key = stack[-2]
+ del stack[-2:]
+ dict = stack[-1]
+ dict[key] = value
+ dispatch[SETITEM] = load_setitem
+
+ def load_setitems(self):
+ stack = self.stack
+ mark = self.marker()
+ dict = stack[mark - 1]
+ for i in range(mark + 1, len(stack), 2):
+ dict[stack[i]] = stack[i + 1]
+
+ del stack[mark:]
+ dispatch[SETITEMS] = load_setitems
+
+ def load_build(self):
+ stack = self.stack
+ value = stack[-1]
+ del stack[-1]
+ inst = stack[-1]
+ try:
+ setstate = inst.__setstate__
+ except AttributeError:
+ try:
+ inst.__dict__.update(value)
+ except RuntimeError:
+ # XXX In restricted execution, the instance's __dict__ is not
+ # accessible. Use the old way of unpickling the instance
+ # variables. This is a semantic different when unpickling in
+ # restricted vs. unrestricted modes.
+ for k, v in value.items():
+ setattr(inst, k, v)
+ else:
+ setstate(value)
+ dispatch[BUILD] = load_build
+
+ def load_mark(self):
+ self.append(self.mark)
+ dispatch[MARK] = load_mark
+
+ def load_stop(self):
+ value = self.stack[-1]
+ del self.stack[-1]
+ raise _Stop(value)
+ dispatch[STOP] = load_stop
+
+# Helper class for load_inst/load_obj
+
+class _EmptyClass:
+ pass
+
+# Shorthands
+
+from StringIO import StringIO
+
+def dump(object, file, bin = 0):
+ Pickler(file, bin).dump(object)
+
+def dumps(object, bin = 0):
+ file = StringIO()
+ Pickler(file, bin).dump(object)
+ return file.getvalue()
+
+def load(file):
+ return Unpickler(file).load()
+
+def loads(str):
+ file = StringIO(str)
+ return Unpickler(file).load()
+
+
+# The rest is used for testing only
+
+class C:
+ def __cmp__(self, other):
+ return cmp(self.__dict__, other.__dict__)
+
+def test():
+ fn = 'out'
+ c = C()
+ c.foo = 1
+ c.bar = 2
+ x = [0, 1, 2, 3]
+ y = ('abc', 'abc', c, c)
+ x.append(y)
+ x.append(y)
+ x.append(5)
+ f = open(fn, 'w')
+ F = Pickler(f)
+ F.dump(x)
+ f.close()
+ f = open(fn, 'r')
+ U = Unpickler(f)
+ x2 = U.load()
+ print x
+ print x2
+ print x == x2
+ print map(id, x)
+ print map(id, x2)
+ print F.memo
+ print U.memo
+
+if __name__ == '__main__':
+ test()
diff --git a/lib/jython/Lib/pipes.py b/lib/jython/Lib/pipes.py new file mode 100644 index 000000000..5a7e13ae5 --- /dev/null +++ b/lib/jython/Lib/pipes.py @@ -0,0 +1,298 @@ +"""Conversion pipeline templates.
+
+The problem:
+------------
+
+Suppose you have some data that you want to convert to another format
+(e.g. from GIF image format to PPM image format). Maybe the
+conversion involves several steps (e.g. piping it through compress or
+uuencode). Some of the conversion steps may require that their input
+is a disk file, others may be able to read standard input; similar for
+their output. The input to the entire conversion may also be read
+from a disk file or from an open file, and similar for its output.
+
+The module lets you construct a pipeline template by sticking one or
+more conversion steps together. It will take care of creating and
+removing temporary files if they are necessary to hold intermediate
+data. You can then use the template to do conversions from many
+different sources to many different destinations. The temporary
+file names used are different each time the template is used.
+
+The templates are objects so you can create templates for many
+different conversion steps and store them in a dictionary, for
+instance.
+
+
+Directions:
+-----------
+
+To create a template:
+ t = Template()
+
+To add a conversion step to a template:
+ t.append(command, kind)
+where kind is a string of two characters: the first is '-' if the
+command reads its standard input or 'f' if it requires a file; the
+second likewise for the output. The command must be valid /bin/sh
+syntax. If input or output files are required, they are passed as
+$IN and $OUT; otherwise, it must be possible to use the command in
+a pipeline.
+
+To add a conversion step at the beginning:
+ t.prepend(command, kind)
+
+To convert a file to another file using a template:
+ sts = t.copy(infile, outfile)
+If infile or outfile are the empty string, standard input is read or
+standard output is written, respectively. The return value is the
+exit status of the conversion pipeline.
+
+To open a file for reading or writing through a conversion pipeline:
+ fp = t.open(file, mode)
+where mode is 'r' to read the file, or 'w' to write it -- just like
+for the built-in function open() or for os.popen().
+
+To create a new template object initialized to a given one:
+ t2 = t.clone()
+
+For an example, see the function test() at the end of the file.
+""" # '
+
+
+import sys
+import re
+
+import os
+import tempfile
+import string
+
+__all__ = ["Template"]
+
+# Conversion step kinds
+
+FILEIN_FILEOUT = 'ff' # Must read & write real files
+STDIN_FILEOUT = '-f' # Must write a real file
+FILEIN_STDOUT = 'f-' # Must read a real file
+STDIN_STDOUT = '--' # Normal pipeline element
+SOURCE = '.-' # Must be first, writes stdout
+SINK = '-.' # Must be last, reads stdin
+
+stepkinds = [FILEIN_FILEOUT, STDIN_FILEOUT, FILEIN_STDOUT, STDIN_STDOUT, \
+ SOURCE, SINK]
+
+
+class Template:
+ """Class representing a pipeline template."""
+
+ def __init__(self):
+ """Template() returns a fresh pipeline template."""
+ self.debugging = 0
+ self.reset()
+
+ def __repr__(self):
+ """t.__repr__() implements `t`."""
+ return '<Template instance, steps=' + `self.steps` + '>'
+
+ def reset(self):
+ """t.reset() restores a pipeline template to its initial state."""
+ self.steps = []
+
+ def clone(self):
+ """t.clone() returns a new pipeline template with identical
+ initial state as the current one."""
+ t = Template()
+ t.steps = self.steps[:]
+ t.debugging = self.debugging
+ return t
+
+ def debug(self, flag):
+ """t.debug(flag) turns debugging on or off."""
+ self.debugging = flag
+
+ def append(self, cmd, kind):
+ """t.append(cmd, kind) adds a new step at the end."""
+ if type(cmd) is not type(''):
+ raise TypeError, \
+ 'Template.append: cmd must be a string'
+ if kind not in stepkinds:
+ raise ValueError, \
+ 'Template.append: bad kind ' + `kind`
+ if kind == SOURCE:
+ raise ValueError, \
+ 'Template.append: SOURCE can only be prepended'
+ if self.steps and self.steps[-1][1] == SINK:
+ raise ValueError, \
+ 'Template.append: already ends with SINK'
+ if kind[0] == 'f' and not re.search(r'\$IN\b', cmd):
+ raise ValueError, \
+ 'Template.append: missing $IN in cmd'
+ if kind[1] == 'f' and not re.search(r'\$OUT\b', cmd):
+ raise ValueError, \
+ 'Template.append: missing $OUT in cmd'
+ self.steps.append((cmd, kind))
+
+ def prepend(self, cmd, kind):
+ """t.prepend(cmd, kind) adds a new step at the front."""
+ if type(cmd) is not type(''):
+ raise TypeError, \
+ 'Template.prepend: cmd must be a string'
+ if kind not in stepkinds:
+ raise ValueError, \
+ 'Template.prepend: bad kind ' + `kind`
+ if kind == SINK:
+ raise ValueError, \
+ 'Template.prepend: SINK can only be appended'
+ if self.steps and self.steps[0][1] == SOURCE:
+ raise ValueError, \
+ 'Template.prepend: already begins with SOURCE'
+ if kind[0] == 'f' and not re.search(r'\$IN\b', cmd):
+ raise ValueError, \
+ 'Template.prepend: missing $IN in cmd'
+ if kind[1] == 'f' and not re.search(r'\$OUT\b', cmd):
+ raise ValueError, \
+ 'Template.prepend: missing $OUT in cmd'
+ self.steps.insert(0, (cmd, kind))
+
+ def open(self, file, rw):
+ """t.open(file, rw) returns a pipe or file object open for
+ reading or writing; the file is the other end of the pipeline."""
+ if rw == 'r':
+ return self.open_r(file)
+ if rw == 'w':
+ return self.open_w(file)
+ raise ValueError, \
+ 'Template.open: rw must be \'r\' or \'w\', not ' + `rw`
+
+ def open_r(self, file):
+ """t.open_r(file) and t.open_w(file) implement
+ t.open(file, 'r') and t.open(file, 'w') respectively."""
+ if not self.steps:
+ return open(file, 'r')
+ if self.steps[-1][1] == SINK:
+ raise ValueError, \
+ 'Template.open_r: pipeline ends width SINK'
+ cmd = self.makepipeline(file, '')
+ return os.popen(cmd, 'r')
+
+ def open_w(self, file):
+ if not self.steps:
+ return open(file, 'w')
+ if self.steps[0][1] == SOURCE:
+ raise ValueError, \
+ 'Template.open_w: pipeline begins with SOURCE'
+ cmd = self.makepipeline('', file)
+ return os.popen(cmd, 'w')
+
+ def copy(self, infile, outfile):
+ return os.system(self.makepipeline(infile, outfile))
+
+ def makepipeline(self, infile, outfile):
+ cmd = makepipeline(infile, self.steps, outfile)
+ if self.debugging:
+ print cmd
+ cmd = 'set -x; ' + cmd
+ return cmd
+
+
+def makepipeline(infile, steps, outfile):
+ # Build a list with for each command:
+ # [input filename or '', command string, kind, output filename or '']
+
+ list = []
+ for cmd, kind in steps:
+ list.append(['', cmd, kind, ''])
+ #
+ # Make sure there is at least one step
+ #
+ if not list:
+ list.append(['', 'cat', '--', ''])
+ #
+ # Take care of the input and output ends
+ #
+ [cmd, kind] = list[0][1:3]
+ if kind[0] == 'f' and not infile:
+ list.insert(0, ['', 'cat', '--', ''])
+ list[0][0] = infile
+ #
+ [cmd, kind] = list[-1][1:3]
+ if kind[1] == 'f' and not outfile:
+ list.append(['', 'cat', '--', ''])
+ list[-1][-1] = outfile
+ #
+ # Invent temporary files to connect stages that need files
+ #
+ garbage = []
+ for i in range(1, len(list)):
+ lkind = list[i-1][2]
+ rkind = list[i][2]
+ if lkind[1] == 'f' or rkind[0] == 'f':
+ temp = tempfile.mktemp()
+ garbage.append(temp)
+ list[i-1][-1] = list[i][0] = temp
+ #
+ for item in list:
+ [inf, cmd, kind, outf] = item
+ if kind[1] == 'f':
+ cmd = 'OUT=' + quote(outf) + '; ' + cmd
+ if kind[0] == 'f':
+ cmd = 'IN=' + quote(inf) + '; ' + cmd
+ if kind[0] == '-' and inf:
+ cmd = cmd + ' <' + quote(inf)
+ if kind[1] == '-' and outf:
+ cmd = cmd + ' >' + quote(outf)
+ item[1] = cmd
+ #
+ cmdlist = list[0][1]
+ for item in list[1:]:
+ [cmd, kind] = item[1:3]
+ if item[0] == '':
+ if 'f' in kind:
+ cmd = '{ ' + cmd + '; }'
+ cmdlist = cmdlist + ' |\n' + cmd
+ else:
+ cmdlist = cmdlist + '\n' + cmd
+ #
+ if garbage:
+ rmcmd = 'rm -f'
+ for file in garbage:
+ rmcmd = rmcmd + ' ' + quote(file)
+ trapcmd = 'trap ' + quote(rmcmd + '; exit') + ' 1 2 3 13 14 15'
+ cmdlist = trapcmd + '\n' + cmdlist + '\n' + rmcmd
+ #
+ return cmdlist
+
+
+# Reliably quote a string as a single argument for /bin/sh
+
+_safechars = string.letters + string.digits + '!@%_-+=:,./' # Safe unquoted
+_funnychars = '"`$\\' # Unsafe inside "double quotes"
+
+def quote(file):
+ for c in file:
+ if c not in _safechars:
+ break
+ else:
+ return file
+ if '\'' not in file:
+ return '\'' + file + '\''
+ res = ''
+ for c in file:
+ if c in _funnychars:
+ c = '\\' + c
+ res = res + c
+ return '"' + res + '"'
+
+
+# Small test program and example
+
+def test():
+ print 'Testing...'
+ t = Template()
+ t.append('togif $IN $OUT', 'ff')
+ t.append('giftoppm', '--')
+ t.append('ppmtogif >$OUT', '-f')
+ t.append('fromgif $IN $OUT', 'ff')
+ t.debug(1)
+ FILE = '/usr/local/images/rgb/rogues/guido.rgb'
+ t.copy(FILE, '@temp')
+ print 'Done.'
diff --git a/lib/jython/Lib/popen2.py b/lib/jython/Lib/popen2.py new file mode 100644 index 000000000..06199c47f --- /dev/null +++ b/lib/jython/Lib/popen2.py @@ -0,0 +1,198 @@ +"""Spawn a command with pipes to its stdin, stdout, and optionally stderr.
+
+The normal os.popen(cmd, mode) call spawns a shell command and provides a
+file interface to just the input or output of the process depending on
+whether mode is 'r' or 'w'. This module provides the functions popen2(cmd)
+and popen3(cmd) which return two or three pipes to the spawned command.
+"""
+
+import os
+import sys
+
+__all__ = ["popen2", "popen3", "popen4"]
+
+MAXFD = 256 # Max number of file descriptors (os.getdtablesize()???)
+
+_active = []
+
+def _cleanup():
+ for inst in _active[:]:
+ inst.poll()
+
+class Popen3:
+ """Class representing a child process. Normally instances are created
+ by the factory functions popen2() and popen3()."""
+
+ sts = -1 # Child not completed yet
+
+ def __init__(self, cmd, capturestderr=0, bufsize=-1):
+ """The parameter 'cmd' is the shell command to execute in a
+ sub-process. The 'capturestderr' flag, if true, specifies that
+ the object should capture standard error output of the child process.
+ The default is false. If the 'bufsize' parameter is specified, it
+ specifies the size of the I/O buffers to/from the child process."""
+ _cleanup()
+ p2cread, p2cwrite = os.pipe()
+ c2pread, c2pwrite = os.pipe()
+ if capturestderr:
+ errout, errin = os.pipe()
+ self.pid = os.fork()
+ if self.pid == 0:
+ # Child
+ os.dup2(p2cread, 0)
+ os.dup2(c2pwrite, 1)
+ if capturestderr:
+ os.dup2(errin, 2)
+ self._run_child(cmd)
+ os.close(p2cread)
+ self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
+ os.close(c2pwrite)
+ self.fromchild = os.fdopen(c2pread, 'r', bufsize)
+ if capturestderr:
+ os.close(errin)
+ self.childerr = os.fdopen(errout, 'r', bufsize)
+ else:
+ self.childerr = None
+ _active.append(self)
+
+ def _run_child(self, cmd):
+ if type(cmd) == type(''):
+ cmd = ['/bin/sh', '-c', cmd]
+ for i in range(3, MAXFD):
+ try:
+ os.close(i)
+ except:
+ pass
+ try:
+ os.execvp(cmd[0], cmd)
+ finally:
+ os._exit(1)
+
+ def poll(self):
+ """Return the exit status of the child process if it has finished,
+ or -1 if it hasn't finished yet."""
+ if self.sts < 0:
+ try:
+ pid, sts = os.waitpid(self.pid, os.WNOHANG)
+ if pid == self.pid:
+ self.sts = sts
+ _active.remove(self)
+ except os.error:
+ pass
+ return self.sts
+
+ def wait(self):
+ """Wait for and return the exit status of the child process."""
+ pid, sts = os.waitpid(self.pid, 0)
+ if pid == self.pid:
+ self.sts = sts
+ _active.remove(self)
+ return self.sts
+
+
+class Popen4(Popen3):
+ childerr = None
+
+ def __init__(self, cmd, bufsize=-1):
+ _cleanup()
+ p2cread, p2cwrite = os.pipe()
+ c2pread, c2pwrite = os.pipe()
+ self.pid = os.fork()
+ if self.pid == 0:
+ # Child
+ os.dup2(p2cread, 0)
+ os.dup2(c2pwrite, 1)
+ os.dup2(c2pwrite, 2)
+ self._run_child(cmd)
+ os.close(p2cread)
+ self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
+ os.close(c2pwrite)
+ self.fromchild = os.fdopen(c2pread, 'r', bufsize)
+ _active.append(self)
+
+
+if sys.platform[:3] == "win":
+ # Some things don't make sense on non-Unix platforms.
+ del Popen3, Popen4
+
+ def popen2(cmd, bufsize=-1, mode='t'):
+ """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
+ specified, it sets the buffer size for the I/O pipes. The file objects
+ (child_stdout, child_stdin) are returned."""
+ w, r = os.popen2(cmd, mode, bufsize)
+ return r, w
+
+ def popen3(cmd, bufsize=-1, mode='t'):
+ """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
+ specified, it sets the buffer size for the I/O pipes. The file objects
+ (child_stdout, child_stdin, child_stderr) are returned."""
+ w, r, e = os.popen3(cmd, mode, bufsize)
+ return r, w, e
+
+ def popen4(cmd, bufsize=-1, mode='t'):
+ """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
+ specified, it sets the buffer size for the I/O pipes. The file objects
+ (child_stdout_stderr, child_stdin) are returned."""
+ w, r = os.popen4(cmd, mode, bufsize)
+ return r, w
+else:
+ def popen2(cmd, bufsize=-1, mode='t'):
+ """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
+ specified, it sets the buffer size for the I/O pipes. The file objects
+ (child_stdout, child_stdin) are returned."""
+ inst = Popen3(cmd, 0, bufsize)
+ return inst.fromchild, inst.tochild
+
+ def popen3(cmd, bufsize=-1, mode='t'):
+ """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
+ specified, it sets the buffer size for the I/O pipes. The file objects
+ (child_stdout, child_stdin, child_stderr) are returned."""
+ inst = Popen3(cmd, 1, bufsize)
+ return inst.fromchild, inst.tochild, inst.childerr
+
+ def popen4(cmd, bufsize=-1, mode='t'):
+ """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
+ specified, it sets the buffer size for the I/O pipes. The file objects
+ (child_stdout_stderr, child_stdin) are returned."""
+ inst = Popen4(cmd, bufsize)
+ return inst.fromchild, inst.tochild
+
+ __all__.extend(["Popen3", "Popen4"])
+
+def _test():
+ cmd = "cat"
+ teststr = "ab cd\n"
+ if os.name == "nt":
+ cmd = "more"
+ # "more" doesn't act the same way across Windows flavors,
+ # sometimes adding an extra newline at the start or the
+ # end. So we strip whitespace off both ends for comparison.
+ expected = teststr.strip()
+ print "testing popen2..."
+ r, w = popen2(cmd)
+ w.write(teststr)
+ w.close()
+ got = r.read()
+ if got.strip() != expected:
+ raise ValueError("wrote %s read %s" % (`teststr`, `got`))
+ print "testing popen3..."
+ try:
+ r, w, e = popen3([cmd])
+ except:
+ r, w, e = popen3(cmd)
+ w.write(teststr)
+ w.close()
+ got = r.read()
+ if got.strip() != expected:
+ raise ValueError("wrote %s read %s" % (`teststr`, `got`))
+ got = e.read()
+ if got:
+ raise ValueError("unexected %s on stderr" % `got`)
+ for inst in _active[:]:
+ inst.wait()
+ if _active:
+ raise ValueError("_active not empty")
+ print "All OK"
+
+if __name__ == '__main__':
+ _test()
diff --git a/lib/jython/Lib/poplib.py b/lib/jython/Lib/poplib.py new file mode 100644 index 000000000..b5f86cde2 --- /dev/null +++ b/lib/jython/Lib/poplib.py @@ -0,0 +1,322 @@ +"""A POP3 client class.
+
+Based on the J. Myers POP3 draft, Jan. 96
+"""
+
+# Author: David Ascher <david_ascher@brown.edu>
+# [heavily stealing from nntplib.py]
+# Updated: Piers Lauder <piers@cs.su.oz.au> [Jul '97]
+# String method conversion and test jig improvements by ESR, February 2001.
+
+# Example (see the test function at the end of this file)
+
+# Imports
+
+import re, socket
+
+__all__ = ["POP3","error_proto"]
+
+# Exception raised when an error or invalid response is received:
+
+class error_proto(Exception): pass
+
+# Standard Port
+POP3_PORT = 110
+
+# Line terminators (we always output CRLF, but accept any of CRLF, LFCR, LF)
+CR = '\r'
+LF = '\n'
+CRLF = CR+LF
+
+
+class POP3:
+
+ """This class supports both the minimal and optional command sets.
+ Arguments can be strings or integers (where appropriate)
+ (e.g.: retr(1) and retr('1') both work equally well.
+
+ Minimal Command Set:
+ USER name user(name)
+ PASS string pass_(string)
+ STAT stat()
+ LIST [msg] list(msg = None)
+ RETR msg retr(msg)
+ DELE msg dele(msg)
+ NOOP noop()
+ RSET rset()
+ QUIT quit()
+
+ Optional Commands (some servers support these):
+ RPOP name rpop(name)
+ APOP name digest apop(name, digest)
+ TOP msg n top(msg, n)
+ UIDL [msg] uidl(msg = None)
+
+ Raises one exception: 'error_proto'.
+
+ Instantiate with:
+ POP3(hostname, port=110)
+
+ NB: the POP protocol locks the mailbox from user
+ authorization until QUIT, so be sure to get in, suck
+ the messages, and quit, each time you access the
+ mailbox.
+
+ POP is a line-based protocol, which means large mail
+ messages consume lots of python cycles reading them
+ line-by-line.
+
+ If it's available on your mail server, use IMAP4
+ instead, it doesn't suffer from the two problems
+ above.
+ """
+
+
+ def __init__(self, host, port = POP3_PORT):
+ self.host = host
+ self.port = port
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.sock.connect((self.host, self.port))
+ self.file = self.sock.makefile('rb')
+ self._debugging = 0
+ self.welcome = self._getresp()
+
+
+ def _putline(self, line):
+ #if self._debugging > 1: print '*put*', `line`
+ self.sock.send('%s%s' % (line, CRLF))
+
+
+ # Internal: send one command to the server (through _putline())
+
+ def _putcmd(self, line):
+ #if self._debugging: print '*cmd*', `line`
+ self._putline(line)
+
+
+ # Internal: return one line from the server, stripping CRLF.
+ # This is where all the CPU time of this module is consumed.
+ # Raise error_proto('-ERR EOF') if the connection is closed.
+
+ def _getline(self):
+ line = self.file.readline()
+ #if self._debugging > 1: print '*get*', `line`
+ if not line: raise error_proto('-ERR EOF')
+ octets = len(line)
+ # server can send any combination of CR & LF
+ # however, 'readline()' returns lines ending in LF
+ # so only possibilities are ...LF, ...CRLF, CR...LF
+ if line[-2:] == CRLF:
+ return line[:-2], octets
+ if line[0] == CR:
+ return line[1:-1], octets
+ return line[:-1], octets
+
+
+ # Internal: get a response from the server.
+ # Raise 'error_proto' if the response doesn't start with '+'.
+
+ def _getresp(self):
+ resp, o = self._getline()
+ #if self._debugging > 1: print '*resp*', `resp`
+ c = resp[:1]
+ if c != '+':
+ raise error_proto(resp)
+ return resp
+
+
+ # Internal: get a response plus following text from the server.
+
+ def _getlongresp(self):
+ resp = self._getresp()
+ list = []; octets = 0
+ line, o = self._getline()
+ while line != '.':
+ if line[:2] == '..':
+ o = o-1
+ line = line[1:]
+ octets = octets + o
+ list.append(line)
+ line, o = self._getline()
+ return resp, list, octets
+
+
+ # Internal: send a command and get the response
+
+ def _shortcmd(self, line):
+ self._putcmd(line)
+ return self._getresp()
+
+
+ # Internal: send a command and get the response plus following text
+
+ def _longcmd(self, line):
+ self._putcmd(line)
+ return self._getlongresp()
+
+
+ # These can be useful:
+
+ def getwelcome(self):
+ return self.welcome
+
+
+ def set_debuglevel(self, level):
+ self._debugging = level
+
+
+ # Here are all the POP commands:
+
+ def user(self, user):
+ """Send user name, return response
+
+ (should indicate password required).
+ """
+ return self._shortcmd('USER %s' % user)
+
+
+ def pass_(self, pswd):
+ """Send password, return response
+
+ (response includes message count, mailbox size).
+
+ NB: mailbox is locked by server from here to 'quit()'
+ """
+ return self._shortcmd('PASS %s' % pswd)
+
+
+ def stat(self):
+ """Get mailbox status.
+
+ Result is tuple of 2 ints (message count, mailbox size)
+ """
+ retval = self._shortcmd('STAT')
+ rets = retval.split()
+ #if self._debugging: print '*stat*', `rets`
+ numMessages = int(rets[1])
+ sizeMessages = int(rets[2])
+ return (numMessages, sizeMessages)
+
+
+ def list(self, which=None):
+ """Request listing, return result.
+
+ Result without a message number argument is in form
+ ['response', ['mesg_num octets', ...]].
+
+ Result when a message number argument is given is a
+ single response: the "scan listing" for that message.
+ """
+ if which:
+ return self._shortcmd('LIST %s' % which)
+ return self._longcmd('LIST')
+
+
+ def retr(self, which):
+ """Retrieve whole message number 'which'.
+
+ Result is in form ['response', ['line', ...], octets].
+ """
+ return self._longcmd('RETR %s' % which)
+
+
+ def dele(self, which):
+ """Delete message number 'which'.
+
+ Result is 'response'.
+ """
+ return self._shortcmd('DELE %s' % which)
+
+
+ def noop(self):
+ """Does nothing.
+
+ One supposes the response indicates the server is alive.
+ """
+ return self._shortcmd('NOOP')
+
+
+ def rset(self):
+ """Not sure what this does."""
+ return self._shortcmd('RSET')
+
+
+ def quit(self):
+ """Signoff: commit changes on server, unlock mailbox, close connection."""
+ try:
+ resp = self._shortcmd('QUIT')
+ except error_proto, val:
+ resp = val
+ self.file.close()
+ self.sock.close()
+ del self.file, self.sock
+ return resp
+
+ #__del__ = quit
+
+
+ # optional commands:
+
+ def rpop(self, user):
+ """Not sure what this does."""
+ return self._shortcmd('RPOP %s' % user)
+
+
+ timestamp = re.compile(r'\+OK.*(<[^>]+>)')
+
+ def apop(self, user, secret):
+ """Authorisation
+
+ - only possible if server has supplied a timestamp in initial greeting.
+
+ Args:
+ user - mailbox user;
+ secret - secret shared between client and server.
+
+ NB: mailbox is locked by server from here to 'quit()'
+ """
+ m = self.timestamp.match(self.welcome)
+ if not m:
+ raise error_proto('-ERR APOP not supported by server')
+ import md5
+ digest = md5.new(m.group(1)+secret).digest()
+ digest = ''.join(map(lambda x:'%02x'%ord(x), digest))
+ return self._shortcmd('APOP %s %s' % (user, digest))
+
+
+ def top(self, which, howmuch):
+ """Retrieve message header of message number 'which'
+ and first 'howmuch' lines of message body.
+
+ Result is in form ['response', ['line', ...], octets].
+ """
+ return self._longcmd('TOP %s %s' % (which, howmuch))
+
+
+ def uidl(self, which=None):
+ """Return message digest (unique id) list.
+
+ If 'which', result contains unique id for that message
+ in the form 'response mesgnum uid', otherwise result is
+ the list ['response', ['mesgnum uid', ...], octets]
+ """
+ if which:
+ return self._shortcmd('UIDL %s' % which)
+ return self._longcmd('UIDL')
+
+
+if __name__ == "__main__":
+ import sys
+ a = POP3(sys.argv[1])
+ print a.getwelcome()
+ a.user(sys.argv[2])
+ a.pass_(sys.argv[3])
+ a.list()
+ (numMsgs, totalSize) = a.stat()
+ for i in range(1, numMsgs + 1):
+ (header, msg, octets) = a.retr(i)
+ print "Message ", `i`, ':'
+ for line in msg:
+ print ' ' + line
+ print '-----------------------'
+ a.quit()
diff --git a/lib/jython/Lib/posixfile.py b/lib/jython/Lib/posixfile.py new file mode 100644 index 000000000..87f6d2249 --- /dev/null +++ b/lib/jython/Lib/posixfile.py @@ -0,0 +1,229 @@ +"""Extended file operations available in POSIX.
+
+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_:
+ """File wrapper class that provides extra POSIX file routines."""
+
+ 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:])
+
+ #
+ # 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
+
+ if not hasattr(posix, 'fdopen'):
+ raise AttributeError, 'dup() method unavailable'
+
+ return posix.fdopen(posix.dup(self._file_.fileno()), self._file_.mode)
+
+ def dup2(self, fd):
+ import posix
+
+ if not hasattr(posix, 'fdopen'):
+ 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'
+
+ # Hack by davem@magnet.com to get locking to go on freebsd;
+ # additions for AIX by Vladimir.Marangozov@imag.fr
+ import sys, os
+ if sys.platform in ('netbsd1',
+ 'openbsd2',
+ 'freebsd2', 'freebsd3', 'freebsd4', 'freebsd5',
+ 'bsdos2', 'bsdos3', 'bsdos4'):
+ flock = struct.pack('lxxxxlxxxxlhh', \
+ l_start, l_len, os.getpid(), l_type, l_whence)
+ elif sys.platform in ['aix3', 'aix4']:
+ flock = struct.pack('hhlllii', \
+ l_type, l_whence, l_start, l_len, 0, 0, 0)
+ else:
+ 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:
+ if sys.platform in ('netbsd1',
+ 'openbsd2',
+ 'freebsd2', 'freebsd3', 'freebsd4', 'freebsd5',
+ 'bsdos2', 'bsdos3', 'bsdos4'):
+ l_start, l_len, l_pid, l_type, l_whence = \
+ struct.unpack('lxxxxlxxxxlhh', flock)
+ elif sys.platform in ['aix3', 'aix4']:
+ l_type, l_whence, l_start, l_len, l_sysid, l_pid, l_vfs = \
+ struct.unpack('hhlllii', flock)
+ elif sys.platform == "linux2":
+ l_type, l_whence, l_start, l_len, l_pid, l_sysid = \
+ struct.unpack('hhllhh', flock)
+ else:
+ 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
+
+def open(name, mode='r', bufsize=-1):
+ """Public routine to open a file as a posixfile object."""
+ return _posixfile_().open(name, mode, bufsize)
+
+def fileopen(file):
+ """Public routine to get a posixfile object from a Python file object."""
+ return _posixfile_().fileopen(file)
+
+#
+# Constants
+#
+SEEK_SET = 0
+SEEK_CUR = 1
+SEEK_END = 2
+
+#
+# End of posixfile.py
+#
diff --git a/lib/jython/Lib/posixpath.py b/lib/jython/Lib/posixpath.py new file mode 100644 index 000000000..8d453b249 --- /dev/null +++ b/lib/jython/Lib/posixpath.py @@ -0,0 +1,381 @@ +"""Common operations on Posix pathnames.
+
+Instead of importing this module directly, import os and refer to
+this module as os.path. The "os.path" name is an alias for this
+module on Posix systems; on other systems (e.g. Mac, Windows),
+os.path provides the same operations in a manner specific to that
+platform, and is an alias to another module (e.g. macpath, ntpath).
+
+Some of this can actually be useful on non-Posix systems too, e.g.
+for manipulation of the pathname component of URLs.
+"""
+
+import os
+import stat
+
+__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
+ "basename","dirname","commonprefix","getsize","getmtime",
+ "getatime","islink","exists","isdir","isfile","ismount",
+ "walk","expanduser","expandvars","normpath","abspath",
+ "samefile","sameopenfile","samestat"]
+
+# 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):
+ """Normalize case of pathname. Has no effect under Posix"""
+ return s
+
+
+# Return whether a path is absolute.
+# Trivial in Posix, harder on the Mac or MS-DOS.
+
+def isabs(s):
+ """Test whether a path is absolute"""
+ return s[:1] == '/'
+
+
+# Join pathnames.
+# Ignore the previous parts if a part is absolute.
+# Insert a '/' unless the first part is empty or already ends in '/'.
+
+def join(a, *p):
+ """Join two or more pathname components, inserting '/' as needed"""
+ path = a
+ for b in p:
+ if b[:1] == '/':
+ path = b
+ elif path == '' or path[-1:] == '/':
+ path = path + b
+ else:
+ path = path + '/' + b
+ return path
+
+
+# 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):
+ """Split a pathname. Returns tuple "(head, tail)" where "tail" is
+ everything after the final slash. Either part may be empty."""
+ i = p.rfind('/') + 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 last dot in the last
+# pathname component; the root is everything before that.
+# It is always true that root + ext == p.
+
+def splitext(p):
+ """Split the extension from a pathname. Extension is everything from the
+ last dot to the end. Returns "(root, ext)", either part may be empty."""
+ 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):
+ """Split a pathname into drive and path. On Posix, drive is always
+ empty."""
+ return '', p
+
+
+# Return the tail (basename) part of a path.
+
+def basename(p):
+ """Returns the final component of a pathname"""
+ return split(p)[1]
+
+
+# Return the head (dirname) part of a path.
+
+def dirname(p):
+ """Returns the directory component of a pathname"""
+ return split(p)[0]
+
+
+# Return the longest prefix of all list elements.
+
+def commonprefix(m):
+ "Given a list of pathnames, returns the longest common leading component"
+ 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
+
+
+# Get size, mtime, atime of files.
+
+def getsize(filename):
+ """Return the size of a file, reported by os.stat()."""
+ st = os.stat(filename)
+ return st[stat.ST_SIZE]
+
+def getmtime(filename):
+ """Return the last modification time of a file, reported by os.stat()."""
+ st = os.stat(filename)
+ return st[stat.ST_MTIME]
+
+def getatime(filename):
+ """Return the last access time of a file, reported by os.stat()."""
+ st = os.stat(filename)
+ return st[stat.ST_ATIME]
+
+
+# Is a path a symbolic link?
+# This will always return false on systems where os.lstat doesn't exist.
+
+def islink(path):
+ """Test whether a path is a symbolic link"""
+ try:
+ st = os.lstat(path)
+ except (os.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):
+ """Test whether a path exists. Returns false for broken symbolic links"""
+ try:
+ st = os.stat(path)
+ except os.error:
+ return 0
+ return 1
+
+
+# Is a path a directory?
+# This follows symbolic links, so both islink() and isdir() can be true
+# for the same path.
+
+def isdir(path):
+ """Test whether a path is a directory"""
+ try:
+ st = os.stat(path)
+ except os.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):
+ """Test whether a path is a regular file"""
+ try:
+ st = os.stat(path)
+ except os.error:
+ return 0
+ return stat.S_ISREG(st[stat.ST_MODE])
+
+
+# Are two filenames really pointing to the same file?
+
+def samefile(f1, f2):
+ """Test whether two pathnames reference the same actual file"""
+ s1 = os.stat(f1)
+ s2 = os.stat(f2)
+ return samestat(s1, s2)
+
+
+# Are two open files really referencing the same file?
+# (Not necessarily the same file descriptor!)
+
+def sameopenfile(fp1, fp2):
+ """Test whether two open file objects reference the same file"""
+ s1 = os.fstat(fp1)
+ s2 = os.fstat(fp2)
+ return samestat(s1, s2)
+
+
+# Are two stat buffers (obtained from stat, fstat or lstat)
+# describing the same file?
+
+def samestat(s1, s2):
+ """Test whether two stat buffers reference the same file"""
+ 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):
+ """Test whether a path is a mount point"""
+ try:
+ s1 = os.stat(path)
+ s2 = os.stat(join(path, '..'))
+ except os.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
+# of 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):
+ """walk(top,func,arg) calls func(arg, d, files) for each directory "d"
+ in the tree rooted at "top" (including "top" itself). "files" is a list
+ of all the files and subdirs in directory "d".
+ """
+ try:
+ names = os.listdir(top)
+ except os.error:
+ return
+ func(arg, top, names)
+ for name in names:
+ name = join(top, name)
+ try:
+ st = os.lstat(name)
+ except os.error:
+ continue
+ if stat.S_ISDIR(st[stat.ST_MODE]):
+ 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):
+ """Expand ~ and ~user constructions. If user or $HOME is unknown,
+ do nothing."""
+ if path[:1] != '~':
+ return path
+ i, n = 1, len(path)
+ while i < n and path[i] != '/':
+ i = i + 1
+ if i == 1:
+ if not os.environ.has_key('HOME'):
+ return path
+ userhome = os.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-existent variables are left unchanged.
+
+_varprog = None
+
+def expandvars(path):
+ """Expand shell variables of form $var and ${var}. Unknown variables
+ are left unchanged."""
+ global _varprog
+ if '$' not in path:
+ return path
+ if not _varprog:
+ import re
+ _varprog = re.compile(r'\$(\w+|\{[^}]*\})')
+ i = 0
+ while 1:
+ m = _varprog.search(path, i)
+ if not m:
+ break
+ i, j = m.span(0)
+ name = m.group(1)
+ if name[:1] == '{' and name[-1:] == '}':
+ name = name[1:-1]
+ if os.environ.has_key(name):
+ tail = path[j:]
+ path = path[:i] + os.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):
+ """Normalize path, eliminating double slashes, etc."""
+ if path == '':
+ return '.'
+ initial_slashes = path.startswith('/')
+ # POSIX allows one or two initial slashes, but treats three or more
+ # as single slash.
+ if (initial_slashes and
+ path.startswith('//') and not path.startswith('///')):
+ initial_slashes = 2
+ comps = path.split('/')
+ new_comps = []
+ for comp in comps:
+ if comp in ('', '.'):
+ continue
+ if (comp != '..' or (not initial_slashes and not new_comps) or
+ (new_comps and new_comps[-1] == '..')):
+ new_comps.append(comp)
+ elif new_comps:
+ new_comps.pop()
+ comps = new_comps
+ path = '/'.join(comps)
+ if initial_slashes:
+ path = '/'*initial_slashes + path
+ return path or '.'
+
+
+def abspath(path):
+ """Return an absolute path."""
+ if not isabs(path):
+ path = join(os.getcwd(), path)
+ return normpath(path)
diff --git a/lib/jython/Lib/pprint.py b/lib/jython/Lib/pprint.py new file mode 100644 index 000000000..cbb97ea87 --- /dev/null +++ b/lib/jython/Lib/pprint.py @@ -0,0 +1,251 @@ +# Author: Fred L. Drake, Jr.
+# fdrake@cnri.reston.va.us, fdrake@acm.org
+#
+# This is a simple little module I wrote to make life easier. I didn't
+# see anything quite like it in the library, though I may have overlooked
+# something. I wrote this when I was trying to read some heavily nested
+# tuples with fairly non-descriptive content. This is modeled very much
+# after Lisp/Scheme - style pretty-printing of lists. If you find it
+# useful, thank small children who sleep at night.
+
+"""Support to pretty-print lists, tuples, & dictionaries recursively.
+
+Very simple, but useful, especially in debugging data structures.
+
+Classes
+-------
+
+PrettyPrinter()
+ Handle pretty-printing operations onto a stream using a configured
+ set of formatting parameters.
+
+Functions
+---------
+
+pformat()
+ Format a Python object into a pretty-printed representation.
+
+pprint()
+ Pretty-print a Python object to a stream [default is sys.sydout].
+
+saferepr()
+ Generate a 'standard' repr()-like value, but protect against recursive
+ data structures.
+
+"""
+
+from types import DictType, ListType, TupleType
+
+try:
+ from cStringIO import StringIO
+except ImportError:
+ from StringIO import StringIO
+
+__all__ = ["pprint","pformat","isreadable","isrecursive","saferepr",
+ "PrettyPrinter"]
+
+def pprint(object, stream=None):
+ """Pretty-print a Python object to a stream [default is sys.sydout]."""
+ printer = PrettyPrinter(stream=stream)
+ printer.pprint(object)
+
+
+def pformat(object):
+ """Format a Python object into a pretty-printed representation."""
+ return PrettyPrinter().pformat(object)
+
+
+def isreadable(object):
+ """Determine if saferepr(object) is readable by eval()."""
+ return PrettyPrinter().isreadable(object)
+
+
+def isrecursive(object):
+ """Determine if object requires a recursive representation."""
+ return PrettyPrinter().isrecursive(object)
+
+
+def saferepr(object):
+ """Version of repr() which can handle recursive data structures."""
+ return _safe_repr(object, {})[0]
+
+
+class PrettyPrinter:
+ def __init__(self, indent=1, width=80, depth=None, stream=None):
+ """Handle pretty printing operations onto a stream using a set of
+ configured parameters.
+
+ indent
+ Number of spaces to indent for each level of nesting.
+
+ width
+ Attempted maximum number of columns in the output.
+
+ depth
+ The maximum depth to print out nested structures.
+
+ stream
+ The desired output stream. If omitted (or false), the standard
+ output stream available at construction will be used.
+
+ """
+ indent = int(indent)
+ width = int(width)
+ assert indent >= 0
+ assert (not depth) or depth > 0, "depth may not be negative"
+ assert width
+ self.__depth = depth
+ self.__indent_per_level = indent
+ self.__width = width
+ if stream:
+ self.__stream = stream
+ else:
+ import sys
+ self.__stream = sys.stdout
+
+ def pprint(self, object):
+ self.__stream.write(self.pformat(object) + "\n")
+
+ def pformat(self, object):
+ sio = StringIO()
+ self.__format(object, sio, 0, 0, {}, 0)
+ return sio.getvalue()
+
+ def isrecursive(self, object):
+ self.__recursive = 0
+ self.pformat(object)
+ return self.__recursive
+
+ def isreadable(self, object):
+ self.__recursive = 0
+ self.__readable = 1
+ self.pformat(object)
+ return self.__readable and not self.__recursive
+
+ def __format(self, object, stream, indent, allowance, context, level):
+ level = level + 1
+ if context.has_key(id(object)):
+ object = _Recursion(object)
+ self.__recursive = 1
+ rep = self.__repr(object, context, level - 1)
+ objid = id(object)
+ context[objid] = 1
+ typ = type(object)
+ sepLines = len(rep) > (self.__width - 1 - indent - allowance)
+
+ if sepLines and typ in (ListType, TupleType):
+ # Pretty-print the sequence.
+ stream.write((typ is ListType) and '[' or '(')
+ if self.__indent_per_level > 1:
+ stream.write((self.__indent_per_level - 1) * ' ')
+ length = len(object)
+ if length:
+ indent = indent + self.__indent_per_level
+ self.__format(object[0], stream, indent, allowance + 1,
+ context, level)
+ if length > 1:
+ for ent in object[1:]:
+ stream.write(',\n' + ' '*indent)
+ self.__format(ent, stream, indent,
+ allowance + 1, context, level)
+ indent = indent - self.__indent_per_level
+ if typ is TupleType and length == 1:
+ stream.write(',')
+ stream.write(((typ is ListType) and ']') or ')')
+
+ elif sepLines and typ is DictType:
+ stream.write('{')
+ if self.__indent_per_level > 1:
+ stream.write((self.__indent_per_level - 1) * ' ')
+ length = len(object)
+ if length:
+ indent = indent + self.__indent_per_level
+ items = object.items()
+ items.sort()
+ key, ent = items[0]
+ rep = self.__repr(key, context, level) + ': '
+ stream.write(rep)
+ self.__format(ent, stream, indent + len(rep),
+ allowance + 1, context, level)
+ if len(items) > 1:
+ for key, ent in items[1:]:
+ rep = self.__repr(key, context, level) + ': '
+ stream.write(',\n' + ' '*indent + rep)
+ self.__format(ent, stream, indent + len(rep),
+ allowance + 1, context, level)
+ indent = indent - self.__indent_per_level
+ stream.write('}')
+
+ else:
+ stream.write(rep)
+
+ del context[objid]
+
+ def __repr(self, object, context, level):
+ repr, readable = _safe_repr(object, context, self.__depth, level)
+ if not readable:
+ self.__readable = 0
+ return repr
+
+
+def _safe_repr(object, context, maxlevels=None, level=0):
+ level = level + 1
+ typ = type(object)
+ if not (typ in (DictType, ListType, TupleType) and object):
+ rep = `object`
+ return rep, (rep and (rep[0] != '<'))
+ if context.has_key(id(object)):
+ return `_Recursion(object)`, 0
+ objid = id(object)
+ context[objid] = 1
+ readable = 1
+ if typ is DictType:
+ if maxlevels and level >= maxlevels:
+ s = "{...}"
+ readable = 0
+ else:
+ items = object.items()
+ k, v = items[0]
+ krepr, kreadable = _safe_repr(k, context, maxlevels, level)
+ vrepr, vreadable = _safe_repr(v, context, maxlevels, level)
+ readable = readable and kreadable and vreadable
+ s = "{%s: %s" % (krepr, vrepr)
+ for k, v in items[1:]:
+ krepr, kreadable = _safe_repr(k, context, maxlevels, level)
+ vrepr, vreadable = _safe_repr(v, context, maxlevels, level)
+ readable = readable and kreadable and vreadable
+ s = "%s, %s: %s" % (s, krepr, vrepr)
+ s = s + "}"
+ else:
+ s, term = (typ is ListType) and ('[', ']') or ('(', ')')
+ if maxlevels and level >= maxlevels:
+ s = s + "..."
+ readable = 0
+ else:
+ subrepr, subreadable = _safe_repr(
+ object[0], context, maxlevels, level)
+ readable = readable and subreadable
+ s = s + subrepr
+ tail = object[1:]
+ if not tail:
+ if typ is TupleType:
+ s = s + ','
+ for ent in tail:
+ subrepr, subreadable = _safe_repr(
+ ent, context, maxlevels, level)
+ readable = readable and subreadable
+ s = "%s, %s" % (s, subrepr)
+ s = s + term
+ del context[objid]
+ return s, readable
+
+
+class _Recursion:
+ # represent a recursive relationship; really only used for the __repr__()
+ # method...
+ def __init__(self, object):
+ self.__repr = "<Recursion on %s with id=%s>" \
+ % (type(object).__name__, id(object))
+
+ def __repr__(self):
+ return self.__repr
diff --git a/lib/jython/Lib/profile.py b/lib/jython/Lib/profile.py new file mode 100644 index 000000000..8a502e67c --- /dev/null +++ b/lib/jython/Lib/profile.py @@ -0,0 +1,580 @@ +#! /usr/bin/env python
+#
+# Class for profiling python code. rev 1.0 6/2/94
+#
+# Based on prior profile module by Sjoerd Mullender...
+# which was hacked somewhat by: Guido van Rossum
+#
+# See profile.doc for more information
+
+"""Class for profiling Python code."""
+
+# Copyright 1994, by InfoSeek Corporation, all rights reserved.
+# Written by James Roskind
+#
+# Permission to use, copy, modify, and distribute this Python software
+# and its associated documentation for any purpose (subject to the
+# restriction in the following sentence) without fee is hereby granted,
+# provided that the above copyright notice appears in all copies, and
+# that both that copyright notice and this permission notice appear in
+# supporting documentation, and that the name of InfoSeek not be used in
+# advertising or publicity pertaining to distribution of the software
+# without specific, written prior permission. This permission is
+# explicitly restricted to the copying and modification of the software
+# to remain in Python, compiled Python, or other languages (such as C)
+# wherein the modified or derived code is exclusively imported into a
+# Python module.
+#
+# INFOSEEK CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+# SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS. IN NO EVENT SHALL INFOSEEK CORPORATION BE LIABLE FOR ANY
+# SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+# RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+# CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+
+
+import sys
+import os
+import time
+import marshal
+
+__all__ = ["run","help","Profile"]
+
+# Sample timer for use with
+#i_count = 0
+#def integer_timer():
+# global i_count
+# i_count = i_count + 1
+# return i_count
+#itimes = integer_timer # replace with C coded timer returning integers
+
+#**************************************************************************
+# The following are the static member functions for the profiler class
+# Note that an instance of Profile() is *not* needed to call them.
+#**************************************************************************
+
+def run(statement, filename=None):
+ """Run statement under profiler optionally saving results in filename
+
+ This function takes a single argument that can be passed to the
+ "exec" statement, and an optional file name. In all cases this
+ routine attempts to "exec" its first argument and gather profiling
+ statistics from the execution. If no file name is present, then this
+ function automatically prints a simple profiling report, sorted by the
+ standard name string (file/line/function-name) that is presented in
+ each line.
+ """
+ prof = Profile()
+ try:
+ prof = prof.run(statement)
+ except SystemExit:
+ pass
+ if filename is not None:
+ prof.dump_stats(filename)
+ else:
+ return prof.print_stats()
+
+# print help
+def help():
+ for dirname in sys.path:
+ fullname = os.path.join(dirname, 'profile.doc')
+ if os.path.exists(fullname):
+ sts = os.system('${PAGER-more} '+fullname)
+ if sts: print '*** Pager exit status:', sts
+ break
+ else:
+ print 'Sorry, can\'t find the help file "profile.doc"',
+ print 'along the Python search path'
+
+
+class Profile:
+ """Profiler class.
+
+ self.cur is always a tuple. Each such tuple corresponds to a stack
+ frame that is currently active (self.cur[-2]). The following are the
+ definitions of its members. We use this external "parallel stack" to
+ avoid contaminating the program that we are profiling. (old profiler
+ used to write into the frames local dictionary!!) Derived classes
+ can change the definition of some entries, as long as they leave
+ [-2:] intact.
+
+ [ 0] = Time that needs to be charged to the parent frame's function.
+ It is used so that a function call will not have to access the
+ timing data for the parent frame.
+ [ 1] = Total time spent in this frame's function, excluding time in
+ subfunctions
+ [ 2] = Cumulative time spent in this frame's function, including time in
+ all subfunctions to this frame.
+ [-3] = Name of the function that corresponds to this frame.
+ [-2] = Actual frame that we correspond to (used to sync exception handling)
+ [-1] = Our parent 6-tuple (corresponds to frame.f_back)
+
+ Timing data for each function is stored as a 5-tuple in the dictionary
+ self.timings[]. The index is always the name stored in self.cur[4].
+ The following are the definitions of the members:
+
+ [0] = The number of times this function was called, not counting direct
+ or indirect recursion,
+ [1] = Number of times this function appears on the stack, minus one
+ [2] = Total time spent internal to this function
+ [3] = Cumulative time that this function was present on the stack. In
+ non-recursive functions, this is the total execution time from start
+ to finish of each invocation of a function, including time spent in
+ all subfunctions.
+ [5] = A dictionary indicating for each function name, the number of times
+ it was called by us.
+ """
+
+ def __init__(self, timer=None):
+ self.timings = {}
+ self.cur = None
+ self.cmd = ""
+
+ self.dispatch = { \
+ 'call' : self.trace_dispatch_call, \
+ 'return' : self.trace_dispatch_return, \
+ 'exception': self.trace_dispatch_exception, \
+ }
+
+ if not timer:
+ if os.name == 'mac':
+ import MacOS
+ self.timer = MacOS.GetTicks
+ self.dispatcher = self.trace_dispatch_mac
+ self.get_time = self.get_time_mac
+ elif hasattr(time, 'clock'):
+ self.timer = time.clock
+ self.dispatcher = self.trace_dispatch_i
+ elif hasattr(os, 'times'):
+ self.timer = os.times
+ self.dispatcher = self.trace_dispatch
+ else:
+ self.timer = time.time
+ self.dispatcher = self.trace_dispatch_i
+ else:
+ self.timer = timer
+ t = self.timer() # test out timer function
+ try:
+ if len(t) == 2:
+ self.dispatcher = self.trace_dispatch
+ else:
+ self.dispatcher = self.trace_dispatch_l
+ except TypeError:
+ self.dispatcher = self.trace_dispatch_i
+ self.t = self.get_time()
+ self.simulate_call('profiler')
+
+
+ def get_time(self): # slow simulation of method to acquire time
+ t = self.timer()
+ if type(t) == type(()) or type(t) == type([]):
+ t = reduce(lambda x,y: x+y, t, 0)
+ return t
+
+ def get_time_mac(self):
+ return self.timer()/60.0
+
+ # Heavily optimized dispatch routine for os.times() timer
+
+ def trace_dispatch(self, frame, event, arg):
+ t = self.timer()
+ t = t[0] + t[1] - self.t # No Calibration constant
+ # t = t[0] + t[1] - self.t - .00053 # Calibration constant
+
+ if self.dispatch[event](frame,t):
+ t = self.timer()
+ self.t = t[0] + t[1]
+ else:
+ r = self.timer()
+ self.t = r[0] + r[1] - t # put back unrecorded delta
+ return
+
+
+
+ # Dispatch routine for best timer program (return = scalar integer)
+
+ def trace_dispatch_i(self, frame, event, arg):
+ t = self.timer() - self.t # - 1 # Integer calibration constant
+ if self.dispatch[event](frame,t):
+ self.t = self.timer()
+ else:
+ self.t = self.timer() - t # put back unrecorded delta
+ return
+
+ # Dispatch routine for macintosh (timer returns time in ticks of 1/60th second)
+
+ def trace_dispatch_mac(self, frame, event, arg):
+ t = self.timer()/60.0 - self.t # - 1 # Integer calibration constant
+ if self.dispatch[event](frame,t):
+ self.t = self.timer()/60.0
+ else:
+ self.t = self.timer()/60.0 - t # put back unrecorded delta
+ return
+
+
+ # SLOW generic dispatch routine for timer returning lists of numbers
+
+ def trace_dispatch_l(self, frame, event, arg):
+ t = self.get_time() - self.t
+
+ if self.dispatch[event](frame,t):
+ self.t = self.get_time()
+ else:
+ self.t = self.get_time()-t # put back unrecorded delta
+ return
+
+
+ def trace_dispatch_exception(self, frame, t):
+ rt, rtt, rct, rfn, rframe, rcur = self.cur
+ if (not rframe is frame) and rcur:
+ return self.trace_dispatch_return(rframe, t)
+ return 0
+
+
+ def trace_dispatch_call(self, frame, t):
+ fcode = frame.f_code
+ fn = (fcode.co_filename, fcode.co_firstlineno, fcode.co_name)
+ self.cur = (t, 0, 0, fn, frame, self.cur)
+ if self.timings.has_key(fn):
+ cc, ns, tt, ct, callers = self.timings[fn]
+ self.timings[fn] = cc, ns + 1, tt, ct, callers
+ else:
+ self.timings[fn] = 0, 0, 0, 0, {}
+ return 1
+
+ def trace_dispatch_return(self, frame, t):
+ # if not frame is self.cur[-2]: raise "Bad return", self.cur[3]
+
+ # Prefix "r" means part of the Returning or exiting frame
+ # Prefix "p" means part of the Previous or older frame
+
+ rt, rtt, rct, rfn, frame, rcur = self.cur
+ rtt = rtt + t
+ sft = rtt + rct
+
+ pt, ptt, pct, pfn, pframe, pcur = rcur
+ self.cur = pt, ptt+rt, pct+sft, pfn, pframe, pcur
+
+ cc, ns, tt, ct, callers = self.timings[rfn]
+ if not ns:
+ ct = ct + sft
+ cc = cc + 1
+ if callers.has_key(pfn):
+ callers[pfn] = callers[pfn] + 1 # hack: gather more
+ # stats such as the amount of time added to ct courtesy
+ # of this specific call, and the contribution to cc
+ # courtesy of this call.
+ else:
+ callers[pfn] = 1
+ self.timings[rfn] = cc, ns - 1, tt+rtt, ct, callers
+
+ return 1
+
+ # The next few function play with self.cmd. By carefully preloading
+ # our parallel stack, we can force the profiled result to include
+ # an arbitrary string as the name of the calling function.
+ # We use self.cmd as that string, and the resulting stats look
+ # very nice :-).
+
+ def set_cmd(self, cmd):
+ if self.cur[-1]: return # already set
+ self.cmd = cmd
+ self.simulate_call(cmd)
+
+ class fake_code:
+ def __init__(self, filename, line, name):
+ self.co_filename = filename
+ self.co_line = line
+ self.co_name = name
+ self.co_firstlineno = 0
+
+ def __repr__(self):
+ return repr((self.co_filename, self.co_line, self.co_name))
+
+ class fake_frame:
+ def __init__(self, code, prior):
+ self.f_code = code
+ self.f_back = prior
+
+ def simulate_call(self, name):
+ code = self.fake_code('profile', 0, name)
+ if self.cur:
+ pframe = self.cur[-2]
+ else:
+ pframe = None
+ frame = self.fake_frame(code, pframe)
+ a = self.dispatch['call'](frame, 0)
+ return
+
+ # collect stats from pending stack, including getting final
+ # timings for self.cmd frame.
+
+ def simulate_cmd_complete(self):
+ t = self.get_time() - self.t
+ while self.cur[-1]:
+ # We *can* cause assertion errors here if
+ # dispatch_trace_return checks for a frame match!
+ a = self.dispatch['return'](self.cur[-2], t)
+ t = 0
+ self.t = self.get_time() - t
+
+
+ def print_stats(self):
+ import pstats
+ pstats.Stats(self).strip_dirs().sort_stats(-1). \
+ print_stats()
+
+ def dump_stats(self, file):
+ f = open(file, 'wb')
+ self.create_stats()
+ marshal.dump(self.stats, f)
+ f.close()
+
+ def create_stats(self):
+ self.simulate_cmd_complete()
+ self.snapshot_stats()
+
+ def snapshot_stats(self):
+ self.stats = {}
+ for func in self.timings.keys():
+ cc, ns, tt, ct, callers = self.timings[func]
+ callers = callers.copy()
+ nc = 0
+ for func_caller in callers.keys():
+ nc = nc + callers[func_caller]
+ self.stats[func] = cc, nc, tt, ct, callers
+
+
+ # The following two methods can be called by clients to use
+ # a profiler to profile a statement, given as a string.
+
+ def run(self, cmd):
+ import __main__
+ dict = __main__.__dict__
+ return self.runctx(cmd, dict, dict)
+
+ def runctx(self, cmd, globals, locals):
+ self.set_cmd(cmd)
+ sys.setprofile(self.dispatcher)
+ try:
+ exec cmd in globals, locals
+ finally:
+ sys.setprofile(None)
+ return self
+
+ # This method is more useful to profile a single function call.
+ def runcall(self, func, *args):
+ self.set_cmd(`func`)
+ sys.setprofile(self.dispatcher)
+ try:
+ return apply(func, args)
+ finally:
+ sys.setprofile(None)
+
+
+ #******************************************************************
+ # The following calculates the overhead for using a profiler. The
+ # problem is that it takes a fair amount of time for the profiler
+ # to stop the stopwatch (from the time it receives an event).
+ # Similarly, there is a delay from the time that the profiler
+ # re-starts the stopwatch before the user's code really gets to
+ # continue. The following code tries to measure the difference on
+ # a per-event basis. The result can the be placed in the
+ # Profile.dispatch_event() routine for the given platform. Note
+ # that this difference is only significant if there are a lot of
+ # events, and relatively little user code per event. For example,
+ # code with small functions will typically benefit from having the
+ # profiler calibrated for the current platform. This *could* be
+ # done on the fly during init() time, but it is not worth the
+ # effort. Also note that if too large a value specified, then
+ # execution time on some functions will actually appear as a
+ # negative number. It is *normal* for some functions (with very
+ # low call counts) to have such negative stats, even if the
+ # calibration figure is "correct."
+ #
+ # One alternative to profile-time calibration adjustments (i.e.,
+ # adding in the magic little delta during each event) is to track
+ # more carefully the number of events (and cumulatively, the number
+ # of events during sub functions) that are seen. If this were
+ # done, then the arithmetic could be done after the fact (i.e., at
+ # display time). Currently, we track only call/return events.
+ # These values can be deduced by examining the callees and callers
+ # vectors for each functions. Hence we *can* almost correct the
+ # internal time figure at print time (note that we currently don't
+ # track exception event processing counts). Unfortunately, there
+ # is currently no similar information for cumulative sub-function
+ # time. It would not be hard to "get all this info" at profiler
+ # time. Specifically, we would have to extend the tuples to keep
+ # counts of this in each frame, and then extend the defs of timing
+ # tuples to include the significant two figures. I'm a bit fearful
+ # that this additional feature will slow the heavily optimized
+ # event/time ratio (i.e., the profiler would run slower, fur a very
+ # low "value added" feature.)
+ #
+ # Plugging in the calibration constant doesn't slow down the
+ # profiler very much, and the accuracy goes way up.
+ #**************************************************************
+
+ def calibrate(self, m):
+ # Modified by Tim Peters
+ n = m
+ s = self.get_time()
+ while n:
+ self.simple()
+ n = n - 1
+ f = self.get_time()
+ my_simple = f - s
+ #print "Simple =", my_simple,
+
+ n = m
+ s = self.get_time()
+ while n:
+ self.instrumented()
+ n = n - 1
+ f = self.get_time()
+ my_inst = f - s
+ # print "Instrumented =", my_inst
+ avg_cost = (my_inst - my_simple)/m
+ #print "Delta/call =", avg_cost, "(profiler fixup constant)"
+ return avg_cost
+
+ # simulate a program with no profiler activity
+ def simple(self):
+ a = 1
+ pass
+
+ # simulate a program with call/return event processing
+ def instrumented(self):
+ a = 1
+ self.profiler_simulation(a, a, a)
+
+ # simulate an event processing activity (from user's perspective)
+ def profiler_simulation(self, x, y, z):
+ t = self.timer()
+ ## t = t[0] + t[1]
+ self.ut = t
+
+
+
+class OldProfile(Profile):
+ """A derived profiler that simulates the old style profile, providing
+ errant results on recursive functions. The reason for the usefulness of
+ this profiler is that it runs faster (i.e., less overhead). It still
+ creates all the caller stats, and is quite useful when there is *no*
+ recursion in the user's code.
+
+ This code also shows how easy it is to create a modified profiler.
+ """
+
+ def trace_dispatch_exception(self, frame, t):
+ rt, rtt, rct, rfn, rframe, rcur = self.cur
+ if rcur and not rframe is frame:
+ return self.trace_dispatch_return(rframe, t)
+ return 0
+
+ def trace_dispatch_call(self, frame, t):
+ fn = `frame.f_code`
+
+ self.cur = (t, 0, 0, fn, frame, self.cur)
+ if self.timings.has_key(fn):
+ tt, ct, callers = self.timings[fn]
+ self.timings[fn] = tt, ct, callers
+ else:
+ self.timings[fn] = 0, 0, {}
+ return 1
+
+ def trace_dispatch_return(self, frame, t):
+ rt, rtt, rct, rfn, frame, rcur = self.cur
+ rtt = rtt + t
+ sft = rtt + rct
+
+ pt, ptt, pct, pfn, pframe, pcur = rcur
+ self.cur = pt, ptt+rt, pct+sft, pfn, pframe, pcur
+
+ tt, ct, callers = self.timings[rfn]
+ if callers.has_key(pfn):
+ callers[pfn] = callers[pfn] + 1
+ else:
+ callers[pfn] = 1
+ self.timings[rfn] = tt+rtt, ct + sft, callers
+
+ return 1
+
+
+ def snapshot_stats(self):
+ self.stats = {}
+ for func in self.timings.keys():
+ tt, ct, callers = self.timings[func]
+ callers = callers.copy()
+ nc = 0
+ for func_caller in callers.keys():
+ nc = nc + callers[func_caller]
+ self.stats[func] = nc, nc, tt, ct, callers
+
+
+
+class HotProfile(Profile):
+ """The fastest derived profile example. It does not calculate
+ caller-callee relationships, and does not calculate cumulative
+ time under a function. It only calculates time spent in a
+ function, so it runs very quickly due to its very low overhead.
+ """
+
+ def trace_dispatch_exception(self, frame, t):
+ rt, rtt, rfn, rframe, rcur = self.cur
+ if rcur and not rframe is frame:
+ return self.trace_dispatch_return(rframe, t)
+ return 0
+
+ def trace_dispatch_call(self, frame, t):
+ self.cur = (t, 0, frame, self.cur)
+ return 1
+
+ def trace_dispatch_return(self, frame, t):
+ rt, rtt, frame, rcur = self.cur
+
+ rfn = `frame.f_code`
+
+ pt, ptt, pframe, pcur = rcur
+ self.cur = pt, ptt+rt, pframe, pcur
+
+ if self.timings.has_key(rfn):
+ nc, tt = self.timings[rfn]
+ self.timings[rfn] = nc + 1, rt + rtt + tt
+ else:
+ self.timings[rfn] = 1, rt + rtt
+
+ return 1
+
+
+ def snapshot_stats(self):
+ self.stats = {}
+ for func in self.timings.keys():
+ nc, tt = self.timings[func]
+ self.stats[func] = nc, nc, tt, 0, {}
+
+
+
+#****************************************************************************
+def Stats(*args):
+ print 'Report generating functions are in the "pstats" module\a'
+
+
+# When invoked as main program, invoke the profiler on a script
+if __name__ == '__main__':
+ import sys
+ import os
+ if not sys.argv[1:]:
+ print "usage: profile.py scriptfile [arg] ..."
+ sys.exit(2)
+
+ filename = sys.argv[1] # Get script filename
+
+ del sys.argv[0] # Hide "profile.py" from argument list
+
+ # Insert script directory in front of module search path
+ sys.path.insert(0, os.path.dirname(filename))
+
+ run('execfile(' + `filename` + ')')
diff --git a/lib/jython/Lib/pstats.py b/lib/jython/Lib/pstats.py new file mode 100644 index 000000000..a58b87f4b --- /dev/null +++ b/lib/jython/Lib/pstats.py @@ -0,0 +1,655 @@ +"""Class for printing reports on profiled python code."""
+
+# Class for printing reports on profiled python code. rev 1.0 4/1/94
+#
+# Based on prior profile module by Sjoerd Mullender...
+# which was hacked somewhat by: Guido van Rossum
+#
+# see profile.doc and profile.py for more info.
+
+# Copyright 1994, by InfoSeek Corporation, all rights reserved.
+# Written by James Roskind
+#
+# Permission to use, copy, modify, and distribute this Python software
+# and its associated documentation for any purpose (subject to the
+# restriction in the following sentence) without fee is hereby granted,
+# provided that the above copyright notice appears in all copies, and
+# that both that copyright notice and this permission notice appear in
+# supporting documentation, and that the name of InfoSeek not be used in
+# advertising or publicity pertaining to distribution of the software
+# without specific, written prior permission. This permission is
+# explicitly restricted to the copying and modification of the software
+# to remain in Python, compiled Python, or other languages (such as C)
+# wherein the modified or derived code is exclusively imported into a
+# Python module.
+#
+# INFOSEEK CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+# SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS. IN NO EVENT SHALL INFOSEEK CORPORATION BE LIABLE FOR ANY
+# SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+# RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+# CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+
+import os
+import time
+import marshal
+import re
+
+import fpformat
+
+__all__ = ["Stats"]
+
+class Stats:
+ """This class is used for creating reports from data generated by the
+ Profile class. It is a "friend" of that class, and imports data either
+ by direct access to members of Profile class, or by reading in a dictionary
+ that was emitted (via marshal) from the Profile class.
+
+ The big change from the previous Profiler (in terms of raw functionality)
+ is that an "add()" method has been provided to combine Stats from
+ several distinct profile runs. Both the constructor and the add()
+ method now take arbitrarily many file names as arguments.
+
+ All the print methods now take an argument that indicates how many lines
+ to print. If the arg is a floating point number between 0 and 1.0, then
+ it is taken as a decimal percentage of the available lines to be printed
+ (e.g., .1 means print 10% of all available lines). If it is an integer,
+ it is taken to mean the number of lines of data that you wish to have
+ printed.
+
+ The sort_stats() method now processes some additional options (i.e., in
+ addition to the old -1, 0, 1, or 2). It takes an arbitrary number of quoted
+ strings to select the sort order. For example sort_stats('time', 'name')
+ sorts on the major key of "internal function time", and on the minor
+ key of 'the name of the function'. Look at the two tables in sort_stats()
+ and get_sort_arg_defs(self) for more examples.
+
+ All methods now return "self", so you can string together commands like:
+ Stats('foo', 'goo').strip_dirs().sort_stats('calls').\
+ print_stats(5).print_callers(5)
+ """
+
+ def __init__(self, *args):
+ if not len(args):
+ arg = None
+ else:
+ arg = args[0]
+ args = args[1:]
+ self.init(arg)
+ apply(self.add, args).ignore()
+
+ def init(self, arg):
+ self.all_callees = None # calc only if needed
+ self.files = []
+ self.fcn_list = None
+ self.total_tt = 0
+ self.total_calls = 0
+ self.prim_calls = 0
+ self.max_name_len = 0
+ self.top_level = {}
+ self.stats = {}
+ self.sort_arg_dict = {}
+ self.load_stats(arg)
+ trouble = 1
+ try:
+ self.get_top_level_stats()
+ trouble = 0
+ finally:
+ if trouble:
+ print "Invalid timing data",
+ if self.files: print self.files[-1],
+ print
+
+
+ def load_stats(self, arg):
+ if not arg: self.stats = {}
+ elif type(arg) == type(""):
+ f = open(arg, 'rb')
+ self.stats = marshal.load(f)
+ f.close()
+ try:
+ file_stats = os.stat(arg)
+ arg = time.ctime(file_stats[8]) + " " + arg
+ except: # in case this is not unix
+ pass
+ self.files = [ arg ]
+ elif hasattr(arg, 'create_stats'):
+ arg.create_stats()
+ self.stats = arg.stats
+ arg.stats = {}
+ if not self.stats:
+ raise TypeError, "Cannot create or construct a " \
+ + `self.__class__` \
+ + " object from '" + `arg` + "'"
+ return
+
+ def get_top_level_stats(self):
+ for func in self.stats.keys():
+ cc, nc, tt, ct, callers = self.stats[func]
+ self.total_calls = self.total_calls + nc
+ self.prim_calls = self.prim_calls + cc
+ self.total_tt = self.total_tt + tt
+ if callers.has_key(("jprofile", 0, "profiler")):
+ self.top_level[func] = None
+ if len(func_std_string(func)) > self.max_name_len:
+ self.max_name_len = len(func_std_string(func))
+
+ def add(self, *arg_list):
+ if not arg_list: return self
+ if len(arg_list) > 1: apply(self.add, arg_list[1:])
+ other = arg_list[0]
+ if type(self) != type(other) or \
+ self.__class__ != other.__class__:
+ other = Stats(other)
+ self.files = self.files + other.files
+ self.total_calls = self.total_calls + other.total_calls
+ self.prim_calls = self.prim_calls + other.prim_calls
+ self.total_tt = self.total_tt + other.total_tt
+ for func in other.top_level.keys():
+ self.top_level[func] = None
+
+ if self.max_name_len < other.max_name_len:
+ self.max_name_len = other.max_name_len
+
+ self.fcn_list = None
+
+ for func in other.stats.keys():
+ if self.stats.has_key(func):
+ old_func_stat = self.stats[func]
+ else:
+ old_func_stat = (0, 0, 0, 0, {},)
+ self.stats[func] = add_func_stats(old_func_stat, \
+ other.stats[func])
+ return self
+
+
+
+ # list the tuple indices and directions for sorting,
+ # along with some printable description
+ sort_arg_dict_default = {\
+ "calls" : (((1,-1), ), "call count"),\
+ "cumulative": (((3,-1), ), "cumulative time"),\
+ "file" : (((4, 1), ), "file name"),\
+ "line" : (((5, 1), ), "line number"),\
+ "module" : (((4, 1), ), "file name"),\
+ "name" : (((6, 1), ), "function name"),\
+ "nfl" : (((6, 1),(4, 1),(5, 1),), "name/file/line"), \
+ "pcalls" : (((0,-1), ), "call count"),\
+ "stdname" : (((7, 1), ), "standard name"),\
+ "time" : (((2,-1), ), "internal time"),\
+ }
+
+ def get_sort_arg_defs(self):
+ """Expand all abbreviations that are unique."""
+ if not self.sort_arg_dict:
+ self.sort_arg_dict = dict = {}
+ std_list = dict.keys()
+ bad_list = {}
+ for word in self.sort_arg_dict_default.keys():
+ fragment = word
+ while fragment:
+ if not fragment:
+ break
+ if dict.has_key(fragment):
+ bad_list[fragment] = 0
+ break
+ dict[fragment] = self. \
+ sort_arg_dict_default[word]
+ fragment = fragment[:-1]
+ for word in bad_list.keys():
+ del dict[word]
+ return self.sort_arg_dict
+
+
+ def sort_stats(self, *field):
+ if not field:
+ self.fcn_list = 0
+ return self
+ if len(field) == 1 and type(field[0]) == type(1):
+ # Be compatible with old profiler
+ field = [ {-1: "stdname", \
+ 0:"calls", \
+ 1:"time", \
+ 2: "cumulative" } [ field[0] ] ]
+
+ sort_arg_defs = self.get_sort_arg_defs()
+ sort_tuple = ()
+ self.sort_type = ""
+ connector = ""
+ for word in field:
+ sort_tuple = sort_tuple + sort_arg_defs[word][0]
+ self.sort_type = self.sort_type + connector + \
+ sort_arg_defs[word][1]
+ connector = ", "
+
+ stats_list = []
+ for func in self.stats.keys():
+ cc, nc, tt, ct, callers = self.stats[func]
+ stats_list.append((cc, nc, tt, ct) + func_split(func) \
+ + (func_std_string(func), func,) )
+
+ stats_list.sort(TupleComp(sort_tuple).compare)
+
+ self.fcn_list = fcn_list = []
+ for tuple in stats_list:
+ fcn_list.append(tuple[-1])
+ return self
+
+
+ def reverse_order(self):
+ if self.fcn_list: self.fcn_list.reverse()
+ return self
+
+ def strip_dirs(self):
+ oldstats = self.stats
+ self.stats = newstats = {}
+ max_name_len = 0
+ for func in oldstats.keys():
+ cc, nc, tt, ct, callers = oldstats[func]
+ newfunc = func_strip_path(func)
+ if len(func_std_string(newfunc)) > max_name_len:
+ max_name_len = len(func_std_string(newfunc))
+ newcallers = {}
+ for func2 in callers.keys():
+ newcallers[func_strip_path(func2)] = \
+ callers[func2]
+
+ if newstats.has_key(newfunc):
+ newstats[newfunc] = add_func_stats( \
+ newstats[newfunc],\
+ (cc, nc, tt, ct, newcallers))
+ else:
+ newstats[newfunc] = (cc, nc, tt, ct, newcallers)
+ old_top = self.top_level
+ self.top_level = new_top = {}
+ for func in old_top.keys():
+ new_top[func_strip_path(func)] = None
+
+ self.max_name_len = max_name_len
+
+ self.fcn_list = None
+ self.all_callees = None
+ return self
+
+
+
+ def calc_callees(self):
+ if self.all_callees: return
+ self.all_callees = all_callees = {}
+ for func in self.stats.keys():
+ if not all_callees.has_key(func):
+ all_callees[func] = {}
+ cc, nc, tt, ct, callers = self.stats[func]
+ for func2 in callers.keys():
+ if not all_callees.has_key(func2):
+ all_callees[func2] = {}
+ all_callees[func2][func] = callers[func2]
+ return
+
+ #******************************************************************
+ # The following functions support actual printing of reports
+ #******************************************************************
+
+ # Optional "amount" is either a line count, or a percentage of lines.
+
+ def eval_print_amount(self, sel, list, msg):
+ new_list = list
+ if type(sel) == type(""):
+ new_list = []
+ for func in list:
+ if re.search(sel, func_std_string(func)):
+ new_list.append(func)
+ else:
+ count = len(list)
+ if type(sel) == type(1.0) and 0.0 <= sel < 1.0:
+ count = int (count * sel + .5)
+ new_list = list[:count]
+ elif type(sel) == type(1) and 0 <= sel < count:
+ count = sel
+ new_list = list[:count]
+ if len(list) != len(new_list):
+ msg = msg + " List reduced from " + `len(list)` \
+ + " to " + `len(new_list)` + \
+ " due to restriction <" + `sel` + ">\n"
+
+ return new_list, msg
+
+
+
+ def get_print_list(self, sel_list):
+ width = self.max_name_len
+ if self.fcn_list:
+ list = self.fcn_list[:]
+ msg = " Ordered by: " + self.sort_type + '\n'
+ else:
+ list = self.stats.keys()
+ msg = " Random listing order was used\n"
+
+ for selection in sel_list:
+ list,msg = self.eval_print_amount(selection, list, msg)
+
+ count = len(list)
+
+ if not list:
+ return 0, list
+ print msg
+ if count < len(self.stats):
+ width = 0
+ for func in list:
+ if len(func_std_string(func)) > width:
+ width = len(func_std_string(func))
+ return width+2, list
+
+ def print_stats(self, *amount):
+ for filename in self.files:
+ print filename
+ if self.files: print
+ indent = " "
+ for func in self.top_level.keys():
+ print indent, func_get_function_name(func)
+
+ print indent, self.total_calls, "function calls",
+ if self.total_calls != self.prim_calls:
+ print "(" + `self.prim_calls`, "primitive calls)",
+ print "in", fpformat.fix(self.total_tt, 3), "CPU seconds"
+ print
+ width, list = self.get_print_list(amount)
+ if list:
+ self.print_title()
+ for func in list:
+ self.print_line(func)
+ print
+ print
+ return self
+
+
+ def print_callees(self, *amount):
+ width, list = self.get_print_list(amount)
+ if list:
+ self.calc_callees()
+
+ self.print_call_heading(width, "called...")
+ for func in list:
+ if self.all_callees.has_key(func):
+ self.print_call_line(width, \
+ func, self.all_callees[func])
+ else:
+ self.print_call_line(width, func, {})
+ print
+ print
+ return self
+
+ def print_callers(self, *amount):
+ width, list = self.get_print_list(amount)
+ if list:
+ self.print_call_heading(width, "was called by...")
+ for func in list:
+ cc, nc, tt, ct, callers = self.stats[func]
+ self.print_call_line(width, func, callers)
+ print
+ print
+ return self
+
+ def print_call_heading(self, name_size, column_title):
+ print "Function ".ljust(name_size) + column_title
+
+
+ def print_call_line(self, name_size, source, call_dict):
+ print func_std_string(source).ljust(name_size),
+ if not call_dict:
+ print "--"
+ return
+ clist = call_dict.keys()
+ clist.sort()
+ name_size = name_size + 1
+ indent = ""
+ for func in clist:
+ name = func_std_string(func)
+ print indent*name_size + name + '(' \
+ + `call_dict[func]`+')', \
+ f8(self.stats[func][3])
+ indent = " "
+
+
+
+ def print_title(self):
+ print 'ncalls'.rjust(9),
+ print 'tottime'.rjust(8),
+ print 'percall'.rjust(8),
+ print 'cumtime'.rjust(8),
+ print 'percall'.rjust(8),
+ print 'filename:lineno(function)'
+
+
+ def print_line(self, func): # hack : should print percentages
+ cc, nc, tt, ct, callers = self.stats[func]
+ c = `nc`
+ if nc != cc:
+ c = c + '/' + `cc`
+ print c.rjust(9),
+ print f8(tt),
+ if nc == 0:
+ print ' '*8,
+ else:
+ print f8(tt/nc),
+ print f8(ct),
+ if cc == 0:
+ print ' '*8,
+ else:
+ print f8(ct/cc),
+ print func_std_string(func)
+
+
+ def ignore(self):
+ pass # has no return value, so use at end of line :-)
+
+
+class TupleComp:
+ """This class provides a generic function for comparing any two tuples.
+ Each instance records a list of tuple-indices (from most significant
+ to least significant), and sort direction (ascending or decending) for
+ each tuple-index. The compare functions can then be used as the function
+ argument to the system sort() function when a list of tuples need to be
+ sorted in the instances order."""
+
+ def __init__(self, comp_select_list):
+ self.comp_select_list = comp_select_list
+
+ def compare (self, left, right):
+ for index, direction in self.comp_select_list:
+ l = left[index]
+ r = right[index]
+ if l < r:
+ return -direction
+ if l > r:
+ return direction
+ return 0
+
+
+
+#**************************************************************************
+
+def func_strip_path(func_name):
+ file, line, name = func_name
+ return os.path.basename(file), line, name
+
+def func_get_function_name(func):
+ return func[2]
+
+def func_std_string(func_name): # match what old profile produced
+ file, line, name = func_name
+ return file + ":" + `line` + "(" + name + ")"
+
+def func_split(func_name):
+ return func_name
+
+#**************************************************************************
+# The following functions combine statists for pairs functions.
+# The bulk of the processing involves correctly handling "call" lists,
+# such as callers and callees.
+#**************************************************************************
+
+def add_func_stats(target, source):
+ """Add together all the stats for two profile entries."""
+ cc, nc, tt, ct, callers = source
+ t_cc, t_nc, t_tt, t_ct, t_callers = target
+ return (cc+t_cc, nc+t_nc, tt+t_tt, ct+t_ct, \
+ add_callers(t_callers, callers))
+
+
+def add_callers(target, source):
+ """Combine two caller lists in a single list."""
+ new_callers = {}
+ for func in target.keys():
+ new_callers[func] = target[func]
+ for func in source.keys():
+ if new_callers.has_key(func):
+ new_callers[func] = source[func] + new_callers[func]
+ else:
+ new_callers[func] = source[func]
+ return new_callers
+
+def count_calls(callers):
+ """Sum the caller statistics to get total number of calls received."""
+ nc = 0
+ for func in callers.keys():
+ nc = nc + callers[func]
+ return nc
+
+#**************************************************************************
+# The following functions support printing of reports
+#**************************************************************************
+
+def f8(x):
+ return fpformat.fix(x, 3).rjust(8)
+
+#**************************************************************************
+# Statistics browser added by ESR, April 2001
+#**************************************************************************
+
+if __name__ == '__main__':
+ import cmd
+ try:
+ import readline
+ except:
+ pass
+
+ class ProfileBrowser(cmd.Cmd):
+ def __init__(self, profile=None):
+ self.prompt = "% "
+ if profile:
+ self.stats = Stats(profile)
+ else:
+ self.stats = None
+
+ def generic(self, fn, line):
+ args = line.split()
+ processed = []
+ for term in args:
+ try:
+ processed.append(int(term))
+ continue
+ except ValueError:
+ pass
+ try:
+ frac = float(term)
+ if frac > 1 or frac < 0:
+ print "Fraction argument mus be in [0, 1]"
+ continue
+ processed.append(frac)
+ continue
+ except ValueError:
+ pass
+ processed.append(term)
+ if self.stats:
+ apply(getattr(self.stats, fn), processed)
+ else:
+ print "No statistics object is loaded."
+ return 0
+
+ def do_add(self, line):
+ self.stats.add(line)
+ return 0
+ def help_add(self):
+ print "Add profile info from given file to current stastics object."
+
+ def do_callees(self, line):
+ return self.generic('print_callees', line)
+ def help_callees(self):
+ print "Print callees statistics from the current stat object."
+
+ def do_callers(self, line):
+ return self.generic('print_callers', line)
+ def help_callers(self):
+ print "Print callers statistics from the current stat object."
+
+ def do_EOF(self, line):
+ print ""
+ return 1
+ def help_EOF(self):
+ print "Leave the profile brower."
+
+ def do_quit(self, line):
+ return 1
+ def help_quit(self):
+ print "Leave the profile brower."
+
+ def do_read(self, line):
+ if line:
+ try:
+ self.stats = Stats(line)
+ except IOError, args:
+ print args[1]
+ return
+ self.prompt = line + "% "
+ elif len(self.prompt > 2):
+ line = self.prompt[-2:]
+ else:
+ print "No statistics object is current -- cannot reload."
+ return 0
+ def help_read(self):
+ print "Read in profile data from a specified file."
+
+ def do_reverse(self, line):
+ self.stats.reverse_order()
+ return 0
+ def help_reverse(self):
+ print "Reverse the sort order of the profiling report."
+
+ def do_sort(self, line):
+ apply(self.stats.sort_stats, line.split())
+ return 0
+ def help_sort(self):
+ print "Sort profile data according to specified keys."
+
+ def do_stats(self, line):
+ return self.generic('print_stats', line)
+ def help_stats(self):
+ print "Print statistics from the current stat object."
+
+ def do_strip(self, line):
+ self.stats.strip_dirs()
+ return 0
+ def help_strip(self):
+ print "Strip leading path information from filenames in the report."
+
+ def postcmd(self, stop, line):
+ if stop:
+ return stop
+ return None
+
+ import sys
+ print "Welcome to the profile statistics browser."
+ if len(sys.argv) > 1:
+ initprofile = sys.argv[1]
+ else:
+ initprofile = None
+ try:
+ ProfileBrowser(initprofile).cmdloop()
+ print "Goodbye."
+ except KeyboardInterrupt:
+ pass
+
+# That's all, folks.
diff --git a/lib/jython/Lib/pyclbr.py b/lib/jython/Lib/pyclbr.py new file mode 100644 index 000000000..d7fa4b61c --- /dev/null +++ b/lib/jython/Lib/pyclbr.py @@ -0,0 +1,338 @@ +"""Parse a Python file and retrieve classes and methods.
+
+Parse enough of a Python file to recognize class and method
+definitions and to find out the superclasses of a class.
+
+The interface consists of a single function:
+ readmodule(module, path)
+module is the name of a Python module, path is an optional list of
+directories where the module is to be searched. If present, path is
+prepended to the system search path sys.path.
+The return value is a dictionary. The keys of the dictionary are
+the names of the classes defined in the module (including classes
+that are defined via the from XXX import YYY construct). The values
+are class instances of the class Class defined here.
+
+A class is described by the class Class in this module. Instances
+of this class have the following instance variables:
+ name -- the name of the class
+ super -- a list of super classes (Class instances)
+ methods -- a dictionary of methods
+ file -- the file in which the class was defined
+ lineno -- the line in the file on which the class statement occurred
+The dictionary of methods uses the method names as keys and the line
+numbers on which the method was defined as values.
+If the name of a super class is not recognized, the corresponding
+entry in the list of super classes is not a class instance but a
+string giving the name of the super class. Since import statements
+are recognized and imported modules are scanned as well, this
+shouldn't happen often.
+
+BUGS
+- Continuation lines are not dealt with at all.
+- While triple-quoted strings won't confuse it, lines that look like
+ def, class, import or "from ... import" stmts inside backslash-continued
+ single-quoted strings are treated like code. The expense of stopping
+ that isn't worth it.
+- Code that doesn't pass tabnanny or python -t will confuse it, unless
+ you set the module TABWIDTH vrbl (default 8) to the correct tab width
+ for the file.
+
+PACKAGE RELATED BUGS
+- If you have a package and a module inside that or another package
+ with the same name, module caching doesn't work properly since the
+ key is the base name of the module/package.
+- The only entry that is returned when you readmodule a package is a
+ __path__ whose value is a list which confuses certain class browsers.
+- When code does:
+ from package import subpackage
+ class MyClass(subpackage.SuperClass):
+ ...
+ It can't locate the parent. It probably needs to have the same
+ hairy logic that the import locator already does. (This logic
+ exists coded in Python in the freeze package.)
+"""
+
+import os
+import sys
+import imp
+import re
+import string
+
+__all__ = ["readmodule"]
+
+TABWIDTH = 8
+
+_getnext = re.compile(r"""
+ (?P<String>
+ \""" [^"\\]* (?:
+ (?: \\. | "(?!"") )
+ [^"\\]*
+ )*
+ \"""
+
+ | ''' [^'\\]* (?:
+ (?: \\. | '(?!'') )
+ [^'\\]*
+ )*
+ '''
+ )
+
+| (?P<Method>
+ ^
+ (?P<MethodIndent> [ \t]* )
+ def [ \t]+
+ (?P<MethodName> [a-zA-Z_] \w* )
+ [ \t]* \(
+ )
+
+| (?P<Class>
+ ^
+ (?P<ClassIndent> [ \t]* )
+ class [ \t]+
+ (?P<ClassName> [a-zA-Z_] \w* )
+ [ \t]*
+ (?P<ClassSupers> \( [^)\n]* \) )?
+ [ \t]* :
+ )
+
+| (?P<Import>
+ ^ import [ \t]+
+ (?P<ImportList> [^#;\n]+ )
+ )
+
+| (?P<ImportFrom>
+ ^ from [ \t]+
+ (?P<ImportFromPath>
+ [a-zA-Z_] \w*
+ (?:
+ [ \t]* \. [ \t]* [a-zA-Z_] \w*
+ )*
+ )
+ [ \t]+
+ import [ \t]+
+ (?P<ImportFromList> [^#;\n]+ )
+ )
+""", re.VERBOSE | re.DOTALL | re.MULTILINE).search
+
+_modules = {} # cache of modules we've seen
+
+# each Python class is represented by an instance of this class
+class Class:
+ '''Class to represent a Python class.'''
+ def __init__(self, module, name, super, file, lineno):
+ self.module = module
+ self.name = name
+ if super is None:
+ super = []
+ self.super = super
+ self.methods = {}
+ self.file = file
+ self.lineno = lineno
+
+ def _addmethod(self, name, lineno):
+ self.methods[name] = lineno
+
+class Function(Class):
+ '''Class to represent a top-level Python function'''
+ def __init__(self, module, name, file, lineno):
+ Class.__init__(self, module, name, None, file, lineno)
+ def _addmethod(self, name, lineno):
+ assert 0, "Function._addmethod() shouldn't be called"
+
+def readmodule(module, path=[], inpackage=0):
+ '''Backwards compatible interface.
+
+ Like readmodule_ex() but strips Function objects from the
+ resulting dictionary.'''
+
+ dict = readmodule_ex(module, path, inpackage)
+ res = {}
+ for key, value in dict.items():
+ if not isinstance(value, Function):
+ res[key] = value
+ return res
+
+def readmodule_ex(module, path=[], inpackage=0):
+ '''Read a module file and return a dictionary of classes.
+
+ Search for MODULE in PATH and sys.path, read and parse the
+ module and return a dictionary with one entry for each class
+ found in the module.'''
+
+ dict = {}
+
+ i = module.rfind('.')
+ if i >= 0:
+ # Dotted module name
+ package = module[:i].strip()
+ submodule = module[i+1:].strip()
+ parent = readmodule(package, path, inpackage)
+ child = readmodule(submodule, parent['__path__'], 1)
+ return child
+
+ if _modules.has_key(module):
+ # we've seen this module before...
+ return _modules[module]
+ if module in sys.builtin_module_names:
+ # this is a built-in module
+ _modules[module] = dict
+ return dict
+
+ # search the path for the module
+ f = None
+ if inpackage:
+ try:
+ f, file, (suff, mode, type) = \
+ imp.find_module(module, path)
+ except ImportError:
+ f = None
+ if f is None:
+ fullpath = list(path) + sys.path
+ f, file, (suff, mode, type) = imp.find_module(module, fullpath)
+ if type == imp.PKG_DIRECTORY:
+ dict['__path__'] = [file]
+ _modules[module] = dict
+ path = [file] + path
+ f, file, (suff, mode, type) = \
+ imp.find_module('__init__', [file])
+ if type != imp.PY_SOURCE:
+ # not Python source, can't do anything with this module
+ f.close()
+ _modules[module] = dict
+ return dict
+
+ _modules[module] = dict
+ imports = []
+ classstack = [] # stack of (class, indent) pairs
+ src = f.read()
+ f.close()
+
+ # To avoid having to stop the regexp at each newline, instead
+ # when we need a line number we simply string.count the number of
+ # newlines in the string since the last time we did this; i.e.,
+ # lineno = lineno + \
+ # string.count(src, '\n', last_lineno_pos, here)
+ # last_lineno_pos = here
+ countnl = string.count
+ lineno, last_lineno_pos = 1, 0
+ i = 0
+ while 1:
+ m = _getnext(src, i)
+ if not m:
+ break
+ start, i = m.span()
+
+ if m.start("Method") >= 0:
+ # found a method definition or function
+ thisindent = _indent(m.group("MethodIndent"))
+ meth_name = m.group("MethodName")
+ lineno = lineno + \
+ countnl(src, '\n',
+ last_lineno_pos, start)
+ last_lineno_pos = start
+ # close all classes indented at least as much
+ while classstack and \
+ classstack[-1][1] >= thisindent:
+ del classstack[-1]
+ if classstack:
+ # it's a class method
+ cur_class = classstack[-1][0]
+ cur_class._addmethod(meth_name, lineno)
+ else:
+ # it's a function
+ f = Function(module, meth_name,
+ file, lineno)
+ dict[meth_name] = f
+
+ elif m.start("String") >= 0:
+ pass
+
+ elif m.start("Class") >= 0:
+ # we found a class definition
+ thisindent = _indent(m.group("ClassIndent"))
+ # close all classes indented at least as much
+ while classstack and \
+ classstack[-1][1] >= thisindent:
+ del classstack[-1]
+ lineno = lineno + \
+ countnl(src, '\n', last_lineno_pos, start)
+ last_lineno_pos = start
+ class_name = m.group("ClassName")
+ inherit = m.group("ClassSupers")
+ if inherit:
+ # the class inherits from other classes
+ inherit = inherit[1:-1].strip()
+ names = []
+ for n in inherit.split(','):
+ n = n.strip()
+ if dict.has_key(n):
+ # we know this super class
+ n = dict[n]
+ else:
+ c = n.split('.')
+ if len(c) > 1:
+ # super class
+ # is of the
+ # form module.class:
+ # look in
+ # module for class
+ m = c[-2]
+ c = c[-1]
+ if _modules.has_key(m):
+ d = _modules[m]
+ if d.has_key(c):
+ n = d[c]
+ names.append(n)
+ inherit = names
+ # remember this class
+ cur_class = Class(module, class_name, inherit,
+ file, lineno)
+ dict[class_name] = cur_class
+ classstack.append((cur_class, thisindent))
+
+ elif m.start("Import") >= 0:
+ # import module
+ for n in m.group("ImportList").split(','):
+ n = n.strip()
+ try:
+ # recursively read the imported module
+ d = readmodule(n, path, inpackage)
+ except:
+ ##print 'module', n, 'not found'
+ pass
+
+ elif m.start("ImportFrom") >= 0:
+ # from module import stuff
+ mod = m.group("ImportFromPath")
+ names = m.group("ImportFromList").split(',')
+ try:
+ # recursively read the imported module
+ d = readmodule(mod, path, inpackage)
+ except:
+ ##print 'module', mod, 'not found'
+ continue
+ # add any classes that were defined in the
+ # imported module to our name space if they
+ # were mentioned in the list
+ for n in names:
+ n = n.strip()
+ if d.has_key(n):
+ dict[n] = d[n]
+ elif n == '*':
+ # only add a name if not
+ # already there (to mimic what
+ # Python does internally)
+ # also don't add names that
+ # start with _
+ for n in d.keys():
+ if n[0] != '_' and \
+ not dict.has_key(n):
+ dict[n] = d[n]
+ else:
+ assert 0, "regexp _getnext found something unexpected"
+
+ return dict
+
+def _indent(ws, _expandtabs=string.expandtabs):
+ return len(_expandtabs(ws, TABWIDTH))
diff --git a/lib/jython/Lib/quopri.py b/lib/jython/Lib/quopri.py new file mode 100644 index 000000000..be674af38 --- /dev/null +++ b/lib/jython/Lib/quopri.py @@ -0,0 +1,152 @@ +#! /usr/bin/env python
+
+"""Conversions to/from quoted-printable transport encoding as per RFC-1521."""
+
+# (Dec 1991 version).
+
+__all__ = ["encode","decode"]
+
+ESCAPE = '='
+MAXLINESIZE = 76
+HEX = '0123456789ABCDEF'
+
+def needsquoting(c, quotetabs):
+ """Decide whether a particular character needs to be quoted.
+
+ The 'quotetabs' flag indicates whether tabs should be quoted."""
+ if c == '\t':
+ return not quotetabs
+ return c == ESCAPE or not(' ' <= c <= '~')
+
+def quote(c):
+ """Quote a single character."""
+ i = ord(c)
+ return ESCAPE + HEX[i/16] + HEX[i%16]
+
+def encode(input, output, quotetabs):
+ """Read 'input', apply quoted-printable encoding, and write to 'output'.
+
+ 'input' and 'output' are files with readline() and write() methods.
+ The 'quotetabs' flag indicates whether tabs should be quoted.
+ """
+ while 1:
+ line = input.readline()
+ if not line:
+ break
+ new = ''
+ last = line[-1:]
+ if last == '\n':
+ line = line[:-1]
+ else:
+ last = ''
+ prev = ''
+ for c in line:
+ if needsquoting(c, quotetabs):
+ c = quote(c)
+ if len(new) + len(c) >= MAXLINESIZE:
+ output.write(new + ESCAPE + '\n')
+ new = ''
+ new = new + c
+ prev = c
+ if prev in (' ', '\t'):
+ output.write(new + ESCAPE + '\n\n')
+ else:
+ output.write(new + '\n')
+
+def decode(input, output):
+ """Read 'input', apply quoted-printable decoding, and write to 'output'.
+
+ 'input' and 'output' are files with readline() and write() methods."""
+ new = ''
+ while 1:
+ line = input.readline()
+ if not line: break
+ i, n = 0, len(line)
+ if n > 0 and line[n-1] == '\n':
+ partial = 0; n = n-1
+ # Strip trailing whitespace
+ while n > 0 and line[n-1] in " \t\r":
+ n = n-1
+ else:
+ partial = 1
+ while i < n:
+ c = line[i]
+ if c != ESCAPE:
+ new = new + c; i = i+1
+ elif i+1 == n and not partial:
+ partial = 1; break
+ elif i+1 < n and line[i+1] == ESCAPE:
+ new = new + ESCAPE; i = i+2
+ elif i+2 < n and ishex(line[i+1]) and ishex(line[i+2]):
+ new = new + chr(unhex(line[i+1:i+3])); i = i+3
+ else: # Bad escape sequence -- leave it in
+ new = new + c; i = i+1
+ if not partial:
+ output.write(new + '\n')
+ new = ''
+ if new:
+ output.write(new)
+
+def ishex(c):
+ """Return true if the character 'c' is a hexadecimal digit."""
+ return '0' <= c <= '9' or 'a' <= c <= 'f' or 'A' <= c <= 'F'
+
+def unhex(s):
+ """Get the integer value of a hexadecimal number."""
+ bits = 0
+ for c in s:
+ if '0' <= c <= '9':
+ i = ord('0')
+ elif 'a' <= c <= 'f':
+ i = ord('a')-10
+ elif 'A' <= c <= 'F':
+ i = ord('A')-10
+ else:
+ break
+ bits = bits*16 + (ord(c) - i)
+ return bits
+
+def test():
+ import sys
+ import getopt
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], 'td')
+ except getopt.error, msg:
+ sys.stdout = sys.stderr
+ print msg
+ print "usage: quopri [-t | -d] [file] ..."
+ print "-t: quote tabs"
+ print "-d: decode; default encode"
+ sys.exit(2)
+ deco = 0
+ tabs = 0
+ for o, a in opts:
+ if o == '-t': tabs = 1
+ if o == '-d': deco = 1
+ if tabs and deco:
+ sys.stdout = sys.stderr
+ print "-t and -d are mutually exclusive"
+ sys.exit(2)
+ if not args: args = ['-']
+ sts = 0
+ for file in args:
+ if file == '-':
+ fp = sys.stdin
+ else:
+ try:
+ fp = open(file)
+ except IOError, msg:
+ sys.stderr.write("%s: can't open (%s)\n" % (file, msg))
+ sts = 1
+ continue
+ if deco:
+ decode(fp, sys.stdout)
+ else:
+ encode(fp, sys.stdout, tabs)
+ if fp is not sys.stdin:
+ fp.close()
+ if sts:
+ sys.exit(sts)
+
+if __name__ == '__main__':
+ test()
diff --git a/lib/jython/Lib/random.py b/lib/jython/Lib/random.py new file mode 100644 index 000000000..6ba9f58a1 --- /dev/null +++ b/lib/jython/Lib/random.py @@ -0,0 +1,663 @@ +"""Random variable generators.
+
+ integers
+ --------
+ uniform within range
+
+ sequences
+ ---------
+ pick random element
+ generate random permutation
+
+ distributions on the real line:
+ ------------------------------
+ uniform
+ normal (Gaussian)
+ lognormal
+ negative exponential
+ gamma
+ beta
+
+ distributions on the circle (angles 0 to 2pi)
+ ---------------------------------------------
+ circular uniform
+ von Mises
+
+Translated from anonymously contributed C/C++ source.
+
+Multi-threading note: the random number generator used here is not thread-
+safe; it is possible that two calls return the same random value. However,
+you can instantiate a different instance of Random() in each thread to get
+generators that don't share state, then use .setstate() and .jumpahead() to
+move the generators to disjoint segments of the full period. For example,
+
+def create_generators(num, delta, firstseed=None):
+ ""\"Return list of num distinct generators.
+ Each generator has its own unique segment of delta elements from
+ Random.random()'s full period.
+ Seed the first generator with optional arg firstseed (default is
+ None, to seed from current time).
+ ""\"
+
+ from random import Random
+ g = Random(firstseed)
+ result = [g]
+ for i in range(num - 1):
+ laststate = g.getstate()
+ g = Random()
+ g.setstate(laststate)
+ g.jumpahead(delta)
+ result.append(g)
+ return result
+
+gens = create_generators(10, 1000000)
+
+That creates 10 distinct generators, which can be passed out to 10 distinct
+threads. The generators don't share state so can be called safely in
+parallel. So long as no thread calls its g.random() more than a million
+times (the second argument to create_generators), the sequences seen by
+each thread will not overlap.
+
+The period of the underlying Wichmann-Hill generator is 6,953,607,871,644,
+and that limits how far this technique can be pushed.
+
+Just for fun, note that since we know the period, .jumpahead() can also be
+used to "move backward in time":
+
+>>> g = Random(42) # arbitrary
+>>> g.random()
+0.25420336316883324
+>>> g.jumpahead(6953607871644L - 1) # move *back* one
+>>> g.random()
+0.25420336316883324
+"""
+# XXX The docstring sucks.
+
+from math import log as _log, exp as _exp, pi as _pi, e as _e
+from math import sqrt as _sqrt, acos as _acos, cos as _cos, sin as _sin
+
+__all__ = ["Random","seed","random","uniform","randint","choice",
+ "randrange","shuffle","normalvariate","lognormvariate",
+ "cunifvariate","expovariate","vonmisesvariate","gammavariate",
+ "stdgamma","gauss","betavariate","paretovariate","weibullvariate",
+ "getstate","setstate","jumpahead","whseed"]
+
+def _verify(name, computed, expected):
+ if abs(computed - expected) > 1e-7:
+ raise ValueError(
+ "computed value for %s deviates too much "
+ "(computed %g, expected %g)" % (name, computed, expected))
+
+NV_MAGICCONST = 4 * _exp(-0.5)/_sqrt(2.0)
+_verify('NV_MAGICCONST', NV_MAGICCONST, 1.71552776992141)
+
+TWOPI = 2.0*_pi
+_verify('TWOPI', TWOPI, 6.28318530718)
+
+LOG4 = _log(4.0)
+_verify('LOG4', LOG4, 1.38629436111989)
+
+SG_MAGICCONST = 1.0 + _log(4.5)
+_verify('SG_MAGICCONST', SG_MAGICCONST, 2.50407739677627)
+
+del _verify
+
+# Translated by Guido van Rossum from C source provided by
+# Adrian Baddeley.
+
+class Random:
+
+ VERSION = 1 # used by getstate/setstate
+
+ def __init__(self, x=None):
+ """Initialize an instance.
+
+ Optional argument x controls seeding, as for Random.seed().
+ """
+
+ self.seed(x)
+ self.gauss_next = None
+
+## -------------------- core generator -------------------
+
+ # Specific to Wichmann-Hill generator. Subclasses wishing to use a
+ # different core generator should override the seed(), random(),
+ # getstate(), setstate() and jumpahead() methods.
+
+ def seed(self, a=None):
+ """Initialize internal state from hashable object.
+
+ None or no argument seeds from current time.
+
+ If a is not None or an int or long, hash(a) is used instead.
+
+ If a is an int or long, a is used directly. Distinct values between
+ 0 and 27814431486575L inclusive are guaranteed to yield distinct
+ internal states (this guarantee is specific to the default
+ Wichmann-Hill generator).
+ """
+
+ if a is None:
+ # Initialize from current time
+ import time
+ a = long(time.time() * 256)
+
+ if type(a) not in (type(3), type(3L)):
+ a = hash(a)
+
+ a, x = divmod(a, 30268)
+ a, y = divmod(a, 30306)
+ a, z = divmod(a, 30322)
+ self._seed = int(x)+1, int(y)+1, int(z)+1
+
+ def random(self):
+ """Get the next random number in the range [0.0, 1.0)."""
+
+ # Wichman-Hill random number generator.
+ #
+ # Wichmann, B. A. & Hill, I. D. (1982)
+ # Algorithm AS 183:
+ # An efficient and portable pseudo-random number generator
+ # Applied Statistics 31 (1982) 188-190
+ #
+ # see also:
+ # Correction to Algorithm AS 183
+ # Applied Statistics 33 (1984) 123
+ #
+ # McLeod, A. I. (1985)
+ # A remark on Algorithm AS 183
+ # Applied Statistics 34 (1985),198-200
+
+ # This part is thread-unsafe:
+ # BEGIN CRITICAL SECTION
+ x, y, z = self._seed
+ x = (171 * x) % 30269
+ y = (172 * y) % 30307
+ z = (170 * z) % 30323
+ self._seed = x, y, z
+ # END CRITICAL SECTION
+
+ # Note: on a platform using IEEE-754 double arithmetic, this can
+ # never return 0.0 (asserted by Tim; proof too long for a comment).
+ return (x/30269.0 + y/30307.0 + z/30323.0) % 1.0
+
+ def getstate(self):
+ """Return internal state; can be passed to setstate() later."""
+ return self.VERSION, self._seed, self.gauss_next
+
+ def setstate(self, state):
+ """Restore internal state from object returned by getstate()."""
+ version = state[0]
+ if version == 1:
+ version, self._seed, self.gauss_next = state
+ else:
+ raise ValueError("state with version %s passed to "
+ "Random.setstate() of version %s" %
+ (version, self.VERSION))
+
+ def jumpahead(self, n):
+ """Act as if n calls to random() were made, but quickly.
+
+ n is an int, greater than or equal to 0.
+
+ Example use: If you have 2 threads and know that each will
+ consume no more than a million random numbers, create two Random
+ objects r1 and r2, then do
+ r2.setstate(r1.getstate())
+ r2.jumpahead(1000000)
+ Then r1 and r2 will use guaranteed-disjoint segments of the full
+ period.
+ """
+
+ if not n >= 0:
+ raise ValueError("n must be >= 0")
+ x, y, z = self._seed
+ x = int(x * pow(171, n, 30269)) % 30269
+ y = int(y * pow(172, n, 30307)) % 30307
+ z = int(z * pow(170, n, 30323)) % 30323
+ self._seed = x, y, z
+
+ def __whseed(self, x=0, y=0, z=0):
+ """Set the Wichmann-Hill seed from (x, y, z).
+
+ These must be integers in the range [0, 256).
+ """
+
+ if not type(x) == type(y) == type(z) == type(0):
+ raise TypeError('seeds must be integers')
+ if not (0 <= x < 256 and 0 <= y < 256 and 0 <= z < 256):
+ raise ValueError('seeds must be in range(0, 256)')
+ if 0 == x == y == z:
+ # Initialize from current time
+ import time
+ t = long(time.time() * 256)
+ t = int((t&0xffffff) ^ (t>>24))
+ t, x = divmod(t, 256)
+ t, y = divmod(t, 256)
+ t, z = divmod(t, 256)
+ # Zero is a poor seed, so substitute 1
+ self._seed = (x or 1, y or 1, z or 1)
+
+ def whseed(self, a=None):
+ """Seed from hashable object's hash code.
+
+ None or no argument seeds from current time. It is not guaranteed
+ that objects with distinct hash codes lead to distinct internal
+ states.
+
+ This is obsolete, provided for compatibility with the seed routine
+ used prior to Python 2.1. Use the .seed() method instead.
+ """
+
+ if a is None:
+ self.__whseed()
+ return
+ a = hash(a)
+ a, x = divmod(a, 256)
+ a, y = divmod(a, 256)
+ a, z = divmod(a, 256)
+ x = (x + a) % 256 or 1
+ y = (y + a) % 256 or 1
+ z = (z + a) % 256 or 1
+ self.__whseed(x, y, z)
+
+## ---- Methods below this point do not need to be overridden when
+## ---- subclassing for the purpose of using a different core generator.
+
+## -------------------- pickle support -------------------
+
+ def __getstate__(self): # for pickle
+ return self.getstate()
+
+ def __setstate__(self, state): # for pickle
+ self.setstate(state)
+
+## -------------------- integer methods -------------------
+
+ def randrange(self, start, stop=None, step=1, int=int, default=None):
+ """Choose a random item from range(start, stop[, step]).
+
+ This fixes the problem with randint() which includes the
+ endpoint; in Python this is usually not what you want.
+ Do not supply the 'int' and 'default' arguments.
+ """
+
+ # This code is a bit messy to make it fast for the
+ # common case while still doing adequate error checking
+ istart = int(start)
+ if istart != start:
+ raise ValueError, "non-integer arg 1 for randrange()"
+ if stop is default:
+ if istart > 0:
+ return int(self.random() * istart)
+ raise ValueError, "empty range for randrange()"
+ istop = int(stop)
+ if istop != stop:
+ raise ValueError, "non-integer stop for randrange()"
+ if step == 1:
+ if istart < istop:
+ return istart + int(self.random() *
+ (istop - istart))
+ raise ValueError, "empty range for randrange()"
+ istep = int(step)
+ if istep != step:
+ raise ValueError, "non-integer step for randrange()"
+ if istep > 0:
+ n = (istop - istart + istep - 1) / istep
+ elif istep < 0:
+ n = (istop - istart + istep + 1) / istep
+ else:
+ raise ValueError, "zero step for randrange()"
+
+ if n <= 0:
+ raise ValueError, "empty range for randrange()"
+ return istart + istep*int(self.random() * n)
+
+ def randint(self, a, b):
+ """Return random integer in range [a, b], including both end points.
+
+ (Deprecated; use randrange(a, b+1).)
+ """
+
+ return self.randrange(a, b+1)
+
+## -------------------- sequence methods -------------------
+
+ def choice(self, seq):
+ """Choose a random element from a non-empty sequence."""
+ return seq[int(self.random() * len(seq))]
+
+ def shuffle(self, x, random=None, int=int):
+ """x, random=random.random -> shuffle list x in place; return None.
+
+ Optional arg random is a 0-argument function returning a random
+ float in [0.0, 1.0); by default, the standard random.random.
+
+ Note that for even rather small len(x), the total number of
+ permutations of x is larger than the period of most random number
+ generators; this implies that "most" permutations of a long
+ sequence can never be generated.
+ """
+
+ if random is None:
+ random = self.random
+ for i in xrange(len(x)-1, 0, -1):
+ # pick an element in x[:i+1] with which to exchange x[i]
+ j = int(random() * (i+1))
+ x[i], x[j] = x[j], x[i]
+
+## -------------------- real-valued distributions -------------------
+
+## -------------------- uniform distribution -------------------
+
+ def uniform(self, a, b):
+ """Get a random number in the range [a, b)."""
+ return a + (b-a) * self.random()
+
+## -------------------- normal distribution --------------------
+
+ def normalvariate(self, mu, sigma):
+ # mu = mean, sigma = standard deviation
+
+ # Uses Kinderman and Monahan method. Reference: Kinderman,
+ # A.J. and Monahan, J.F., "Computer generation of random
+ # variables using the ratio of uniform deviates", ACM Trans
+ # Math Software, 3, (1977), pp257-260.
+
+ random = self.random
+ while 1:
+ u1 = random()
+ u2 = random()
+ z = NV_MAGICCONST*(u1-0.5)/u2
+ zz = z*z/4.0
+ if zz <= -_log(u2):
+ break
+ return mu + z*sigma
+
+## -------------------- lognormal distribution --------------------
+
+ def lognormvariate(self, mu, sigma):
+ return _exp(self.normalvariate(mu, sigma))
+
+## -------------------- circular uniform --------------------
+
+ def cunifvariate(self, mean, arc):
+ # mean: mean angle (in radians between 0 and pi)
+ # arc: range of distribution (in radians between 0 and pi)
+
+ return (mean + arc * (self.random() - 0.5)) % _pi
+
+## -------------------- exponential distribution --------------------
+
+ def expovariate(self, lambd):
+ # lambd: rate lambd = 1/mean
+ # ('lambda' is a Python reserved word)
+
+ random = self.random
+ u = random()
+ while u <= 1e-7:
+ u = random()
+ return -_log(u)/lambd
+
+## -------------------- von Mises distribution --------------------
+
+ def vonmisesvariate(self, mu, kappa):
+ # mu: mean angle (in radians between 0 and 2*pi)
+ # kappa: concentration parameter kappa (>= 0)
+ # if kappa = 0 generate uniform random angle
+
+ # Based upon an algorithm published in: Fisher, N.I.,
+ # "Statistical Analysis of Circular Data", Cambridge
+ # University Press, 1993.
+
+ # Thanks to Magnus Kessler for a correction to the
+ # implementation of step 4.
+
+ random = self.random
+ if kappa <= 1e-6:
+ return TWOPI * random()
+
+ a = 1.0 + _sqrt(1.0 + 4.0 * kappa * kappa)
+ b = (a - _sqrt(2.0 * a))/(2.0 * kappa)
+ r = (1.0 + b * b)/(2.0 * b)
+
+ while 1:
+ u1 = random()
+
+ z = _cos(_pi * u1)
+ f = (1.0 + r * z)/(r + z)
+ c = kappa * (r - f)
+
+ u2 = random()
+
+ if not (u2 >= c * (2.0 - c) and u2 > c * _exp(1.0 - c)):
+ break
+
+ u3 = random()
+ if u3 > 0.5:
+ theta = (mu % TWOPI) + _acos(f)
+ else:
+ theta = (mu % TWOPI) - _acos(f)
+
+ return theta
+
+## -------------------- gamma distribution --------------------
+
+ def gammavariate(self, alpha, beta):
+ # beta times standard gamma
+ ainv = _sqrt(2.0 * alpha - 1.0)
+ return beta * self.stdgamma(alpha, ainv, alpha - LOG4, alpha + ainv)
+
+ def stdgamma(self, alpha, ainv, bbb, ccc):
+ # ainv = sqrt(2 * alpha - 1)
+ # bbb = alpha - log(4)
+ # ccc = alpha + ainv
+
+ random = self.random
+ if alpha <= 0.0:
+ raise ValueError, 'stdgamma: alpha must be > 0.0'
+
+ if alpha > 1.0:
+
+ # Uses R.C.H. Cheng, "The generation of Gamma
+ # variables with non-integral shape parameters",
+ # Applied Statistics, (1977), 26, No. 1, p71-74
+
+ while 1:
+ u1 = random()
+ u2 = random()
+ v = _log(u1/(1.0-u1))/ainv
+ x = alpha*_exp(v)
+ z = u1*u1*u2
+ r = bbb+ccc*v-x
+ if r + SG_MAGICCONST - 4.5*z >= 0.0 or r >= _log(z):
+ return x
+
+ elif alpha == 1.0:
+ # expovariate(1)
+ u = random()
+ while u <= 1e-7:
+ u = random()
+ return -_log(u)
+
+ else: # alpha is between 0 and 1 (exclusive)
+
+ # Uses ALGORITHM GS of Statistical Computing - Kennedy & Gentle
+
+ while 1:
+ u = random()
+ b = (_e + alpha)/_e
+ p = b*u
+ if p <= 1.0:
+ x = pow(p, 1.0/alpha)
+ else:
+ # p > 1
+ x = -_log((b-p)/alpha)
+ u1 = random()
+ if not (((p <= 1.0) and (u1 > _exp(-x))) or
+ ((p > 1) and (u1 > pow(x, alpha - 1.0)))):
+ break
+ return x
+
+
+## -------------------- Gauss (faster alternative) --------------------
+
+ def gauss(self, mu, sigma):
+
+ # When x and y are two variables from [0, 1), uniformly
+ # distributed, then
+ #
+ # cos(2*pi*x)*sqrt(-2*log(1-y))
+ # sin(2*pi*x)*sqrt(-2*log(1-y))
+ #
+ # are two *independent* variables with normal distribution
+ # (mu = 0, sigma = 1).
+ # (Lambert Meertens)
+ # (corrected version; bug discovered by Mike Miller, fixed by LM)
+
+ # Multithreading note: When two threads call this function
+ # simultaneously, it is possible that they will receive the
+ # same return value. The window is very small though. To
+ # avoid this, you have to use a lock around all calls. (I
+ # didn't want to slow this down in the serial case by using a
+ # lock here.)
+
+ random = self.random
+ z = self.gauss_next
+ self.gauss_next = None
+ if z is None:
+ x2pi = random() * TWOPI
+ g2rad = _sqrt(-2.0 * _log(1.0 - random()))
+ z = _cos(x2pi) * g2rad
+ self.gauss_next = _sin(x2pi) * g2rad
+
+ return mu + z*sigma
+
+## -------------------- beta --------------------
+## See
+## http://sourceforge.net/bugs/?func=detailbug&bug_id=130030&group_id=5470
+## for Ivan Frohne's insightful analysis of why the original implementation:
+##
+## def betavariate(self, alpha, beta):
+## # Discrete Event Simulation in C, pp 87-88.
+##
+## y = self.expovariate(alpha)
+## z = self.expovariate(1.0/beta)
+## return z/(y+z)
+##
+## was dead wrong, and how it probably got that way.
+
+ def betavariate(self, alpha, beta):
+ # This version due to Janne Sinkkonen, and matches all the std
+ # texts (e.g., Knuth Vol 2 Ed 3 pg 134 "the beta distribution").
+ y = self.gammavariate(alpha, 1.)
+ if y == 0:
+ return 0.0
+ else:
+ return y / (y + self.gammavariate(beta, 1.))
+
+## -------------------- Pareto --------------------
+
+ def paretovariate(self, alpha):
+ # Jain, pg. 495
+
+ u = self.random()
+ return 1.0 / pow(u, 1.0/alpha)
+
+## -------------------- Weibull --------------------
+
+ def weibullvariate(self, alpha, beta):
+ # Jain, pg. 499; bug fix courtesy Bill Arms
+
+ u = self.random()
+ return alpha * pow(-_log(u), 1.0/beta)
+
+## -------------------- test program --------------------
+
+def _test_generator(n, funccall):
+ import time
+ print n, 'times', funccall
+ code = compile(funccall, funccall, 'eval')
+ sum = 0.0
+ sqsum = 0.0
+ smallest = 1e10
+ largest = -1e10
+ t0 = time.time()
+ for i in range(n):
+ x = eval(code)
+ sum = sum + x
+ sqsum = sqsum + x*x
+ smallest = min(x, smallest)
+ largest = max(x, largest)
+ t1 = time.time()
+ print round(t1-t0, 3), 'sec,',
+ avg = sum/n
+ stddev = _sqrt(sqsum/n - avg*avg)
+ print 'avg %g, stddev %g, min %g, max %g' % \
+ (avg, stddev, smallest, largest)
+
+def _test(N=200):
+ print 'TWOPI =', TWOPI
+ print 'LOG4 =', LOG4
+ print 'NV_MAGICCONST =', NV_MAGICCONST
+ print 'SG_MAGICCONST =', SG_MAGICCONST
+ _test_generator(N, 'random()')
+ _test_generator(N, 'normalvariate(0.0, 1.0)')
+ _test_generator(N, 'lognormvariate(0.0, 1.0)')
+ _test_generator(N, 'cunifvariate(0.0, 1.0)')
+ _test_generator(N, 'expovariate(1.0)')
+ _test_generator(N, 'vonmisesvariate(0.0, 1.0)')
+ _test_generator(N, 'gammavariate(0.5, 1.0)')
+ _test_generator(N, 'gammavariate(0.9, 1.0)')
+ _test_generator(N, 'gammavariate(1.0, 1.0)')
+ _test_generator(N, 'gammavariate(2.0, 1.0)')
+ _test_generator(N, 'gammavariate(20.0, 1.0)')
+ _test_generator(N, 'gammavariate(200.0, 1.0)')
+ _test_generator(N, 'gauss(0.0, 1.0)')
+ _test_generator(N, 'betavariate(3.0, 3.0)')
+ _test_generator(N, 'paretovariate(1.0)')
+ _test_generator(N, 'weibullvariate(1.0, 1.0)')
+
+ # Test jumpahead.
+ s = getstate()
+ jumpahead(N)
+ r1 = random()
+ # now do it the slow way
+ setstate(s)
+ for i in range(N):
+ random()
+ r2 = random()
+ if r1 != r2:
+ raise ValueError("jumpahead test failed " + `(N, r1, r2)`)
+
+# Create one instance, seeded from current time, and export its methods
+# as module-level functions. The functions are not threadsafe, and state
+# is shared across all uses (both in the user's code and in the Python
+# libraries), but that's fine for most programs and is easier for the
+# casual user than making them instantiate their own Random() instance.
+_inst = Random()
+seed = _inst.seed
+random = _inst.random
+uniform = _inst.uniform
+randint = _inst.randint
+choice = _inst.choice
+randrange = _inst.randrange
+shuffle = _inst.shuffle
+normalvariate = _inst.normalvariate
+lognormvariate = _inst.lognormvariate
+cunifvariate = _inst.cunifvariate
+expovariate = _inst.expovariate
+vonmisesvariate = _inst.vonmisesvariate
+gammavariate = _inst.gammavariate
+stdgamma = _inst.stdgamma
+gauss = _inst.gauss
+betavariate = _inst.betavariate
+paretovariate = _inst.paretovariate
+weibullvariate = _inst.weibullvariate
+getstate = _inst.getstate
+setstate = _inst.setstate
+jumpahead = _inst.jumpahead
+whseed = _inst.whseed
+
+if __name__ == '__main__':
+ _test()
diff --git a/lib/jython/Lib/re.py b/lib/jython/Lib/re.py new file mode 100644 index 000000000..a2d386d18 --- /dev/null +++ b/lib/jython/Lib/re.py @@ -0,0 +1,11 @@ +
+__all__ = [ "match", "search", "sub", "subn", "split", "findall",
+ "compile", "purge", "template", "escape", "I", "L", "M", "S", "X",
+ "U", "IGNORECASE", "LOCALE", "MULTILINE", "DOTALL", "VERBOSE",
+ "UNICODE", "error" ]
+
+import sre, sys
+module = sys.modules['re']
+for name in __all__:
+ setattr(module, name, getattr(sre, name))
+
diff --git a/lib/jython/Lib/reconvert.py b/lib/jython/Lib/reconvert.py new file mode 100644 index 000000000..0860255c3 --- /dev/null +++ b/lib/jython/Lib/reconvert.py @@ -0,0 +1,188 @@ +#! /usr/bin/env python1.5
+
+r"""Convert old ("regex") regular expressions to new syntax ("re").
+
+When imported as a module, there are two functions, with their own
+strings:
+
+ convert(s, syntax=None) -- convert a regex regular expression to re syntax
+
+ quote(s) -- return a quoted string literal
+
+When used as a script, read a Python string literal (or any other
+expression evaluating to a string) from stdin, and write the
+translated expression to stdout as a string literal. Unless stdout is
+a tty, no trailing \n is written to stdout. This is done so that it
+can be used with Emacs C-U M-| (shell-command-on-region with argument
+which filters the region through the shell command).
+
+No attempt has been made at coding for performance.
+
+Translation table...
+
+ \( ( (unless RE_NO_BK_PARENS set)
+ \) ) (unless RE_NO_BK_PARENS set)
+ \| | (unless RE_NO_BK_VBAR set)
+ \< \b (not quite the same, but alla...)
+ \> \b (not quite the same, but alla...)
+ \` \A
+ \' \Z
+
+Not translated...
+
+ .
+ ^
+ $
+ *
+ + (unless RE_BK_PLUS_QM set, then to \+)
+ ? (unless RE_BK_PLUS_QM set, then to \?)
+ \
+ \b
+ \B
+ \w
+ \W
+ \1 ... \9
+
+Special cases...
+
+ Non-printable characters are always replaced by their 3-digit
+ escape code (except \t, \n, \r, which use mnemonic escapes)
+
+ Newline is turned into | when RE_NEWLINE_OR is set
+
+XXX To be done...
+
+ [...] (different treatment of backslashed items?)
+ [^...] (different treatment of backslashed items?)
+ ^ $ * + ? (in some error contexts these are probably treated differently)
+ \vDD \DD (in the regex docs but only works when RE_ANSI_HEX set)
+
+"""
+
+
+import regex
+from regex_syntax import * # RE_*
+
+__all__ = ["convert","quote"]
+
+# Default translation table
+mastertable = {
+ r'\<': r'\b',
+ r'\>': r'\b',
+ r'\`': r'\A',
+ r'\'': r'\Z',
+ r'\(': '(',
+ r'\)': ')',
+ r'\|': '|',
+ '(': r'\(',
+ ')': r'\)',
+ '|': r'\|',
+ '\t': r'\t',
+ '\n': r'\n',
+ '\r': r'\r',
+}
+
+
+def convert(s, syntax=None):
+ """Convert a regex regular expression to re syntax.
+
+ The first argument is the regular expression, as a string object,
+ just like it would be passed to regex.compile(). (I.e., pass the
+ actual string object -- string quotes must already have been
+ removed and the standard escape processing has already been done,
+ e.g. by eval().)
+
+ The optional second argument is the regex syntax variant to be
+ used. This is an integer mask as passed to regex.set_syntax();
+ the flag bits are defined in regex_syntax. When not specified, or
+ when None is given, the current regex syntax mask (as retrieved by
+ regex.get_syntax()) is used -- which is 0 by default.
+
+ The return value is a regular expression, as a string object that
+ could be passed to re.compile(). (I.e., no string quotes have
+ been added -- use quote() below, or repr().)
+
+ The conversion is not always guaranteed to be correct. More
+ syntactical analysis should be performed to detect borderline
+ cases and decide what to do with them. For example, 'x*?' is not
+ translated correctly.
+
+ """
+ table = mastertable.copy()
+ if syntax is None:
+ syntax = regex.get_syntax()
+ if syntax & RE_NO_BK_PARENS:
+ del table[r'\('], table[r'\)']
+ del table['('], table[')']
+ if syntax & RE_NO_BK_VBAR:
+ del table[r'\|']
+ del table['|']
+ if syntax & RE_BK_PLUS_QM:
+ table['+'] = r'\+'
+ table['?'] = r'\?'
+ table[r'\+'] = '+'
+ table[r'\?'] = '?'
+ if syntax & RE_NEWLINE_OR:
+ table['\n'] = '|'
+ res = ""
+
+ i = 0
+ end = len(s)
+ while i < end:
+ c = s[i]
+ i = i+1
+ if c == '\\':
+ c = s[i]
+ i = i+1
+ key = '\\' + c
+ key = table.get(key, key)
+ res = res + key
+ else:
+ c = table.get(c, c)
+ res = res + c
+ return res
+
+
+def quote(s, quote=None):
+ """Convert a string object to a quoted string literal.
+
+ This is similar to repr() but will return a "raw" string (r'...'
+ or r"...") when the string contains backslashes, instead of
+ doubling all backslashes. The resulting string does *not* always
+ evaluate to the same string as the original; however it will do
+ just the right thing when passed into re.compile().
+
+ The optional second argument forces the string quote; it must be
+ a single character which is a valid Python string quote.
+
+ """
+ if quote is None:
+ q = "'"
+ altq = "'"
+ if q in s and altq not in s:
+ q = altq
+ else:
+ assert quote in ('"', "'")
+ q = quote
+ res = q
+ for c in s:
+ if c == q: c = '\\' + c
+ elif c < ' ' or c > '~': c = "\\%03o" % ord(c)
+ res = res + c
+ res = res + q
+ if '\\' in res:
+ res = 'r' + res
+ return res
+
+
+def main():
+ """Main program -- called when run as a script."""
+ import sys
+ s = eval(sys.stdin.read())
+ sys.stdout.write(quote(convert(s)))
+ if sys.stdout.isatty():
+ sys.stdout.write("\n")
+
+
+if __name__ == '__main__':
+ main()
diff --git a/lib/jython/Lib/repr.py b/lib/jython/Lib/repr.py new file mode 100644 index 000000000..e152bfd6c --- /dev/null +++ b/lib/jython/Lib/repr.py @@ -0,0 +1,95 @@ +"""Redo the `...` (representation) but with limits on most sizes."""
+
+__all__ = ["Repr","repr"]
+
+class Repr:
+ def __init__(self):
+ self.maxlevel = 6
+ self.maxtuple = 6
+ self.maxlist = 6
+ self.maxdict = 4
+ self.maxstring = 30
+ self.maxlong = 40
+ self.maxother = 20
+ def repr(self, x):
+ return self.repr1(x, self.maxlevel)
+ def repr1(self, x, level):
+ typename = `type(x)`[7:-2] # "<type '......'>"
+ if ' ' in typename:
+ parts = typename.split()
+ typename = '_'.join(parts)
+ if hasattr(self, 'repr_' + typename):
+ return getattr(self, 'repr_' + typename)(x, level)
+ else:
+ s = `x`
+ if len(s) > self.maxother:
+ i = max(0, (self.maxother-3)/2)
+ j = max(0, self.maxother-3-i)
+ s = s[:i] + '...' + s[len(s)-j:]
+ return s
+ def repr_tuple(self, x, level):
+ n = len(x)
+ if n == 0: return '()'
+ if level <= 0: return '(...)'
+ s = ''
+ for i in range(min(n, self.maxtuple)):
+ if s: s = s + ', '
+ s = s + self.repr1(x[i], level-1)
+ if n > self.maxtuple: s = s + ', ...'
+ elif n == 1: s = s + ','
+ return '(' + s + ')'
+ def repr_list(self, x, level):
+ n = len(x)
+ if n == 0: return '[]'
+ if level <= 0: return '[...]'
+ s = ''
+ for i in range(min(n, self.maxlist)):
+ if s: s = s + ', '
+ s = s + self.repr1(x[i], level-1)
+ if n > self.maxlist: s = s + ', ...'
+ return '[' + s + ']'
+ def repr_dictionary(self, x, level):
+ n = len(x)
+ if n == 0: return '{}'
+ if level <= 0: return '{...}'
+ s = ''
+ keys = x.keys()
+ keys.sort()
+ for i in range(min(n, self.maxdict)):
+ if s: s = s + ', '
+ key = keys[i]
+ s = s + self.repr1(key, level-1)
+ s = s + ': ' + self.repr1(x[key], level-1)
+ if n > self.maxdict: s = s + ', ...'
+ return '{' + s + '}'
+ def repr_string(self, x, level):
+ s = `x[:self.maxstring]`
+ if len(s) > self.maxstring:
+ i = max(0, (self.maxstring-3)/2)
+ j = max(0, self.maxstring-3-i)
+ s = `x[:i] + x[len(x)-j:]`
+ s = s[:i] + '...' + s[len(s)-j:]
+ return s
+ def repr_long_int(self, x, level):
+ s = `x` # XXX Hope this isn't too slow...
+ if len(s) > self.maxlong:
+ i = max(0, (self.maxlong-3)/2)
+ j = max(0, self.maxlong-3-i)
+ s = s[:i] + '...' + s[len(s)-j:]
+ return s
+ def repr_instance(self, x, level):
+ try:
+ s = `x`
+ # Bugs in x.__repr__() can cause arbitrary
+ # exceptions -- then make up something
+ except:
+ return '<' + x.__class__.__name__ + ' instance at ' + \
+ hex(id(x))[2:] + '>'
+ if len(s) > self.maxstring:
+ i = max(0, (self.maxstring-3)/2)
+ j = max(0, self.maxstring-3-i)
+ s = s[:i] + '...' + s[len(s)-j:]
+ return s
+
+aRepr = Repr()
+repr = aRepr.repr
diff --git a/lib/jython/Lib/rfc822.py b/lib/jython/Lib/rfc822.py new file mode 100644 index 000000000..95c39b062 --- /dev/null +++ b/lib/jython/Lib/rfc822.py @@ -0,0 +1,965 @@ +"""RFC-822 message manipulation class.
+
+XXX This is only a very rough sketch of a full RFC-822 parser;
+in particular the tokenizing of addresses does not adhere to all the
+quoting rules.
+
+Directions for use:
+
+To create a Message object: first open a file, e.g.:
+ fp = open(file, 'r')
+You can use any other legal way of getting an open file object, e.g. use
+sys.stdin or call os.popen().
+Then pass the open file object to the Message() constructor:
+ m = Message(fp)
+
+This class can work with any input object that supports a readline
+method. If the input object has seek and tell capability, the
+rewindbody method will work; also illegal lines will be pushed back
+onto the input stream. If the input object lacks seek but has an
+`unread' method that can push back a line of input, Message will use
+that to push back illegal lines. Thus this class can be used to parse
+messages coming from a buffered stream.
+
+The optional `seekable' argument is provided as a workaround for
+certain stdio libraries in which tell() discards buffered data before
+discovering that the lseek() system call doesn't work. For maximum
+portability, you should set the seekable argument to zero to prevent
+that initial \code{tell} when passing in an unseekable object such as
+a a file object created from a socket object. If it is 1 on entry --
+which it is by default -- the tell() method of the open file object is
+called once; if this raises an exception, seekable is reset to 0. For
+other nonzero values of seekable, this test is not made.
+
+To get the text of a particular header there are several methods:
+ str = m.getheader(name)
+ str = m.getrawheader(name)
+where name is the name of the header, e.g. 'Subject'.
+The difference is that getheader() strips the leading and trailing
+whitespace, while getrawheader() doesn't. Both functions retain
+embedded whitespace (including newlines) exactly as they are
+specified in the header, and leave the case of the text unchanged.
+
+For addresses and address lists there are functions
+ realname, mailaddress = m.getaddr(name) and
+ list = m.getaddrlist(name)
+where the latter returns a list of (realname, mailaddr) tuples.
+
+There is also a method
+ time = m.getdate(name)
+which parses a Date-like field and returns a time-compatible tuple,
+i.e. a tuple such as returned by time.localtime() or accepted by
+time.mktime().
+
+See the class definition for lower level access methods.
+
+There are also some utility functions here.
+"""
+# Cleanup and extensions by Eric S. Raymond <esr@thyrsus.com>
+
+import time
+
+__all__ = ["Message","AddressList","parsedate","parsedate_tz","mktime_tz"]
+
+_blanklines = ('\r\n', '\n') # Optimization for islast()
+
+
+class Message:
+ """Represents a single RFC-822-compliant message."""
+
+ def __init__(self, fp, seekable = 1):
+ """Initialize the class instance and read the headers."""
+ if seekable == 1:
+ # Exercise tell() to make sure it works
+ # (and then assume seek() works, too)
+ try:
+ fp.tell()
+ except:
+ seekable = 0
+ else:
+ seekable = 1
+ self.fp = fp
+ self.seekable = seekable
+ self.startofheaders = None
+ self.startofbody = None
+ #
+ if self.seekable:
+ try:
+ self.startofheaders = self.fp.tell()
+ except IOError:
+ self.seekable = 0
+ #
+ self.readheaders()
+ #
+ if self.seekable:
+ try:
+ self.startofbody = self.fp.tell()
+ except IOError:
+ self.seekable = 0
+
+ def rewindbody(self):
+ """Rewind the file to the start of the body (if seekable)."""
+ if not self.seekable:
+ raise IOError, "unseekable file"
+ self.fp.seek(self.startofbody)
+
+ def readheaders(self):
+ """Read header lines.
+
+ Read header lines up to the entirely blank line that
+ terminates them. The (normally blank) line that ends the
+ headers is skipped, but not included in the returned list.
+ If a non-header line ends the headers, (which is an error),
+ an attempt is made to backspace over it; it is never
+ included in the returned list.
+
+ The variable self.status is set to the empty string if all
+ went well, otherwise it is an error message.
+ The variable self.headers is a completely uninterpreted list
+ of lines contained in the header (so printing them will
+ reproduce the header exactly as it appears in the file).
+ """
+ self.dict = {}
+ self.unixfrom = ''
+ self.headers = list = []
+ self.status = ''
+ headerseen = ""
+ firstline = 1
+ startofline = unread = tell = None
+ if hasattr(self.fp, 'unread'):
+ unread = self.fp.unread
+ elif self.seekable:
+ tell = self.fp.tell
+ while 1:
+ if tell:
+ try:
+ startofline = tell()
+ except IOError:
+ startofline = tell = None
+ self.seekable = 0
+ line = self.fp.readline()
+ if not line:
+ self.status = 'EOF in headers'
+ break
+ # Skip unix From name time lines
+ if firstline and line.startswith('From '):
+ self.unixfrom = self.unixfrom + line
+ continue
+ firstline = 0
+ if headerseen and line[0] in ' \t':
+ # It's a continuation line.
+ list.append(line)
+ x = (self.dict[headerseen] + "\n " + line.strip())
+ self.dict[headerseen] = x.strip()
+ continue
+ elif self.iscomment(line):
+ # It's a comment. Ignore it.
+ continue
+ elif self.islast(line):
+ # Note! No pushback here! The delimiter line gets eaten.
+ break
+ headerseen = self.isheader(line)
+ if headerseen:
+ # It's a legal header line, save it.
+ list.append(line)
+ self.dict[headerseen] = line[len(headerseen)+1:].strip()
+ continue
+ else:
+ # It's not a header line; throw it back and stop here.
+ if not self.dict:
+ self.status = 'No headers'
+ else:
+ self.status = 'Non-header line where header expected'
+ # Try to undo the read.
+ if unread:
+ unread(line)
+ elif tell:
+ self.fp.seek(startofline)
+ else:
+ self.status = self.status + '; bad seek'
+ break
+
+ def isheader(self, line):
+ """Determine whether a given line is a legal header.
+
+ This method should return the header name, suitably canonicalized.
+ You may override this method in order to use Message parsing
+ on tagged data in RFC822-like formats with special header formats.
+ """
+ i = line.find(':')
+ if i > 0:
+ return line[:i].lower()
+ else:
+ return None
+
+ def islast(self, line):
+ """Determine whether a line is a legal end of RFC-822 headers.
+
+ You may override this method if your application wants
+ to bend the rules, e.g. to strip trailing whitespace,
+ or to recognize MH template separators ('--------').
+ For convenience (e.g. for code reading from sockets) a
+ line consisting of \r\n also matches.
+ """
+ return line in _blanklines
+
+ def iscomment(self, line):
+ """Determine whether a line should be skipped entirely.
+
+ You may override this method in order to use Message parsing
+ on tagged data in RFC822-like formats that support embedded
+ comments or free-text data.
+ """
+ return None
+
+ def getallmatchingheaders(self, name):
+ """Find all header lines matching a given header name.
+
+ Look through the list of headers and find all lines
+ matching a given header name (and their continuation
+ lines). A list of the lines is returned, without
+ interpretation. If the header does not occur, an
+ empty list is returned. If the header occurs multiple
+ times, all occurrences are returned. Case is not
+ important in the header name.
+ """
+ name = name.lower() + ':'
+ n = len(name)
+ list = []
+ hit = 0
+ for line in self.headers:
+ if line[:n].lower() == name:
+ hit = 1
+ elif not line[:1].isspace():
+ hit = 0
+ if hit:
+ list.append(line)
+ return list
+
+ def getfirstmatchingheader(self, name):
+ """Get the first header line matching name.
+
+ This is similar to getallmatchingheaders, but it returns
+ only the first matching header (and its continuation
+ lines).
+ """
+ name = name.lower() + ':'
+ n = len(name)
+ list = []
+ hit = 0
+ for line in self.headers:
+ if hit:
+ if not line[:1].isspace():
+ break
+ elif line[:n].lower() == name:
+ hit = 1
+ if hit:
+ list.append(line)
+ return list
+
+ def getrawheader(self, name):
+ """A higher-level interface to getfirstmatchingheader().
+
+ Return a string containing the literal text of the
+ header but with the keyword stripped. All leading,
+ trailing and embedded whitespace is kept in the
+ string, however.
+ Return None if the header does not occur.
+ """
+
+ list = self.getfirstmatchingheader(name)
+ if not list:
+ return None
+ list[0] = list[0][len(name) + 1:]
+ return ''.join(list)
+
+ def getheader(self, name, default=None):
+ """Get the header value for a name.
+
+ This is the normal interface: it returns a stripped
+ version of the header value for a given header name,
+ or None if it doesn't exist. This uses the dictionary
+ version which finds the *last* such header.
+ """
+ try:
+ return self.dict[name.lower()]
+ except KeyError:
+ return default
+ get = getheader
+
+ def getheaders(self, name):
+ """Get all values for a header.
+
+ This returns a list of values for headers given more than once;
+ each value in the result list is stripped in the same way as the
+ result of getheader(). If the header is not given, return an
+ empty list.
+ """
+ result = []
+ current = ''
+ have_header = 0
+ for s in self.getallmatchingheaders(name):
+ if s[0].isspace():
+ if current:
+ current = "%s\n %s" % (current, s.strip())
+ else:
+ current = s.strip()
+ else:
+ if have_header:
+ result.append(current)
+ current = s[s.find(":") + 1:].strip()
+ have_header = 1
+ if have_header:
+ result.append(current)
+ return result
+
+ def getaddr(self, name):
+ """Get a single address from a header, as a tuple.
+
+ An example return value:
+ ('Guido van Rossum', 'guido@cwi.nl')
+ """
+ # New, by Ben Escoto
+ alist = self.getaddrlist(name)
+ if alist:
+ return alist[0]
+ else:
+ return (None, None)
+
+ def getaddrlist(self, name):
+ """Get a list of addresses from a header.
+
+ Retrieves a list of addresses from a header, where each address is a
+ tuple as returned by getaddr(). Scans all named headers, so it works
+ properly with multiple To: or Cc: headers for example.
+
+ """
+ raw = []
+ for h in self.getallmatchingheaders(name):
+ if h[0] in ' \t':
+ raw.append(h)
+ else:
+ if raw:
+ raw.append(', ')
+ i = h.find(':')
+ if i > 0:
+ addr = h[i+1:]
+ raw.append(addr)
+ alladdrs = ''.join(raw)
+ a = AddrlistClass(alladdrs)
+ return a.getaddrlist()
+
+ def getdate(self, name):
+ """Retrieve a date field from a header.
+
+ Retrieves a date field from the named header, returning
+ a tuple compatible with time.mktime().
+ """
+ try:
+ data = self[name]
+ except KeyError:
+ return None
+ return parsedate(data)
+
+ def getdate_tz(self, name):
+ """Retrieve a date field from a header as a 10-tuple.
+
+ The first 9 elements make up a tuple compatible with
+ time.mktime(), and the 10th is the offset of the poster's
+ time zone from GMT/UTC.
+ """
+ try:
+ data = self[name]
+ except KeyError:
+ return None
+ return parsedate_tz(data)
+
+
+ # Access as a dictionary (only finds *last* header of each type):
+
+ def __len__(self):
+ """Get the number of headers in a message."""
+ return len(self.dict)
+
+ def __getitem__(self, name):
+ """Get a specific header, as from a dictionary."""
+ return self.dict[name.lower()]
+
+ def __setitem__(self, name, value):
+ """Set the value of a header.
+
+ Note: This is not a perfect inversion of __getitem__, because
+ any changed headers get stuck at the end of the raw-headers list
+ rather than where the altered header was.
+ """
+ del self[name] # Won't fail if it doesn't exist
+ self.dict[name.lower()] = value
+ text = name + ": " + value
+ lines = text.split("\n")
+ for line in lines:
+ self.headers.append(line + "\n")
+
+ def __delitem__(self, name):
+ """Delete all occurrences of a specific header, if it is present."""
+ name = name.lower()
+ if not self.dict.has_key(name):
+ return
+ del self.dict[name]
+ name = name + ':'
+ n = len(name)
+ list = []
+ hit = 0
+ for i in range(len(self.headers)):
+ line = self.headers[i]
+ if line[:n].lower() == name:
+ hit = 1
+ elif not line[:1].isspace():
+ hit = 0
+ if hit:
+ list.append(i)
+ list.reverse()
+ for i in list:
+ del self.headers[i]
+
+ def has_key(self, name):
+ """Determine whether a message contains the named header."""
+ return self.dict.has_key(name.lower())
+
+ def keys(self):
+ """Get all of a message's header field names."""
+ return self.dict.keys()
+
+ def values(self):
+ """Get all of a message's header field values."""
+ return self.dict.values()
+
+ def items(self):
+ """Get all of a message's headers.
+
+ Returns a list of name, value tuples.
+ """
+ return self.dict.items()
+
+ def __str__(self):
+ str = ''
+ for hdr in self.headers:
+ str = str + hdr
+ return str
+
+
+# Utility functions
+# -----------------
+
+# XXX Should fix unquote() and quote() to be really conformant.
+# XXX The inverses of the parse functions may also be useful.
+
+
+def unquote(str):
+ """Remove quotes from a string."""
+ if len(str) > 1:
+ if str[0] == '"' and str[-1:] == '"':
+ return str[1:-1]
+ if str[0] == '<' and str[-1:] == '>':
+ return str[1:-1]
+ return str
+
+
+def quote(str):
+ """Add quotes around a string."""
+ return str.replace('\\', '\\\\').replace('"', '\\"')
+
+
+def parseaddr(address):
+ """Parse an address into a (realname, mailaddr) tuple."""
+ a = AddrlistClass(address)
+ list = a.getaddrlist()
+ if not list:
+ return (None, None)
+ else:
+ return list[0]
+
+
+class AddrlistClass:
+ """Address parser class by Ben Escoto.
+
+ To understand what this class does, it helps to have a copy of
+ RFC-822 in front of you.
+
+ Note: this class interface is deprecated and may be removed in the future.
+ Use rfc822.AddressList instead.
+ """
+
+ def __init__(self, field):
+ """Initialize a new instance.
+
+ `field' is an unparsed address header field, containing
+ one or more addresses.
+ """
+ self.specials = '()<>@,:;.\"[]'
+ self.pos = 0
+ self.LWS = ' \t'
+ self.CR = '\r\n'
+ self.atomends = self.specials + self.LWS + self.CR
+ self.field = field
+ self.commentlist = []
+
+ def gotonext(self):
+ """Parse up to the start of the next address."""
+ while self.pos < len(self.field):
+ if self.field[self.pos] in self.LWS + '\n\r':
+ self.pos = self.pos + 1
+ elif self.field[self.pos] == '(':
+ self.commentlist.append(self.getcomment())
+ else: break
+
+ def getaddrlist(self):
+ """Parse all addresses.
+
+ Returns a list containing all of the addresses.
+ """
+ ad = self.getaddress()
+ if ad:
+ return ad + self.getaddrlist()
+ else: return []
+
+ def getaddress(self):
+ """Parse the next address."""
+ self.commentlist = []
+ self.gotonext()
+
+ oldpos = self.pos
+ oldcl = self.commentlist
+ plist = self.getphraselist()
+
+ self.gotonext()
+ returnlist = []
+
+ if self.pos >= len(self.field):
+ # Bad email address technically, no domain.
+ if plist:
+ returnlist = [(' '.join(self.commentlist), plist[0])]
+
+ elif self.field[self.pos] in '.@':
+ # email address is just an addrspec
+ # this isn't very efficient since we start over
+ self.pos = oldpos
+ self.commentlist = oldcl
+ addrspec = self.getaddrspec()
+ returnlist = [(' '.join(self.commentlist), addrspec)]
+
+ elif self.field[self.pos] == ':':
+ # address is a group
+ returnlist = []
+
+ fieldlen = len(self.field)
+ self.pos = self.pos + 1
+ while self.pos < len(self.field):
+ self.gotonext()
+ if self.pos < fieldlen and self.field[self.pos] == ';':
+ self.pos = self.pos + 1
+ break
+ returnlist = returnlist + self.getaddress()
+
+ elif self.field[self.pos] == '<':
+ # Address is a phrase then a route addr
+ routeaddr = self.getrouteaddr()
+
+ if self.commentlist:
+ returnlist = [(' '.join(plist) + ' (' + \
+ ' '.join(self.commentlist) + ')', routeaddr)]
+ else: returnlist = [(' '.join(plist), routeaddr)]
+
+ else:
+ if plist:
+ returnlist = [(' '.join(self.commentlist), plist[0])]
+ elif self.field[self.pos] in self.specials:
+ self.pos = self.pos + 1
+
+ self.gotonext()
+ if self.pos < len(self.field) and self.field[self.pos] == ',':
+ self.pos = self.pos + 1
+ return returnlist
+
+ def getrouteaddr(self):
+ """Parse a route address (Return-path value).
+
+ This method just skips all the route stuff and returns the addrspec.
+ """
+ if self.field[self.pos] != '<':
+ return
+
+ expectroute = 0
+ self.pos = self.pos + 1
+ self.gotonext()
+ adlist = None
+ while self.pos < len(self.field):
+ if expectroute:
+ self.getdomain()
+ expectroute = 0
+ elif self.field[self.pos] == '>':
+ self.pos = self.pos + 1
+ break
+ elif self.field[self.pos] == '@':
+ self.pos = self.pos + 1
+ expectroute = 1
+ elif self.field[self.pos] == ':':
+ self.pos = self.pos + 1
+ expectaddrspec = 1
+ else:
+ adlist = self.getaddrspec()
+ self.pos = self.pos + 1
+ break
+ self.gotonext()
+
+ return adlist
+
+ def getaddrspec(self):
+ """Parse an RFC-822 addr-spec."""
+ aslist = []
+
+ self.gotonext()
+ while self.pos < len(self.field):
+ if self.field[self.pos] == '.':
+ aslist.append('.')
+ self.pos = self.pos + 1
+ elif self.field[self.pos] == '"':
+ aslist.append('"%s"' % self.getquote())
+ elif self.field[self.pos] in self.atomends:
+ break
+ else: aslist.append(self.getatom())
+ self.gotonext()
+
+ if self.pos >= len(self.field) or self.field[self.pos] != '@':
+ return ''.join(aslist)
+
+ aslist.append('@')
+ self.pos = self.pos + 1
+ self.gotonext()
+ return ''.join(aslist) + self.getdomain()
+
+ def getdomain(self):
+ """Get the complete domain name from an address."""
+ sdlist = []
+ while self.pos < len(self.field):
+ if self.field[self.pos] in self.LWS:
+ self.pos = self.pos + 1
+ elif self.field[self.pos] == '(':
+ self.commentlist.append(self.getcomment())
+ elif self.field[self.pos] == '[':
+ sdlist.append(self.getdomainliteral())
+ elif self.field[self.pos] == '.':
+ self.pos = self.pos + 1
+ sdlist.append('.')
+ elif self.field[self.pos] in self.atomends:
+ break
+ else: sdlist.append(self.getatom())
+ return ''.join(sdlist)
+
+ def getdelimited(self, beginchar, endchars, allowcomments = 1):
+ """Parse a header fragment delimited by special characters.
+
+ `beginchar' is the start character for the fragment.
+ If self is not looking at an instance of `beginchar' then
+ getdelimited returns the empty string.
+
+ `endchars' is a sequence of allowable end-delimiting characters.
+ Parsing stops when one of these is encountered.
+
+ If `allowcomments' is non-zero, embedded RFC-822 comments
+ are allowed within the parsed fragment.
+ """
+ if self.field[self.pos] != beginchar:
+ return ''
+
+ slist = ['']
+ quote = 0
+ self.pos = self.pos + 1
+ while self.pos < len(self.field):
+ if quote == 1:
+ slist.append(self.field[self.pos])
+ quote = 0
+ elif self.field[self.pos] in endchars:
+ self.pos = self.pos + 1
+ break
+ elif allowcomments and self.field[self.pos] == '(':
+ slist.append(self.getcomment())
+ elif self.field[self.pos] == '\\':
+ quote = 1
+ else:
+ slist.append(self.field[self.pos])
+ self.pos = self.pos + 1
+
+ return ''.join(slist)
+
+ def getquote(self):
+ """Get a quote-delimited fragment from self's field."""
+ return self.getdelimited('"', '"\r', 0)
+
+ def getcomment(self):
+ """Get a parenthesis-delimited fragment from self's field."""
+ return self.getdelimited('(', ')\r', 1)
+
+ def getdomainliteral(self):
+ """Parse an RFC-822 domain-literal."""
+ return '[%s]' % self.getdelimited('[', ']\r', 0)
+
+ def getatom(self):
+ """Parse an RFC-822 atom."""
+ atomlist = ['']
+
+ while self.pos < len(self.field):
+ if self.field[self.pos] in self.atomends:
+ break
+ else: atomlist.append(self.field[self.pos])
+ self.pos = self.pos + 1
+
+ return ''.join(atomlist)
+
+ def getphraselist(self):
+ """Parse a sequence of RFC-822 phrases.
+
+ A phrase is a sequence of words, which are in turn either
+ RFC-822 atoms or quoted-strings. Phrases are canonicalized
+ by squeezing all runs of continuous whitespace into one space.
+ """
+ plist = []
+
+ while self.pos < len(self.field):
+ if self.field[self.pos] in self.LWS:
+ self.pos = self.pos + 1
+ elif self.field[self.pos] == '"':
+ plist.append(self.getquote())
+ elif self.field[self.pos] == '(':
+ self.commentlist.append(self.getcomment())
+ elif self.field[self.pos] in self.atomends:
+ break
+ else: plist.append(self.getatom())
+
+ return plist
+
+class AddressList(AddrlistClass):
+ """An AddressList encapsulates a list of parsed RFC822 addresses."""
+ def __init__(self, field):
+ AddrlistClass.__init__(self, field)
+ if field:
+ self.addresslist = self.getaddrlist()
+ else:
+ self.addresslist = []
+
+ def __len__(self):
+ return len(self.addresslist)
+
+ def __str__(self):
+ return ", ".join(map(dump_address_pair, self.addresslist))
+
+ def __add__(self, other):
+ # Set union
+ newaddr = AddressList(None)
+ newaddr.addresslist = self.addresslist[:]
+ for x in other.addresslist:
+ if not x in self.addresslist:
+ newaddr.addresslist.append(x)
+ return newaddr
+
+ def __iadd__(self, other):
+ # Set union, in-place
+ for x in other.addresslist:
+ if not x in self.addresslist:
+ self.addresslist.append(x)
+ return self
+
+ def __sub__(self, other):
+ # Set difference
+ newaddr = AddressList(None)
+ for x in self.addresslist:
+ if not x in other.addresslist:
+ newaddr.addresslist.append(x)
+ return newaddr
+
+ def __isub__(self, other):
+ # Set difference, in-place
+ for x in other.addresslist:
+ if x in self.addresslist:
+ self.addresslist.remove(x)
+ return self
+
+ def __getitem__(self, index):
+ # Make indexing, slices, and 'in' work
+ return self.addresslist[index]
+
+def dump_address_pair(pair):
+ """Dump a (name, address) pair in a canonicalized form."""
+ if pair[0]:
+ return '"' + pair[0] + '" <' + pair[1] + '>'
+ else:
+ return pair[1]
+
+# Parse a date field
+
+_monthnames = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul',
+ 'aug', 'sep', 'oct', 'nov', 'dec',
+ 'january', 'february', 'march', 'april', 'may', 'june', 'july',
+ 'august', 'september', 'october', 'november', 'december']
+_daynames = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']
+
+# The timezone table does not include the military time zones defined
+# in RFC822, other than Z. According to RFC1123, the description in
+# RFC822 gets the signs wrong, so we can't rely on any such time
+# zones. RFC1123 recommends that numeric timezone indicators be used
+# instead of timezone names.
+
+_timezones = {'UT':0, 'UTC':0, 'GMT':0, 'Z':0,
+ 'AST': -400, 'ADT': -300, # Atlantic (used in Canada)
+ 'EST': -500, 'EDT': -400, # Eastern
+ 'CST': -600, 'CDT': -500, # Central
+ 'MST': -700, 'MDT': -600, # Mountain
+ 'PST': -800, 'PDT': -700 # Pacific
+ }
+
+
+def parsedate_tz(data):
+ """Convert a date string to a time tuple.
+
+ Accounts for military timezones.
+ """
+ data = data.split()
+ if data[0][-1] in (',', '.') or data[0].lower() in _daynames:
+ # There's a dayname here. Skip it
+ del data[0]
+ if len(data) == 3: # RFC 850 date, deprecated
+ stuff = data[0].split('-')
+ if len(stuff) == 3:
+ data = stuff + data[1:]
+ if len(data) == 4:
+ s = data[3]
+ i = s.find('+')
+ if i > 0:
+ data[3:] = [s[:i], s[i+1:]]
+ else:
+ data.append('') # Dummy tz
+ if len(data) < 5:
+ return None
+ data = data[:5]
+ [dd, mm, yy, tm, tz] = data
+ mm = mm.lower()
+ if not mm in _monthnames:
+ dd, mm = mm, dd.lower()
+ if not mm in _monthnames:
+ return None
+ mm = _monthnames.index(mm)+1
+ if mm > 12: mm = mm - 12
+ if dd[-1] == ',':
+ dd = dd[:-1]
+ i = yy.find(':')
+ if i > 0:
+ yy, tm = tm, yy
+ if yy[-1] == ',':
+ yy = yy[:-1]
+ if not yy[0].isdigit():
+ yy, tz = tz, yy
+ if tm[-1] == ',':
+ tm = tm[:-1]
+ tm = tm.split(':')
+ if len(tm) == 2:
+ [thh, tmm] = tm
+ tss = '0'
+ elif len(tm) == 3:
+ [thh, tmm, tss] = tm
+ else:
+ return None
+ try:
+ yy = int(yy)
+ dd = int(dd)
+ thh = int(thh)
+ tmm = int(tmm)
+ tss = int(tss)
+ except ValueError:
+ return None
+ tzoffset = None
+ tz = tz.upper()
+ if _timezones.has_key(tz):
+ tzoffset = _timezones[tz]
+ else:
+ try:
+ tzoffset = int(tz)
+ except ValueError:
+ pass
+ # Convert a timezone offset into seconds ; -0500 -> -18000
+ if tzoffset:
+ if tzoffset < 0:
+ tzsign = -1
+ tzoffset = -tzoffset
+ else:
+ tzsign = 1
+ tzoffset = tzsign * ( (tzoffset/100)*3600 + (tzoffset % 100)*60)
+ tuple = (yy, mm, dd, thh, tmm, tss, 0, 0, 0, tzoffset)
+ return tuple
+
+
+def parsedate(data):
+ """Convert a time string to a time tuple."""
+ t = parsedate_tz(data)
+ if type(t) == type( () ):
+ return t[:9]
+ else: return t
+
+
+def mktime_tz(data):
+ """Turn a 10-tuple as returned by parsedate_tz() into a UTC timestamp."""
+ if data[9] is None:
+ # No zone info, so localtime is better assumption than GMT
+ return time.mktime(data[:8] + (-1,))
+ else:
+ t = time.mktime(data[:8] + (0,))
+ return t - data[9] - time.timezone
+
+def formatdate(timeval=None):
+ """Returns time format preferred for Internet standards.
+
+ Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
+ """
+ if timeval is None:
+ timeval = time.time()
+ return "%s" % time.strftime('%a, %d %b %Y %H:%M:%S GMT',
+ time.gmtime(timeval))
+
+
+# When used as script, run a small test program.
+# The first command line argument must be a filename containing one
+# message in RFC-822 format.
+
+if __name__ == '__main__':
+ import sys, os
+ file = os.path.join(os.environ['HOME'], 'Mail/inbox/1')
+ if sys.argv[1:]: file = sys.argv[1]
+ f = open(file, 'r')
+ m = Message(f)
+ print 'From:', m.getaddr('from')
+ print 'To:', m.getaddrlist('to')
+ print 'Subject:', m.getheader('subject')
+ print 'Date:', m.getheader('date')
+ date = m.getdate_tz('date')
+ tz = date[-1]
+ date = time.localtime(mktime_tz(date))
+ if date:
+ print 'ParsedDate:', time.asctime(date),
+ hhmmss = tz
+ hhmm, ss = divmod(hhmmss, 60)
+ hh, mm = divmod(hhmm, 60)
+ print "%+03d%02d" % (hh, mm),
+ if ss: print ".%02d" % ss,
+ print
+ else:
+ print 'ParsedDate:', None
+ m.rewindbody()
+ n = 0
+ while f.readline():
+ n = n + 1
+ print 'Lines:', n
+ print '-'*70
+ print 'len =', len(m)
+ if m.has_key('Date'): print 'Date =', m['Date']
+ if m.has_key('X-Nonsense'): pass
+ print 'keys =', m.keys()
+ print 'values =', m.values()
+ print 'items =', m.items()
diff --git a/lib/jython/Lib/sched.py b/lib/jython/Lib/sched.py new file mode 100644 index 000000000..80cb7eb8e --- /dev/null +++ b/lib/jython/Lib/sched.py @@ -0,0 +1,106 @@ +"""A generally useful event scheduler class.
+
+Each instance of this class manages its own queue.
+No multi-threading is implied; you are supposed to hack that
+yourself, or use a single instance per application.
+
+Each instance is parametrized with two functions, one that is
+supposed to return the current time, one that is supposed to
+implement a delay. You can implement real-time scheduling by
+substituting time and sleep from built-in module time, or you can
+implement simulated time by writing your own functions. This can
+also be used to integrate scheduling with STDWIN events; the delay
+function is allowed to modify the queue. Time can be expressed as
+integers or floating point numbers, as long as it is consistent.
+
+Events are specified by tuples (time, priority, action, argument).
+As in UNIX, lower priority numbers mean higher priority; in this
+way the queue can be maintained fully sorted. Execution of the
+event means calling the action function, passing it the argument.
+Remember that in Python, multiple function arguments can be packed
+in a tuple. The action function may be an instance method so it
+has another way to reference private data (besides global variables).
+Parameterless functions or methods cannot be used, however.
+"""
+
+# XXX The timefunc and delayfunc should have been defined as methods
+# XXX so you can define new kinds of schedulers using subclassing
+# XXX instead of having to define a module or class just to hold
+# XXX the global state of your particular time and delay functions.
+
+import bisect
+
+__all__ = ["scheduler"]
+
+class scheduler:
+ def __init__(self, timefunc, delayfunc):
+ """Initialize a new instance, passing the time and delay
+ functions"""
+ self.queue = []
+ self.timefunc = timefunc
+ self.delayfunc = delayfunc
+
+ def enterabs(self, time, priority, action, argument):
+ """Enter a new event in the queue at an absolute time.
+
+ Returns an ID for the event which can be used to remove it,
+ if necessary.
+
+ """
+ event = time, priority, action, argument
+ bisect.insort(self.queue, event)
+ return event # The ID
+
+ def enter(self, delay, priority, action, argument):
+ """A variant that specifies the time as a relative time.
+
+ This is actually the more commonly used interface.
+
+ """
+ time = self.timefunc() + delay
+ return self.enterabs(time, priority, action, argument)
+
+ def cancel(self, event):
+ """Remove an event from the queue.
+
+ This must be presented the ID as returned by enter().
+ If the event is not in the queue, this raises RuntimeError.
+
+ """
+ self.queue.remove(event)
+
+ def empty(self):
+ """Check whether the queue is empty."""
+ return len(self.queue) == 0
+
+ def run(self):
+ """Execute events until the queue is empty.
+
+ When there is a positive delay until the first event, the
+ delay function is called and the event is left in the queue;
+ otherwise, the event is removed from the queue and executed
+ (its action function is called, passing it the argument). If
+ the delay function returns prematurely, it is simply
+ restarted.
+
+ It is legal for both the delay function and the action
+ function to to modify the queue or to raise an exception;
+ exceptions are not caught but the scheduler's state remains
+ well-defined so run() may be called again.
+
+ A questionably hack is added to allow other threads to run:
+ just after an event is executed, a delay of 0 is executed, to
+ avoid monopolizing the CPU when other threads are also
+ runnable.
+
+ """
+ q = self.queue
+ while q:
+ time, priority, action, argument = q[0]
+ now = self.timefunc()
+ if now < time:
+ self.delayfunc(time - now)
+ else:
+ del q[0]
+ void = apply(action, argument)
+ self.delayfunc(0) # Let other threads run
diff --git a/lib/jython/Lib/sgmllib.py b/lib/jython/Lib/sgmllib.py new file mode 100644 index 000000000..1295cdbbd --- /dev/null +++ b/lib/jython/Lib/sgmllib.py @@ -0,0 +1,533 @@ +"""A parser for SGML, using the derived class as a static DTD."""
+
+# XXX This only supports those SGML features used by HTML.
+
+# XXX There should be a way to distinguish between PCDATA (parsed
+# character data -- the normal case), RCDATA (replaceable character
+# data -- only char and entity references and end tags are special)
+# and CDATA (character data -- only end tags are special).
+
+
+import re
+import string
+
+__all__ = ["SGMLParser"]
+
+# Regular expressions used for parsing
+
+interesting = re.compile('[&<]')
+incomplete = re.compile('&([a-zA-Z][a-zA-Z0-9]*|#[0-9]*)?|'
+ '<([a-zA-Z][^<>]*|'
+ '/([a-zA-Z][^<>]*)?|'
+ '![^<>]*)?')
+
+entityref = re.compile('&([a-zA-Z][-.a-zA-Z0-9]*)[^a-zA-Z0-9]')
+charref = re.compile('&#([0-9]+)[^0-9]')
+
+starttagopen = re.compile('<[>a-zA-Z]')
+shorttagopen = re.compile('<[a-zA-Z][-.a-zA-Z0-9]*/')
+shorttag = re.compile('<([a-zA-Z][-.a-zA-Z0-9]*)/([^/]*)/')
+piopen = re.compile('<\?')
+piclose = re.compile('>')
+endtagopen = re.compile('</[<>a-zA-Z]')
+endbracket = re.compile('[<>]')
+special = re.compile('<![^<>]*>')
+commentopen = re.compile('<!--')
+commentclose = re.compile(r'--\s*>')
+tagfind = re.compile('[a-zA-Z][-_.a-zA-Z0-9]*')
+attrfind = re.compile(
+ r'\s*([a-zA-Z_][-.a-zA-Z_0-9]*)(\s*=\s*'
+ r'(\'[^\']*\'|"[^"]*"|[-a-zA-Z0-9./:;+*%?!&$\(\)_#=~\'"]*))?')
+
+declname = re.compile(r'[a-zA-Z][-_.a-zA-Z0-9]*\s*')
+declstringlit = re.compile(r'(\'[^\']*\'|"[^"]*")\s*')
+
+
+class SGMLParseError(RuntimeError):
+ """Exception raised for all parse errors."""
+ pass
+
+
+# SGML parser base class -- find tags and call handler functions.
+# Usage: p = SGMLParser(); p.feed(data); ...; p.close().
+# The dtd is defined by deriving a class which defines methods
+# with special names to handle tags: start_foo and end_foo to handle
+# <foo> and </foo>, respectively, or do_foo to handle <foo> by itself.
+# (Tags are converted to lower case for this purpose.) The data
+# between tags is passed to the parser by calling self.handle_data()
+# with some data as argument (the data may be split up in arbitrary
+# chunks). Entity references are passed by calling
+# self.handle_entityref() with the entity reference as argument.
+
+class SGMLParser:
+
+ # Interface -- initialize and reset this instance
+ def __init__(self, verbose=0):
+ self.verbose = verbose
+ self.reset()
+
+ # Interface -- reset this instance. Loses all unprocessed data
+ def reset(self):
+ self.rawdata = ''
+ self.stack = []
+ self.lasttag = '???'
+ self.nomoretags = 0
+ self.literal = 0
+
+ # For derived classes only -- enter literal mode (CDATA) till EOF
+ def setnomoretags(self):
+ self.nomoretags = self.literal = 1
+
+ # For derived classes only -- enter literal mode (CDATA)
+ def setliteral(self, *args):
+ self.literal = 1
+
+ # Interface -- feed some data to the parser. Call this as
+ # often as you want, with as little or as much text as you
+ # want (may include '\n'). (This just saves the text, all the
+ # processing is done by goahead().)
+ def feed(self, data):
+ self.rawdata = self.rawdata + data
+ self.goahead(0)
+
+ # Interface -- handle the remaining data
+ def close(self):
+ self.goahead(1)
+
+ # Internal -- handle data as far as reasonable. May leave state
+ # and data to be processed by a subsequent call. If 'end' is
+ # true, force handling all data as if followed by EOF marker.
+ def goahead(self, end):
+ rawdata = self.rawdata
+ i = 0
+ n = len(rawdata)
+ while i < n:
+ if self.nomoretags:
+ self.handle_data(rawdata[i:n])
+ i = n
+ break
+ match = interesting.search(rawdata, i)
+ if match: j = match.start(0)
+ else: j = n
+ if i < j: self.handle_data(rawdata[i:j])
+ i = j
+ if i == n: break
+ if rawdata[i] == '<':
+ if starttagopen.match(rawdata, i):
+ if self.literal:
+ self.handle_data(rawdata[i])
+ i = i+1
+ continue
+ k = self.parse_starttag(i)
+ if k < 0: break
+ i = k
+ continue
+ if endtagopen.match(rawdata, i):
+ k = self.parse_endtag(i)
+ if k < 0: break
+ i = k
+ self.literal = 0
+ continue
+ if commentopen.match(rawdata, i):
+ if self.literal:
+ self.handle_data(rawdata[i])
+ i = i+1
+ continue
+ k = self.parse_comment(i)
+ if k < 0: break
+ i = i+k
+ continue
+ if piopen.match(rawdata, i):
+ if self.literal:
+ self.handle_data(rawdata[i])
+ i = i+1
+ continue
+ k = self.parse_pi(i)
+ if k < 0: break
+ i = i+k
+ continue
+ match = special.match(rawdata, i)
+ if match:
+ if self.literal:
+ self.handle_data(rawdata[i])
+ i = i+1
+ continue
+ # This is some sort of declaration; in "HTML as
+ # deployed," this should only be the document type
+ # declaration ("<!DOCTYPE html...>").
+ k = self.parse_declaration(i)
+ if k < 0: break
+ i = k
+ continue
+ elif rawdata[i] == '&':
+ match = charref.match(rawdata, i)
+ if match:
+ name = match.group(1)
+ self.handle_charref(name)
+ i = match.end(0)
+ if rawdata[i-1] != ';': i = i-1
+ continue
+ match = entityref.match(rawdata, i)
+ if match:
+ name = match.group(1)
+ self.handle_entityref(name)
+ i = match.end(0)
+ if rawdata[i-1] != ';': i = i-1
+ continue
+ else:
+ raise SGMLParseError('neither < nor & ??')
+ # We get here only if incomplete matches but
+ # nothing else
+ match = incomplete.match(rawdata, i)
+ if not match:
+ self.handle_data(rawdata[i])
+ i = i+1
+ continue
+ j = match.end(0)
+ if j == n:
+ break # Really incomplete
+ self.handle_data(rawdata[i:j])
+ i = j
+ # end while
+ if end and i < n:
+ self.handle_data(rawdata[i:n])
+ i = n
+ self.rawdata = rawdata[i:]
+ # XXX if end: check for empty stack
+
+ # Internal -- parse comment, return length or -1 if not terminated
+ def parse_comment(self, i):
+ rawdata = self.rawdata
+ if rawdata[i:i+4] != '<!--':
+ raise SGMLParseError('unexpected call to parse_comment()')
+ match = commentclose.search(rawdata, i+4)
+ if not match:
+ return -1
+ j = match.start(0)
+ self.handle_comment(rawdata[i+4: j])
+ j = match.end(0)
+ return j-i
+
+ # Internal -- parse declaration.
+ def parse_declaration(self, i):
+ rawdata = self.rawdata
+ j = i + 2
+ # in practice, this should look like: ((name|stringlit) S*)+ '>'
+ while 1:
+ c = rawdata[j:j+1]
+ if c == ">":
+ # end of declaration syntax
+ self.handle_decl(rawdata[i+2:j])
+ return j + 1
+ if c in "\"'":
+ m = declstringlit.match(rawdata, j)
+ if not m:
+ # incomplete or an error?
+ return -1
+ j = m.end()
+ elif c in "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ":
+ m = declname.match(rawdata, j)
+ if not m:
+ # incomplete or an error?
+ return -1
+ j = m.end()
+ elif i == len(rawdata):
+ # end of buffer between tokens
+ return -1
+ else:
+ raise SGMLParseError(
+ "unexpected char in declaration: %s" % `rawdata[i]`)
+ assert 0, "can't get here!"
+
+ # Internal -- parse processing instr, return length or -1 if not terminated
+ def parse_pi(self, i):
+ rawdata = self.rawdata
+ if rawdata[i:i+2] != '<?':
+ raise SGMLParseError('unexpected call to parse_pi()')
+ match = piclose.search(rawdata, i+2)
+ if not match:
+ return -1
+ j = match.start(0)
+ self.handle_pi(rawdata[i+2: j])
+ j = match.end(0)
+ return j-i
+
+ __starttag_text = None
+ def get_starttag_text(self):
+ return self.__starttag_text
+
+ # Internal -- handle starttag, return length or -1 if not terminated
+ def parse_starttag(self, i):
+ self.__starttag_text = None
+ start_pos = i
+ rawdata = self.rawdata
+ if shorttagopen.match(rawdata, i):
+ # SGML shorthand: <tag/data/ == <tag>data</tag>
+ # XXX Can data contain &... (entity or char refs)?
+ # XXX Can data contain < or > (tag characters)?
+ # XXX Can there be whitespace before the first /?
+ match = shorttag.match(rawdata, i)
+ if not match:
+ return -1
+ tag, data = match.group(1, 2)
+ self.__starttag_text = '<%s/' % tag
+ tag = tag.lower()
+ k = match.end(0)
+ self.finish_shorttag(tag, data)
+ self.__starttag_text = rawdata[start_pos:match.end(1) + 1]
+ return k
+ # XXX The following should skip matching quotes (' or ")
+ match = endbracket.search(rawdata, i+1)
+ if not match:
+ return -1
+ j = match.start(0)
+ # Now parse the data between i+1 and j into a tag and attrs
+ attrs = []
+ if rawdata[i:i+2] == '<>':
+ # SGML shorthand: <> == <last open tag seen>
+ k = j
+ tag = self.lasttag
+ else:
+ match = tagfind.match(rawdata, i+1)
+ if not match:
+ raise SGMLParseError('unexpected call to parse_starttag')
+ k = match.end(0)
+ tag = rawdata[i+1:k].lower()
+ self.lasttag = tag
+ while k < j:
+ match = attrfind.match(rawdata, k)
+ if not match: break
+ attrname, rest, attrvalue = match.group(1, 2, 3)
+ if not rest:
+ attrvalue = attrname
+ elif attrvalue[:1] == '\'' == attrvalue[-1:] or \
+ attrvalue[:1] == '"' == attrvalue[-1:]:
+ attrvalue = attrvalue[1:-1]
+ attrs.append((attrname.lower(), attrvalue))
+ k = match.end(0)
+ if rawdata[j] == '>':
+ j = j+1
+ self.__starttag_text = rawdata[start_pos:j]
+ self.finish_starttag(tag, attrs)
+ return j
+
+ # Internal -- parse endtag
+ def parse_endtag(self, i):
+ rawdata = self.rawdata
+ match = endbracket.search(rawdata, i+1)
+ if not match:
+ return -1
+ j = match.start(0)
+ tag = rawdata[i+2:j].strip().lower()
+ if rawdata[j] == '>':
+ j = j+1
+ self.finish_endtag(tag)
+ return j
+
+ # Internal -- finish parsing of <tag/data/ (same as <tag>data</tag>)
+ def finish_shorttag(self, tag, data):
+ self.finish_starttag(tag, [])
+ self.handle_data(data)
+ self.finish_endtag(tag)
+
+ # Internal -- finish processing of start tag
+ # Return -1 for unknown tag, 0 for open-only tag, 1 for balanced tag
+ def finish_starttag(self, tag, attrs):
+ try:
+ method = getattr(self, 'start_' + tag)
+ except AttributeError:
+ try:
+ method = getattr(self, 'do_' + tag)
+ except AttributeError:
+ self.unknown_starttag(tag, attrs)
+ return -1
+ else:
+ self.handle_starttag(tag, method, attrs)
+ return 0
+ else:
+ self.stack.append(tag)
+ self.handle_starttag(tag, method, attrs)
+ return 1
+
+ # Internal -- finish processing of end tag
+ def finish_endtag(self, tag):
+ if not tag:
+ found = len(self.stack) - 1
+ if found < 0:
+ self.unknown_endtag(tag)
+ return
+ else:
+ if tag not in self.stack:
+ try:
+ method = getattr(self, 'end_' + tag)
+ except AttributeError:
+ self.unknown_endtag(tag)
+ else:
+ self.report_unbalanced(tag)
+ return
+ found = len(self.stack)
+ for i in range(found):
+ if self.stack[i] == tag: found = i
+ while len(self.stack) > found:
+ tag = self.stack[-1]
+ try:
+ method = getattr(self, 'end_' + tag)
+ except AttributeError:
+ method = None
+ if method:
+ self.handle_endtag(tag, method)
+ else:
+ self.unknown_endtag(tag)
+ del self.stack[-1]
+
+ # Overridable -- handle start tag
+ def handle_starttag(self, tag, method, attrs):
+ method(attrs)
+
+ # Overridable -- handle end tag
+ def handle_endtag(self, tag, method):
+ method()
+
+ # Example -- report an unbalanced </...> tag.
+ def report_unbalanced(self, tag):
+ if self.verbose:
+ print '*** Unbalanced </' + tag + '>'
+ print '*** Stack:', self.stack
+
+ # Example -- handle character reference, no need to override
+ def handle_charref(self, name):
+ try:
+ n = int(name)
+ except ValueError:
+ self.unknown_charref(name)
+ return
+ if not 0 <= n <= 255:
+ self.unknown_charref(name)
+ return
+ self.handle_data(chr(n))
+
+ # Definition of entities -- derived classes may override
+ entitydefs = \
+ {'lt': '<', 'gt': '>', 'amp': '&', 'quot': '"', 'apos': '\''}
+
+ # Example -- handle entity reference, no need to override
+ def handle_entityref(self, name):
+ table = self.entitydefs
+ if table.has_key(name):
+ self.handle_data(table[name])
+ else:
+ self.unknown_entityref(name)
+ return
+
+ # Example -- handle data, should be overridden
+ def handle_data(self, data):
+ pass
+
+ # Example -- handle comment, could be overridden
+ def handle_comment(self, data):
+ pass
+
+ # Example -- handle declaration, could be overridden
+ def handle_decl(self, decl):
+ pass
+
+ # Example -- handle processing instruction, could be overridden
+ def handle_pi(self, data):
+ pass
+
+ # To be overridden -- handlers for unknown objects
+ def unknown_starttag(self, tag, attrs): pass
+ def unknown_endtag(self, tag): pass
+ def unknown_charref(self, ref): pass
+ def unknown_entityref(self, ref): pass
+
+
+class TestSGMLParser(SGMLParser):
+
+ def __init__(self, verbose=0):
+ self.testdata = ""
+ SGMLParser.__init__(self, verbose)
+
+ def handle_data(self, data):
+ self.testdata = self.testdata + data
+ if len(`self.testdata`) >= 70:
+ self.flush()
+
+ def flush(self):
+ data = self.testdata
+ if data:
+ self.testdata = ""
+ print 'data:', `data`
+
+ def handle_comment(self, data):
+ self.flush()
+ r = `data`
+ if len(r) > 68:
+ r = r[:32] + '...' + r[-32:]
+ print 'comment:', r
+
+ def unknown_starttag(self, tag, attrs):
+ self.flush()
+ if not attrs:
+ print 'start tag: <' + tag + '>'
+ else:
+ print 'start tag: <' + tag,
+ for name, value in attrs:
+ print name + '=' + '"' + value + '"',
+ print '>'
+
+ def unknown_endtag(self, tag):
+ self.flush()
+ print 'end tag: </' + tag + '>'
+
+ def unknown_entityref(self, ref):
+ self.flush()
+ print '*** unknown entity ref: &' + ref + ';'
+
+ def unknown_charref(self, ref):
+ self.flush()
+ print '*** unknown char ref: &#' + ref + ';'
+
+ def close(self):
+ SGMLParser.close(self)
+ self.flush()
+
+
+def test(args = None):
+ import sys
+
+ if not args:
+ args = sys.argv[1:]
+
+ if args and args[0] == '-s':
+ args = args[1:]
+ klass = SGMLParser
+ else:
+ klass = TestSGMLParser
+
+ if args:
+ file = args[0]
+ else:
+ file = 'test.html'
+
+ if file == '-':
+ f = sys.stdin
+ else:
+ try:
+ f = open(file, 'r')
+ except IOError, msg:
+ print file, ":", msg
+ sys.exit(1)
+
+ data = f.read()
+ if f is not sys.stdin:
+ f.close()
+
+ x = klass()
+ for c in data:
+ x.feed(c)
+ x.close()
+
+
+if __name__ == '__main__':
+ test()
diff --git a/lib/jython/Lib/shelve.py b/lib/jython/Lib/shelve.py new file mode 100644 index 000000000..fca698590 --- /dev/null +++ b/lib/jython/Lib/shelve.py @@ -0,0 +1,158 @@ +"""Manage shelves of pickled objects.
+
+A "shelf" is a persistent, dictionary-like object. The difference
+with dbm databases is that the values (not the keys!) in a shelf can
+be essentially arbitrary Python objects -- anything that the "pickle"
+module can handle. This includes most class instances, recursive data
+types, and objects containing lots of shared sub-objects. The keys
+are ordinary strings.
+
+To summarize the interface (key is a string, data is an arbitrary
+object):
+
+ import shelve
+ d = shelve.open(filename) # open, with (g)dbm filename -- no suffix
+
+ d[key] = data # store data at key (overwrites old data if
+ # using an existing key)
+ data = d[key] # retrieve data at key (raise KeyError if no
+ # such key)
+ del d[key] # delete data stored at key (raises KeyError
+ # if no such key)
+ flag = d.has_key(key) # true if the key exists
+ list = d.keys() # a list of all existing keys (slow!)
+
+ d.close() # close it
+
+Dependent on the implementation, closing a persistent dictionary may
+or may not be necessary to flush changes to disk.
+"""
+
+# Try using cPickle and cStringIO if available.
+
+try:
+ from cPickle import Pickler, Unpickler
+except ImportError:
+ from pickle import Pickler, Unpickler
+
+try:
+ from cStringIO import StringIO
+except ImportError:
+ from StringIO import StringIO
+
+__all__ = ["Shelf","BsdDbShelf","DbfilenameShelf","open"]
+
+class Shelf:
+ """Base class for shelf implementations.
+
+ This is initialized with a dictionary-like object.
+ See the module's __doc__ string for an overview of the interface.
+ """
+
+ def __init__(self, dict):
+ self.dict = dict
+
+ def keys(self):
+ return self.dict.keys()
+
+ def __len__(self):
+ return len(self.dict)
+
+ def has_key(self, key):
+ return self.dict.has_key(key)
+
+ def get(self, key, default=None):
+ if self.dict.has_key(key):
+ return self[key]
+ return default
+
+ def __getitem__(self, key):
+ f = StringIO(self.dict[key])
+ return Unpickler(f).load()
+
+ def __setitem__(self, key, value):
+ f = StringIO()
+ p = Pickler(f)
+ p.dump(value)
+ self.dict[key] = f.getvalue()
+
+ def __delitem__(self, key):
+ del self.dict[key]
+
+ def close(self):
+ try:
+ self.dict.close()
+ except:
+ pass
+ self.dict = 0
+
+ def __del__(self):
+ self.close()
+
+ def sync(self):
+ if hasattr(self.dict, 'sync'):
+ self.dict.sync()
+
+
+class BsdDbShelf(Shelf):
+ """Shelf implementation using the "BSD" db interface.
+
+ This adds methods first(), next(), previous(), last() and
+ set_location() that have no counterpart in [g]dbm databases.
+
+ The actual database must be opened using one of the "bsddb"
+ modules "open" routines (i.e. bsddb.hashopen, bsddb.btopen or
+ bsddb.rnopen) and passed to the constructor.
+
+ See the module's __doc__ string for an overview of the interface.
+ """
+
+ def __init__(self, dict):
+ Shelf.__init__(self, dict)
+
+ def set_location(self, key):
+ (key, value) = self.dict.set_location(key)
+ f = StringIO(value)
+ return (key, Unpickler(f).load())
+
+ def next(self):
+ (key, value) = self.dict.next()
+ f = StringIO(value)
+ return (key, Unpickler(f).load())
+
+ def previous(self):
+ (key, value) = self.dict.previous()
+ f = StringIO(value)
+ return (key, Unpickler(f).load())
+
+ def first(self):
+ (key, value) = self.dict.first()
+ f = StringIO(value)
+ return (key, Unpickler(f).load())
+
+ def last(self):
+ (key, value) = self.dict.last()
+ f = StringIO(value)
+ return (key, Unpickler(f).load())
+
+
+class DbfilenameShelf(Shelf):
+ """Shelf implementation using the "anydbm" generic dbm interface.
+
+ This is initialized with the filename for the dbm database.
+ See the module's __doc__ string for an overview of the interface.
+ """
+
+ def __init__(self, filename, flag='c'):
+ import anydbm
+ Shelf.__init__(self, anydbm.open(filename, flag))
+
+
+def open(filename, flag='c'):
+ """Open a persistent dictionary for reading and writing.
+
+ Argument is the filename for the dbm database.
+ See the module's __doc__ string for an overview of the interface.
+ """
+
+ return DbfilenameShelf(filename, flag)
diff --git a/lib/jython/Lib/shutil.py b/lib/jython/Lib/shutil.py new file mode 100644 index 000000000..c11d46bee --- /dev/null +++ b/lib/jython/Lib/shutil.py @@ -0,0 +1,138 @@ +"""Utility functions for copying files and directory trees.
+
+XXX The functions here don't copy the resource fork or other metadata on Mac.
+
+"""
+
+import os
+import sys
+import stat
+
+__all__ = ["copyfileobj","copyfile","copymode","copystat","copy","copy2",
+ "copytree","rmtree"]
+
+def copyfileobj(fsrc, fdst, length=16*1024):
+ """copy data from file-like object fsrc to file-like object fdst"""
+ while 1:
+ buf = fsrc.read(length)
+ if not buf:
+ break
+ fdst.write(buf)
+
+
+def copyfile(src, dst):
+ """Copy data from src to dst"""
+ fsrc = None
+ fdst = None
+ try:
+ fsrc = open(src, 'rb')
+ fdst = open(dst, 'wb')
+ copyfileobj(fsrc, fdst)
+ finally:
+ if fdst:
+ fdst.close()
+ if fsrc:
+ fsrc.close()
+
+def copymode(src, dst):
+ """Copy mode bits from src to dst"""
+ if hasattr(os, 'chmod'):
+ st = os.stat(src)
+ mode = stat.S_IMODE(st[stat.ST_MODE])
+ os.chmod(dst, mode)
+
+def copystat(src, dst):
+ """Copy all stat info (mode bits, atime and mtime) from src to dst"""
+ st = os.stat(src)
+ mode = stat.S_IMODE(st[stat.ST_MODE])
+ if hasattr(os, 'utime'):
+ os.utime(dst, (st[stat.ST_ATIME], st[stat.ST_MTIME]))
+ if hasattr(os, 'chmod'):
+ os.chmod(dst, mode)
+
+
+def copy(src, dst):
+ """Copy data and mode bits ("cp src dst").
+
+ The destination may be a directory.
+
+ """
+ if os.path.isdir(dst):
+ dst = os.path.join(dst, os.path.basename(src))
+ copyfile(src, dst)
+ copymode(src, dst)
+
+def copy2(src, dst):
+ """Copy data and all stat info ("cp -p src dst").
+
+ The destination may be a directory.
+
+ """
+ if os.path.isdir(dst):
+ dst = os.path.join(dst, os.path.basename(src))
+ copyfile(src, dst)
+ copystat(src, dst)
+
+
+def copytree(src, dst, symlinks=0):
+ """Recursively copy a directory tree using copy2().
+
+ The destination directory must not already exist.
+ Error are reported to standard output.
+
+ If the optional symlinks flag is true, symbolic links in the
+ source tree result in symbolic links in the destination tree; if
+ it is false, the contents of the files pointed to by symbolic
+ links are copied.
+
+ XXX Consider this example code rather than the ultimate tool.
+
+ """
+ names = os.listdir(src)
+ os.mkdir(dst)
+ for name in names:
+ srcname = os.path.join(src, name)
+ dstname = os.path.join(dst, name)
+ try:
+ if symlinks and os.path.islink(srcname):
+ linkto = os.readlink(srcname)
+ os.symlink(linkto, dstname)
+ elif os.path.isdir(srcname):
+ copytree(srcname, dstname, symlinks)
+ else:
+ copy2(srcname, dstname)
+ # XXX What about devices, sockets etc.?
+ except (IOError, os.error), why:
+ print "Can't copy %s to %s: %s" % (`srcname`, `dstname`, str(why))
+
+def rmtree(path, ignore_errors=0, onerror=None):
+ """Recursively delete a directory tree.
+
+ If ignore_errors is set, errors are ignored; otherwise, if
+ onerror is set, it is called to handle the error; otherwise, an
+ exception is raised.
+
+ """
+ cmdtuples = []
+ _build_cmdtuple(path, cmdtuples)
+ for cmd in cmdtuples:
+ try:
+ apply(cmd[0], (cmd[1],))
+ except:
+ exc = sys.exc_info()
+ if ignore_errors:
+ pass
+ elif onerror:
+ onerror(cmd[0], cmd[1], exc)
+ else:
+ raise exc[0], (exc[1][0], exc[1][1] + ' removing '+cmd[1])
+
+# Helper for rmtree()
+def _build_cmdtuple(path, cmdtuples):
+ for f in os.listdir(path):
+ real_f = os.path.join(path,f)
+ if os.path.isdir(real_f) and not os.path.islink(real_f):
+ _build_cmdtuple(real_f, cmdtuples)
+ else:
+ cmdtuples.append((os.remove, real_f))
+ cmdtuples.append((os.rmdir, path))
diff --git a/lib/jython/Lib/site.py b/lib/jython/Lib/site.py new file mode 100644 index 000000000..15f2fd9b9 --- /dev/null +++ b/lib/jython/Lib/site.py @@ -0,0 +1,285 @@ +"""Append module search paths for third-party packages to sys.path.
+
+****************************************************************
+* This module is automatically imported during initialization. *
+****************************************************************
+
+In earlier versions of Python (up to 1.5a3), scripts or modules that
+needed to use site-specific modules would place ``import site''
+somewhere near the top of their code. Because of the automatic
+import, this is no longer necessary (but code that does it still
+works).
+
+This will append site-specific paths to to the module search path. On
+Unix, it starts with sys.prefix and sys.exec_prefix (if different) and
+appends lib/python<version>/site-packages as well as lib/site-python.
+On other platforms (mainly Mac and Windows), it uses just sys.prefix
+\(and sys.exec_prefix, if different, but this is unlikely). The
+resulting directories, if they exist, are appended to sys.path, and
+also inspected for path configuration files.
+
+A path configuration file is a file whose name has the form
+<package>.pth; its contents are additional directories (one per line)
+to be added to sys.path. Non-existing directories (or
+non-directories) are never added to sys.path; no directory is added to
+sys.path more than once. Blank lines and lines beginning with
+\code{#} are skipped. Lines starting with \code{import} are executed.
+
+For example, suppose sys.prefix and sys.exec_prefix are set to
+/usr/local and there is a directory /usr/local/lib/python1.5/site-packages
+with three subdirectories, foo, bar and spam, and two path
+configuration files, foo.pth and bar.pth. Assume foo.pth contains the
+following:
+
+ # foo package configuration
+ foo
+ bar
+ bletch
+
+and bar.pth contains:
+
+ # bar package configuration
+ bar
+
+Then the following directories are added to sys.path, in this order:
+
+ /usr/local/lib/python1.5/site-packages/bar
+ /usr/local/lib/python1.5/site-packages/foo
+
+Note that bletch is omitted because it doesn't exist; bar precedes foo
+because bar.pth comes alphabetically before foo.pth; and spam is
+omitted because it is not mentioned in either path configuration file.
+
+After these path manipulations, an attempt is made to import a module
+named sitecustomize, which can perform arbitrary additional
+site-specific customizations. If this import fails with an
+ImportError exception, it is silently ignored.
+
+"""
+
+import sys, os
+
+if os.sep==".":
+ endsep = "/"
+else:
+ endsep = "."
+
+
+def makepath(*paths):
+ dir = os.path.abspath(os.path.join(*paths))
+ return dir, os.path.normcase(dir)
+
+for m in sys.modules.values():
+ if hasattr(m, "__file__") and m.__file__:
+ m.__file__ = os.path.abspath(m.__file__)
+del m
+
+# This ensures that the initial path provided by the interpreter contains
+# only absolute pathnames, even if we're running from the build directory.
+L = []
+dirs_in_sys_path = {}
+for dir in sys.path:
+ dir, dircase = makepath(dir)
+ if not dirs_in_sys_path.has_key(dircase):
+ L.append(dir)
+ dirs_in_sys_path[dircase] = 1
+sys.path[:] = L
+del dir, L
+
+# Append ./build/lib.<platform> in case we're running in the build dir
+# (especially for Guido :-)
+if os.name == "posix" and os.path.basename(sys.path[-1]) == "Modules":
+ from distutils.util import get_platform
+ s = "build/lib.%s-%.3s" % (get_platform(), sys.version)
+ s = os.path.join(os.path.dirname(sys.path[-1]), s)
+ sys.path.append(s)
+ del get_platform, s
+
+def addsitedir(sitedir):
+ sitedir, sitedircase = makepath(sitedir)
+ if not dirs_in_sys_path.has_key(sitedircase):
+ sys.path.append(sitedir) # Add path component
+ try:
+ names = os.listdir(sitedir)
+ except os.error:
+ return
+ names.sort()
+ for name in names:
+ if name[-4:] == endsep + "pth":
+ addpackage(sitedir, name)
+
+def addpackage(sitedir, name):
+ fullname = os.path.join(sitedir, name)
+ try:
+ f = open(fullname)
+ except IOError:
+ return
+ while 1:
+ dir = f.readline()
+ if not dir:
+ break
+ if dir[0] == '#':
+ continue
+ if dir.startswith("import"):
+ exec dir
+ continue
+ if dir[-1] == '\n':
+ dir = dir[:-1]
+ dir, dircase = makepath(sitedir, dir)
+ if not dirs_in_sys_path.has_key(dircase) and os.path.exists(dir):
+ sys.path.append(dir)
+ dirs_in_sys_path[dircase] = 1
+
+prefixes = [sys.prefix]
+if sys.exec_prefix != sys.prefix:
+ prefixes.append(sys.exec_prefix)
+for prefix in prefixes:
+ if prefix:
+ if os.sep == '/':
+ sitedirs = [os.path.join(prefix,
+ "lib",
+ "python" + sys.version[:3],
+ "site-packages"),
+ os.path.join(prefix, "lib", "site-python")]
+ elif os.sep == ':':
+ sitedirs = [os.path.join(prefix, "lib", "site-packages")]
+ else:
+ sitedirs = [prefix]
+ for sitedir in sitedirs:
+ if os.path.isdir(sitedir):
+ addsitedir(sitedir)
+
+
+# Define new built-ins 'quit' and 'exit'.
+# These are simply strings that display a hint on how to exit.
+if os.sep == ':':
+ exit = 'Use Cmd-Q to quit.'
+elif os.sep == '\\':
+ exit = 'Use Ctrl-Z plus Return to exit.'
+else:
+ exit = 'Use Ctrl-D (i.e. EOF) to exit.'
+import __builtin__
+__builtin__.quit = __builtin__.exit = exit
+del exit
+
+# interactive prompt objects for printing the license text, a list of
+# contributors and the copyright notice.
+class _Printer:
+ MAXLINES = 23
+
+ def __init__(self, name, data, files=(), dirs=()):
+ self.__name = name
+ self.__data = data
+ self.__files = files
+ self.__dirs = dirs
+ self.__lines = None
+
+ def __setup(self):
+ if self.__lines:
+ return
+ data = None
+ for dir in self.__dirs:
+ for file in self.__files:
+ file = os.path.join(dir, file)
+ try:
+ fp = open(file)
+ data = fp.read()
+ fp.close()
+ break
+ except IOError:
+ pass
+ if data:
+ break
+ if not data:
+ data = self.__data
+ self.__lines = data.split('\n')
+ self.__linecnt = len(self.__lines)
+
+ def __repr__(self):
+ self.__setup()
+ if len(self.__lines) <= self.MAXLINES:
+ return "\n".join(self.__lines)
+ else:
+ return "Type %s() to see the full %s text" % ((self.__name,)*2)
+
+ def __call__(self):
+ self.__setup()
+ prompt = 'Hit Return for more, or q (and Return) to quit: '
+ lineno = 0
+ while 1:
+ try:
+ for i in range(lineno, lineno + self.MAXLINES):
+ print self.__lines[i]
+ except IndexError:
+ break
+ else:
+ lineno += self.MAXLINES
+ key = None
+ while key is None:
+ key = raw_input(prompt)
+ if key not in ('', 'q'):
+ key = None
+ if key == 'q':
+ break
+
+__builtin__.copyright = _Printer("copyright", sys.copyright)
+if sys.platform[:4] == 'java':
+ __builtin__.credits = _Printer(
+ "credits",
+ "Jython is maintained by the Jython developers (www.jython.org).")
+else:
+ __builtin__.credits = _Printer("credits", """\
+Thanks to CWI, CNRI, BeOpen.com, Digital Creations and a cast of thousands
+for supporting Python development. See www.python.org for more information.""")
+here = os.path.dirname(os.__file__)
+__builtin__.license = _Printer(
+ "license", "See http://www.pythonlabs.com/products/python2.0/license.html",
+ ["LICENSE.txt", "LICENSE"],
+ [os.path.join(here, os.pardir), here, os.curdir])
+
+
+# Set the string encoding used by the Unicode implementation. The
+# default is 'ascii', but if you're willing to experiment, you can
+# change this.
+
+encoding = "ascii" # Default value set by _PyUnicode_Init()
+
+if 0:
+ # Enable to support locale aware default string encodings.
+ import locale
+ loc = locale.getdefaultlocale()
+ if loc[1]:
+ encoding = loc[1]
+
+if 0:
+ # Enable to switch off string to Unicode coercion and implicit
+ # Unicode to string conversion.
+ encoding = "undefined"
+
+if encoding != "ascii":
+ sys.setdefaultencoding(encoding)
+
+#
+# Run custom site specific code, if available.
+#
+try:
+ import sitecustomize
+except ImportError:
+ pass
+
+#
+# Remove sys.setdefaultencoding() so that users cannot change the
+# encoding after initialization. The test for presence is needed when
+# this module is run as a script, because this code is executed twice.
+#
+if hasattr(sys, "setdefaultencoding"):
+ del sys.setdefaultencoding
+
+def _test():
+ print "sys.path = ["
+ for dir in sys.path:
+ print " %s," % `dir`
+ print "]"
+
+if __name__ == '__main__':
+ _test()
diff --git a/lib/jython/Lib/smtplib.py b/lib/jython/Lib/smtplib.py new file mode 100644 index 000000000..c43326329 --- /dev/null +++ b/lib/jython/Lib/smtplib.py @@ -0,0 +1,543 @@ +#! /usr/bin/env python
+
+'''SMTP/ESMTP client class.
+
+This should follow RFC 821 (SMTP) and RFC 1869 (ESMTP).
+
+Notes:
+
+Please remember, when doing ESMTP, that the names of the SMTP service
+extensions are NOT the same thing as the option keywords for the RCPT
+and MAIL commands!
+
+Example:
+
+ >>> import smtplib
+ >>> s=smtplib.SMTP("localhost")
+ >>> print s.help()
+ This is Sendmail version 8.8.4
+ Topics:
+ HELO EHLO MAIL RCPT DATA
+ RSET NOOP QUIT HELP VRFY
+ EXPN VERB ETRN DSN
+ For more info use "HELP <topic>".
+ To report bugs in the implementation send email to
+ sendmail-bugs@sendmail.org.
+ For local information send email to Postmaster at your site.
+ End of HELP info
+ >>> s.putcmd("vrfy","someone@here")
+ >>> s.getreply()
+ (250, "Somebody OverHere <somebody@here.my.org>")
+ >>> s.quit()
+'''
+
+# Author: The Dragon De Monsyne <dragondm@integral.org>
+# ESMTP support, test code and doc fixes added by
+# Eric S. Raymond <esr@thyrsus.com>
+# Better RFC 821 compliance (MAIL and RCPT, and CRLF in data)
+# by Carey Evans <c.evans@clear.net.nz>, for picky mail servers.
+#
+# This was modified from the Python 1.5 library HTTP lib.
+
+import socket
+import re
+import rfc822
+import types
+
+__all__ = ["SMTPException","SMTPServerDisconnected","SMTPResponseException",
+ "SMTPSenderRefused","SMTPRecipientsRefused","SMTPDataError",
+ "SMTPConnectError","SMTPHeloError","quoteaddr","quotedata",
+ "SMTP"]
+
+SMTP_PORT = 25
+CRLF="\r\n"
+
+# Exception classes used by this module.
+class SMTPException(Exception):
+ """Base class for all exceptions raised by this module."""
+
+class SMTPServerDisconnected(SMTPException):
+ """Not connected to any SMTP server.
+
+ This exception is raised when the server unexpectedly disconnects,
+ or when an attempt is made to use the SMTP instance before
+ connecting it to a server.
+ """
+
+class SMTPResponseException(SMTPException):
+ """Base class for all exceptions that include an SMTP error code.
+
+ These exceptions are generated in some instances when the SMTP
+ server returns an error code. The error code is stored in the
+ `smtp_code' attribute of the error, and the `smtp_error' attribute
+ is set to the error message.
+ """
+
+ def __init__(self, code, msg):
+ self.smtp_code = code
+ self.smtp_error = msg
+ self.args = (code, msg)
+
+class SMTPSenderRefused(SMTPResponseException):
+ """Sender address refused.
+ In addition to the attributes set by on all SMTPResponseException
+ exceptions, this sets `sender' to the string that the SMTP refused.
+ """
+
+ def __init__(self, code, msg, sender):
+ self.smtp_code = code
+ self.smtp_error = msg
+ self.sender = sender
+ self.args = (code, msg, sender)
+
+class SMTPRecipientsRefused(SMTPException):
+ """All recipient addresses refused.
+ The errors for each recipient are accessible through the attribute
+ 'recipients', which is a dictionary of exactly the same sort as
+ SMTP.sendmail() returns.
+ """
+
+ def __init__(self, recipients):
+ self.recipients = recipients
+ self.args = ( recipients,)
+
+
+class SMTPDataError(SMTPResponseException):
+ """The SMTP server didn't accept the data."""
+
+class SMTPConnectError(SMTPResponseException):
+ """Error during connection establishment."""
+
+class SMTPHeloError(SMTPResponseException):
+ """The server refused our HELO reply."""
+
+
+def quoteaddr(addr):
+ """Quote a subset of the email addresses defined by RFC 821.
+
+ Should be able to handle anything rfc822.parseaddr can handle.
+ """
+ m=None
+ try:
+ m=rfc822.parseaddr(addr)[1]
+ except AttributeError:
+ pass
+ if not m:
+ #something weird here.. punt -ddm
+ return addr
+ else:
+ return "<%s>" % m
+
+def quotedata(data):
+ """Quote data for email.
+
+ Double leading '.', and change Unix newline '\\n', or Mac '\\r' into
+ Internet CRLF end-of-line.
+ """
+ return re.sub(r'(?m)^\.', '..',
+ re.sub(r'(?:\r\n|\n|\r(?!\n))', CRLF, data))
+
+
+class SMTP:
+ """This class manages a connection to an SMTP or ESMTP server.
+ SMTP Objects:
+ SMTP objects have the following attributes:
+ helo_resp
+ This is the message given by the server in response to the
+ most recent HELO command.
+
+ ehlo_resp
+ This is the message given by the server in response to the
+ most recent EHLO command. This is usually multiline.
+
+ does_esmtp
+ This is a True value _after you do an EHLO command_, if the
+ server supports ESMTP.
+
+ esmtp_features
+ This is a dictionary, which, if the server supports ESMTP,
+ will _after you do an EHLO command_, contain the names of the
+ SMTP service extensions this server supports, and their
+ parameters (if any).
+
+ Note, all extension names are mapped to lower case in the
+ dictionary.
+
+ See each method's docstrings for details. In general, there is a
+ method of the same name to perform each SMTP command. There is also a
+ method called 'sendmail' that will do an entire mail transaction.
+ """
+ debuglevel = 0
+ file = None
+ helo_resp = None
+ ehlo_resp = None
+ does_esmtp = 0
+
+ def __init__(self, host = '', port = 0):
+ """Initialize a new instance.
+
+ If specified, `host' is the name of the remote host to which to
+ connect. If specified, `port' specifies the port to which to connect.
+ By default, smtplib.SMTP_PORT is used. An SMTPConnectError is raised
+ if the specified `host' doesn't respond correctly.
+
+ """
+ self.esmtp_features = {}
+ if host:
+ (code, msg) = self.connect(host, port)
+ if code != 220:
+ raise SMTPConnectError(code, msg)
+
+ def set_debuglevel(self, debuglevel):
+ """Set the debug output level.
+
+ A non-false value results in debug messages for connection and for all
+ messages sent to and received from the server.
+
+ """
+ self.debuglevel = debuglevel
+
+ def connect(self, host='localhost', port = 0):
+ """Connect to a host on a given port.
+
+ If the hostname ends with a colon (`:') followed by a number, and
+ there is no port specified, that suffix will be stripped off and the
+ number interpreted as the port number to use.
+
+ Note: This method is automatically invoked by __init__, if a host is
+ specified during instantiation.
+
+ """
+ if not port:
+ i = host.find(':')
+ if i >= 0:
+ host, port = host[:i], host[i+1:]
+ try: port = int(port)
+ except ValueError:
+ raise socket.error, "nonnumeric port"
+ if not port: port = SMTP_PORT
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ if self.debuglevel > 0: print 'connect:', (host, port)
+ try:
+ self.sock.connect((host, port))
+ except socket.error:
+ self.close()
+ raise
+ (code,msg)=self.getreply()
+ if self.debuglevel >0 : print "connect:", msg
+ return (code,msg)
+
+ def send(self, str):
+ """Send `str' to the server."""
+ if self.debuglevel > 0: print 'send:', `str`
+ if self.sock:
+ try:
+ sendptr = 0
+ while sendptr < len(str):
+ sendptr = sendptr + self.sock.send(str[sendptr:])
+ except socket.error:
+ raise SMTPServerDisconnected('Server not connected')
+ else:
+ raise SMTPServerDisconnected('please run connect() first')
+
+ def putcmd(self, cmd, args=""):
+ """Send a command to the server."""
+ if args == "":
+ str = '%s%s' % (cmd, CRLF)
+ else:
+ str = '%s %s%s' % (cmd, args, CRLF)
+ self.send(str)
+
+ def getreply(self):
+ """Get a reply from the server.
+
+ Returns a tuple consisting of:
+
+ - server response code (e.g. '250', or such, if all goes well)
+ Note: returns -1 if it can't read response code.
+
+ - server response string corresponding to response code (multiline
+ responses are converted to a single, multiline string).
+
+ Raises SMTPServerDisconnected if end-of-file is reached.
+ """
+ resp=[]
+ if self.file is None:
+ self.file = self.sock.makefile('rb')
+ while 1:
+ line = self.file.readline()
+ if line == '':
+ self.close()
+ raise SMTPServerDisconnected("Connection unexpectedly closed")
+ if self.debuglevel > 0: print 'reply:', `line`
+ resp.append(line[4:].strip())
+ code=line[:3]
+ # Check that the error code is syntactically correct.
+ # Don't attempt to read a continuation line if it is broken.
+ try:
+ errcode = int(code)
+ except ValueError:
+ errcode = -1
+ break
+ # Check if multiline response.
+ if line[3:4]!="-":
+ break
+
+ errmsg = "\n".join(resp)
+ if self.debuglevel > 0:
+ print 'reply: retcode (%s); Msg: %s' % (errcode,errmsg)
+ return errcode, errmsg
+
+ def docmd(self, cmd, args=""):
+ """Send a command, and return its response code."""
+ self.putcmd(cmd,args)
+ return self.getreply()
+
+ # std smtp commands
+ def helo(self, name=''):
+ """SMTP 'helo' command.
+ Hostname to send for this command defaults to the FQDN of the local
+ host.
+ """
+ if name:
+ self.putcmd("helo", name)
+ else:
+ self.putcmd("helo", socket.getfqdn())
+ (code,msg)=self.getreply()
+ self.helo_resp=msg
+ return (code,msg)
+
+ def ehlo(self, name=''):
+ """ SMTP 'ehlo' command.
+ Hostname to send for this command defaults to the FQDN of the local
+ host.
+ """
+ if name:
+ self.putcmd("ehlo", name)
+ else:
+ self.putcmd("ehlo", socket.getfqdn())
+ (code,msg)=self.getreply()
+ # According to RFC1869 some (badly written)
+ # MTA's will disconnect on an ehlo. Toss an exception if
+ # that happens -ddm
+ if code == -1 and len(msg) == 0:
+ raise SMTPServerDisconnected("Server not connected")
+ self.ehlo_resp=msg
+ if code != 250:
+ return (code,msg)
+ self.does_esmtp=1
+ #parse the ehlo response -ddm
+ resp=self.ehlo_resp.split('\n')
+ del resp[0]
+ for each in resp:
+ m=re.match(r'(?P<feature>[A-Za-z0-9][A-Za-z0-9\-]*)',each)
+ if m:
+ feature=m.group("feature").lower()
+ params=m.string[m.end("feature"):].strip()
+ self.esmtp_features[feature]=params
+ return (code,msg)
+
+ def has_extn(self, opt):
+ """Does the server support a given SMTP service extension?"""
+ return self.esmtp_features.has_key(opt.lower())
+
+ def help(self, args=''):
+ """SMTP 'help' command.
+ Returns help text from server."""
+ self.putcmd("help", args)
+ return self.getreply()
+
+ def rset(self):
+ """SMTP 'rset' command -- resets session."""
+ return self.docmd("rset")
+
+ def noop(self):
+ """SMTP 'noop' command -- doesn't do anything :>"""
+ return self.docmd("noop")
+
+ def mail(self,sender,options=[]):
+ """SMTP 'mail' command -- begins mail xfer session."""
+ optionlist = ''
+ if options and self.does_esmtp:
+ optionlist = ' ' + ' '.join(options)
+ self.putcmd("mail", "FROM:%s%s" % (quoteaddr(sender) ,optionlist))
+ return self.getreply()
+
+ def rcpt(self,recip,options=[]):
+ """SMTP 'rcpt' command -- indicates 1 recipient for this mail."""
+ optionlist = ''
+ if options and self.does_esmtp:
+ optionlist = ' ' + ' '.join(options)
+ self.putcmd("rcpt","TO:%s%s" % (quoteaddr(recip),optionlist))
+ return self.getreply()
+
+ def data(self,msg):
+ """SMTP 'DATA' command -- sends message data to server.
+
+ Automatically quotes lines beginning with a period per rfc821.
+ Raises SMTPDataError if there is an unexpected reply to the
+ DATA command; the return value from this method is the final
+ response code received when the all data is sent.
+ """
+ self.putcmd("data")
+ (code,repl)=self.getreply()
+ if self.debuglevel >0 : print "data:", (code,repl)
+ if code != 354:
+ raise SMTPDataError(code,repl)
+ else:
+ q = quotedata(msg)
+ if q[-2:] != CRLF:
+ q = q + CRLF
+ q = q + "." + CRLF
+ self.send(q)
+ (code,msg)=self.getreply()
+ if self.debuglevel >0 : print "data:", (code,msg)
+ return (code,msg)
+
+ def verify(self, address):
+ """SMTP 'verify' command -- checks for address validity."""
+ self.putcmd("vrfy", quoteaddr(address))
+ return self.getreply()
+ # a.k.a.
+ vrfy=verify
+
+ def expn(self, address):
+ """SMTP 'verify' command -- checks for address validity."""
+ self.putcmd("expn", quoteaddr(address))
+ return self.getreply()
+
+ # some useful methods
+ def sendmail(self, from_addr, to_addrs, msg, mail_options=[],
+ rcpt_options=[]):
+ """This command performs an entire mail transaction.
+
+ The arguments are:
+ - from_addr : The address sending this mail.
+ - to_addrs : A list of addresses to send this mail to. A bare
+ string will be treated as a list with 1 address.
+ - msg : The message to send.
+ - mail_options : List of ESMTP options (such as 8bitmime) for the
+ mail command.
+ - rcpt_options : List of ESMTP options (such as DSN commands) for
+ all the rcpt commands.
+
+ If there has been no previous EHLO or HELO command this session, this
+ method tries ESMTP EHLO first. If the server does ESMTP, message size
+ and each of the specified options will be passed to it. If EHLO
+ fails, HELO will be tried and ESMTP options suppressed.
+
+ This method will return normally if the mail is accepted for at least
+ one recipient. It returns a dictionary, with one entry for each
+ recipient that was refused. Each entry contains a tuple of the SMTP
+ error code and the accompanying error message sent by the server.
+
+ This method may raise the following exceptions:
+
+ SMTPHeloError The server didn't reply properly to
+ the helo greeting.
+ SMTPRecipientsRefused The server rejected ALL recipients
+ (no mail was sent).
+ SMTPSenderRefused The server didn't accept the from_addr.
+ SMTPDataError The server replied with an unexpected
+ error code (other than a refusal of
+ a recipient).
+
+ Note: the connection will be open even after an exception is raised.
+
+ Example:
+
+ >>> import smtplib
+ >>> s=smtplib.SMTP("localhost")
+ >>> tolist=["one@one.org","two@two.org","three@three.org","four@four.org"]
+ >>> msg = '''
+ ... From: Me@my.org
+ ... Subject: testin'...
+ ...
+ ... This is a test '''
+ >>> s.sendmail("me@my.org",tolist,msg)
+ { "three@three.org" : ( 550 ,"User unknown" ) }
+ >>> s.quit()
+
+ In the above example, the message was accepted for delivery to three
+ of the four addresses, and one was rejected, with the error code
+ 550. If all addresses are accepted, then the method will return an
+ empty dictionary.
+
+ """
+ if self.helo_resp is None and self.ehlo_resp is None:
+ if not (200 <= self.ehlo()[0] <= 299):
+ (code,resp) = self.helo()
+ if not (200 <= code <= 299):
+ raise SMTPHeloError(code, resp)
+ esmtp_opts = []
+ if self.does_esmtp:
+ # Hmmm? what's this? -ddm
+ # self.esmtp_features['7bit']=""
+ if self.has_extn('size'):
+ esmtp_opts.append("size=" + `len(msg)`)
+ for option in mail_options:
+ esmtp_opts.append(option)
+
+ (code,resp) = self.mail(from_addr, esmtp_opts)
+ if code != 250:
+ self.rset()
+ raise SMTPSenderRefused(code, resp, from_addr)
+ senderrs={}
+ if type(to_addrs) == types.StringType:
+ to_addrs = [to_addrs]
+ for each in to_addrs:
+ (code,resp)=self.rcpt(each, rcpt_options)
+ if (code != 250) and (code != 251):
+ senderrs[each]=(code,resp)
+ if len(senderrs)==len(to_addrs):
+ # the server refused all our recipients
+ self.rset()
+ raise SMTPRecipientsRefused(senderrs)
+ (code,resp) = self.data(msg)
+ if code != 250:
+ self.rset()
+ raise SMTPDataError(code, resp)
+ #if we got here then somebody got our mail
+ return senderrs
+
+
+ def close(self):
+ """Close the connection to the SMTP server."""
+ if self.file:
+ self.file.close()
+ self.file = None
+ if self.sock:
+ self.sock.close()
+ self.sock = None
+
+
+ def quit(self):
+ """Terminate the SMTP session."""
+ self.docmd("quit")
+ self.close()
+
+
+# Test the sendmail method, which tests most of the others.
+# Note: This always sends to localhost.
+if __name__ == '__main__':
+ import sys, rfc822
+
+ def prompt(prompt):
+ sys.stdout.write(prompt + ": ")
+ return sys.stdin.readline().strip()
+
+ fromaddr = prompt("From")
+ toaddrs = prompt("To").split(',')
+ print "Enter message, end with ^D:"
+ msg = ''
+ while 1:
+ line = sys.stdin.readline()
+ if not line:
+ break
+ msg = msg + line
+ print "Message length is " + `len(msg)`
+
+ server = SMTP('localhost')
+ server.set_debuglevel(1)
+ server.sendmail(fromaddr, toaddrs, msg)
+ server.quit()
diff --git a/lib/jython/Lib/sndhdr.py b/lib/jython/Lib/sndhdr.py new file mode 100644 index 000000000..382a3511a --- /dev/null +++ b/lib/jython/Lib/sndhdr.py @@ -0,0 +1,228 @@ +"""Routines to 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 what() calls whathdr(). (It used to also use some
+heuristics for raw data, but this doesn't work very well.)
+
+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.
+
+__all__ = ["what","whathdr"]
+
+def what(filename):
+ """Guess the type of a sound file"""
+ res = whathdr(filename)
+ return res
+
+
+def whathdr(filename):
+ """Recognize sound headers"""
+ 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 ***'
+
+if __name__ == '__main__':
+ test()
diff --git a/lib/jython/Lib/socket.py b/lib/jython/Lib/socket.py new file mode 100644 index 000000000..1aaf2eacc --- /dev/null +++ b/lib/jython/Lib/socket.py @@ -0,0 +1,361 @@ +"""Preliminary socket module.
+
+XXX Restrictions:
+
+- Only INET sockets
+- No asynchronous behavior
+- No socket options
+- Can't do a very good gethostbyaddr() right...
+
+"""
+
+import java.net
+import org.python.core
+import jarray
+import string
+
+__all__ = ['AF_INET', 'SOCK_DGRAM', 'SOCK_RAW', 'SOCK_RDM', 'SOCK_SEQPACKET',
+ 'SOCK_STREAM', 'SocketType', 'error', 'getfqdn', 'gethostbyaddr',
+ 'gethostbyname', 'gethostname', 'socket']
+
+error = IOError
+
+AF_INET = 2
+
+SOCK_DGRAM = 1
+SOCK_STREAM = 2
+SOCK_RAW = 3 # not supported
+SOCK_RDM = 4 # not supported
+SOCK_SEQPACKET = 5 # not supported
+SOL_SOCKET = 0xFFFF
+SO_REUSEADDR = 4
+
+def _gethostbyaddr(name):
+ # This is as close as I can get; at least the types are correct...
+ addresses = java.net.InetAddress.getAllByName(gethostbyname(name))
+ names = []
+ addrs = []
+ for addr in addresses:
+ names.append(addr.getHostName())
+ addrs.append(addr.getHostAddress())
+ return (names, addrs)
+
+def getfqdn(name=None):
+ """
+ Return a fully qualified domain name for name. If name is omitted or empty
+ it is interpreted as the local host. To find the fully qualified name,
+ the hostname returned by gethostbyaddr() is checked, then aliases for the
+ host, if available. The first name which includes a period is selected.
+ In case no fully qualified domain name is available, the hostname is retur
+ New in version 2.0.
+ """
+ if not name:
+ name = gethostname()
+ names, addrs = _gethostbyaddr(name)
+ for a in names:
+ if a.find(".") >= 0:
+ return a
+ return name
+
+def gethostname():
+ return java.net.InetAddress.getLocalHost().getHostName()
+
+def gethostbyname(name):
+ return java.net.InetAddress.getByName(name).getHostAddress()
+
+def gethostbyaddr(name):
+ names, addrs = _gethostbyaddr(name)
+ return (names[0], names, addrs)
+
+
+def socket(family, type, flags=0):
+ assert family == AF_INET
+ assert type in (SOCK_DGRAM, SOCK_STREAM)
+ assert flags == 0
+ if type == SOCK_STREAM:
+ return _tcpsocket()
+ else:
+ return _udpsocket()
+
+
+class _tcpsocket:
+
+ sock = None
+ istream = None
+ ostream = None
+ addr = None
+ server = 0
+ file_count = 0
+ reuse_addr = 0
+
+ def bind(self, addr, port=None):
+ if port is not None:
+ addr = (addr, port)
+ assert not self.sock
+ assert not self.addr
+ host, port = addr # format check
+ self.addr = addr
+
+ def listen(self, backlog=50):
+ "This signifies a server socket"
+ assert not self.sock
+ self.server = 1
+ if self.addr:
+ host, port = self.addr
+ else:
+ host, port = "", 0
+ if host:
+ a = java.net.InetAddress.getByName(host)
+ self.sock = java.net.ServerSocket(port, backlog, a)
+ else:
+ self.sock = java.net.ServerSocket(port, backlog)
+ if hasattr(self.sock, "setReuseAddress"):
+ self.sock.setReuseAddress(self.reuse_addr)
+
+ def accept(self):
+ "This signifies a server socket"
+ if not self.sock:
+ self.listen()
+ assert self.server
+ sock = self.sock.accept()
+ host = sock.getInetAddress().getHostName()
+ port = sock.getPort()
+ conn = _tcpsocket()
+ conn._setup(sock)
+ return conn, (host, port)
+
+ def connect(self, addr, port=None):
+ "This signifies a client socket"
+ if port is not None:
+ addr = (addr, port)
+ assert not self.sock
+ host, port = addr
+ if host == "":
+ host = java.net.InetAddress.getLocalHost()
+ self._setup(java.net.Socket(host, port))
+
+ def _setup(self, sock):
+ self.sock = sock
+ if hasattr(self.sock, "setReuseAddress"):
+ self.sock.setReuseAddress(self.reuse_addr)
+ self.istream = sock.getInputStream()
+ self.ostream = sock.getOutputStream()
+
+ def recv(self, n):
+ assert self.sock
+ data = jarray.zeros(n, 'b')
+ m = self.istream.read(data)
+ if m <= 0:
+ return ""
+ if m < n:
+ data = data[:m]
+ return data.tostring()
+
+ def send(self, s):
+ assert self.sock
+ n = len(s)
+ self.ostream.write(s)
+ return n
+
+ def getsockname(self):
+ if not self.sock:
+ host, port = self.addr or ("", 0)
+ host = java.net.InetAddress.getByName(host).getHostAddress()
+ else:
+ if self.server:
+ host = self.sock.getInetAddress().getHostAddress()
+ else:
+ host = self.sock.getLocalAddress().getHostAddress()
+ port = self.sock.getLocalPort()
+ return (host, port)
+
+ def getpeername(self):
+ assert self.sock
+ assert not self.server
+ host = self.sock.getInetAddress().getHostAddress()
+ port = self.sock.getPort()
+ return (host, port)
+
+ def setsockopt(self, level, optname, value):
+ if optname == SO_REUSEADDR:
+ self.reuse_addr = value
+
+ def getsockopt(self, level, optname):
+ if optname == SO_REUSEADDR:
+ return self.reuse_addr
+
+ def makefile(self, mode="r", bufsize=-1):
+ file = None
+ if self.istream:
+ if self.ostream:
+ file = org.python.core.PyFile(self.istream, self.ostream,
+ "<socket>", mode)
+ else:
+ file = org.python.core.PyFile(self.istream, "<socket>", mode)
+ elif self.ostream:
+ file = org.python.core.PyFile(self.ostream, "<socket>", mode)
+ else:
+ raise IOError, "both istream and ostream have been shut down"
+ if file:
+ return _tcpsocket.FileWrapper(self, file)
+
+ class FileWrapper:
+ def __init__(self, socket, file):
+ self.socket = socket
+ self.sock = socket.sock
+ self.istream = socket.istream
+ self.ostream = socket.ostream
+
+ self.file = file
+ self.read = file.read
+ self.readline = file.readline
+ self.readlines = file.readlines
+ self.write = file.write
+ self.writelines = file.writelines
+ self.flush = file.flush
+ self.seek = file.seek
+ self.tell = file.tell
+
+ self.socket.file_count += 1
+
+ def close(self):
+ if self.file.closed:
+ # Already closed
+ return
+
+ self.socket.file_count -= 1
+ self.file.close()
+
+ if self.socket.file_count == 0 and self.socket.sock == 0:
+ # This is the last file Only close the socket and streams
+ # if there are no outstanding files left.
+ if self.sock:
+ self.sock.close()
+ if self.istream:
+ self.istream.close()
+ if self.ostream:
+ self.ostream.close()
+
+ def shutdown(self, how):
+ assert how in (0, 1, 2)
+ assert self.sock
+ if how in (0, 2):
+ self.istream = None
+ if how in (1, 2):
+ self.ostream = None
+
+ def close(self):
+ sock = self.sock
+ istream = self.istream
+ ostream = self.ostream
+ self.sock = 0
+ self.istream = 0
+ self.ostream = 0
+ # Only close the socket and streams if there are no
+ # outstanding files left.
+ if self.file_count == 0:
+ if istream:
+ istream.close()
+ if ostream:
+ ostream.close()
+ if sock:
+ sock.close()
+
+
+class _udpsocket:
+
+ def __init__(self):
+ self.sock = None
+ self.addr = None
+
+ def bind(self, addr, port=None):
+ if port is not None:
+ addr = (addr, port)
+ assert not self.sock
+ host, port = addr
+ if host == "":
+ self.sock = java.net.DatagramSocket(port)
+ else:
+ a = java.net.InetAddress.getByName(host)
+ self.sock = java.net.DatagramSocket(port, a)
+
+ def connect(self, addr, port=None):
+ if port is not None:
+ addr = (addr, port)
+ host, port = addr # format check
+ assert not self.addr
+ if not self.sock:
+ self.sock = java.net.DatagramSocket()
+ self.addr = addr # convert host to InetAddress instance?
+
+ def sendto(self, data, addr):
+ n = len(data)
+ if not self.sock:
+ self.sock = java.net.DatagramSocket()
+ host, port = addr
+ bytes = jarray.array(map(ord, data), 'b')
+ a = java.net.InetAddress.getByName(host)
+ packet = java.net.DatagramPacket(bytes, n, a, port)
+ self.sock.send(packet)
+ return n
+
+ def send(self, data):
+ assert self.addr
+ return self.sendto(self.addr)
+
+ def recvfrom(self, n):
+ assert self.sock
+ bytes = jarray.zeros(n, 'b')
+ packet = java.net.DatagramPacket(bytes, n)
+ self.sock.receive(packet)
+ host = packet.getAddress().getHostName()
+ port = packet.getPort()
+ m = packet.getLength()
+ if m < n:
+ bytes = bytes[:m]
+ return bytes.tostring(), (host, port)
+
+ def recv(self, n):
+ assert self.sock
+ bytes = jarray.zeros(n, 'b')
+ packet = java.net.DatagramPacket(bytes, n)
+ self.sock.receive(packet)
+ m = packet.getLength()
+ if m < n:
+ bytes = bytes[:m]
+ return bytes.tostring()
+
+ def getsockname(self):
+ assert self.sock
+ host = self.sock.getLocalAddress().getHostName()
+ port = self.sock.getLocalPort()
+ return (host, port)
+
+ def getpeername(self):
+ assert self.sock
+ host = self.sock.getInetAddress().getHostName()
+ port = self.sock.getPort()
+ return (host, port)
+
+ def __del__(self):
+ self.close()
+
+ def close(self):
+ sock = self.sock
+ self.sock = 0
+ sock.close()
+
+SocketType = _tcpsocket
+
+def test():
+ s = socket(AF_INET, SOCK_STREAM)
+ s.connect(("", 80))
+ s.send("GET / HTTP/1.0\r\n\r\n")
+ while 1:
+ data = s.recv(2000)
+ print data
+ if not data:
+ break
+
+if __name__ == '__main__':
+ test()
diff --git a/lib/jython/Lib/sre.py b/lib/jython/Lib/sre.py new file mode 100644 index 000000000..d159a77d5 --- /dev/null +++ b/lib/jython/Lib/sre.py @@ -0,0 +1,261 @@ +#
+# Secret Labs' Regular Expression Engine
+#
+# re-compatible interface for the sre matching engine
+#
+# Copyright (c) 1998-2001 by Secret Labs AB. All rights reserved.
+#
+# This version of the SRE library can be redistributed under CNRI's
+# Python 1.6 license. For any other use, please contact Secret Labs
+# AB (info@pythonware.com).
+#
+# Portions of this engine have been developed in cooperation with
+# CNRI. Hewlett-Packard provided funding for 1.6 integration and
+# other compatibility work.
+#
+
+import sre_compile
+import sre_parse
+
+# public symbols
+__all__ = [ "match", "search", "sub", "subn", "split", "findall",
+ "compile", "purge", "template", "escape", "I", "L", "M", "S", "X",
+ "U", "IGNORECASE", "LOCALE", "MULTILINE", "DOTALL", "VERBOSE",
+ "UNICODE", "error" ]
+
+__version__ = "2.1b2"
+
+# this module works under 1.5.2 and later. don't use string methods
+import string
+
+# flags
+I = IGNORECASE = sre_compile.SRE_FLAG_IGNORECASE # ignore case
+L = LOCALE = sre_compile.SRE_FLAG_LOCALE # assume current 8-bit locale
+U = UNICODE = sre_compile.SRE_FLAG_UNICODE # assume unicode locale
+M = MULTILINE = sre_compile.SRE_FLAG_MULTILINE # make anchors look for newline
+S = DOTALL = sre_compile.SRE_FLAG_DOTALL # make dot match newline
+X = VERBOSE = sre_compile.SRE_FLAG_VERBOSE # ignore whitespace and comments
+
+# sre extensions (experimental, don't rely on these)
+T = TEMPLATE = sre_compile.SRE_FLAG_TEMPLATE # disable backtracking
+DEBUG = sre_compile.SRE_FLAG_DEBUG # dump pattern after compilation
+
+# sre exception
+error = sre_compile.error
+
+# --------------------------------------------------------------------
+# public interface
+
+def match(pattern, string, flags=0):
+ """Try to apply the pattern at the start of the string, returning
+ a match object, or None if no match was found."""
+ return _compile(pattern, flags).match(string)
+
+def search(pattern, string, flags=0):
+ """Scan through string looking for a match to the pattern, returning
+ a match object, or None if no match was found."""
+ return _compile(pattern, flags).search(string)
+
+def sub(pattern, repl, string, count=0):
+ """Return the string obtained by replacing the leftmost
+ non-overlapping occurrences of the pattern in string by the
+ replacement repl"""
+ return _compile(pattern, 0).sub(repl, string, count)
+
+def subn(pattern, repl, string, count=0):
+ """Return a 2-tuple containing (new_string, number).
+ new_string is the string obtained by replacing the leftmost
+ non-overlapping occurrences of the pattern in the source
+ string by the replacement repl. number is the number of
+ substitutions that were made."""
+ return _compile(pattern, 0).subn(repl, string, count)
+
+def split(pattern, string, maxsplit=0):
+ """Split the source string by the occurrences of the pattern,
+ returning a list containing the resulting substrings."""
+ return _compile(pattern, 0).split(string, maxsplit)
+
+def findall(pattern, string, maxsplit=0):
+ """Return a list of all non-overlapping matches in the string.
+
+ If one or more groups are present in the pattern, return a
+ list of groups; this will be a list of tuples if the pattern
+ has more than one group.
+
+ Empty matches are included in the result."""
+ return _compile(pattern, 0).findall(string, maxsplit)
+
+def compile(pattern, flags=0):
+ "Compile a regular expression pattern, returning a pattern object."
+ return _compile(pattern, flags)
+
+def purge():
+ "Clear the regular expression cache"
+ _cache.clear()
+ _cache_repl.clear()
+
+def template(pattern, flags=0):
+ "Compile a template pattern, returning a pattern object"
+ return _compile(pattern, flags|T)
+
+def escape(pattern):
+ "Escape all non-alphanumeric characters in pattern."
+ s = list(pattern)
+ for i in range(len(pattern)):
+ c = pattern[i]
+ if not ("a" <= c <= "z" or "A" <= c <= "Z" or "0" <= c <= "9"):
+ if c == "\000":
+ s[i] = "\\000"
+ else:
+ s[i] = "\\" + c
+ return _join(s, pattern)
+
+# --------------------------------------------------------------------
+# internals
+
+_cache = {}
+_cache_repl = {}
+
+_MAXCACHE = 100
+
+def _join(seq, sep):
+ # internal: join into string having the same type as sep
+ return string.join(seq, sep[:0])
+
+def _compile(*key):
+ # internal: compile pattern
+ p = _cache.get(key)
+ if p is not None:
+ return p
+ pattern, flags = key
+ if type(pattern) not in sre_compile.STRING_TYPES:
+ return pattern
+ try:
+ p = sre_compile.compile(pattern, flags)
+ except error, v:
+ raise error, v # invalid expression
+ if len(_cache) >= _MAXCACHE:
+ _cache.clear()
+ _cache[key] = p
+ return p
+
+def _compile_repl(*key):
+ # internal: compile replacement pattern
+ p = _cache_repl.get(key)
+ if p is not None:
+ return p
+ repl, pattern = key
+ try:
+ p = sre_parse.parse_template(repl, pattern)
+ except error, v:
+ raise error, v # invalid expression
+ if len(_cache_repl) >= _MAXCACHE:
+ _cache_repl.clear()
+ _cache_repl[key] = p
+ return p
+
+def _expand(pattern, match, template):
+ # internal: match.expand implementation hook
+ template = sre_parse.parse_template(template, pattern)
+ return sre_parse.expand_template(template, match)
+
+def _sub(pattern, template, string, count=0):
+ # internal: pattern.sub implementation hook
+ return _subn(pattern, template, string, count)[0]
+
+def _subn(pattern, template, string, count=0):
+ # internal: pattern.subn implementation hook
+ if callable(template):
+ filter = template
+ else:
+ template = _compile_repl(template, pattern)
+ def filter(match, template=template):
+ return sre_parse.expand_template(template, match)
+ n = i = 0
+ s = []
+ append = s.append
+ c = pattern.scanner(string)
+ while not count or n < count:
+ m = c.search()
+ if not m:
+ break
+ b, e = m.span()
+ if i < b:
+ append(string[i:b])
+ append(filter(m))
+ i = e
+ n = n + 1
+ append(string[i:])
+ return _join(s, string[:0]), n
+
+def _split(pattern, string, maxsplit=0):
+ # internal: pattern.split implementation hook
+ n = i = 0
+ s = []
+ append = s.append
+ extend = s.extend
+ c = pattern.scanner(string)
+ g = pattern.groups
+ while not maxsplit or n < maxsplit:
+ m = c.search()
+ if not m:
+ break
+ b, e = m.span()
+ if b == e:
+ if i >= len(string):
+ break
+ continue
+ append(string[i:b])
+ if g and b != e:
+ extend(list(m.groups()))
+ i = e
+ n = n + 1
+ append(string[i:])
+ return s
+
+# register myself for pickling
+
+import copy_reg
+
+def _pickle(p):
+ return _compile, (p.pattern, p.flags)
+
+copy_reg.pickle(type(_compile("", 0)), _pickle, _compile)
+
+# --------------------------------------------------------------------
+# experimental stuff (see python-dev discussions for details)
+
+class Scanner:
+ def __init__(self, lexicon):
+ from sre_constants import BRANCH, SUBPATTERN
+ self.lexicon = lexicon
+ # combine phrases into a compound pattern
+ p = []
+ s = sre_parse.Pattern()
+ for phrase, action in lexicon:
+ p.append(sre_parse.SubPattern(s, [
+ (SUBPATTERN, (len(p), sre_parse.parse(phrase))),
+ ]))
+ p = sre_parse.SubPattern(s, [(BRANCH, (None, p))])
+ s.groups = len(p)
+ self.scanner = sre_compile.compile(p)
+ def scan(self, string):
+ result = []
+ append = result.append
+ match = self.scanner.match
+ i = 0
+ while 1:
+ m = match(string, i)
+ if not m:
+ break
+ j = m.end()
+ if i == j:
+ break
+ action = self.lexicon[m.lastindex][1]
+ if callable(action):
+ self.match = m
+ action = action(self, m.group())
+ if action is not None:
+ append(action)
+ i = j
+ return result, string[i:]
diff --git a/lib/jython/Lib/sre_compile.py b/lib/jython/Lib/sre_compile.py new file mode 100644 index 000000000..f247f00e1 --- /dev/null +++ b/lib/jython/Lib/sre_compile.py @@ -0,0 +1,386 @@ +#
+# Secret Labs' Regular Expression Engine
+#
+# convert template to internal format
+#
+# Copyright (c) 1997-2001 by Secret Labs AB. All rights reserved.
+#
+# See the sre.py file for information on usage and redistribution.
+#
+
+import _sre
+
+from sre_constants import *
+
+assert _sre.MAGIC == MAGIC, "SRE module mismatch"
+
+MAXCODE = 65535
+
+def _compile(code, pattern, flags):
+ # internal: compile a (sub)pattern
+ emit = code.append
+ for op, av in pattern:
+ if op in (LITERAL, NOT_LITERAL):
+ if flags & SRE_FLAG_IGNORECASE:
+ emit(OPCODES[OP_IGNORE[op]])
+ emit(_sre.getlower(av, flags))
+ else:
+ emit(OPCODES[op])
+ emit(av)
+ elif op is IN:
+ if flags & SRE_FLAG_IGNORECASE:
+ emit(OPCODES[OP_IGNORE[op]])
+ def fixup(literal, flags=flags):
+ return _sre.getlower(literal, flags)
+ else:
+ emit(OPCODES[op])
+ fixup = lambda x: x
+ skip = len(code); emit(0)
+ _compile_charset(av, flags, code, fixup)
+ code[skip] = len(code) - skip
+ elif op is ANY:
+ if flags & SRE_FLAG_DOTALL:
+ emit(OPCODES[ANY_ALL])
+ else:
+ emit(OPCODES[ANY])
+ elif op in (REPEAT, MIN_REPEAT, MAX_REPEAT):
+ if flags & SRE_FLAG_TEMPLATE:
+ raise error, "internal: unsupported template operator"
+ emit(OPCODES[REPEAT])
+ skip = len(code); emit(0)
+ emit(av[0])
+ emit(av[1])
+ _compile(code, av[2], flags)
+ emit(OPCODES[SUCCESS])
+ code[skip] = len(code) - skip
+ elif _simple(av) and op == MAX_REPEAT:
+ emit(OPCODES[REPEAT_ONE])
+ skip = len(code); emit(0)
+ emit(av[0])
+ emit(av[1])
+ _compile(code, av[2], flags)
+ emit(OPCODES[SUCCESS])
+ code[skip] = len(code) - skip
+ else:
+ emit(OPCODES[REPEAT])
+ skip = len(code); emit(0)
+ emit(av[0])
+ emit(av[1])
+ _compile(code, av[2], flags)
+ code[skip] = len(code) - skip
+ if op == MAX_REPEAT:
+ emit(OPCODES[MAX_UNTIL])
+ else:
+ emit(OPCODES[MIN_UNTIL])
+ elif op is SUBPATTERN:
+ if av[0]:
+ emit(OPCODES[MARK])
+ emit((av[0]-1)*2)
+ # _compile_info(code, av[1], flags)
+ _compile(code, av[1], flags)
+ if av[0]:
+ emit(OPCODES[MARK])
+ emit((av[0]-1)*2+1)
+ elif op in (SUCCESS, FAILURE):
+ emit(OPCODES[op])
+ elif op in (ASSERT, ASSERT_NOT):
+ emit(OPCODES[op])
+ skip = len(code); emit(0)
+ if av[0] >= 0:
+ emit(0) # look ahead
+ else:
+ lo, hi = av[1].getwidth()
+ if lo != hi:
+ raise error, "look-behind requires fixed-width pattern"
+ emit(lo) # look behind
+ _compile(code, av[1], flags)
+ emit(OPCODES[SUCCESS])
+ code[skip] = len(code) - skip
+ elif op is CALL:
+ emit(OPCODES[op])
+ skip = len(code); emit(0)
+ _compile(code, av, flags)
+ emit(OPCODES[SUCCESS])
+ code[skip] = len(code) - skip
+ elif op is AT:
+ emit(OPCODES[op])
+ if flags & SRE_FLAG_MULTILINE:
+ av = AT_MULTILINE.get(av, av)
+ if flags & SRE_FLAG_LOCALE:
+ av = AT_LOCALE.get(av, av)
+ elif flags & SRE_FLAG_UNICODE:
+ av = AT_UNICODE.get(av, av)
+ emit(ATCODES[av])
+ elif op is BRANCH:
+ emit(OPCODES[op])
+ tail = []
+ for av in av[1]:
+ skip = len(code); emit(0)
+ # _compile_info(code, av, flags)
+ _compile(code, av, flags)
+ emit(OPCODES[JUMP])
+ tail.append(len(code)); emit(0)
+ code[skip] = len(code) - skip
+ emit(0) # end of branch
+ for tail in tail:
+ code[tail] = len(code) - tail
+ elif op is CATEGORY:
+ emit(OPCODES[op])
+ if flags & SRE_FLAG_LOCALE:
+ av = CH_LOCALE[av]
+ elif flags & SRE_FLAG_UNICODE:
+ av = CH_UNICODE[av]
+ emit(CHCODES[av])
+ elif op is GROUPREF:
+ if flags & SRE_FLAG_IGNORECASE:
+ emit(OPCODES[OP_IGNORE[op]])
+ else:
+ emit(OPCODES[op])
+ emit(av-1)
+ else:
+ raise ValueError, ("unsupported operand type", op)
+
+def _compile_charset(charset, flags, code, fixup=None):
+ # compile charset subprogram
+ emit = code.append
+ if not fixup:
+ fixup = lambda x: x
+ for op, av in _optimize_charset(charset, fixup):
+ emit(OPCODES[op])
+ if op is NEGATE:
+ pass
+ elif op is LITERAL:
+ emit(fixup(av))
+ elif op is RANGE:
+ emit(fixup(av[0]))
+ emit(fixup(av[1]))
+ elif op is CHARSET:
+ code.extend(av)
+ elif op is CATEGORY:
+ if flags & SRE_FLAG_LOCALE:
+ emit(CHCODES[CH_LOCALE[av]])
+ elif flags & SRE_FLAG_UNICODE:
+ emit(CHCODES[CH_UNICODE[av]])
+ else:
+ emit(CHCODES[av])
+ else:
+ raise error, "internal: unsupported set operator"
+ emit(OPCODES[FAILURE])
+
+def _optimize_charset(charset, fixup):
+ # internal: optimize character set
+ out = []
+ charmap = [0]*256
+ try:
+ for op, av in charset:
+ if op is NEGATE:
+ out.append((op, av))
+ elif op is LITERAL:
+ charmap[fixup(av)] = 1
+ elif op is RANGE:
+ for i in range(fixup(av[0]), fixup(av[1])+1):
+ charmap[i] = 1
+ elif op is CATEGORY:
+ # XXX: could append to charmap tail
+ return charset # cannot compress
+ except IndexError:
+ # character set contains unicode characters
+ return charset
+ # compress character map
+ i = p = n = 0
+ runs = []
+ for c in charmap:
+ if c:
+ if n == 0:
+ p = i
+ n = n + 1
+ elif n:
+ runs.append((p, n))
+ n = 0
+ i = i + 1
+ if n:
+ runs.append((p, n))
+ if len(runs) <= 2:
+ # use literal/range
+ for p, n in runs:
+ if n == 1:
+ out.append((LITERAL, p))
+ else:
+ out.append((RANGE, (p, p+n-1)))
+ if len(out) < len(charset):
+ return out
+ else:
+ # use bitmap
+ data = []
+ m = 1; v = 0
+ for c in charmap:
+ if c:
+ v = v + m
+ m = m << 1
+ if m > MAXCODE:
+ data.append(v)
+ m = 1; v = 0
+ out.append((CHARSET, data))
+ return out
+ return charset
+
+def _simple(av):
+ # check if av is a "simple" operator
+ lo, hi = av[2].getwidth()
+ if lo == 0 and hi == MAXREPEAT:
+ raise error, "nothing to repeat"
+ return lo == hi == 1 and av[2][0][0] != SUBPATTERN
+
+def _compile_info(code, pattern, flags):
+ # internal: compile an info block. in the current version,
+ # this contains min/max pattern width, and an optional literal
+ # prefix or a character map
+ lo, hi = pattern.getwidth()
+ if lo == 0:
+ return # not worth it
+ # look for a literal prefix
+ prefix = []
+ prefix_skip = 0
+ charset = [] # not used
+ if not (flags & SRE_FLAG_IGNORECASE):
+ # look for literal prefix
+ for op, av in pattern.data:
+ if op is LITERAL:
+ if len(prefix) == prefix_skip:
+ prefix_skip = prefix_skip + 1
+ prefix.append(av)
+ elif op is SUBPATTERN and len(av[1]) == 1:
+ op, av = av[1][0]
+ if op is LITERAL:
+ prefix.append(av)
+ else:
+ break
+ else:
+ break
+ # if no prefix, look for charset prefix
+ if not prefix and pattern.data:
+ op, av = pattern.data[0]
+ if op is SUBPATTERN and av[1]:
+ op, av = av[1][0]
+ if op is LITERAL:
+ charset.append((op, av))
+ elif op is BRANCH:
+ c = []
+ for p in av[1]:
+ if not p:
+ break
+ op, av = p[0]
+ if op is LITERAL:
+ c.append((op, av))
+ else:
+ break
+ else:
+ charset = c
+ elif op is BRANCH:
+ c = []
+ for p in av[1]:
+ if not p:
+ break
+ op, av = p[0]
+ if op is LITERAL:
+ c.append((op, av))
+ else:
+ break
+ else:
+ charset = c
+ elif op is IN:
+ charset = av
+## if prefix:
+## print "*** PREFIX", prefix, prefix_skip
+## if charset:
+## print "*** CHARSET", charset
+ # add an info block
+ emit = code.append
+ emit(OPCODES[INFO])
+ skip = len(code); emit(0)
+ # literal flag
+ mask = 0
+ if prefix:
+ mask = SRE_INFO_PREFIX
+ if len(prefix) == prefix_skip == len(pattern.data):
+ mask = mask + SRE_INFO_LITERAL
+ elif charset:
+ mask = mask + SRE_INFO_CHARSET
+ emit(mask)
+ # pattern length
+ if lo < MAXCODE:
+ emit(lo)
+ else:
+ emit(MAXCODE)
+ prefix = prefix[:MAXCODE]
+ if hi < MAXCODE:
+ emit(hi)
+ else:
+ emit(0)
+ # add literal prefix
+ if prefix:
+ emit(len(prefix)) # length
+ emit(prefix_skip) # skip
+ code.extend(prefix)
+ # generate overlap table
+ table = [-1] + ([0]*len(prefix))
+ for i in range(len(prefix)):
+ table[i+1] = table[i]+1
+ while table[i+1] > 0 and prefix[i] != prefix[table[i+1]-1]:
+ table[i+1] = table[table[i+1]-1]+1
+ code.extend(table[1:]) # don't store first entry
+ elif charset:
+ _compile_charset(charset, 0, code)
+ code[skip] = len(code) - skip
+
+STRING_TYPES = [type("")]
+
+try:
+ STRING_TYPES.append(type(unicode("")))
+except NameError:
+ pass
+
+def _code(p, flags):
+
+ flags = p.pattern.flags | flags
+ code = []
+
+ # compile info block
+ _compile_info(code, p, flags)
+
+ # compile the pattern
+ _compile(code, p.data, flags)
+
+ code.append(OPCODES[SUCCESS])
+
+ return code
+
+def compile(p, flags=0):
+ # internal: convert pattern list to internal format
+
+ if type(p) in STRING_TYPES:
+ import sre_parse
+ pattern = p
+ p = sre_parse.parse(p, flags)
+ else:
+ pattern = None
+
+ code = _code(p, flags)
+
+ # print code
+
+ # XXX: <fl> get rid of this limitation!
+ assert p.pattern.groups <= 100,\
+ "sorry, but this version only supports 100 named groups"
+
+ # map in either direction
+ groupindex = p.pattern.groupdict
+ indexgroup = [None] * p.pattern.groups
+ for k, i in groupindex.items():
+ indexgroup[i] = k
+
+ return _sre.compile(
+ pattern, flags, code,
+ p.pattern.groups-1,
+ groupindex, indexgroup
+ )
diff --git a/lib/jython/Lib/sre_constants.py b/lib/jython/Lib/sre_constants.py new file mode 100644 index 000000000..bd6de4109 --- /dev/null +++ b/lib/jython/Lib/sre_constants.py @@ -0,0 +1,256 @@ +#
+# Secret Labs' Regular Expression Engine
+#
+# various symbols used by the regular expression engine.
+# run this script to update the _sre include files!
+#
+# Copyright (c) 1998-2001 by Secret Labs AB. All rights reserved.
+#
+# See the sre.py file for information on usage and redistribution.
+#
+
+# update when constants are added or removed
+
+MAGIC = 20010320
+
+# max code word in this release
+
+MAXREPEAT = 65535
+
+# SRE standard exception (access as sre.error)
+# should this really be here?
+
+class error(Exception):
+ pass
+
+# operators
+
+FAILURE = "failure"
+SUCCESS = "success"
+
+ANY = "any"
+ANY_ALL = "any_all"
+ASSERT = "assert"
+ASSERT_NOT = "assert_not"
+AT = "at"
+BRANCH = "branch"
+CALL = "call"
+CATEGORY = "category"
+CHARSET = "charset"
+GROUPREF = "groupref"
+GROUPREF_IGNORE = "groupref_ignore"
+IN = "in"
+IN_IGNORE = "in_ignore"
+INFO = "info"
+JUMP = "jump"
+LITERAL = "literal"
+LITERAL_IGNORE = "literal_ignore"
+MARK = "mark"
+MAX_REPEAT = "max_repeat"
+MAX_UNTIL = "max_until"
+MIN_REPEAT = "min_repeat"
+MIN_UNTIL = "min_until"
+NEGATE = "negate"
+NOT_LITERAL = "not_literal"
+NOT_LITERAL_IGNORE = "not_literal_ignore"
+RANGE = "range"
+REPEAT = "repeat"
+REPEAT_ONE = "repeat_one"
+SUBPATTERN = "subpattern"
+
+# positions
+AT_BEGINNING = "at_beginning"
+AT_BEGINNING_LINE = "at_beginning_line"
+AT_BEGINNING_STRING = "at_beginning_string"
+AT_BOUNDARY = "at_boundary"
+AT_NON_BOUNDARY = "at_non_boundary"
+AT_END = "at_end"
+AT_END_LINE = "at_end_line"
+AT_END_STRING = "at_end_string"
+AT_LOC_BOUNDARY = "at_loc_boundary"
+AT_LOC_NON_BOUNDARY = "at_loc_non_boundary"
+AT_UNI_BOUNDARY = "at_uni_boundary"
+AT_UNI_NON_BOUNDARY = "at_uni_non_boundary"
+
+# categories
+CATEGORY_DIGIT = "category_digit"
+CATEGORY_NOT_DIGIT = "category_not_digit"
+CATEGORY_SPACE = "category_space"
+CATEGORY_NOT_SPACE = "category_not_space"
+CATEGORY_WORD = "category_word"
+CATEGORY_NOT_WORD = "category_not_word"
+CATEGORY_LINEBREAK = "category_linebreak"
+CATEGORY_NOT_LINEBREAK = "category_not_linebreak"
+CATEGORY_LOC_WORD = "category_loc_word"
+CATEGORY_LOC_NOT_WORD = "category_loc_not_word"
+CATEGORY_UNI_DIGIT = "category_uni_digit"
+CATEGORY_UNI_NOT_DIGIT = "category_uni_not_digit"
+CATEGORY_UNI_SPACE = "category_uni_space"
+CATEGORY_UNI_NOT_SPACE = "category_uni_not_space"
+CATEGORY_UNI_WORD = "category_uni_word"
+CATEGORY_UNI_NOT_WORD = "category_uni_not_word"
+CATEGORY_UNI_LINEBREAK = "category_uni_linebreak"
+CATEGORY_UNI_NOT_LINEBREAK = "category_uni_not_linebreak"
+
+OPCODES = [
+
+ # failure=0 success=1 (just because it looks better that way :-)
+ FAILURE, SUCCESS,
+
+ ANY, ANY_ALL,
+ ASSERT, ASSERT_NOT,
+ AT,
+ BRANCH,
+ CALL,
+ CATEGORY,
+ CHARSET,
+ GROUPREF, GROUPREF_IGNORE,
+ IN, IN_IGNORE,
+ INFO,
+ JUMP,
+ LITERAL, LITERAL_IGNORE,
+ MARK,
+ MAX_UNTIL,
+ MIN_UNTIL,
+ NOT_LITERAL, NOT_LITERAL_IGNORE,
+ NEGATE,
+ RANGE,
+ REPEAT,
+ REPEAT_ONE,
+ SUBPATTERN
+
+]
+
+ATCODES = [
+ AT_BEGINNING, AT_BEGINNING_LINE, AT_BEGINNING_STRING, AT_BOUNDARY,
+ AT_NON_BOUNDARY, AT_END, AT_END_LINE, AT_END_STRING,
+ AT_LOC_BOUNDARY, AT_LOC_NON_BOUNDARY, AT_UNI_BOUNDARY,
+ AT_UNI_NON_BOUNDARY
+]
+
+CHCODES = [
+ CATEGORY_DIGIT, CATEGORY_NOT_DIGIT, CATEGORY_SPACE,
+ CATEGORY_NOT_SPACE, CATEGORY_WORD, CATEGORY_NOT_WORD,
+ CATEGORY_LINEBREAK, CATEGORY_NOT_LINEBREAK, CATEGORY_LOC_WORD,
+ CATEGORY_LOC_NOT_WORD, CATEGORY_UNI_DIGIT, CATEGORY_UNI_NOT_DIGIT,
+ CATEGORY_UNI_SPACE, CATEGORY_UNI_NOT_SPACE, CATEGORY_UNI_WORD,
+ CATEGORY_UNI_NOT_WORD, CATEGORY_UNI_LINEBREAK,
+ CATEGORY_UNI_NOT_LINEBREAK
+]
+
+def makedict(list):
+ d = {}
+ i = 0
+ for item in list:
+ d[item] = i
+ i = i + 1
+ return d
+
+OPCODES = makedict(OPCODES)
+ATCODES = makedict(ATCODES)
+CHCODES = makedict(CHCODES)
+
+# replacement operations for "ignore case" mode
+OP_IGNORE = {
+ GROUPREF: GROUPREF_IGNORE,
+ IN: IN_IGNORE,
+ LITERAL: LITERAL_IGNORE,
+ NOT_LITERAL: NOT_LITERAL_IGNORE
+}
+
+AT_MULTILINE = {
+ AT_BEGINNING: AT_BEGINNING_LINE,
+ AT_END: AT_END_LINE
+}
+
+AT_LOCALE = {
+ AT_BOUNDARY: AT_LOC_BOUNDARY,
+ AT_NON_BOUNDARY: AT_LOC_NON_BOUNDARY
+}
+
+AT_UNICODE = {
+ AT_BOUNDARY: AT_UNI_BOUNDARY,
+ AT_NON_BOUNDARY: AT_UNI_NON_BOUNDARY
+}
+
+CH_LOCALE = {
+ CATEGORY_DIGIT: CATEGORY_DIGIT,
+ CATEGORY_NOT_DIGIT: CATEGORY_NOT_DIGIT,
+ CATEGORY_SPACE: CATEGORY_SPACE,
+ CATEGORY_NOT_SPACE: CATEGORY_NOT_SPACE,
+ CATEGORY_WORD: CATEGORY_LOC_WORD,
+ CATEGORY_NOT_WORD: CATEGORY_LOC_NOT_WORD,
+ CATEGORY_LINEBREAK: CATEGORY_LINEBREAK,
+ CATEGORY_NOT_LINEBREAK: CATEGORY_NOT_LINEBREAK
+}
+
+CH_UNICODE = {
+ CATEGORY_DIGIT: CATEGORY_UNI_DIGIT,
+ CATEGORY_NOT_DIGIT: CATEGORY_UNI_NOT_DIGIT,
+ CATEGORY_SPACE: CATEGORY_UNI_SPACE,
+ CATEGORY_NOT_SPACE: CATEGORY_UNI_NOT_SPACE,
+ CATEGORY_WORD: CATEGORY_UNI_WORD,
+ CATEGORY_NOT_WORD: CATEGORY_UNI_NOT_WORD,
+ CATEGORY_LINEBREAK: CATEGORY_UNI_LINEBREAK,
+ CATEGORY_NOT_LINEBREAK: CATEGORY_UNI_NOT_LINEBREAK
+}
+
+# flags
+SRE_FLAG_TEMPLATE = 1 # template mode (disable backtracking)
+SRE_FLAG_IGNORECASE = 2 # case insensitive
+SRE_FLAG_LOCALE = 4 # honour system locale
+SRE_FLAG_MULTILINE = 8 # treat target as multiline string
+SRE_FLAG_DOTALL = 16 # treat target as a single string
+SRE_FLAG_UNICODE = 32 # use unicode locale
+SRE_FLAG_VERBOSE = 64 # ignore whitespace and comments
+SRE_FLAG_DEBUG = 128 # debugging
+
+# flags for INFO primitive
+SRE_INFO_PREFIX = 1 # has prefix
+SRE_INFO_LITERAL = 2 # entire pattern is literal (given by prefix)
+SRE_INFO_CHARSET = 4 # pattern starts with character from given set
+
+if __name__ == "__main__":
+ import string
+ def dump(f, d, prefix):
+ items = d.items()
+ items.sort(lambda a, b: cmp(a[1], b[1]))
+ for k, v in items:
+ f.write("#define %s_%s %s\n" % (prefix, string.upper(k), v))
+ f = open("sre_constants.h", "w")
+ f.write("""\
+/*
+ * Secret Labs' Regular Expression Engine
+ *
+ * regular expression matching engine
+ *
+ * NOTE: This file is generated by sre_constants.py. If you need
+ * to change anything in here, edit sre_constants.py and run it.
+ *
+ * Copyright (c) 1997-2001 by Secret Labs AB. All rights reserved.
+ *
+ * See the _sre.c file for information on usage and redistribution.
+ */
+
+""")
+
+ f.write("#define SRE_MAGIC %d\n" % MAGIC)
+
+ dump(f, OPCODES, "SRE_OP")
+ dump(f, ATCODES, "SRE")
+ dump(f, CHCODES, "SRE")
+
+ f.write("#define SRE_FLAG_TEMPLATE %d\n" % SRE_FLAG_TEMPLATE)
+ f.write("#define SRE_FLAG_IGNORECASE %d\n" % SRE_FLAG_IGNORECASE)
+ f.write("#define SRE_FLAG_LOCALE %d\n" % SRE_FLAG_LOCALE)
+ f.write("#define SRE_FLAG_MULTILINE %d\n" % SRE_FLAG_MULTILINE)
+ f.write("#define SRE_FLAG_DOTALL %d\n" % SRE_FLAG_DOTALL)
+ f.write("#define SRE_FLAG_UNICODE %d\n" % SRE_FLAG_UNICODE)
+ f.write("#define SRE_FLAG_VERBOSE %d\n" % SRE_FLAG_VERBOSE)
+
+ f.write("#define SRE_INFO_PREFIX %d\n" % SRE_INFO_PREFIX)
+ f.write("#define SRE_INFO_LITERAL %d\n" % SRE_INFO_LITERAL)
+ f.write("#define SRE_INFO_CHARSET %d\n" % SRE_INFO_CHARSET)
+
+ f.close()
+ print "done"
diff --git a/lib/jython/Lib/sre_parse.py b/lib/jython/Lib/sre_parse.py new file mode 100644 index 000000000..94b224afb --- /dev/null +++ b/lib/jython/Lib/sre_parse.py @@ -0,0 +1,732 @@ +#
+# Secret Labs' Regular Expression Engine
+#
+# convert re-style regular expression to sre pattern
+#
+# Copyright (c) 1998-2001 by Secret Labs AB. All rights reserved.
+#
+# See the sre.py file for information on usage and redistribution.
+#
+
+# XXX: show string offset and offending character for all errors
+
+# this module works under 1.5.2 and later. don't use string methods
+import string, sys
+
+from sre_constants import *
+
+SPECIAL_CHARS = ".\\[{()*+?^$|"
+REPEAT_CHARS = "*+?{"
+
+DIGITS = tuple("0123456789")
+
+OCTDIGITS = tuple("01234567")
+HEXDIGITS = tuple("0123456789abcdefABCDEF")
+
+WHITESPACE = tuple(" \t\n\r\v\f")
+
+ESCAPES = {
+ r"\a": (LITERAL, ord("\a")),
+ r"\b": (LITERAL, ord("\b")),
+ r"\f": (LITERAL, ord("\f")),
+ r"\n": (LITERAL, ord("\n")),
+ r"\r": (LITERAL, ord("\r")),
+ r"\t": (LITERAL, ord("\t")),
+ r"\v": (LITERAL, ord("\v")),
+ r"\\": (LITERAL, ord("\\"))
+}
+
+CATEGORIES = {
+ r"\A": (AT, AT_BEGINNING_STRING), # start of string
+ r"\b": (AT, AT_BOUNDARY),
+ r"\B": (AT, AT_NON_BOUNDARY),
+ r"\d": (IN, [(CATEGORY, CATEGORY_DIGIT)]),
+ r"\D": (IN, [(CATEGORY, CATEGORY_NOT_DIGIT)]),
+ r"\s": (IN, [(CATEGORY, CATEGORY_SPACE)]),
+ r"\S": (IN, [(CATEGORY, CATEGORY_NOT_SPACE)]),
+ r"\w": (IN, [(CATEGORY, CATEGORY_WORD)]),
+ r"\W": (IN, [(CATEGORY, CATEGORY_NOT_WORD)]),
+ r"\Z": (AT, AT_END_STRING), # end of string
+}
+
+FLAGS = {
+ # standard flags
+ "i": SRE_FLAG_IGNORECASE,
+ "L": SRE_FLAG_LOCALE,
+ "m": SRE_FLAG_MULTILINE,
+ "s": SRE_FLAG_DOTALL,
+ "x": SRE_FLAG_VERBOSE,
+ # extensions
+ "t": SRE_FLAG_TEMPLATE,
+ "u": SRE_FLAG_UNICODE,
+}
+
+# figure out best way to convert hex/octal numbers to integers
+try:
+ int("10", 8)
+ atoi = int # 2.0 and later
+except TypeError:
+ atoi = string.atoi # 1.5.2
+
+class Pattern:
+ # master pattern object. keeps track of global attributes
+ def __init__(self):
+ self.flags = 0
+ self.open = []
+ self.groups = 1
+ self.groupdict = {}
+ def opengroup(self, name=None):
+ gid = self.groups
+ self.groups = gid + 1
+ if name:
+ self.groupdict[name] = gid
+ self.open.append(gid)
+ return gid
+ def closegroup(self, gid):
+ self.open.remove(gid)
+ def checkgroup(self, gid):
+ return gid < self.groups and gid not in self.open
+
+class SubPattern:
+ # a subpattern, in intermediate form
+ def __init__(self, pattern, data=None):
+ self.pattern = pattern
+ if not data:
+ data = []
+ self.data = data
+ self.width = None
+ def dump(self, level=0):
+ nl = 1
+ for op, av in self.data:
+ print level*" " + op,; nl = 0
+ if op == "in":
+ # member sublanguage
+ print; nl = 1
+ for op, a in av:
+ print (level+1)*" " + op, a
+ elif op == "branch":
+ print; nl = 1
+ i = 0
+ for a in av[1]:
+ if i > 0:
+ print level*" " + "or"
+ a.dump(level+1); nl = 1
+ i = i + 1
+ elif type(av) in (type(()), type([])):
+ for a in av:
+ if isinstance(a, SubPattern):
+ if not nl: print
+ a.dump(level+1); nl = 1
+ else:
+ print a, ; nl = 0
+ else:
+ print av, ; nl = 0
+ if not nl: print
+ def __repr__(self):
+ return repr(self.data)
+ def __len__(self):
+ return len(self.data)
+ def __delitem__(self, index):
+ del self.data[index]
+ def __getitem__(self, index):
+ return self.data[index]
+ def __setitem__(self, index, code):
+ self.data[index] = code
+ def __getslice__(self, start, stop):
+ return SubPattern(self.pattern, self.data[start:stop])
+ def insert(self, index, code):
+ self.data.insert(index, code)
+ def append(self, code):
+ self.data.append(code)
+ def getwidth(self):
+ # determine the width (min, max) for this subpattern
+ if self.width:
+ return self.width
+ lo = hi = 0L
+ for op, av in self.data:
+ if op is BRANCH:
+ i = sys.maxint
+ j = 0
+ for av in av[1]:
+ l, h = av.getwidth()
+ i = min(i, l)
+ j = max(j, h)
+ lo = lo + i
+ hi = hi + j
+ elif op is CALL:
+ i, j = av.getwidth()
+ lo = lo + i
+ hi = hi + j
+ elif op is SUBPATTERN:
+ i, j = av[1].getwidth()
+ lo = lo + i
+ hi = hi + j
+ elif op in (MIN_REPEAT, MAX_REPEAT):
+ i, j = av[2].getwidth()
+ lo = lo + long(i) * av[0]
+ hi = hi + long(j) * av[1]
+ elif op in (ANY, RANGE, IN, LITERAL, NOT_LITERAL, CATEGORY):
+ lo = lo + 1
+ hi = hi + 1
+ elif op == SUCCESS:
+ break
+ self.width = int(min(lo, sys.maxint)), int(min(hi, sys.maxint))
+ return self.width
+
+class Tokenizer:
+ def __init__(self, string):
+ self.string = string
+ self.index = 0
+ self.__next()
+ def __next(self):
+ if self.index >= len(self.string):
+ self.next = None
+ return
+ char = self.string[self.index]
+ if char[0] == "\\":
+ try:
+ c = self.string[self.index + 1]
+ except IndexError:
+ raise error, "bogus escape"
+ char = char + c
+ self.index = self.index + len(char)
+ self.next = char
+ def match(self, char, skip=1):
+ if char == self.next:
+ if skip:
+ self.__next()
+ return 1
+ return 0
+ def get(self):
+ this = self.next
+ self.__next()
+ return this
+ def tell(self):
+ return self.index, self.next
+ def seek(self, index):
+ self.index, self.next = index
+
+def isident(char):
+ return "a" <= char <= "z" or "A" <= char <= "Z" or char == "_"
+
+def isdigit(char):
+ return "0" <= char <= "9"
+
+def isname(name):
+ # check that group name is a valid string
+ if not isident(name[0]):
+ return 0
+ for char in name:
+ if not isident(char) and not isdigit(char):
+ return 0
+ return 1
+
+def _group(escape, groups):
+ # check if the escape string represents a valid group
+ try:
+ gid = atoi(escape[1:])
+ if gid and gid < groups:
+ return gid
+ except ValueError:
+ pass
+ return None # not a valid group
+
+def _class_escape(source, escape):
+ # handle escape code inside character class
+ code = ESCAPES.get(escape)
+ if code:
+ return code
+ code = CATEGORIES.get(escape)
+ if code:
+ return code
+ try:
+ if escape[1:2] == "x":
+ # hexadecimal escape (exactly two digits)
+ while source.next in HEXDIGITS and len(escape) < 4:
+ escape = escape + source.get()
+ escape = escape[2:]
+ if len(escape) != 2:
+ raise error, "bogus escape: %s" % repr("\\" + escape)
+ return LITERAL, atoi(escape, 16) & 0xff
+ elif str(escape[1:2]) in OCTDIGITS:
+ # octal escape (up to three digits)
+ while source.next in OCTDIGITS and len(escape) < 5:
+ escape = escape + source.get()
+ escape = escape[1:]
+ return LITERAL, atoi(escape, 8) & 0xff
+ if len(escape) == 2:
+ return LITERAL, ord(escape[1])
+ except ValueError:
+ pass
+ raise error, "bogus escape: %s" % repr(escape)
+
+def _escape(source, escape, state):
+ # handle escape code in expression
+ code = CATEGORIES.get(escape)
+ if code:
+ return code
+ code = ESCAPES.get(escape)
+ if code:
+ return code
+ try:
+ if escape[1:2] == "x":
+ # hexadecimal escape
+ while source.next in HEXDIGITS and len(escape) < 4:
+ escape = escape + source.get()
+ if len(escape) != 4:
+ raise ValueError
+ return LITERAL, atoi(escape[2:], 16) & 0xff
+ elif escape[1:2] == "0":
+ # octal escape
+ while source.next in OCTDIGITS and len(escape) < 4:
+ escape = escape + source.get()
+ return LITERAL, atoi(escape[1:], 8) & 0xff
+ elif escape[1:2] in DIGITS:
+ # octal escape *or* decimal group reference (sigh)
+ here = source.tell()
+ if source.next in DIGITS:
+ escape = escape + source.get()
+ if (escape[1] in OCTDIGITS and escape[2] in OCTDIGITS and
+ source.next in OCTDIGITS):
+ # got three octal digits; this is an octal escape
+ escape = escape + source.get()
+ return LITERAL, atoi(escape[1:], 8) & 0xff
+ # got at least one decimal digit; this is a group reference
+ group = _group(escape, state.groups)
+ if group:
+ if not state.checkgroup(group):
+ raise error, "cannot refer to open group"
+ return GROUPREF, group
+ raise ValueError
+ if len(escape) == 2:
+ return LITERAL, ord(escape[1])
+ except ValueError:
+ pass
+ raise error, "bogus escape: %s" % repr(escape)
+
+def _parse_sub(source, state, nested=1):
+ # parse an alternation: a|b|c
+
+ items = []
+ while 1:
+ items.append(_parse(source, state))
+ if source.match("|"):
+ continue
+ if not nested:
+ break
+ if not source.next or source.match(")", 0):
+ break
+ else:
+ raise error, "pattern not properly closed"
+
+ if len(items) == 1:
+ return items[0]
+
+ subpattern = SubPattern(state)
+
+ # check if all items share a common prefix
+ while 1:
+ prefix = None
+ for item in items:
+ if not item:
+ break
+ if prefix is None:
+ prefix = item[0]
+ elif item[0] != prefix:
+ break
+ else:
+ # all subitems start with a common "prefix".
+ # move it out of the branch
+ for item in items:
+ del item[0]
+ subpattern.append(prefix)
+ continue # check next one
+ break
+
+ # check if the branch can be replaced by a character set
+ for item in items:
+ if len(item) != 1 or item[0][0] != LITERAL:
+ break
+ else:
+ # we can store this as a character set instead of a
+ # branch (the compiler may optimize this even more)
+ set = []
+ for item in items:
+ set.append(item[0])
+ subpattern.append((IN, set))
+ return subpattern
+
+ subpattern.append((BRANCH, (None, items)))
+ return subpattern
+
+def _parse(source, state):
+ # parse a simple pattern
+
+ subpattern = SubPattern(state)
+
+ while 1:
+
+ if source.next in ("|", ")"):
+ break # end of subpattern
+ this = source.get()
+ if this is None:
+ break # end of pattern
+
+ if state.flags & SRE_FLAG_VERBOSE:
+ # skip whitespace and comments
+ if this in WHITESPACE:
+ continue
+ if this == "#":
+ while 1:
+ this = source.get()
+ if this in (None, "\n"):
+ break
+ continue
+
+ if this and this[0] not in SPECIAL_CHARS:
+ subpattern.append((LITERAL, ord(this)))
+
+ elif this == "[":
+ # character set
+ set = []
+## if source.match(":"):
+## pass # handle character classes
+ if source.match("^"):
+ set.append((NEGATE, None))
+ # check remaining characters
+ start = set[:]
+ while 1:
+ this = source.get()
+ if this == "]" and set != start:
+ break
+ elif this and this[0] == "\\":
+ code1 = _class_escape(source, this)
+ elif this:
+ code1 = LITERAL, ord(this)
+ else:
+ raise error, "unexpected end of regular expression"
+ if source.match("-"):
+ # potential range
+ this = source.get()
+ if this == "]":
+ if code1[0] is IN:
+ code1 = code1[1][0]
+ set.append(code1)
+ set.append((LITERAL, ord("-")))
+ break
+ else:
+ if this[0] == "\\":
+ code2 = _class_escape(source, this)
+ else:
+ code2 = LITERAL, ord(this)
+ if code1[0] != LITERAL or code2[0] != LITERAL:
+ raise error, "bad character range"
+ lo = code1[1]
+ hi = code2[1]
+ if hi < lo:
+ raise error, "bad character range"
+ set.append((RANGE, (lo, hi)))
+ else:
+ if code1[0] is IN:
+ code1 = code1[1][0]
+ set.append(code1)
+
+ # XXX: <fl> should move set optimization to compiler!
+ if len(set)==1 and set[0][0] is LITERAL:
+ subpattern.append(set[0]) # optimization
+ elif len(set)==2 and set[0][0] is NEGATE and set[1][0] is LITERAL:
+ subpattern.append((NOT_LITERAL, set[1][1])) # optimization
+ else:
+ # XXX: <fl> should add charmap optimization here
+ subpattern.append((IN, set))
+
+ elif this and this[0] in REPEAT_CHARS:
+ # repeat previous item
+ if this == "?":
+ min, max = 0, 1
+ elif this == "*":
+ min, max = 0, MAXREPEAT
+
+ elif this == "+":
+ min, max = 1, MAXREPEAT
+ elif this == "{":
+ here = source.tell()
+ min, max = 0, MAXREPEAT
+ lo = hi = ""
+ while source.next in DIGITS:
+ lo = lo + source.get()
+ if source.match(","):
+ while source.next in DIGITS:
+ hi = hi + source.get()
+ else:
+ hi = lo
+ if not source.match("}"):
+ subpattern.append((LITERAL, ord(this)))
+ source.seek(here)
+ continue
+ if lo:
+ min = atoi(lo)
+ if hi:
+ max = atoi(hi)
+ if max < min:
+ raise error, "bad repeat interval"
+ else:
+ raise error, "not supported"
+ # figure out which item to repeat
+ if subpattern:
+ item = subpattern[-1:]
+ else:
+ item = None
+ if not item or (len(item) == 1 and item[0][0] == AT):
+ raise error, "nothing to repeat"
+ if item[0][0] in (MIN_REPEAT, MAX_REPEAT):
+ raise error, "multiple repeat"
+ if source.match("?"):
+ subpattern[-1] = (MIN_REPEAT, (min, max, item))
+ else:
+ subpattern[-1] = (MAX_REPEAT, (min, max, item))
+
+ elif this == ".":
+ subpattern.append((ANY, None))
+
+ elif this == "(":
+ group = 1
+ name = None
+ if source.match("?"):
+ group = 0
+ # options
+ if source.match("P"):
+ # python extensions
+ if source.match("<"):
+ # named group: skip forward to end of name
+ name = ""
+ while 1:
+ char = source.get()
+ if char is None:
+ raise error, "unterminated name"
+ if char == ">":
+ break
+ name = name + char
+ group = 1
+ if not isname(name):
+ raise error, "bad character in group name"
+ elif source.match("="):
+ # named backreference
+ name = ""
+ while 1:
+ char = source.get()
+ if char is None:
+ raise error, "unterminated name"
+ if char == ")":
+ break
+ name = name + char
+ if not isname(name):
+ raise error, "bad character in group name"
+ gid = state.groupdict.get(name)
+ if gid is None:
+ raise error, "unknown group name"
+ subpattern.append((GROUPREF, gid))
+ continue
+ else:
+ char = source.get()
+ if char is None:
+ raise error, "unexpected end of pattern"
+ raise error, "unknown specifier: ?P%s" % char
+ elif source.match(":"):
+ # non-capturing group
+ group = 2
+ elif source.match("#"):
+ # comment
+ while 1:
+ if source.next is None or source.next == ")":
+ break
+ source.get()
+ if not source.match(")"):
+ raise error, "unbalanced parenthesis"
+ continue
+ elif source.next in ("=", "!", "<"):
+ # lookahead assertions
+ char = source.get()
+ dir = 1
+ if char == "<":
+ if source.next not in ("=", "!"):
+ raise error, "syntax error"
+ dir = -1 # lookbehind
+ char = source.get()
+ p = _parse_sub(source, state)
+ if not source.match(")"):
+ raise error, "unbalanced parenthesis"
+ if char == "=":
+ subpattern.append((ASSERT, (dir, p)))
+ else:
+ subpattern.append((ASSERT_NOT, (dir, p)))
+ continue
+ else:
+ # flags
+ if not FLAGS.has_key(source.next):
+ raise error, "unexpected end of pattern"
+ while FLAGS.has_key(source.next):
+ state.flags = state.flags | FLAGS[source.get()]
+ if group:
+ # parse group contents
+ if group == 2:
+ # anonymous group
+ group = None
+ else:
+ group = state.opengroup(name)
+ p = _parse_sub(source, state)
+ if not source.match(")"):
+ raise error, "unbalanced parenthesis"
+ if group is not None:
+ state.closegroup(group)
+ subpattern.append((SUBPATTERN, (group, p)))
+ else:
+ while 1:
+ char = source.get()
+ if char is None:
+ raise error, "unexpected end of pattern"
+ if char == ")":
+ break
+ raise error, "unknown extension"
+
+ elif this == "^":
+ subpattern.append((AT, AT_BEGINNING))
+
+ elif this == "$":
+ subpattern.append((AT, AT_END))
+
+ elif this and this[0] == "\\":
+ code = _escape(source, this, state)
+ subpattern.append(code)
+
+ else:
+ raise error, "parser error"
+
+ return subpattern
+
+def parse(str, flags=0, pattern=None):
+ # parse 're' pattern into list of (opcode, argument) tuples
+
+ source = Tokenizer(str)
+
+ if pattern is None:
+ pattern = Pattern()
+ pattern.flags = flags
+ pattern.str = str
+
+ p = _parse_sub(source, pattern, 0)
+
+ tail = source.get()
+ if tail == ")":
+ raise error, "unbalanced parenthesis"
+ elif tail:
+ raise error, "bogus characters at end of regular expression"
+
+ if flags & SRE_FLAG_DEBUG:
+ p.dump()
+
+ if not (flags & SRE_FLAG_VERBOSE) and p.pattern.flags & SRE_FLAG_VERBOSE:
+ # the VERBOSE flag was switched on inside the pattern. to be
+ # on the safe side, we'll parse the whole thing again...
+ return parse(str, p.pattern.flags)
+
+ return p
+
+def parse_template(source, pattern):
+ # parse 're' replacement string into list of literals and
+ # group references
+ s = Tokenizer(source)
+ p = []
+ a = p.append
+ def literal(literal, p=p):
+ if p and p[-1][0] is LITERAL:
+ p[-1] = LITERAL, p[-1][1] + literal
+ else:
+ p.append((LITERAL, literal))
+ sep = source[:0]
+ if type(sep) is type(""):
+ char = chr
+ else:
+ char = unichr
+ while 1:
+ this = s.get()
+ if this is None:
+ break # end of replacement string
+ if this and this[0] == "\\":
+ # group
+ if this == "\\g":
+ name = ""
+ if s.match("<"):
+ while 1:
+ char = s.get()
+ if char is None:
+ raise error, "unterminated group name"
+ if char == ">":
+ break
+ name = name + char
+ if not name:
+ raise error, "bad group name"
+ try:
+ index = atoi(name)
+ except ValueError:
+ if not isname(name):
+ raise error, "bad character in group name"
+ try:
+ index = pattern.groupindex[name]
+ except KeyError:
+ raise IndexError, "unknown group name"
+ a((MARK, index))
+ elif len(this) > 1 and this[1] in DIGITS:
+ code = None
+ while 1:
+ group = _group(this, pattern.groups+1)
+ if group:
+ if (s.next not in DIGITS or
+ not _group(this + s.next, pattern.groups+1)):
+ code = MARK, group
+ break
+ elif s.next in OCTDIGITS:
+ this = this + s.get()
+ else:
+ break
+ if not code:
+ this = this[1:]
+ code = LITERAL, char(atoi(this[-6:], 8) & 0xff)
+ if code[0] is LITERAL:
+ literal(code[1])
+ else:
+ a(code)
+ else:
+ try:
+ this = char(ESCAPES[this][1])
+ except KeyError:
+ pass
+ literal(this)
+ else:
+ literal(this)
+ # convert template to groups and literals lists
+ i = 0
+ groups = []
+ literals = []
+ for c, s in p:
+ if c is MARK:
+ groups.append((i, s))
+ literals.append(None)
+ else:
+ literals.append(s)
+ i = i + 1
+ return groups, literals
+
+def expand_template(template, match):
+ g = match.group
+ sep = match.string[:0]
+ groups, literals = template
+ literals = literals[:]
+ try:
+ for index, group in groups:
+ literals[index] = s = g(group)
+ if s is None:
+ raise IndexError
+ except IndexError:
+ raise error, "empty group"
+ return string.join(literals, sep)
diff --git a/lib/jython/Lib/stat.py b/lib/jython/Lib/stat.py new file mode 100644 index 000000000..8bccf98ef --- /dev/null +++ b/lib/jython/Lib/stat.py @@ -0,0 +1,86 @@ +"""Constants/functions for interpreting results of os.stat() and os.lstat().
+
+Suggested usage: from stat import *
+"""
+
+# XXX Strictly spoken, this module may have to be adapted for each POSIX
+# implementation; in practice, however, the numeric constants used by
+# stat() are almost universal (even for stat() emulations on non-UNIX
+# systems like MS-DOS).
+
+# Indices for stat struct members in tuple returned by os.stat()
+
+ST_MODE = 0
+ST_INO = 1
+ST_DEV = 2
+ST_NLINK = 3
+ST_UID = 4
+ST_GID = 5
+ST_SIZE = 6
+ST_ATIME = 7
+ST_MTIME = 8
+ST_CTIME = 9
+
+# Extract bits from the mode
+
+def S_IMODE(mode):
+ return mode & 07777
+
+def S_IFMT(mode):
+ return mode & 0170000
+
+# Constants used as S_IFMT() for various file types
+# (not all are implemented on all systems)
+
+S_IFDIR = 0040000
+S_IFCHR = 0020000
+S_IFBLK = 0060000
+S_IFREG = 0100000
+S_IFIFO = 0010000
+S_IFLNK = 0120000
+S_IFSOCK = 0140000
+
+# Functions to test for each file type
+
+def S_ISDIR(mode):
+ return S_IFMT(mode) == S_IFDIR
+
+def S_ISCHR(mode):
+ return S_IFMT(mode) == S_IFCHR
+
+def S_ISBLK(mode):
+ return S_IFMT(mode) == S_IFBLK
+
+def S_ISREG(mode):
+ return S_IFMT(mode) == S_IFREG
+
+def S_ISFIFO(mode):
+ return S_IFMT(mode) == S_IFIFO
+
+def S_ISLNK(mode):
+ return S_IFMT(mode) == S_IFLNK
+
+def S_ISSOCK(mode):
+ return S_IFMT(mode) == S_IFSOCK
+
+# Names for permission bits
+
+S_ISUID = 04000
+S_ISGID = 02000
+S_ENFMT = S_ISGID
+S_ISVTX = 01000
+S_IREAD = 00400
+S_IWRITE = 00200
+S_IEXEC = 00100
+S_IRWXU = 00700
+S_IRUSR = 00400
+S_IWUSR = 00200
+S_IXUSR = 00100
+S_IRWXG = 00070
+S_IRGRP = 00040
+S_IWGRP = 00020
+S_IXGRP = 00010
+S_IRWXO = 00007
+S_IROTH = 00004
+S_IWOTH = 00002
+S_IXOTH = 00001
diff --git a/lib/jython/Lib/string.py b/lib/jython/Lib/string.py new file mode 100644 index 000000000..02f8453ec --- /dev/null +++ b/lib/jython/Lib/string.py @@ -0,0 +1,421 @@ +# module 'string' -- A collection of string operations
+
+# Warning: most of the code you see here isn't normally used nowadays. With
+# Python 1.6, many of these functions are implemented as methods on the
+# standard string object. They used to be implemented by a built-in module
+# called strop, but strop is now obsolete itself.
+
+"""Common string manipulations.
+
+Public module variables:
+
+whitespace -- a string containing all characters considered whitespace
+lowercase -- a string containing all characters considered lowercase letters
+uppercase -- a string containing all characters considered uppercase letters
+letters -- a string containing all characters considered letters
+digits -- a string containing all characters considered decimal digits
+hexdigits -- a string containing all characters considered hexadecimal digits
+octdigits -- a string containing all characters considered octal digits
+
+"""
+
+# Some strings for ctype-style character classification
+whitespace = ' \t\n\r\v\f'
+lowercase = 'abcdefghijklmnopqrstuvwxyz'
+uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+letters = lowercase + uppercase
+digits = '0123456789'
+hexdigits = digits + 'abcdef' + 'ABCDEF'
+octdigits = '01234567'
+
+# Case conversion helpers
+_idmap = ''
+for i in range(256): _idmap = _idmap + chr(i)
+del i
+
+# Backward compatible names for exceptions
+index_error = ValueError
+atoi_error = ValueError
+atof_error = ValueError
+atol_error = ValueError
+
+# convert UPPER CASE letters to lower case
+def lower(s):
+ """lower(s) -> string
+
+ Return a copy of the string s converted to lowercase.
+
+ """
+ return s.lower()
+
+# Convert lower case letters to UPPER CASE
+def upper(s):
+ """upper(s) -> string
+
+ Return a copy of the string s converted to uppercase.
+
+ """
+ return s.upper()
+
+# Swap lower case letters and UPPER CASE
+def swapcase(s):
+ """swapcase(s) -> string
+
+ Return a copy of the string s with upper case characters
+ converted to lowercase and vice versa.
+
+ """
+ return s.swapcase()
+
+# Strip leading and trailing tabs and spaces
+def strip(s):
+ """strip(s) -> string
+
+ Return a copy of the string s with leading and trailing
+ whitespace removed.
+
+ """
+ return s.strip()
+
+# Strip leading tabs and spaces
+def lstrip(s):
+ """lstrip(s) -> string
+
+ Return a copy of the string s with leading whitespace removed.
+
+ """
+ return s.lstrip()
+
+# Strip trailing tabs and spaces
+def rstrip(s):
+ """rstrip(s) -> string
+
+ Return a copy of the string s with trailing whitespace
+ removed.
+
+ """
+ return s.rstrip()
+
+
+# Split a string into a list of space/tab-separated words
+# NB: split(s) is NOT the same as splitfields(s, ' ')!
+def split(s, sep=None, maxsplit=-1):
+ """split(str [,sep [,maxsplit]]) -> list of strings
+
+ Return a list of the words in the string s, using sep as the
+ delimiter string. If maxsplit is nonzero, splits into at most
+ maxsplit words If sep is not specified, any whitespace string
+ is a separator. Maxsplit defaults to -1.
+
+ (split and splitfields are synonymous)
+
+ """
+ return s.split(sep, maxsplit)
+splitfields = split
+
+# Join fields with optional separator
+def join(words, sep = ' '):
+ """join(list [,sep]) -> string
+
+ Return a string composed of the words in list, with
+ intervening occurences of sep. The default separator is a
+ single space.
+
+ (joinfields and join are synonymous)
+
+ """
+ return sep.join(words)
+joinfields = join
+
+# for a little bit of speed
+_apply = apply
+
+# Find substring, raise exception if not found
+def index(s, *args):
+ """index(s, sub [,start [,end]]) -> int
+
+ Like find but raises ValueError when the substring is not found.
+
+ """
+ return _apply(s.index, args)
+
+# Find last substring, raise exception if not found
+def rindex(s, *args):
+ """rindex(s, sub [,start [,end]]) -> int
+
+ Like rfind but raises ValueError when the substring is not found.
+
+ """
+ return _apply(s.rindex, args)
+
+# Count non-overlapping occurrences of substring
+def count(s, *args):
+ """count(s, sub[, start[,end]]) -> int
+
+ Return the number of occurrences of substring sub in string
+ s[start:end]. Optional arguments start and end are
+ interpreted as in slice notation.
+
+ """
+ return _apply(s.count, args)
+
+# Find substring, return -1 if not found
+def find(s, *args):
+ """find(s, sub [,start [,end]]) -> in
+
+ Return the lowest index in s where substring sub is found,
+ such that sub is contained within s[start,end]. Optional
+ arguments start and end are interpreted as in slice notation.
+
+ Return -1 on failure.
+
+ """
+ return _apply(s.find, args)
+
+# Find last substring, return -1 if not found
+def rfind(s, *args):
+ """rfind(s, sub [,start [,end]]) -> int
+
+ Return the highest index in s where substring sub is found,
+ such that sub is contained within s[start,end]. Optional
+ arguments start and end are interpreted as in slice notation.
+
+ Return -1 on failure.
+
+ """
+ return _apply(s.rfind, args)
+
+# for a bit of speed
+_float = float
+_int = int
+_long = long
+_StringType = type('')
+
+# Convert string to float
+def atof(s):
+ """atof(s) -> float
+
+ Return the floating point number represented by the string s.
+
+ """
+ if type(s) == _StringType:
+ return _float(s)
+ else:
+ raise TypeError('argument 1: expected string, %s found' %
+ type(s).__name__)
+
+# Convert string to integer
+def atoi(*args):
+ """atoi(s [,base]) -> int
+
+ Return the integer represented by the string s in the given
+ base, which defaults to 10. The string s must consist of one
+ or more digits, possibly preceded by a sign. If base is 0, it
+ is chosen from the leading characters of s, 0 for octal, 0x or
+ 0X for hexadecimal. If base is 16, a preceding 0x or 0X is
+ accepted.
+
+ """
+ try:
+ s = args[0]
+ except IndexError:
+ raise TypeError('function requires at least 1 argument: %d given' %
+ len(args))
+ # Don't catch type error resulting from too many arguments to int(). The
+ # error message isn't compatible but the error type is, and this function
+ # is complicated enough already.
+ if type(s) == _StringType:
+ return _apply(_int, args)
+ else:
+ raise TypeError('argument 1: expected string, %s found' %
+ type(s).__name__)
+
+
+# Convert string to long integer
+def atol(*args):
+ """atol(s [,base]) -> long
+
+ Return the long integer represented by the string s in the
+ given base, which defaults to 10. The string s must consist
+ of one or more digits, possibly preceded by a sign. If base
+ is 0, it is chosen from the leading characters of s, 0 for
+ octal, 0x or 0X for hexadecimal. If base is 16, a preceding
+ 0x or 0X is accepted. A trailing L or l is not accepted,
+ unless base is 0.
+
+ """
+ try:
+ s = args[0]
+ except IndexError:
+ raise TypeError('function requires at least 1 argument: %d given' %
+ len(args))
+ # Don't catch type error resulting from too many arguments to long(). The
+ # error message isn't compatible but the error type is, and this function
+ # is complicated enough already.
+ if type(s) == _StringType:
+ return _apply(_long, args)
+ else:
+ raise TypeError('argument 1: expected string, %s found' %
+ type(s).__name__)
+
+
+# Left-justify a string
+def ljust(s, width):
+ """ljust(s, width) -> string
+
+ Return a left-justified version of s, in a field of the
+ specified width, padded with spaces as needed. The string is
+ never truncated.
+
+ """
+ n = width - len(s)
+ if n <= 0: return s
+ return s + ' '*n
+
+# Right-justify a string
+def rjust(s, width):
+ """rjust(s, width) -> string
+
+ Return a right-justified version of s, in a field of the
+ specified width, padded with spaces as needed. The string is
+ never truncated.
+
+ """
+ n = width - len(s)
+ if n <= 0: return s
+ return ' '*n + s
+
+# Center a string
+def center(s, width):
+ """center(s, width) -> string
+
+ Return a center version of s, in a field of the specified
+ width. padded with spaces as needed. The string is never
+ truncated.
+
+ """
+ n = width - len(s)
+ if n <= 0: return s
+ half = n/2
+ if n%2 and width%2:
+ # This ensures that center(center(s, i), j) = center(s, j)
+ half = half+1
+ return ' '*half + s + ' '*(n-half)
+
+# Zero-fill a number, e.g., (12, 3) --> '012' and (-3, 3) --> '-03'
+# Decadent feature: the argument may be a string or a number
+# (Use of this is deprecated; it should be a string as with ljust c.s.)
+def zfill(x, width):
+ """zfill(x, width) -> string
+
+ Pad a numeric string x with zeros on the left, to fill a field
+ of the specified width. The string x is never truncated.
+
+ """
+ if type(x) == type(''): s = x
+ else: s = `x`
+ n = len(s)
+ if n >= width: return s
+ sign = ''
+ if s[0] in ('-', '+'):
+ sign, s = s[0], s[1:]
+ return sign + '0'*(width-n) + s
+
+# Expand tabs in a string.
+# Doesn't take non-printing chars into account, but does understand \n.
+def expandtabs(s, tabsize=8):
+ """expandtabs(s [,tabsize]) -> string
+
+ Return a copy of the string s with all tab characters replaced
+ by the appropriate number of spaces, depending on the current
+ column, and the tabsize (default 8).
+
+ """
+ res = line = ''
+ for c in s:
+ if c == '\t':
+ c = ' '*(tabsize - len(line) % tabsize)
+ line = line + c
+ if c == '\n':
+ res = res + line
+ line = ''
+ return res + line
+
+# Character translation through look-up table.
+def translate(s, table, deletions=""):
+ """translate(s,table [,deletechars]) -> string
+
+ Return a copy of the string s, where all characters occurring
+ in the optional argument deletechars are removed, and the
+ remaining characters have been mapped through the given
+ translation table, which must be a string of length 256.
+
+ """
+ return s.translate(table, deletions)
+
+# Capitalize a string, e.g. "aBc dEf" -> "Abc def".
+def capitalize(s):
+ """capitalize(s) -> string
+
+ Return a copy of the string s with only its first character
+ capitalized.
+
+ """
+ return s.capitalize()
+
+# Capitalize the words in a string, e.g. " aBc dEf " -> "Abc Def".
+# See also regsub.capwords().
+def capwords(s, sep=None):
+ """capwords(s, [sep]) -> string
+
+ Split the argument into words using split, capitalize each
+ word using capitalize, and join the capitalized words using
+ join. Note that this replaces runs of whitespace characters by
+ a single space.
+
+ """
+ return join(map(capitalize, s.split(sep)), sep or ' ')
+
+# Construct a translation string
+_idmapL = None
+def maketrans(fromstr, tostr):
+ """maketrans(frm, to) -> string
+
+ Return a translation table (a string of 256 bytes long)
+ suitable for use in string.translate. The strings frm and to
+ must be of the same length.
+
+ """
+ if len(fromstr) != len(tostr):
+ raise ValueError, "maketrans arguments must have same length"
+ global _idmapL
+ if not _idmapL:
+ _idmapL = map(None, _idmap)
+ L = _idmapL[:]
+ fromstr = map(ord, fromstr)
+ for i in range(len(fromstr)):
+ L[fromstr[i]] = tostr[i]
+ return joinfields(L, "")
+
+# Substring replacement (global)
+def replace(s, old, new, maxsplit=-1):
+ """replace (str, old, new[, maxsplit]) -> string
+
+ Return a copy of string str with all occurrences of substring
+ old replaced by new. If the optional argument maxsplit is
+ given, only the first maxsplit occurrences are replaced.
+
+ """
+ return s.replace(old, new, maxsplit)
+
+
+# Try importing optional built-in module "strop" -- if it exists,
+# it redefines some string operations that are 100-1000 times faster.
+# It also defines values for whitespace, lowercase and uppercase
+# that match <ctype.h>'s definitions.
+
+try:
+ from strop import maketrans, lowercase, uppercase, whitespace
+ letters = lowercase + uppercase
+except ImportError:
+ pass # Use the original versions
diff --git a/lib/jython/Lib/symbol.py b/lib/jython/Lib/symbol.py new file mode 100644 index 000000000..c73bbd12a --- /dev/null +++ b/lib/jython/Lib/symbol.py @@ -0,0 +1,93 @@ +#! /usr/bin/env python
+
+"""Non-terminal symbols of Python grammar (from "graminit.h")."""
+
+# This file is automatically generated; please don't muck it up!
+#
+# To update the symbols in this file, 'cd' to the top directory of
+# the python source tree after building the interpreter and run:
+#
+# python Lib/symbol.py
+
+#--start constants--
+single_input = 256
+file_input = 257
+eval_input = 258
+funcdef = 259
+parameters = 260
+varargslist = 261
+fpdef = 262
+fplist = 263
+stmt = 264
+simple_stmt = 265
+small_stmt = 266
+expr_stmt = 267
+augassign = 268
+print_stmt = 269
+del_stmt = 270
+pass_stmt = 271
+flow_stmt = 272
+break_stmt = 273
+continue_stmt = 274
+return_stmt = 275
+raise_stmt = 276
+import_stmt = 277
+import_as_name = 278
+dotted_as_name = 279
+dotted_name = 280
+global_stmt = 281
+exec_stmt = 282
+assert_stmt = 283
+compound_stmt = 284
+if_stmt = 285
+while_stmt = 286
+for_stmt = 287
+try_stmt = 288
+except_clause = 289
+suite = 290
+test = 291
+and_test = 292
+not_test = 293
+comparison = 294
+comp_op = 295
+expr = 296
+xor_expr = 297
+and_expr = 298
+shift_expr = 299
+arith_expr = 300
+term = 301
+factor = 302
+power = 303
+atom = 304
+listmaker = 305
+lambdef = 306
+trailer = 307
+subscriptlist = 308
+subscript = 309
+sliceop = 310
+exprlist = 311
+testlist = 312
+dictmaker = 313
+classdef = 314
+arglist = 315
+argument = 316
+list_iter = 317
+list_for = 318
+list_if = 319
+#--end constants--
+
+sym_name = {}
+for _name, _value in globals().items():
+ if type(_value) is type(0):
+ sym_name[_value] = _name
+
+
+def main():
+ import sys
+ import token
+ if len(sys.argv) == 1:
+ sys.argv = sys.argv + ["Include/graminit.h", "Lib/symbol.py"]
+ token.main()
+
+if __name__ == "__main__":
+ main()
diff --git a/lib/jython/Lib/telnetlib.py b/lib/jython/Lib/telnetlib.py new file mode 100644 index 000000000..467af4873 --- /dev/null +++ b/lib/jython/Lib/telnetlib.py @@ -0,0 +1,504 @@ +"""TELNET client class.
+
+Based on RFC 854: TELNET Protocol Specification, by J. Postel and
+J. Reynolds
+
+Example:
+
+>>> from telnetlib import Telnet
+>>> tn = Telnet('www.python.org', 79) # connect to finger port
+>>> tn.write('guido\r\n')
+>>> print tn.read_all()
+Login Name TTY Idle When Where
+guido Guido van Rossum pts/2 <Dec 2 11:10> snag.cnri.reston..
+
+>>>
+
+Note that read_all() won't read until eof -- it just reads some data
+-- but it guarantees to read at least one byte unless EOF is hit.
+
+It is possible to pass a Telnet object to select.select() in order to
+wait until more data is available. Note that in this case,
+read_eager() may return '' even if there was data on the socket,
+because the protocol negotiation may have eaten the data. This is why
+EOFError is needed in some cases to distinguish between "no data" and
+"connection closed" (since the socket also appears ready for reading
+when it is closed).
+
+Bugs:
+- may hang when connection is slow in the middle of an IAC sequence
+
+To do:
+- option negotiation
+- timeout should be intrinsic to the connection object instead of an
+ option on one of the read calls only
+
+"""
+
+
+# Imported modules
+import sys
+import socket
+import select
+
+__all__ = ["Telnet"]
+
+# Tunable parameters
+DEBUGLEVEL = 0
+
+# Telnet protocol defaults
+TELNET_PORT = 23
+
+# Telnet protocol characters (don't change)
+IAC = chr(255) # "Interpret As Command"
+DONT = chr(254)
+DO = chr(253)
+WONT = chr(252)
+WILL = chr(251)
+theNULL = chr(0)
+
+
+class Telnet:
+
+ """Telnet interface class.
+
+ An instance of this class represents a connection to a telnet
+ server. The instance is initially not connected; the open()
+ method must be used to establish a connection. Alternatively, the
+ host name and optional port number can be passed to the
+ constructor, too.
+
+ Don't try to reopen an already connected instance.
+
+ This class has many read_*() methods. Note that some of them
+ raise EOFError when the end of the connection is read, because
+ they can return an empty string for other reasons. See the
+ individual doc strings.
+
+ read_until(expected, [timeout])
+ Read until the expected string has been seen, or a timeout is
+ hit (default is no timeout); may block.
+
+ read_all()
+ Read all data until EOF; may block.
+
+ read_some()
+ Read at least one byte or EOF; may block.
+
+ read_very_eager()
+ Read all data available already queued or on the socket,
+ without blocking.
+
+ read_eager()
+ Read either data already queued or some data available on the
+ socket, without blocking.
+
+ read_lazy()
+ Read all data in the raw queue (processing it first), without
+ doing any socket I/O.
+
+ read_very_lazy()
+ Reads all data in the cooked queue, without doing any socket
+ I/O.
+
+ """
+
+ def __init__(self, host=None, port=0):
+ """Constructor.
+
+ When called without arguments, create an unconnected instance.
+ With a hostname argument, it connects the instance; a port
+ number is optional.
+
+ """
+ self.debuglevel = DEBUGLEVEL
+ self.host = host
+ self.port = port
+ self.sock = None
+ self.rawq = ''
+ self.irawq = 0
+ self.cookedq = ''
+ self.eof = 0
+ if host:
+ self.open(host, port)
+
+ def open(self, host, port=0):
+ """Connect to a host.
+
+ The optional second argument is the port number, which
+ defaults to the standard telnet port (23).
+
+ Don't try to reopen an already connected instance.
+
+ """
+ self.eof = 0
+ if not port:
+ port = TELNET_PORT
+ self.host = host
+ self.port = port
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.sock.connect((self.host, self.port))
+
+ def __del__(self):
+ """Destructor -- close the connection."""
+ self.close()
+
+ def msg(self, msg, *args):
+ """Print a debug message, when the debug level is > 0.
+
+ If extra arguments are present, they are substituted in the
+ message using the standard string formatting operator.
+
+ """
+ if self.debuglevel > 0:
+ print 'Telnet(%s,%d):' % (self.host, self.port),
+ if args:
+ print msg % args
+ else:
+ print msg
+
+ def set_debuglevel(self, debuglevel):
+ """Set the debug level.
+
+ The higher it is, the more debug output you get (on sys.stdout).
+
+ """
+ self.debuglevel = debuglevel
+
+ def close(self):
+ """Close the connection."""
+ if self.sock:
+ self.sock.close()
+ self.sock = 0
+ self.eof = 1
+
+ def get_socket(self):
+ """Return the socket object used internally."""
+ return self.sock
+
+ def fileno(self):
+ """Return the fileno() of the socket object used internally."""
+ return self.sock.fileno()
+
+ def write(self, buffer):
+ """Write a string to the socket, doubling any IAC characters.
+
+ Can block if the connection is blocked. May raise
+ socket.error if the connection is closed.
+
+ """
+ if IAC in buffer:
+ buffer = buffer.replace(IAC, IAC+IAC)
+ self.msg("send %s", `buffer`)
+ self.sock.send(buffer)
+
+ def read_until(self, match, timeout=None):
+ """Read until a given string is encountered or until timeout.
+
+ When no match is found, return whatever is available instead,
+ possibly the empty string. Raise EOFError if the connection
+ is closed and no cooked data is available.
+
+ """
+ n = len(match)
+ self.process_rawq()
+ i = self.cookedq.find(match)
+ if i >= 0:
+ i = i+n
+ buf = self.cookedq[:i]
+ self.cookedq = self.cookedq[i:]
+ return buf
+ s_reply = ([self], [], [])
+ s_args = s_reply
+ if timeout is not None:
+ s_args = s_args + (timeout,)
+ while not self.eof and apply(select.select, s_args) == s_reply:
+ i = max(0, len(self.cookedq)-n)
+ self.fill_rawq()
+ self.process_rawq()
+ i = self.cookedq.find(match, i)
+ if i >= 0:
+ i = i+n
+ buf = self.cookedq[:i]
+ self.cookedq = self.cookedq[i:]
+ return buf
+ return self.read_very_lazy()
+
+ def read_all(self):
+ """Read all data until EOF; block until connection closed."""
+ self.process_rawq()
+ while not self.eof:
+ self.fill_rawq()
+ self.process_rawq()
+ buf = self.cookedq
+ self.cookedq = ''
+ return buf
+
+ def read_some(self):
+ """Read at least one byte of cooked data unless EOF is hit.
+
+ Return '' if EOF is hit. Block if no data is immediately
+ available.
+
+ """
+ self.process_rawq()
+ while not self.cookedq and not self.eof:
+ self.fill_rawq()
+ self.process_rawq()
+ buf = self.cookedq
+ self.cookedq = ''
+ return buf
+
+ def read_very_eager(self):
+ """Read everything that's possible without blocking in I/O (eager).
+
+ Raise EOFError if connection closed and no cooked data
+ available. Return '' if no cooked data available otherwise.
+ Don't block unless in the midst of an IAC sequence.
+
+ """
+ self.process_rawq()
+ while not self.eof and self.sock_avail():
+ self.fill_rawq()
+ self.process_rawq()
+ return self.read_very_lazy()
+
+ def read_eager(self):
+ """Read readily available data.
+
+ Raise EOFError if connection closed and no cooked data
+ available. Return '' if no cooked data available otherwise.
+ Don't block unless in the midst of an IAC sequence.
+
+ """
+ self.process_rawq()
+ while not self.cookedq and not self.eof and self.sock_avail():
+ self.fill_rawq()
+ self.process_rawq()
+ return self.read_very_lazy()
+
+ def read_lazy(self):
+ """Process and return data that's already in the queues (lazy).
+
+ Raise EOFError if connection closed and no data available.
+ Return '' if no cooked data available otherwise. Don't block
+ unless in the midst of an IAC sequence.
+
+ """
+ self.process_rawq()
+ return self.read_very_lazy()
+
+ def read_very_lazy(self):
+ """Return any data available in the cooked queue (very lazy).
+
+ Raise EOFError if connection closed and no data available.
+ Return '' if no cooked data available otherwise. Don't block.
+
+ """
+ buf = self.cookedq
+ self.cookedq = ''
+ if not buf and self.eof and not self.rawq:
+ raise EOFError, 'telnet connection closed'
+ return buf
+
+ def process_rawq(self):
+ """Transfer from raw queue to cooked queue.
+
+ Set self.eof when connection is closed. Don't block unless in
+ the midst of an IAC sequence.
+
+ """
+ buf = ''
+ try:
+ while self.rawq:
+ c = self.rawq_getchar()
+ if c == theNULL:
+ continue
+ if c == "\021":
+ continue
+ if c != IAC:
+ buf = buf + c
+ continue
+ c = self.rawq_getchar()
+ if c == IAC:
+ buf = buf + c
+ elif c in (DO, DONT):
+ opt = self.rawq_getchar()
+ self.msg('IAC %s %d', c == DO and 'DO' or 'DONT', ord(c))
+ self.sock.send(IAC + WONT + opt)
+ elif c in (WILL, WONT):
+ opt = self.rawq_getchar()
+ self.msg('IAC %s %d',
+ c == WILL and 'WILL' or 'WONT', ord(c))
+ self.sock.send(IAC + DONT + opt)
+ else:
+ self.msg('IAC %s not recognized' % `c`)
+ except EOFError: # raised by self.rawq_getchar()
+ pass
+ self.cookedq = self.cookedq + buf
+
+ def rawq_getchar(self):
+ """Get next char from raw queue.
+
+ Block if no data is immediately available. Raise EOFError
+ when connection is closed.
+
+ """
+ if not self.rawq:
+ self.fill_rawq()
+ if self.eof:
+ raise EOFError
+ c = self.rawq[self.irawq]
+ self.irawq = self.irawq + 1
+ if self.irawq >= len(self.rawq):
+ self.rawq = ''
+ self.irawq = 0
+ return c
+
+ def fill_rawq(self):
+ """Fill raw queue from exactly one recv() system call.
+
+ Block if no data is immediately available. Set self.eof when
+ connection is closed.
+
+ """
+ if self.irawq >= len(self.rawq):
+ self.rawq = ''
+ self.irawq = 0
+ # The buffer size should be fairly small so as to avoid quadratic
+ # behavior in process_rawq() above
+ buf = self.sock.recv(50)
+ self.msg("recv %s", `buf`)
+ self.eof = (not buf)
+ self.rawq = self.rawq + buf
+
+ def sock_avail(self):
+ """Test whether data is available on the socket."""
+ return select.select([self], [], [], 0) == ([self], [], [])
+
+ def interact(self):
+ """Interaction function, emulates a very dumb telnet client."""
+ if sys.platform == "win32":
+ self.mt_interact()
+ return
+ while 1:
+ rfd, wfd, xfd = select.select([self, sys.stdin], [], [])
+ if self in rfd:
+ try:
+ text = self.read_eager()
+ except EOFError:
+ print '*** Connection closed by remote host ***'
+ break
+ if text:
+ sys.stdout.write(text)
+ sys.stdout.flush()
+ if sys.stdin in rfd:
+ line = sys.stdin.readline()
+ if not line:
+ break
+ self.write(line)
+
+ def mt_interact(self):
+ """Multithreaded version of interact()."""
+ import thread
+ thread.start_new_thread(self.listener, ())
+ while 1:
+ line = sys.stdin.readline()
+ if not line:
+ break
+ self.write(line)
+
+ def listener(self):
+ """Helper for mt_interact() -- this executes in the other thread."""
+ while 1:
+ try:
+ data = self.read_eager()
+ except EOFError:
+ print '*** Connection closed by remote host ***'
+ return
+ if data:
+ sys.stdout.write(data)
+ else:
+ sys.stdout.flush()
+
+ def expect(self, list, timeout=None):
+ """Read until one from a list of a regular expressions matches.
+
+ The first argument is a list of regular expressions, either
+ compiled (re.RegexObject instances) or uncompiled (strings).
+ The optional second argument is a timeout, in seconds; default
+ is no timeout.
+
+ Return a tuple of three items: the index in the list of the
+ first regular expression that matches; the match object
+ returned; and the text read up till and including the match.
+
+ If EOF is read and no text was read, raise EOFError.
+ Otherwise, when nothing matches, return (-1, None, text) where
+ text is the text received so far (may be the empty string if a
+ timeout happened).
+
+ If a regular expression ends with a greedy match (e.g. '.*')
+ or if more than one expression can match the same input, the
+ results are undeterministic, and may depend on the I/O timing.
+
+ """
+ re = None
+ list = list[:]
+ indices = range(len(list))
+ for i in indices:
+ if not hasattr(list[i], "search"):
+ if not re: import re
+ list[i] = re.compile(list[i])
+ while 1:
+ self.process_rawq()
+ for i in indices:
+ m = list[i].search(self.cookedq)
+ if m:
+ e = m.end()
+ text = self.cookedq[:e]
+ self.cookedq = self.cookedq[e:]
+ return (i, m, text)
+ if self.eof:
+ break
+ if timeout is not None:
+ r, w, x = select.select([self.fileno()], [], [], timeout)
+ if not r:
+ break
+ self.fill_rawq()
+ text = self.read_very_lazy()
+ if not text and self.eof:
+ raise EOFError
+ return (-1, None, text)
+
+
+def test():
+ """Test program for telnetlib.
+
+ Usage: python telnetlib.py [-d] ... [host [port]]
+
+ Default host is localhost; default port is 23.
+
+ """
+ debuglevel = 0
+ while sys.argv[1:] and sys.argv[1] == '-d':
+ debuglevel = debuglevel+1
+ del sys.argv[1]
+ host = 'localhost'
+ if sys.argv[1:]:
+ host = sys.argv[1]
+ port = 0
+ if sys.argv[2:]:
+ portstr = sys.argv[2]
+ try:
+ port = int(portstr)
+ except ValueError:
+ port = socket.getservbyname(portstr, 'tcp')
+ tn = Telnet()
+ tn.set_debuglevel(debuglevel)
+ tn.open(host, port)
+ tn.interact()
+ tn.close()
+
+if __name__ == '__main__':
+ test()
diff --git a/lib/jython/Lib/tempfile.py b/lib/jython/Lib/tempfile.py new file mode 100644 index 000000000..02f3693e0 --- /dev/null +++ b/lib/jython/Lib/tempfile.py @@ -0,0 +1,205 @@ +"""Temporary files and filenames."""
+
+# XXX This tries to be not UNIX specific, but I don't know beans about
+# how to choose a temp directory or filename on MS-DOS or other
+# systems so it may have to be changed...
+
+import os
+
+__all__ = ["mktemp", "TemporaryFile", "tempdir", "gettempprefix"]
+
+# Parameters that the caller may set to override the defaults
+tempdir = None
+template = None
+
+def gettempdir():
+ """Function to calculate the directory to use."""
+ global tempdir
+ if tempdir is not None:
+ return tempdir
+ try:
+ pwd = os.getcwd()
+ except (AttributeError, os.error):
+ pwd = os.curdir
+ attempdirs = ['/tmp', '/var/tmp', '/usr/tmp', pwd]
+ if os.name == 'nt':
+ attempdirs.insert(0, 'C:\\TEMP')
+ attempdirs.insert(0, '\\TEMP')
+ elif os.name == 'mac':
+ import macfs, MACFS
+ try:
+ refnum, dirid = macfs.FindFolder(MACFS.kOnSystemDisk,
+ MACFS.kTemporaryFolderType, 1)
+ dirname = macfs.FSSpec((refnum, dirid, '')).as_pathname()
+ attempdirs.insert(0, dirname)
+ except macfs.error:
+ pass
+ for envname in 'TMPDIR', 'TEMP', 'TMP':
+ if os.environ.has_key(envname):
+ attempdirs.insert(0, os.environ[envname])
+ testfile = gettempprefix() + 'test'
+ for dir in attempdirs:
+ try:
+ filename = os.path.join(dir, testfile)
+ if os.name == 'posix':
+ try:
+ fd = os.open(filename,
+ os.O_RDWR | os.O_CREAT | os.O_EXCL, 0700)
+ except OSError:
+ pass
+ else:
+ fp = os.fdopen(fd, 'w')
+ fp.write('blat')
+ fp.close()
+ os.unlink(filename)
+ del fp, fd
+ tempdir = dir
+ break
+ else:
+ fp = open(filename, 'w')
+ fp.write('blat')
+ fp.close()
+ os.unlink(filename)
+ tempdir = dir
+ break
+ except IOError:
+ pass
+ if tempdir is None:
+ msg = "Can't find a usable temporary directory amongst " + `attempdirs`
+ raise IOError, msg
+ return tempdir
+
+
+# template caches the result of gettempprefix, for speed, when possible.
+# XXX unclear why this isn't "_template"; left it "template" for backward
+# compatibility.
+if os.name == "posix":
+ # We don't try to cache the template on posix: the pid may change on us
+ # between calls due to a fork, and on Linux the pid changes even for
+ # another thread in the same process. Since any attempt to keep the
+ # cache in synch would have to call os.getpid() anyway in order to make
+ # sure the pid hasn't changed between calls, a cache wouldn't save any
+ # time. In addition, a cache is difficult to keep correct with the pid
+ # changing willy-nilly, and earlier attempts proved buggy (races).
+ template = None
+
+# Else the pid never changes, so gettempprefix always returns the same
+# string.
+elif os.name == "nt":
+ template = '~' + `os.getpid()` + '-'
+elif os.name == 'mac':
+ template = 'Python-Tmp-'
+else:
+ template = 'tmp' # XXX might choose a better one
+
+def gettempprefix():
+ """Function to calculate a prefix of the filename to use.
+
+ This incorporates the current process id on systems that support such a
+ notion, so that concurrent processes don't generate the same prefix.
+ """
+
+ global template
+ if template is None:
+ return '@' + `os.getpid()` + '.'
+ else:
+ return template
+
+
+def mktemp(suffix=""):
+ """User-callable function to return a unique temporary file name."""
+ dir = gettempdir()
+ pre = gettempprefix()
+ while 1:
+ i = _counter.get_next()
+ file = os.path.join(dir, pre + str(i) + suffix)
+ if not os.path.exists(file):
+ return file
+
+
+class TemporaryFileWrapper:
+ """Temporary file wrapper
+
+ This class provides a wrapper around files opened for temporary use.
+ In particular, it seeks to automatically remove the file when it is
+ no longer needed.
+ """
+ def __init__(self, file, path):
+ self.file = file
+ self.path = path
+
+ def close(self):
+ self.file.close()
+ os.unlink(self.path)
+
+ def __del__(self):
+ try: self.close()
+ except: pass
+
+ def __getattr__(self, name):
+ file = self.__dict__['file']
+ a = getattr(file, name)
+ if type(a) != type(0):
+ setattr(self, name, a)
+ return a
+
+
+def TemporaryFile(mode='w+b', bufsize=-1, suffix=""):
+ """Create and return a temporary file (opened read-write by default)."""
+ name = mktemp(suffix)
+ if os.name == 'posix':
+ # Unix -- be very careful
+ fd = os.open(name, os.O_RDWR|os.O_CREAT|os.O_EXCL, 0700)
+ try:
+ os.unlink(name)
+ return os.fdopen(fd, mode, bufsize)
+ except:
+ os.close(fd)
+ raise
+ else:
+ # Non-unix -- can't unlink file that's still open, use wrapper
+ file = open(name, mode, bufsize)
+ return TemporaryFileWrapper(file, name)
+
+# In order to generate unique names, mktemp() uses _counter.get_next().
+# This returns a unique integer on each call, in a threadsafe way (i.e.,
+# multiple threads will never see the same integer). The integer will
+# usually be a Python int, but if _counter.get_next() is called often
+# enough, it will become a Python long.
+# Note that the only name that survives this next block of code
+# is "_counter".
+
+class _ThreadSafeCounter:
+ def __init__(self, mutex, initialvalue=0):
+ self.mutex = mutex
+ self.i = initialvalue
+
+ def get_next(self):
+ self.mutex.acquire()
+ result = self.i
+ try:
+ newi = result + 1
+ except OverflowError:
+ newi = long(result) + 1
+ self.i = newi
+ self.mutex.release()
+ return result
+
+try:
+ import thread
+
+except ImportError:
+ class _DummyMutex:
+ def acquire(self):
+ pass
+
+ release = acquire
+
+ _counter = _ThreadSafeCounter(_DummyMutex())
+ del _DummyMutex
+
+else:
+ _counter = _ThreadSafeCounter(thread.allocate_lock())
+ del thread
+
+del _ThreadSafeCounter
diff --git a/lib/jython/Lib/test/pystone.py b/lib/jython/Lib/test/pystone.py new file mode 100644 index 000000000..a77532d46 --- /dev/null +++ b/lib/jython/Lib/test/pystone.py @@ -0,0 +1,252 @@ +#! /usr/bin/env python
+
+"""
+"PYSTONE" Benchmark Program
+
+Version: Python/1.1 (corresponds to C/1.1 plus 2 Pystone fixes)
+
+Author: Reinhold P. Weicker, CACM Vol 27, No 10, 10/84 pg. 1013.
+
+ Translated from ADA to C by Rick Richardson.
+ Every method to preserve ADA-likeness has been used,
+ at the expense of C-ness.
+
+ Translated from C to Python by Guido van Rossum.
+
+Version History:
+
+ Version 1.1 corrects two bugs in version 1.0:
+
+ First, it leaked memory: in Proc1(), NextRecord ends
+ up having a pointer to itself. I have corrected this
+ by zapping NextRecord.PtrComp at the end of Proc1().
+
+ Second, Proc3() used the operator != to compare a
+ record to None. This is rather inefficient and not
+ true to the intention of the original benchmark (where
+ a pointer comparison to None is intended; the !=
+ operator attempts to find a method __cmp__ to do value
+ comparison of the record). Version 1.1 runs 5-10
+ percent faster than version 1.0, so benchmark figures
+ of different versions can't be compared directly.
+
+"""
+
+LOOPS = 10000
+
+from time import clock
+
+__version__ = "1.1"
+
+[Ident1, Ident2, Ident3, Ident4, Ident5] = range(1, 6)
+
+class Record:
+
+ def __init__(self, PtrComp = None, Discr = 0, EnumComp = 0,
+ IntComp = 0, StringComp = 0):
+ self.PtrComp = PtrComp
+ self.Discr = Discr
+ self.EnumComp = EnumComp
+ self.IntComp = IntComp
+ self.StringComp = StringComp
+
+ def copy(self):
+ return Record(self.PtrComp, self.Discr, self.EnumComp,
+ self.IntComp, self.StringComp)
+
+TRUE = 1
+FALSE = 0
+
+def main():
+ benchtime, stones = pystones()
+ print "Pystone(%s) time for %d passes = %g" % \
+ (__version__, LOOPS, benchtime)
+ print "This machine benchmarks at %g pystones/second" % stones
+
+
+def pystones(loops=LOOPS):
+ return Proc0(loops)
+
+IntGlob = 0
+BoolGlob = FALSE
+Char1Glob = '\0'
+Char2Glob = '\0'
+Array1Glob = [0]*51
+Array2Glob = map(lambda x: x[:], [Array1Glob]*51)
+PtrGlb = None
+PtrGlbNext = None
+
+def Proc0(loops=LOOPS):
+ global IntGlob
+ global BoolGlob
+ global Char1Glob
+ global Char2Glob
+ global Array1Glob
+ global Array2Glob
+ global PtrGlb
+ global PtrGlbNext
+
+ starttime = clock()
+ for i in range(loops):
+ pass
+ nulltime = clock() - starttime
+
+ PtrGlbNext = Record()
+ PtrGlb = Record()
+ PtrGlb.PtrComp = PtrGlbNext
+ PtrGlb.Discr = Ident1
+ PtrGlb.EnumComp = Ident3
+ PtrGlb.IntComp = 40
+ PtrGlb.StringComp = "DHRYSTONE PROGRAM, SOME STRING"
+ String1Loc = "DHRYSTONE PROGRAM, 1'ST STRING"
+ Array2Glob[8][7] = 10
+
+ starttime = clock()
+
+ for i in range(loops):
+ Proc5()
+ Proc4()
+ IntLoc1 = 2
+ IntLoc2 = 3
+ String2Loc = "DHRYSTONE PROGRAM, 2'ND STRING"
+ EnumLoc = Ident2
+ BoolGlob = not Func2(String1Loc, String2Loc)
+ while IntLoc1 < IntLoc2:
+ IntLoc3 = 5 * IntLoc1 - IntLoc2
+ IntLoc3 = Proc7(IntLoc1, IntLoc2)
+ IntLoc1 = IntLoc1 + 1
+ Proc8(Array1Glob, Array2Glob, IntLoc1, IntLoc3)
+ PtrGlb = Proc1(PtrGlb)
+ CharIndex = 'A'
+ while CharIndex <= Char2Glob:
+ if EnumLoc == Func1(CharIndex, 'C'):
+ EnumLoc = Proc6(Ident1)
+ CharIndex = chr(ord(CharIndex)+1)
+ IntLoc3 = IntLoc2 * IntLoc1
+ IntLoc2 = IntLoc3 / IntLoc1
+ IntLoc2 = 7 * (IntLoc3 - IntLoc2) - IntLoc1
+ IntLoc1 = Proc2(IntLoc1)
+
+ benchtime = clock() - starttime - nulltime
+ return benchtime, (loops / benchtime)
+
+def Proc1(PtrParIn):
+ PtrParIn.PtrComp = NextRecord = PtrGlb.copy()
+ PtrParIn.IntComp = 5
+ NextRecord.IntComp = PtrParIn.IntComp
+ NextRecord.PtrComp = PtrParIn.PtrComp
+ NextRecord.PtrComp = Proc3(NextRecord.PtrComp)
+ if NextRecord.Discr == Ident1:
+ NextRecord.IntComp = 6
+ NextRecord.EnumComp = Proc6(PtrParIn.EnumComp)
+ NextRecord.PtrComp = PtrGlb.PtrComp
+ NextRecord.IntComp = Proc7(NextRecord.IntComp, 10)
+ else:
+ PtrParIn = NextRecord.copy()
+ NextRecord.PtrComp = None
+ return PtrParIn
+
+def Proc2(IntParIO):
+ IntLoc = IntParIO + 10
+ while 1:
+ if Char1Glob == 'A':
+ IntLoc = IntLoc - 1
+ IntParIO = IntLoc - IntGlob
+ EnumLoc = Ident1
+ if EnumLoc == Ident1:
+ break
+ return IntParIO
+
+def Proc3(PtrParOut):
+ global IntGlob
+
+ if PtrGlb is not None:
+ PtrParOut = PtrGlb.PtrComp
+ else:
+ IntGlob = 100
+ PtrGlb.IntComp = Proc7(10, IntGlob)
+ return PtrParOut
+
+def Proc4():
+ global Char2Glob
+
+ BoolLoc = Char1Glob == 'A'
+ BoolLoc = BoolLoc or BoolGlob
+ Char2Glob = 'B'
+
+def Proc5():
+ global Char1Glob
+ global BoolGlob
+
+ Char1Glob = 'A'
+ BoolGlob = FALSE
+
+def Proc6(EnumParIn):
+ EnumParOut = EnumParIn
+ if not Func3(EnumParIn):
+ EnumParOut = Ident4
+ if EnumParIn == Ident1:
+ EnumParOut = Ident1
+ elif EnumParIn == Ident2:
+ if IntGlob > 100:
+ EnumParOut = Ident1
+ else:
+ EnumParOut = Ident4
+ elif EnumParIn == Ident3:
+ EnumParOut = Ident2
+ elif EnumParIn == Ident4:
+ pass
+ elif EnumParIn == Ident5:
+ EnumParOut = Ident3
+ return EnumParOut
+
+def Proc7(IntParI1, IntParI2):
+ IntLoc = IntParI1 + 2
+ IntParOut = IntParI2 + IntLoc
+ return IntParOut
+
+def Proc8(Array1Par, Array2Par, IntParI1, IntParI2):
+ global IntGlob
+
+ IntLoc = IntParI1 + 5
+ Array1Par[IntLoc] = IntParI2
+ Array1Par[IntLoc+1] = Array1Par[IntLoc]
+ Array1Par[IntLoc+30] = IntLoc
+ for IntIndex in range(IntLoc, IntLoc+2):
+ Array2Par[IntLoc][IntIndex] = IntLoc
+ Array2Par[IntLoc][IntLoc-1] = Array2Par[IntLoc][IntLoc-1] + 1
+ Array2Par[IntLoc+20][IntLoc] = Array1Par[IntLoc]
+ IntGlob = 5
+
+def Func1(CharPar1, CharPar2):
+ CharLoc1 = CharPar1
+ CharLoc2 = CharLoc1
+ if CharLoc2 != CharPar2:
+ return Ident1
+ else:
+ return Ident2
+
+def Func2(StrParI1, StrParI2):
+ IntLoc = 1
+ while IntLoc <= 1:
+ if Func1(StrParI1[IntLoc], StrParI2[IntLoc+1]) == Ident1:
+ CharLoc = 'A'
+ IntLoc = IntLoc + 1
+ if CharLoc >= 'W' and CharLoc <= 'Z':
+ IntLoc = 7
+ if CharLoc == 'X':
+ return TRUE
+ else:
+ if StrParI1 > StrParI2:
+ IntLoc = IntLoc + 7
+ return TRUE
+ else:
+ return FALSE
+
+def Func3(EnumParIn):
+ EnumLoc = EnumParIn
+ if EnumLoc == Ident3: return TRUE
+ return FALSE
+
+if __name__ == '__main__':
+ main()
diff --git a/lib/jython/Lib/threading.py b/lib/jython/Lib/threading.py new file mode 100644 index 000000000..77fdcbdaf --- /dev/null +++ b/lib/jython/Lib/threading.py @@ -0,0 +1,633 @@ +"""Proposed new threading module, emulating a subset of Java's threading model."""
+
+import sys
+import time
+import thread
+import traceback
+import StringIO
+
+# Rename some stuff so "from threading import *" is safe
+
+_sys = sys
+del sys
+
+_time = time.time
+_sleep = time.sleep
+del time
+
+_start_new_thread = thread.start_new_thread
+_allocate_lock = thread.allocate_lock
+_get_ident = thread.get_ident
+ThreadError = thread.error
+del thread
+
+_print_exc = traceback.print_exc
+del traceback
+
+_StringIO = StringIO.StringIO
+del StringIO
+
+
+# Debug support (adapted from ihooks.py)
+
+_VERBOSE = 0
+
+if __debug__:
+
+ class _Verbose:
+
+ def __init__(self, verbose=None):
+ if verbose is None:
+ verbose = _VERBOSE
+ self.__verbose = verbose
+
+ def _note(self, format, *args):
+ if self.__verbose:
+ format = format % args
+ format = "%s: %s\n" % (
+ currentThread().getName(), format)
+ _sys.stderr.write(format)
+
+else:
+ # Disable this when using "python -O"
+ class _Verbose:
+ def __init__(self, verbose=None):
+ pass
+ def _note(self, *args):
+ pass
+
+
+# Synchronization classes
+
+Lock = _allocate_lock
+
+def RLock(*args, **kwargs):
+ return apply(_RLock, args, kwargs)
+
+class _RLock(_Verbose):
+
+ def __init__(self, verbose=None):
+ _Verbose.__init__(self, verbose)
+ self.__block = _allocate_lock()
+ self.__owner = None
+ self.__count = 0
+
+ def __repr__(self):
+ return "<%s(%s, %d)>" % (
+ self.__class__.__name__,
+ self.__owner and self.__owner.getName(),
+ self.__count)
+
+ def acquire(self, blocking=1):
+ me = currentThread()
+ if self.__owner is me:
+ self.__count = self.__count + 1
+ if __debug__:
+ self._note("%s.acquire(%s): recursive success", self, blocking)
+ return 1
+ rc = self.__block.acquire(blocking)
+ if rc:
+ self.__owner = me
+ self.__count = 1
+ if __debug__:
+ self._note("%s.acquire(%s): initial succes", self, blocking)
+ else:
+ if __debug__:
+ self._note("%s.acquire(%s): failure", self, blocking)
+ return rc
+
+ def release(self):
+ me = currentThread()
+ assert self.__owner is me, "release() of un-acquire()d lock"
+ self.__count = count = self.__count - 1
+ if not count:
+ self.__owner = None
+ self.__block.release()
+ if __debug__:
+ self._note("%s.release(): final release", self)
+ else:
+ if __debug__:
+ self._note("%s.release(): non-final release", self)
+
+ # Internal methods used by condition variables
+
+ def _acquire_restore(self, (count, owner)):
+ self.__block.acquire()
+ self.__count = count
+ self.__owner = owner
+ if __debug__:
+ self._note("%s._acquire_restore()", self)
+
+ def _release_save(self):
+ if __debug__:
+ self._note("%s._release_save()", self)
+ count = self.__count
+ self.__count = 0
+ owner = self.__owner
+ self.__owner = None
+ self.__block.release()
+ return (count, owner)
+
+ def _is_owned(self):
+ return self.__owner is currentThread()
+
+
+def Condition(*args, **kwargs):
+ return apply(_Condition, args, kwargs)
+
+class _Condition(_Verbose):
+
+ def __init__(self, lock=None, verbose=None):
+ _Verbose.__init__(self, verbose)
+ if lock is None:
+ lock = RLock()
+ self.__lock = lock
+ # Export the lock's acquire() and release() methods
+ self.acquire = lock.acquire
+ self.release = lock.release
+ # If the lock defines _release_save() and/or _acquire_restore(),
+ # these override the default implementations (which just call
+ # release() and acquire() on the lock). Ditto for _is_owned().
+ try:
+ self._release_save = lock._release_save
+ except AttributeError:
+ pass
+ try:
+ self._acquire_restore = lock._acquire_restore
+ except AttributeError:
+ pass
+ try:
+ self._is_owned = lock._is_owned
+ except AttributeError:
+ pass
+ self.__waiters = []
+
+ def __repr__(self):
+ return "<Condition(%s, %d)>" % (self.__lock, len(self.__waiters))
+
+ def _release_save(self):
+ self.__lock.release() # No state to save
+
+ def _acquire_restore(self, x):
+ self.__lock.acquire() # Ignore saved state
+
+ def _is_owned(self):
+ if self.__lock.acquire(0):
+ self.__lock.release()
+ return 0
+ else:
+ return 1
+
+ def wait(self, timeout=None):
+ me = currentThread()
+ assert self._is_owned(), "wait() of un-acquire()d lock"
+ waiter = _allocate_lock()
+ waiter.acquire()
+ self.__waiters.append(waiter)
+ saved_state = self._release_save()
+ try: # restore state no matter what (e.g., KeyboardInterrupt)
+ if timeout is None:
+ waiter.acquire()
+ if __debug__:
+ self._note("%s.wait(): got it", self)
+ else:
+ endtime = _time() + timeout
+ delay = 0.000001 # 1 usec
+ while 1:
+ gotit = waiter.acquire(0)
+ if gotit or _time() >= endtime:
+ break
+ _sleep(delay)
+ if delay < 1.0:
+ delay = delay * 2.0
+ if not gotit:
+ if __debug__:
+ self._note("%s.wait(%s): timed out", self, timeout)
+ try:
+ self.__waiters.remove(waiter)
+ except ValueError:
+ pass
+ else:
+ if __debug__:
+ self._note("%s.wait(%s): got it", self, timeout)
+ finally:
+ self._acquire_restore(saved_state)
+
+ def notify(self, n=1):
+ me = currentThread()
+ assert self._is_owned(), "notify() of un-acquire()d lock"
+ __waiters = self.__waiters
+ waiters = __waiters[:n]
+ if not waiters:
+ if __debug__:
+ self._note("%s.notify(): no waiters", self)
+ return
+ self._note("%s.notify(): notifying %d waiter%s", self, n,
+ n!=1 and "s" or "")
+ for waiter in waiters:
+ waiter.release()
+ try:
+ __waiters.remove(waiter)
+ except ValueError:
+ pass
+
+ def notifyAll(self):
+ self.notify(len(self.__waiters))
+
+
+def Semaphore(*args, **kwargs):
+ return apply(_Semaphore, args, kwargs)
+
+class _Semaphore(_Verbose):
+
+ # After Tim Peters' semaphore class, but not quite the same (no maximum)
+
+ def __init__(self, value=1, verbose=None):
+ assert value >= 0, "Semaphore initial value must be >= 0"
+ _Verbose.__init__(self, verbose)
+ self.__cond = Condition(Lock())
+ self.__value = value
+
+ def acquire(self, blocking=1):
+ rc = 0
+ self.__cond.acquire()
+ while self.__value == 0:
+ if not blocking:
+ break
+ self.__cond.wait()
+ else:
+ self.__value = self.__value - 1
+ rc = 1
+ self.__cond.release()
+ return rc
+
+ def release(self):
+ self.__cond.acquire()
+ self.__value = self.__value + 1
+ self.__cond.notify()
+ self.__cond.release()
+
+
+def Event(*args, **kwargs):
+ return apply(_Event, args, kwargs)
+
+class _Event(_Verbose):
+
+ # After Tim Peters' event class (without is_posted())
+
+ def __init__(self, verbose=None):
+ _Verbose.__init__(self, verbose)
+ self.__cond = Condition(Lock())
+ self.__flag = 0
+
+ def isSet(self):
+ return self.__flag
+
+ def set(self):
+ self.__cond.acquire()
+ self.__flag = 1
+ self.__cond.notifyAll()
+ self.__cond.release()
+
+ def clear(self):
+ self.__cond.acquire()
+ self.__flag = 0
+ self.__cond.release()
+
+ def wait(self, timeout=None):
+ self.__cond.acquire()
+ if not self.__flag:
+ self.__cond.wait(timeout)
+ self.__cond.release()
+
+
+# Helper to generate new thread names
+_counter = 0
+def _newname(template="Thread-%d"):
+ global _counter
+ _counter = _counter + 1
+ return template % _counter
+
+# Active thread administration
+_active_limbo_lock = _allocate_lock()
+_active = {}
+_limbo = {}
+
+
+# Main class for threads
+
+class Thread(_Verbose):
+
+ __initialized = 0
+
+ def __init__(self, group=None, target=None, name=None,
+ args=(), kwargs={}, verbose=None):
+ assert group is None, "group argument must be None for now"
+ _Verbose.__init__(self, verbose)
+ self.__target = target
+ self.__name = str(name or _newname())
+ self.__args = args
+ self.__kwargs = kwargs
+ self.__daemonic = self._set_daemon()
+ self.__started = 0
+ self.__stopped = 0
+ self.__block = Condition(Lock())
+ self.__initialized = 1
+
+ def _set_daemon(self):
+ # Overridden in _MainThread and _DummyThread
+ return currentThread().isDaemon()
+
+ def __repr__(self):
+ assert self.__initialized, "Thread.__init__() was not called"
+ status = "initial"
+ if self.__started:
+ status = "started"
+ if self.__stopped:
+ status = "stopped"
+ if self.__daemonic:
+ status = status + " daemon"
+ return "<%s(%s, %s)>" % (self.__class__.__name__, self.__name, status)
+
+ def start(self):
+ assert self.__initialized, "Thread.__init__() not called"
+ assert not self.__started, "thread already started"
+ if __debug__:
+ self._note("%s.start(): starting thread", self)
+ _active_limbo_lock.acquire()
+ _limbo[self] = self
+ _active_limbo_lock.release()
+ _start_new_thread(self.__bootstrap, ())
+ self.__started = 1
+ _sleep(0.000001) # 1 usec, to let the thread run (Solaris hack)
+
+ def run(self):
+ if self.__target:
+ apply(self.__target, self.__args, self.__kwargs)
+
+ def __bootstrap(self):
+ try:
+ self.__started = 1
+ _active_limbo_lock.acquire()
+ _active[_get_ident()] = self
+ del _limbo[self]
+ _active_limbo_lock.release()
+ if __debug__:
+ self._note("%s.__bootstrap(): thread started", self)
+ try:
+ self.run()
+ except SystemExit:
+ if __debug__:
+ self._note("%s.__bootstrap(): raised SystemExit", self)
+ except:
+ if __debug__:
+ self._note("%s.__bootstrap(): unhandled exception", self)
+ s = _StringIO()
+ _print_exc(file=s)
+ _sys.stderr.write("Exception in thread %s:\n%s\n" %
+ (self.getName(), s.getvalue()))
+ else:
+ if __debug__:
+ self._note("%s.__bootstrap(): normal return", self)
+ finally:
+ self.__stop()
+ self.__delete()
+
+ def __stop(self):
+ self.__block.acquire()
+ self.__stopped = 1
+ self.__block.notifyAll()
+ self.__block.release()
+
+ def __delete(self):
+ _active_limbo_lock.acquire()
+ del _active[_get_ident()]
+ _active_limbo_lock.release()
+
+ def join(self, timeout=None):
+ assert self.__initialized, "Thread.__init__() not called"
+ assert self.__started, "cannot join thread before it is started"
+ assert self is not currentThread(), "cannot join current thread"
+ if __debug__:
+ if not self.__stopped:
+ self._note("%s.join(): waiting until thread stops", self)
+ self.__block.acquire()
+ if timeout is None:
+ while not self.__stopped:
+ self.__block.wait()
+ if __debug__:
+ self._note("%s.join(): thread stopped", self)
+ else:
+ deadline = _time() + timeout
+ while not self.__stopped:
+ delay = deadline - _time()
+ if delay <= 0:
+ if __debug__:
+ self._note("%s.join(): timed out", self)
+ break
+ self.__block.wait(delay)
+ else:
+ if __debug__:
+ self._note("%s.join(): thread stopped", self)
+ self.__block.release()
+
+ def getName(self):
+ assert self.__initialized, "Thread.__init__() not called"
+ return self.__name
+
+ def setName(self, name):
+ assert self.__initialized, "Thread.__init__() not called"
+ self.__name = str(name)
+
+ def isAlive(self):
+ assert self.__initialized, "Thread.__init__() not called"
+ return self.__started and not self.__stopped
+
+ def isDaemon(self):
+ assert self.__initialized, "Thread.__init__() not called"
+ return self.__daemonic
+
+ def setDaemon(self, daemonic):
+ assert self.__initialized, "Thread.__init__() not called"
+ assert not self.__started, "cannot set daemon status of active thread"
+ self.__daemonic = daemonic
+
+
+# Special thread class to represent the main thread
+# This is garbage collected through an exit handler
+
+class _MainThread(Thread):
+
+ def __init__(self):
+ Thread.__init__(self, name="MainThread")
+ self._Thread__started = 1
+ _active_limbo_lock.acquire()
+ _active[_get_ident()] = self
+ _active_limbo_lock.release()
+ import atexit
+ atexit.register(self.__exitfunc)
+
+ def _set_daemon(self):
+ return 0
+
+ def __exitfunc(self):
+ self._Thread__stop()
+ t = _pickSomeNonDaemonThread()
+ if t:
+ if __debug__:
+ self._note("%s: waiting for other threads", self)
+ while t:
+ t.join()
+ t = _pickSomeNonDaemonThread()
+ if __debug__:
+ self._note("%s: exiting", self)
+ self._Thread__delete()
+
+def _pickSomeNonDaemonThread():
+ for t in enumerate():
+ if not t.isDaemon() and t.isAlive():
+ return t
+ return None
+
+
+# Dummy thread class to represent threads not started here.
+# These aren't garbage collected when they die,
+# nor can they be waited for.
+# Their purpose is to return *something* from currentThread().
+# They are marked as daemon threads so we won't wait for them
+# when we exit (conform previous semantics).
+
+class _DummyThread(Thread):
+
+ def __init__(self):
+ Thread.__init__(self, name=_newname("Dummy-%d"))
+ self._Thread__started = 1
+ _active_limbo_lock.acquire()
+ _active[_get_ident()] = self
+ _active_limbo_lock.release()
+
+ def _set_daemon(self):
+ return 1
+
+ def join(self):
+ assert 0, "cannot join a dummy thread"
+
+
+# Global API functions
+
+def currentThread():
+ try:
+ return _active[_get_ident()]
+ except KeyError:
+ ##print "currentThread(): no current thread for", _get_ident()
+ return _DummyThread()
+
+def activeCount():
+ _active_limbo_lock.acquire()
+ count = len(_active) + len(_limbo)
+ _active_limbo_lock.release()
+ return count
+
+def enumerate():
+ _active_limbo_lock.acquire()
+ active = _active.values() + _limbo.values()
+ _active_limbo_lock.release()
+ return active
+
+
+# Create the main thread object
+
+_MainThread()
+
+
+# Self-test code
+
+def _test():
+
+ import random
+
+ class BoundedQueue(_Verbose):
+
+ def __init__(self, limit):
+ _Verbose.__init__(self)
+ self.mon = RLock()
+ self.rc = Condition(self.mon)
+ self.wc = Condition(self.mon)
+ self.limit = limit
+ self.queue = []
+
+ def put(self, item):
+ self.mon.acquire()
+ while len(self.queue) >= self.limit:
+ self._note("put(%s): queue full", item)
+ self.wc.wait()
+ self.queue.append(item)
+ self._note("put(%s): appended, length now %d",
+ item, len(self.queue))
+ self.rc.notify()
+ self.mon.release()
+
+ def get(self):
+ self.mon.acquire()
+ while not self.queue:
+ self._note("get(): queue empty")
+ self.rc.wait()
+ item = self.queue[0]
+ del self.queue[0]
+ self._note("get(): got %s, %d left", item, len(self.queue))
+ self.wc.notify()
+ self.mon.release()
+ return item
+
+ class ProducerThread(Thread):
+
+ def __init__(self, queue, quota):
+ Thread.__init__(self, name="Producer")
+ self.queue = queue
+ self.quota = quota
+
+ def run(self):
+ from random import random
+ counter = 0
+ while counter < self.quota:
+ counter = counter + 1
+ self.queue.put("%s.%d" % (self.getName(), counter))
+ _sleep(random() * 0.00001)
+
+
+ class ConsumerThread(Thread):
+
+ def __init__(self, queue, count):
+ Thread.__init__(self, name="Consumer")
+ self.queue = queue
+ self.count = count
+
+ def run(self):
+ while self.count > 0:
+ item = self.queue.get()
+ print item
+ self.count = self.count - 1
+
+ import time
+
+ NP = 3
+ QL = 4
+ NI = 5
+
+ Q = BoundedQueue(QL)
+ P = []
+ for i in range(NP):
+ t = ProducerThread(Q, NI)
+ t.setName("Producer-%d" % (i+1))
+ P.append(t)
+ C = ConsumerThread(Q, NI*NP)
+ for t in P:
+ t.start()
+ _sleep(0.000001)
+ C.start()
+ for t in P:
+ t.join()
+ C.join()
+
+if __name__ == '__main__':
+ _test()
diff --git a/lib/jython/Lib/token.py b/lib/jython/Lib/token.py new file mode 100644 index 000000000..dd91abe28 --- /dev/null +++ b/lib/jython/Lib/token.py @@ -0,0 +1,139 @@ +#! /usr/bin/env python
+
+"""Token constants (from "token.h")."""
+
+# This file is automatically generated; please don't muck it up!
+#
+# To update the symbols in this file, 'cd' to the top directory of
+# the python source tree after building the interpreter and run:
+#
+# python Lib/token.py
+
+#--start constants--
+ENDMARKER = 0
+NAME = 1
+NUMBER = 2
+STRING = 3
+NEWLINE = 4
+INDENT = 5
+DEDENT = 6
+LPAR = 7
+RPAR = 8
+LSQB = 9
+RSQB = 10
+COLON = 11
+COMMA = 12
+SEMI = 13
+PLUS = 14
+MINUS = 15
+STAR = 16
+SLASH = 17
+VBAR = 18
+AMPER = 19
+LESS = 20
+GREATER = 21
+EQUAL = 22
+DOT = 23
+PERCENT = 24
+BACKQUOTE = 25
+LBRACE = 26
+RBRACE = 27
+EQEQUAL = 28
+NOTEQUAL = 29
+LESSEQUAL = 30
+GREATEREQUAL = 31
+TILDE = 32
+CIRCUMFLEX = 33
+LEFTSHIFT = 34
+RIGHTSHIFT = 35
+DOUBLESTAR = 36
+PLUSEQUAL = 37
+MINEQUAL = 38
+STAREQUAL = 39
+SLASHEQUAL = 40
+PERCENTEQUAL = 41
+AMPEREQUAL = 42
+VBAREQUAL = 43
+CIRCUMFLEXEQUAL = 44
+LEFTSHIFTEQUAL = 45
+RIGHTSHIFTEQUAL = 46
+DOUBLESTAREQUAL = 47
+OP = 48
+ERRORTOKEN = 49
+N_TOKENS = 50
+NT_OFFSET = 256
+#--end constants--
+
+tok_name = {}
+for _name, _value in globals().items():
+ if type(_value) is type(0):
+ tok_name[_value] = _name
+
+
+def ISTERMINAL(x):
+ return x < NT_OFFSET
+
+def ISNONTERMINAL(x):
+ return x >= NT_OFFSET
+
+def ISEOF(x):
+ return x == ENDMARKER
+
+
+def main():
+ import re
+ import string
+ import sys
+ args = sys.argv[1:]
+ inFileName = args and args[0] or "Include/token.h"
+ outFileName = "Lib/token.py"
+ if len(args) > 1:
+ outFileName = args[1]
+ try:
+ fp = open(inFileName)
+ except IOError, err:
+ sys.stdout.write("I/O error: %s\n" % str(err))
+ sys.exit(1)
+ lines = fp.read().split("\n")
+ fp.close()
+ prog = re.compile(
+ "#define[ \t][ \t]*([A-Z][A-Z_]*)[ \t][ \t]*([0-9][0-9]*)",
+ re.IGNORECASE)
+ tokens = {}
+ for line in lines:
+ match = prog.match(line)
+ if match:
+ name, val = match.group(1, 2)
+ val = int(val)
+ tokens[val] = name # reverse so we can sort them...
+ keys = tokens.keys()
+ keys.sort()
+ # load the output skeleton from the target:
+ try:
+ fp = open(outFileName)
+ except IOError, err:
+ sys.stderr.write("I/O error: %s\n" % str(err))
+ sys.exit(2)
+ format = fp.read().split("\n")
+ fp.close()
+ try:
+ start = format.index("#--start constants--") + 1
+ end = format.index("#--end constants--")
+ except ValueError:
+ sys.stderr.write("target does not contain format markers")
+ sys.exit(3)
+ lines = []
+ for val in keys:
+ lines.append("%s = %d" % (tokens[val], val))
+ format[start:end] = lines
+ try:
+ fp = open(outFileName, 'w')
+ except IOError, err:
+ sys.stderr.write("I/O error: %s\n" % str(err))
+ sys.exit(4)
+ fp.write("\n".join(format))
+ fp.close()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/lib/jython/Lib/tokenize.py b/lib/jython/Lib/tokenize.py new file mode 100644 index 000000000..fd15d2887 --- /dev/null +++ b/lib/jython/Lib/tokenize.py @@ -0,0 +1,240 @@ +"""Tokenization help for Python programs.
+
+This module exports a function called 'tokenize()' that breaks a stream of
+text into Python tokens. It accepts a readline-like method which is called
+repeatedly to get the next line of input (or "" for EOF) and a "token-eater"
+function which is called once for each token found. The latter function is
+passed the token type, a string containing the token, the starting and
+ending (row, column) coordinates of the token, and the original line. It is
+designed to match the working of the Python tokenizer exactly, except that
+it produces COMMENT tokens for comments and gives type OP for all operators."""
+
+__author__ = 'Ka-Ping Yee <ping@lfw.org>'
+__credits__ = \
+ 'GvR, ESR, Tim Peters, Thomas Wouters, Fred Drake, Skip Montanaro'
+
+import string, re
+from token import *
+
+import token
+__all__ = [x for x in dir(token) if x[0] != '_'] + ["COMMENT", "tokenize", "NL"]
+del token
+
+COMMENT = N_TOKENS
+tok_name[COMMENT] = 'COMMENT'
+NL = N_TOKENS + 1
+tok_name[NL] = 'NL'
+N_TOKENS += 2
+
+def group(*choices): return '(' + '|'.join(choices) + ')'
+def any(*choices): return apply(group, choices) + '*'
+def maybe(*choices): return apply(group, choices) + '?'
+
+Whitespace = r'[ \f\t]*'
+Comment = r'#[^\r\n]*'
+Ignore = Whitespace + any(r'\\\r?\n' + Whitespace) + maybe(Comment)
+Name = r'[a-zA-Z_]\w*'
+
+Hexnumber = r'0[xX][\da-fA-F]*[lL]?'
+Octnumber = r'0[0-7]*[lL]?'
+Decnumber = r'[1-9]\d*[lL]?'
+Intnumber = group(Hexnumber, Octnumber, Decnumber)
+Exponent = r'[eE][-+]?\d+'
+Pointfloat = group(r'\d+\.\d*', r'\.\d+') + maybe(Exponent)
+Expfloat = r'[1-9]\d*' + Exponent
+Floatnumber = group(Pointfloat, Expfloat)
+Imagnumber = group(r'0[jJ]', r'[1-9]\d*[jJ]', Floatnumber + r'[jJ]')
+Number = group(Imagnumber, Floatnumber, Intnumber)
+
+# Tail end of ' string.
+Single = r"[^'\\]*(?:\\.[^'\\]*)*'"
+# Tail end of " string.
+Double = r'[^"\\]*(?:\\.[^"\\]*)*"'
+# Tail end of ''' string.
+Single3 = r"[^'\\]*(?:(?:\\.|'(?!''))[^'\\]*)*'''"
+# Tail end of """ string.
+Double3 = r'[^"\\]*(?:(?:\\.|"(?!""))[^"\\]*)*"""'
+Triple = group("[uU]?[rR]?'''", '[uU]?[rR]?"""')
+# Single-line ' or " string.
+String = group(r"[uU]?[rR]?'[^\n'\\]*(?:\\.[^\n'\\]*)*'",
+ r'[uU]?[rR]?"[^\n"\\]*(?:\\.[^\n"\\]*)*"')
+
+# Because of leftmost-then-longest match semantics, be sure to put the
+# longest operators first (e.g., if = came before ==, == would get
+# recognized as two instances of =).
+Operator = group(r"\*\*=?", r">>=?", r"<<=?", r"<>", r"!=",
+ r"[+\-*/%&|^=<>]=?",
+ r"~")
+
+Bracket = '[][(){}]'
+Special = group(r'\r?\n', r'[:;.,`]')
+Funny = group(Operator, Bracket, Special)
+
+PlainToken = group(Number, Funny, String, Name)
+Token = Ignore + PlainToken
+
+# First (or only) line of ' or " string.
+ContStr = group(r"[uU]?[rR]?'[^\n'\\]*(?:\\.[^\n'\\]*)*" +
+ group("'", r'\\\r?\n'),
+ r'[uU]?[rR]?"[^\n"\\]*(?:\\.[^\n"\\]*)*' +
+ group('"', r'\\\r?\n'))
+PseudoExtras = group(r'\\\r?\n', Comment, Triple)
+PseudoToken = Whitespace + group(PseudoExtras, Number, Funny, ContStr, Name)
+
+tokenprog, pseudoprog, single3prog, double3prog = map(
+ re.compile, (Token, PseudoToken, Single3, Double3))
+endprogs = {"'": re.compile(Single), '"': re.compile(Double),
+ "'''": single3prog, '"""': double3prog,
+ "r'''": single3prog, 'r"""': double3prog,
+ "u'''": single3prog, 'u"""': double3prog,
+ "ur'''": single3prog, 'ur"""': double3prog,
+ "R'''": single3prog, 'R"""': double3prog,
+ "U'''": single3prog, 'U"""': double3prog,
+ "uR'''": single3prog, 'uR"""': double3prog,
+ "Ur'''": single3prog, 'Ur"""': double3prog,
+ "UR'''": single3prog, 'UR"""': double3prog,
+ 'r': None, 'R': None, 'u': None, 'U': None}
+
+tabsize = 8
+
+class TokenError(Exception): pass
+
+class StopTokenizing(Exception): pass
+
+def printtoken(type, token, (srow, scol), (erow, ecol), line): # for testing
+ print "%d,%d-%d,%d:\t%s\t%s" % \
+ (srow, scol, erow, ecol, tok_name[type], repr(token))
+
+def tokenize(readline, tokeneater=printtoken):
+ try:
+ tokenize_loop(readline, tokeneater)
+ except StopTokenizing:
+ pass
+
+def tokenize_loop(readline, tokeneater):
+ lnum = parenlev = continued = 0
+ namechars, numchars = string.letters + '_', string.digits
+ contstr, needcont = '', 0
+ contline = None
+ indents = [0]
+
+ while 1: # loop over lines in stream
+ line = readline()
+ lnum = lnum + 1
+ pos, max = 0, len(line)
+
+ if contstr: # continued string
+ if not line:
+ raise TokenError, ("EOF in multi-line string", strstart)
+ endmatch = endprog.match(line)
+ if endmatch:
+ pos = end = endmatch.end(0)
+ tokeneater(STRING, contstr + line[:end],
+ strstart, (lnum, end), contline + line)
+ contstr, needcont = '', 0
+ contline = None
+ elif needcont and line[-2:] != '\\\n' and line[-3:] != '\\\r\n':
+ tokeneater(ERRORTOKEN, contstr + line,
+ strstart, (lnum, len(line)), contline)
+ contstr = ''
+ contline = None
+ continue
+ else:
+ contstr = contstr + line
+ contline = contline + line
+ continue
+
+ elif parenlev == 0 and not continued: # new statement
+ if not line: break
+ column = 0
+ while pos < max: # measure leading whitespace
+ if line[pos] == ' ': column = column + 1
+ elif line[pos] == '\t': column = (column/tabsize + 1)*tabsize
+ elif line[pos] == '\f': column = 0
+ else: break
+ pos = pos + 1
+ if pos == max: break
+
+ if line[pos] in '#\r\n': # skip comments or blank lines
+ tokeneater((NL, COMMENT)[line[pos] == '#'], line[pos:],
+ (lnum, pos), (lnum, len(line)), line)
+ continue
+
+ if column > indents[-1]: # count indents or dedents
+ indents.append(column)
+ tokeneater(INDENT, line[:pos], (lnum, 0), (lnum, pos), line)
+ while column < indents[-1]:
+ indents = indents[:-1]
+ tokeneater(DEDENT, '', (lnum, pos), (lnum, pos), line)
+
+ else: # continued statement
+ if not line:
+ raise TokenError, ("EOF in multi-line statement", (lnum, 0))
+ continued = 0
+
+ while pos < max:
+ pseudomatch = pseudoprog.match(line, pos)
+ if pseudomatch: # scan for tokens
+ start, end = pseudomatch.span(1)
+ spos, epos, pos = (lnum, start), (lnum, end), end
+ token, initial = line[start:end], line[start]
+
+ if initial in numchars or \
+ (initial == '.' and token != '.'): # ordinary number
+ tokeneater(NUMBER, token, spos, epos, line)
+ elif initial in '\r\n':
+ tokeneater(parenlev > 0 and NL or NEWLINE,
+ token, spos, epos, line)
+ elif initial == '#':
+ tokeneater(COMMENT, token, spos, epos, line)
+ elif token in ("'''", '"""', # triple-quoted
+ "r'''", 'r"""', "R'''", 'R"""',
+ "u'''", 'u"""', "U'''", 'U"""',
+ "ur'''", 'ur"""', "Ur'''", 'Ur"""',
+ "uR'''", 'uR"""', "UR'''", 'UR"""'):
+ endprog = endprogs[token]
+ endmatch = endprog.match(line, pos)
+ if endmatch: # all on one line
+ pos = endmatch.end(0)
+ token = line[start:pos]
+ tokeneater(STRING, token, spos, (lnum, pos), line)
+ else:
+ strstart = (lnum, start) # multiple lines
+ contstr = line[start:]
+ contline = line
+ break
+ elif initial in ("'", '"') or \
+ token[:2] in ("r'", 'r"', "R'", 'R"',
+ "u'", 'u"', "U'", 'U"') or \
+ token[:3] in ("ur'", 'ur"', "Ur'", 'Ur"',
+ "uR'", 'uR"', "UR'", 'UR"' ):
+ if token[-1] == '\n': # continued string
+ strstart = (lnum, start)
+ endprog = (endprogs[initial] or endprogs[token[1]] or
+ endprogs[token[2]])
+ contstr, needcont = line[start:], 1
+ contline = line
+ break
+ else: # ordinary string
+ tokeneater(STRING, token, spos, epos, line)
+ elif initial in namechars: # ordinary name
+ tokeneater(NAME, token, spos, epos, line)
+ elif initial == '\\': # continued stmt
+ continued = 1
+ else:
+ if initial in '([{': parenlev = parenlev + 1
+ elif initial in ')]}': parenlev = parenlev - 1
+ tokeneater(OP, token, spos, epos, line)
+ else:
+ tokeneater(ERRORTOKEN, line[pos],
+ (lnum, pos), (lnum, pos+1), line)
+ pos = pos + 1
+
+ for indent in indents[1:]: # pop remaining indent levels
+ tokeneater(DEDENT, '', (lnum, 0), (lnum, 0), '')
+ tokeneater(ENDMARKER, '', (lnum, 0), (lnum, 0), '')
+
+if __name__ == '__main__': # testing
+ import sys
+ if len(sys.argv) > 1: tokenize(open(sys.argv[1]).readline)
+ else: tokenize(sys.stdin.readline)
diff --git a/lib/jython/Lib/traceback.py b/lib/jython/Lib/traceback.py new file mode 100644 index 000000000..993252aae --- /dev/null +++ b/lib/jython/Lib/traceback.py @@ -0,0 +1,301 @@ +"""Extract, format and print information about Python stack traces."""
+
+import linecache
+import sys
+import types
+
+__all__ = ['extract_stack', 'extract_tb', 'format_exception',
+ 'format_exception_only', 'format_list', 'format_stack',
+ 'format_tb', 'print_exc', 'print_exception', 'print_last',
+ 'print_stack', 'print_tb', 'tb_lineno']
+
+def _print(file, str='', terminator='\n'):
+ file.write(str+terminator)
+
+
+def print_list(extracted_list, file=None):
+ """Print the list of tuples as returned by extract_tb() or
+ extract_stack() as a formatted stack trace to the given file."""
+ if not file:
+ file = sys.stderr
+ for filename, lineno, name, line in extracted_list:
+ _print(file,
+ ' File "%s", line %d, in %s' % (filename,lineno,name))
+ if line:
+ _print(file, ' %s' % line.strip())
+
+def format_list(extracted_list):
+ """Format a list of traceback entry tuples for printing.
+
+ Given a list of tuples as returned by extract_tb() or
+ extract_stack(), return a list of strings ready for printing.
+ Each string in the resulting list corresponds to the item with the
+ same index in the argument list. Each string ends in a newline;
+ the strings may contain internal newlines as well, for those items
+ whose source text line is not None.
+ """
+ list = []
+ for filename, lineno, name, line in extracted_list:
+ item = ' File "%s", line %d, in %s\n' % (filename,lineno,name)
+ if line:
+ item = item + ' %s\n' % line.strip()
+ list.append(item)
+ return list
+
+
+def print_tb(tb, limit=None, file=None):
+ """Print up to 'limit' stack trace entries from the traceback 'tb'.
+
+ If 'limit' is omitted or None, all entries are printed. If 'file'
+ is omitted or None, the output goes to sys.stderr; otherwise
+ 'file' should be an open file or file-like object with a write()
+ method.
+ """
+ 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_lineno(tb)
+ 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, ' ' + line.strip())
+ tb = tb.tb_next
+ n = n+1
+
+def format_tb(tb, limit = None):
+ """A shorthand for 'format_list(extract_stack(f, limit))."""
+ return format_list(extract_tb(tb, limit))
+
+def extract_tb(tb, limit = None):
+ """Return list of up to limit pre-processed entries from traceback.
+
+ This is useful for alternate formatting of stack traces. If
+ 'limit' is omitted or None, all entries are extracted. A
+ pre-processed stack trace entry is a quadruple (filename, line
+ number, function name, text) representing the information that is
+ usually printed for a stack trace. The text is a string with
+ leading and trailing whitespace stripped; if the source is not
+ available it is 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_lineno(tb)
+ co = f.f_code
+ filename = co.co_filename
+ name = co.co_name
+ line = linecache.getline(filename, lineno)
+ if line: line = line.strip()
+ 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):
+ """Print exception up to 'limit' stack trace entries from 'tb' to 'file'.
+
+ This differs from print_tb() in the following ways: (1) if
+ traceback is not None, it prints a header "Traceback (most recent
+ call last):"; (2) it prints the exception type and value after the
+ stack trace; (3) if type is SyntaxError and value has the
+ appropriate format, it prints the line where the syntax error
+ occurred with a caret on the next line indicating the approximate
+ position of the error.
+ """
+ if not file:
+ file = sys.stderr
+ if tb:
+ _print(file, 'Traceback (most recent call 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):
+ """Format a stack trace and the exception information.
+
+ The arguments have the same meaning as the corresponding arguments
+ to print_exception(). The return value is a list of strings, each
+ ending in a newline and some containing internal newlines. When
+ these lines are concatenated and printed, exactly the same text is
+ printed as does print_exception().
+ """
+ if tb:
+ list = ['Traceback (most recent call last):\n']
+ list = list + format_tb(tb, limit)
+ else:
+ list = []
+ list = list + format_exception_only(etype, value)
+ return list
+
+def format_exception_only(etype, value):
+ """Format the exception part of a traceback.
+
+ The arguments are the exception type and value such as given by
+ sys.last_type and sys.last_value. The return value is a list of
+ strings, each ending in a newline. Normally, the list contains a
+ single string; however, for SyntaxError exceptions, it contains
+ several lines that (when printed) display detailed information
+ about where the syntax error occurred. The message indicating
+ which exception occurred is the always last string in the list.
+ """
+ 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))
+ if line is not None:
+ i = 0
+ while i < len(line) and line[i].isspace():
+ i = i+1
+ list.append(' %s\n' % line.strip())
+ if offset is not None:
+ s = ' '
+ for c in line[i:offset-1]:
+ if c.isspace():
+ s = s + c
+ else:
+ s = s + ' '
+ list.append('%s^\n' % s)
+ value = msg
+ s = _some_str(value)
+ if s:
+ list.append('%s: %s\n' % (str(stype), s))
+ else:
+ list.append('%s\n' % str(stype))
+ return list
+
+def _some_str(value):
+ try:
+ return str(value)
+ except:
+ return '<unprintable %s object>' % type(value).__name__
+
+
+def print_exc(limit=None, file=None):
+ """Shorthand for 'print_exception(sys.exc_type, sys.exc_value, sys.exc_traceback, limit, file)'.
+ (In fact, it uses sys.exc_info() to retrieve the same information
+ in a thread-safe way.)"""
+ if not file:
+ file = sys.stderr
+ try:
+ etype, value, tb = sys.exc_info()
+ print_exception(etype, value, tb, limit, file)
+ finally:
+ etype = value = tb = None
+
+def print_last(limit=None, file=None):
+ """This is a shorthand for 'print_exception(sys.last_type,
+ sys.last_value, sys.last_traceback, limit, file)'."""
+ if not file:
+ file = sys.stderr
+ print_exception(sys.last_type, sys.last_value, sys.last_traceback,
+ limit, file)
+
+
+def print_stack(f=None, limit=None, file=None):
+ """Print a stack trace from its invocation point.
+
+ The optional 'f' argument can be used to specify an alternate
+ stack frame at which to start. The optional 'limit' and 'file'
+ arguments have the same meaning as for print_exception().
+ """
+ if f is None:
+ try:
+ raise ZeroDivisionError
+ except ZeroDivisionError:
+ f = sys.exc_info()[2].tb_frame.f_back
+ print_list(extract_stack(f, limit), file)
+
+def format_stack(f=None, limit=None):
+ """Shorthand for 'format_list(extract_stack(f, limit))'."""
+ if f is None:
+ try:
+ raise ZeroDivisionError
+ except ZeroDivisionError:
+ f = sys.exc_info()[2].tb_frame.f_back
+ return format_list(extract_stack(f, limit))
+
+def extract_stack(f=None, limit = None):
+ """Extract the raw traceback from the current stack frame.
+
+ The return value has the same format as for extract_tb(). The
+ optional 'f' and 'limit' arguments have the same meaning as for
+ print_stack(). Each item in the list is a quadruple (filename,
+ line number, function name, text), and the entries are in order
+ from oldest to newest stack frame.
+ """
+ if f is None:
+ try:
+ raise ZeroDivisionError
+ except ZeroDivisionError:
+ f = sys.exc_info()[2].tb_frame.f_back
+ if limit is None:
+ if hasattr(sys, 'tracebacklimit'):
+ limit = sys.tracebacklimit
+ list = []
+ n = 0
+ while f is not None and (limit is None or n < limit):
+ lineno = f.f_lineno # XXX Too bad if -O is used
+ co = f.f_code
+ filename = co.co_filename
+ name = co.co_name
+ line = linecache.getline(filename, lineno)
+ if line: line = line.strip()
+ else: line = None
+ list.append((filename, lineno, name, line))
+ f = f.f_back
+ n = n+1
+ list.reverse()
+ return list
+
+def tb_lineno(tb):
+ """Calculate correct line number of traceback given in tb.
+
+ Even works with -O on.
+ """
+ # Coded by Marc-Andre Lemburg from the example of PyCode_Addr2Line()
+ # in compile.c.
+ # Revised version by Jim Hugunin to work with JPython too.
+
+ c = tb.tb_frame.f_code
+ if not hasattr(c, 'co_lnotab'):
+ return tb.tb_lineno
+
+ tab = c.co_lnotab
+ line = c.co_firstlineno
+ stopat = tb.tb_lasti
+ addr = 0
+ for i in range(0, len(tab), 2):
+ addr = addr + ord(tab[i])
+ if addr > stopat:
+ break
+ line = line + ord(tab[i+1])
+ return line
diff --git a/lib/jython/Lib/tzparse.py b/lib/jython/Lib/tzparse.py new file mode 100644 index 000000000..a6d55042b --- /dev/null +++ b/lib/jython/Lib/tzparse.py @@ -0,0 +1,98 @@ +"""Parse a timezone specification."""
+
+# XXX Unfinished.
+# XXX Only the typical form "XXXhhYYY;ddd/hh,ddd/hh" is currently supported.
+
+import warnings
+warnings.warn(
+ "The tzparse module is obsolete and will disappear in the future",
+ DeprecationWarning)
+
+tzpat = ('^([A-Z][A-Z][A-Z])([-+]?[0-9]+)([A-Z][A-Z][A-Z]);'
+ '([0-9]+)/([0-9]+),([0-9]+)/([0-9]+)$')
+
+tzprog = None
+
+def tzparse(tzstr):
+ """Given a timezone spec, return a tuple of information
+ (tzname, delta, dstname, daystart, hourstart, dayend, hourend),
+ where 'tzname' is the name of the timezone, 'delta' is the offset
+ in hours from GMT, 'dstname' is the name of the daylight-saving
+ timezone, and 'daystart'/'hourstart' and 'dayend'/'hourend'
+ specify the starting and ending points for daylight saving time."""
+ global tzprog
+ if tzprog is None:
+ import re
+ tzprog = re.compile(tzpat)
+ match = tzprog.match(tzstr)
+ if not match:
+ raise ValueError, 'not the TZ syntax I understand'
+ subs = []
+ for i in range(1, 8):
+ subs.append(match.group(i))
+ for i in (1, 3, 4, 5, 6):
+ subs[i] = eval(subs[i])
+ [tzname, delta, dstname, daystart, hourstart, dayend, hourend] = subs
+ return (tzname, delta, dstname, daystart, hourstart, dayend, hourend)
+
+def tzlocaltime(secs, params):
+ """Given a Unix time in seconds and a tuple of information about
+ a timezone as returned by tzparse(), return the local time in the
+ form (year, month, day, hour, min, sec, yday, wday, tzname)."""
+ import time
+ (tzname, delta, dstname, daystart, hourstart, dayend, hourend) = params
+ year, month, days, hours, mins, secs, yday, wday, isdst = \
+ time.gmtime(secs - delta*3600)
+ if (daystart, hourstart) <= (yday+1, hours) < (dayend, hourend):
+ tzname = dstname
+ hours = hours + 1
+ return year, month, days, hours, mins, secs, yday, wday, tzname
+
+def tzset():
+ """Determine the current timezone from the "TZ" environment variable."""
+ global tzparams, timezone, altzone, daylight, tzname
+ import os
+ tzstr = os.environ['TZ']
+ tzparams = tzparse(tzstr)
+ timezone = tzparams[1] * 3600
+ altzone = timezone - 3600
+ daylight = 1
+ tzname = tzparams[0], tzparams[2]
+
+def isdst(secs):
+ """Return true if daylight-saving time is in effect for the given
+ Unix time in the current timezone."""
+ import time
+ (tzname, delta, dstname, daystart, hourstart, dayend, hourend) = \
+ tzparams
+ year, month, days, hours, mins, secs, yday, wday, isdst = \
+ time.gmtime(secs - delta*3600)
+ return (daystart, hourstart) <= (yday+1, hours) < (dayend, hourend)
+
+tzset()
+
+def localtime(secs):
+ """Get the local time in the current timezone."""
+ return tzlocaltime(secs, tzparams)
+
+def test():
+ from time import asctime, gmtime
+ import time, sys
+ now = time.time()
+ x = localtime(now)
+ tm = x[:-1] + (0,)
+ print 'now =', now, '=', asctime(tm), x[-1]
+ now = now - now % (24*3600)
+ if sys.argv[1:]: now = now + eval(sys.argv[1])
+ x = gmtime(now)
+ tm = x[:-1] + (0,)
+ print 'gmtime =', now, '=', asctime(tm), 'yday =', x[-2]
+ jan1 = now - x[-2]*24*3600
+ x = localtime(jan1)
+ tm = x[:-1] + (0,)
+ print 'jan1 =', jan1, '=', asctime(tm), x[-1]
+ for d in range(85, 95) + range(265, 275):
+ t = jan1 + d*24*3600
+ x = localtime(t)
+ tm = x[:-1] + (0,)
+ print 'd =', d, 't =', t, '=', asctime(tm), x[-1]
diff --git a/lib/jython/Lib/unittest.py b/lib/jython/Lib/unittest.py new file mode 100644 index 000000000..8588a20a4 --- /dev/null +++ b/lib/jython/Lib/unittest.py @@ -0,0 +1,711 @@ +#!/usr/bin/env python
+'''
+Python unit testing framework, based on Erich Gamma's JUnit and Kent Beck's
+Smalltalk testing framework.
+
+This module contains the core framework classes that form the basis of
+specific test cases and suites (TestCase, TestSuite etc.), and also a
+text-based utility class for running the tests and reporting the results
+(TextTestRunner).
+
+Simple usage:
+
+ import unittest
+
+ class IntegerArithmenticTestCase(unittest.TestCase):
+ def testAdd(self): ## test method names begin 'test*'
+ self.assertEquals((1 + 2), 3)
+ self.assertEquals(0 + 1, 1)
+ def testMultiply(self);
+ self.assertEquals((0 * 10), 0)
+ self.assertEquals((5 * 8), 40)
+
+ if __name__ == '__main__':
+ unittest.main()
+
+Further information is available in the bundled documentation, and from
+
+ http://pyunit.sourceforge.net/
+
+Copyright (c) 1999, 2000, 2001 Steve Purcell
+This module is free software, and you may redistribute it and/or modify
+it under the same terms as Python itself, so long as this copyright message
+and disclaimer are retained in their original form.
+
+IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
+THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS,
+AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
+SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'''
+
+__author__ = "Steve Purcell"
+__email__ = "stephen_purcell at yahoo dot com"
+__version__ = "$Revision: 1.7 $"[11:-2]
+
+import time
+import sys
+import traceback
+import string
+import os
+import types
+
+##############################################################################
+# Test framework core
+##############################################################################
+
+class TestResult:
+ """Holder for test result information.
+
+ Test results are automatically managed by the TestCase and TestSuite
+ classes, and do not need to be explicitly manipulated by writers of tests.
+
+ Each instance holds the total number of tests run, and collections of
+ failures and errors that occurred among those test runs. The collections
+ contain tuples of (testcase, exceptioninfo), where exceptioninfo is a
+ tuple of values as returned by sys.exc_info().
+ """
+ def __init__(self):
+ self.failures = []
+ self.errors = []
+ self.testsRun = 0
+ self.shouldStop = 0
+
+ def startTest(self, test):
+ "Called when the given test is about to be run"
+ self.testsRun = self.testsRun + 1
+
+ def stopTest(self, test):
+ "Called when the given test has been run"
+ pass
+
+ def addError(self, test, err):
+ "Called when an error has occurred"
+ self.errors.append((test, err))
+
+ def addFailure(self, test, err):
+ "Called when a failure has occurred"
+ self.failures.append((test, err))
+
+ def addSuccess(self, test):
+ "Called when a test has completed successfully"
+ pass
+
+ def wasSuccessful(self):
+ "Tells whether or not this result was a success"
+ return len(self.failures) == len(self.errors) == 0
+
+ def stop(self):
+ "Indicates that the tests should be aborted"
+ self.shouldStop = 1
+
+ def __repr__(self):
+ return "<%s run=%i errors=%i failures=%i>" % \
+ (self.__class__, self.testsRun, len(self.errors),
+ len(self.failures))
+
+
+class TestCase:
+ """A class whose instances are single test cases.
+
+ By default, the test code itself should be placed in a method named
+ 'runTest'.
+
+ If the fixture may be used for many test cases, create as
+ many test methods as are needed. When instantiating such a TestCase
+ subclass, specify in the constructor arguments the name of the test method
+ that the instance is to execute.
+
+ Test authors should subclass TestCase for their own tests. Construction
+ and deconstruction of the test's environment ('fixture') can be
+ implemented by overriding the 'setUp' and 'tearDown' methods respectively.
+
+ If it is necessary to override the __init__ method, the base class
+ __init__ method must always be called. It is important that subclasses
+ should not change the signature of their __init__ method, since instances
+ of the classes are instantiated automatically by parts of the framework
+ in order to be run.
+ """
+
+ # This attribute determines which exception will be raised when
+ # the instance's assertion methods fail; test methods raising this
+ # exception will be deemed to have 'failed' rather than 'errored'
+
+ failureException = AssertionError
+
+ def __init__(self, methodName='runTest'):
+ """Create an instance of the class that will use the named test
+ method when executed. Raises a ValueError if the instance does
+ not have a method with the specified name.
+ """
+ try:
+ self.__testMethodName = methodName
+ testMethod = getattr(self, methodName)
+ self.__testMethodDoc = testMethod.__doc__
+ except AttributeError:
+ raise ValueError, "no such test method in %s: %s" % \
+ (self.__class__, methodName)
+
+ def setUp(self):
+ "Hook method for setting up the test fixture before exercising it."
+ pass
+
+ def tearDown(self):
+ "Hook method for deconstructing the test fixture after testing it."
+ pass
+
+ def countTestCases(self):
+ return 1
+
+ def defaultTestResult(self):
+ return TestResult()
+
+ def shortDescription(self):
+ """Returns a one-line description of the test, or None if no
+ description has been provided.
+
+ The default implementation of this method returns the first line of
+ the specified test method's docstring.
+ """
+ doc = self.__testMethodDoc
+ return doc and string.strip(string.split(doc, "\n")[0]) or None
+
+ def id(self):
+ return "%s.%s" % (self.__class__, self.__testMethodName)
+
+ def __str__(self):
+ return "%s (%s)" % (self.__testMethodName, self.__class__)
+
+ def __repr__(self):
+ return "<%s testMethod=%s>" % \
+ (self.__class__, self.__testMethodName)
+
+ def run(self, result=None):
+ return self(result)
+
+ def __call__(self, result=None):
+ if result is None: result = self.defaultTestResult()
+ result.startTest(self)
+ testMethod = getattr(self, self.__testMethodName)
+ try:
+ try:
+ self.setUp()
+ except:
+ result.addError(self,self.__exc_info())
+ return
+
+ ok = 0
+ try:
+ testMethod()
+ ok = 1
+ except self.failureException, e:
+ result.addFailure(self,self.__exc_info())
+ except:
+ result.addError(self,self.__exc_info())
+
+ try:
+ self.tearDown()
+ except:
+ result.addError(self,self.__exc_info())
+ ok = 0
+ if ok: result.addSuccess(self)
+ finally:
+ result.stopTest(self)
+
+ def debug(self):
+ """Run the test without collecting errors in a TestResult"""
+ self.setUp()
+ getattr(self, self.__testMethodName)()
+ self.tearDown()
+
+ def __exc_info(self):
+ """Return a version of sys.exc_info() with the traceback frame
+ minimised; usually the top level of the traceback frame is not
+ needed.
+ """
+ exctype, excvalue, tb = sys.exc_info()
+ if sys.platform[:4] == 'java': ## tracebacks look different in Jython
+ return (exctype, excvalue, tb)
+ newtb = tb.tb_next
+ if newtb is None:
+ return (exctype, excvalue, tb)
+ return (exctype, excvalue, newtb)
+
+ def fail(self, msg=None):
+ """Fail immediately, with the given message."""
+ raise self.failureException, msg
+
+ def failIf(self, expr, msg=None):
+ "Fail the test if the expression is true."
+ if expr: raise self.failureException, msg
+
+ def failUnless(self, expr, msg=None):
+ """Fail the test unless the expression is true."""
+ if not expr: raise self.failureException, msg
+
+ def failUnlessRaises(self, excClass, callableObj, *args, **kwargs):
+ """Fail unless an exception of class excClass is thrown
+ by callableObj when invoked with arguments args and keyword
+ arguments kwargs. If a different type of exception is
+ thrown, it will not be caught, and the test case will be
+ deemed to have suffered an error, exactly as for an
+ unexpected exception.
+ """
+ try:
+ apply(callableObj, args, kwargs)
+ except excClass:
+ return
+ else:
+ if hasattr(excClass,'__name__'): excName = excClass.__name__
+ else: excName = str(excClass)
+ raise self.failureException, excName
+
+ def failUnlessEqual(self, first, second, msg=None):
+ """Fail if the two objects are unequal as determined by the '!='
+ operator.
+ """
+ if first != second:
+ raise self.failureException, (msg or '%s != %s' % (first, second))
+
+ def failIfEqual(self, first, second, msg=None):
+ """Fail if the two objects are equal as determined by the '=='
+ operator.
+ """
+ if first == second:
+ raise self.failureException, (msg or '%s == %s' % (first, second))
+
+ assertEqual = assertEquals = failUnlessEqual
+
+ assertNotEqual = assertNotEquals = failIfEqual
+
+ assertRaises = failUnlessRaises
+
+ assert_ = failUnless
+
+
+
+class TestSuite:
+ """A test suite is a composite test consisting of a number of TestCases.
+
+ For use, create an instance of TestSuite, then add test case instances.
+ When all tests have been added, the suite can be passed to a test
+ runner, such as TextTestRunner. It will run the individual test cases
+ in the order in which they were added, aggregating the results. When
+ subclassing, do not forget to call the base class constructor.
+ """
+ def __init__(self, tests=()):
+ self._tests = []
+ self.addTests(tests)
+
+ def __repr__(self):
+ return "<%s tests=%s>" % (self.__class__, self._tests)
+
+ __str__ = __repr__
+
+ def countTestCases(self):
+ cases = 0
+ for test in self._tests:
+ cases = cases + test.countTestCases()
+ return cases
+
+ def addTest(self, test):
+ self._tests.append(test)
+
+ def addTests(self, tests):
+ for test in tests:
+ self.addTest(test)
+
+ def run(self, result):
+ return self(result)
+
+ def __call__(self, result):
+ for test in self._tests:
+ if result.shouldStop:
+ break
+ test(result)
+ return result
+
+ def debug(self):
+ """Run the tests without collecting errors in a TestResult"""
+ for test in self._tests: test.debug()
+
+
+class FunctionTestCase(TestCase):
+ """A test case that wraps a test function.
+
+ This is useful for slipping pre-existing test functions into the
+ PyUnit framework. Optionally, set-up and tidy-up functions can be
+ supplied. As with TestCase, the tidy-up ('tearDown') function will
+ always be called if the set-up ('setUp') function ran successfully.
+ """
+
+ def __init__(self, testFunc, setUp=None, tearDown=None,
+ description=None):
+ TestCase.__init__(self)
+ self.__setUpFunc = setUp
+ self.__tearDownFunc = tearDown
+ self.__testFunc = testFunc
+ self.__description = description
+
+ def setUp(self):
+ if self.__setUpFunc is not None:
+ self.__setUpFunc()
+
+ def tearDown(self):
+ if self.__tearDownFunc is not None:
+ self.__tearDownFunc()
+
+ def runTest(self):
+ self.__testFunc()
+
+ def id(self):
+ return self.__testFunc.__name__
+
+ def __str__(self):
+ return "%s (%s)" % (self.__class__, self.__testFunc.__name__)
+
+ def __repr__(self):
+ return "<%s testFunc=%s>" % (self.__class__, self.__testFunc)
+
+ def shortDescription(self):
+ if self.__description is not None: return self.__description
+ doc = self.__testFunc.__doc__
+ return doc and string.strip(string.split(doc, "\n")[0]) or None
+
+
+
+##############################################################################
+# Locating and loading tests
+##############################################################################
+
+class TestLoader:
+ """This class is responsible for loading tests according to various
+ criteria and returning them wrapped in a Test
+ """
+ testMethodPrefix = 'test'
+ sortTestMethodsUsing = cmp
+ suiteClass = TestSuite
+
+ def loadTestsFromTestCase(self, testCaseClass):
+ """Return a suite of all tests cases contained in testCaseClass"""
+ return self.suiteClass(map(testCaseClass,
+ self.getTestCaseNames(testCaseClass)))
+
+ def loadTestsFromModule(self, module):
+ """Return a suite of all tests cases contained in the given module"""
+ tests = []
+ for name in dir(module):
+ obj = getattr(module, name)
+ if type(obj) == types.ClassType and issubclass(obj, TestCase):
+ tests.append(self.loadTestsFromTestCase(obj))
+ return self.suiteClass(tests)
+
+ def loadTestsFromName(self, name, module=None):
+ """Return a suite of all tests cases given a string specifier.
+
+ The name may resolve either to a module, a test case class, a
+ test method within a test case class, or a callable object which
+ returns a TestCase or TestSuite instance.
+
+ The method optionally resolves the names relative to a given module.
+ """
+ parts = string.split(name, '.')
+ if module is None:
+ if not parts:
+ raise ValueError, "incomplete test name: %s" % name
+ else:
+ parts_copy = parts[:]
+ while parts_copy:
+ try:
+ module = __import__(string.join(parts_copy,'.'))
+ break
+ except ImportError:
+ del parts_copy[-1]
+ if not parts_copy: raise
+ parts = parts[1:]
+ obj = module
+ for part in parts:
+ obj = getattr(obj, part)
+
+ if type(obj) == types.ModuleType:
+ return self.loadTestsFromModule(obj)
+ elif type(obj) == types.ClassType and issubclass(obj, TestCase):
+ return self.loadTestsFromTestCase(obj)
+ elif type(obj) == types.UnboundMethodType:
+ return obj.im_class(obj.__name__)
+ elif callable(obj):
+ test = obj()
+ if not isinstance(test, TestCase) and \
+ not isinstance(test, TestSuite):
+ raise ValueError, \
+ "calling %s returned %s, not a test" % obj,test
+ return test
+ else:
+ raise ValueError, "don't know how to make test from: %s" % obj
+
+ def loadTestsFromNames(self, names, module=None):
+ """Return a suite of all tests cases found using the given sequence
+ of string specifiers. See 'loadTestsFromName()'.
+ """
+ suites = []
+ for name in names:
+ suites.append(self.loadTestsFromName(name, module))
+ return self.suiteClass(suites)
+
+ def getTestCaseNames(self, testCaseClass):
+ """Return a sorted sequence of method names found within testCaseClass
+ """
+ testFnNames = filter(lambda n,p=self.testMethodPrefix: n[:len(p)] == p,
+ dir(testCaseClass))
+ for baseclass in testCaseClass.__bases__:
+ for testFnName in self.getTestCaseNames(baseclass):
+ if testFnName not in testFnNames: # handle overridden methods
+ testFnNames.append(testFnName)
+ if self.sortTestMethodsUsing:
+ testFnNames.sort(self.sortTestMethodsUsing)
+ return testFnNames
+
+
+
+defaultTestLoader = TestLoader()
+
+
+##############################################################################
+# Patches for old functions: these functions should be considered obsolete
+##############################################################################
+
+def _makeLoader(prefix, sortUsing, suiteClass=None):
+ loader = TestLoader()
+ loader.sortTestMethodsUsing = sortUsing
+ loader.testMethodPrefix = prefix
+ if suiteClass: loader.suiteClass = suiteClass
+ return loader
+
+def getTestCaseNames(testCaseClass, prefix, sortUsing=cmp):
+ return _makeLoader(prefix, sortUsing).getTestCaseNames(testCaseClass)
+
+def makeSuite(testCaseClass, prefix='test', sortUsing=cmp, suiteClass=TestSuite):
+ return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase(testCaseClass)
+
+def findTestCases(module, prefix='test', sortUsing=cmp, suiteClass=TestSuite):
+ return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(module)
+
+
+##############################################################################
+# Text UI
+##############################################################################
+
+class _WritelnDecorator:
+ """Used to decorate file-like objects with a handy 'writeln' method"""
+ def __init__(self,stream):
+ self.stream = stream
+
+ def __getattr__(self, attr):
+ return getattr(self.stream,attr)
+
+ def writeln(self, *args):
+ if args: apply(self.write, args)
+ self.write('\n') # text-mode streams translate to \r\n if needed
+
+
+class _TextTestResult(TestResult):
+ """A test result class that can print formatted text results to a stream.
+
+ Used by TextTestRunner.
+ """
+ separator1 = '=' * 70
+ separator2 = '-' * 70
+
+ def __init__(self, stream, descriptions, verbosity):
+ TestResult.__init__(self)
+ self.stream = stream
+ self.showAll = verbosity > 1
+ self.dots = verbosity == 1
+ self.descriptions = descriptions
+
+ def getDescription(self, test):
+ if self.descriptions:
+ return test.shortDescription() or str(test)
+ else:
+ return str(test)
+
+ def startTest(self, test):
+ TestResult.startTest(self, test)
+ if self.showAll:
+ self.stream.write(self.getDescription(test))
+ self.stream.write(" ... ")
+
+ def addSuccess(self, test):
+ TestResult.addSuccess(self, test)
+ if self.showAll:
+ self.stream.writeln("ok")
+ elif self.dots:
+ self.stream.write('.')
+
+ def addError(self, test, err):
+ TestResult.addError(self, test, err)
+ if self.showAll:
+ self.stream.writeln("ERROR")
+ elif self.dots:
+ self.stream.write('E')
+ if err[0] is KeyboardInterrupt:
+ self.shouldStop = 1
+
+ def addFailure(self, test, err):
+ TestResult.addFailure(self, test, err)
+ if self.showAll:
+ self.stream.writeln("FAIL")
+ elif self.dots:
+ self.stream.write('F')
+
+ def printErrors(self):
+ if self.dots or self.showAll:
+ self.stream.writeln()
+ self.printErrorList('ERROR', self.errors)
+ self.printErrorList('FAIL', self.failures)
+
+ def printErrorList(self, flavour, errors):
+ for test, err in errors:
+ self.stream.writeln(self.separator1)
+ self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
+ self.stream.writeln(self.separator2)
+ for line in apply(traceback.format_exception, err):
+ for l in string.split(line,"\n")[:-1]:
+ self.stream.writeln("%s" % l)
+
+
+class TextTestRunner:
+ """A test runner class that displays results in textual form.
+
+ It prints out the names of tests as they are run, errors as they
+ occur, and a summary of the results at the end of the test run.
+ """
+ def __init__(self, stream=sys.stderr, descriptions=1, verbosity=1):
+ self.stream = _WritelnDecorator(stream)
+ self.descriptions = descriptions
+ self.verbosity = verbosity
+
+ def _makeResult(self):
+ return _TextTestResult(self.stream, self.descriptions, self.verbosity)
+
+ def run(self, test):
+ "Run the given test case or test suite."
+ result = self._makeResult()
+ startTime = time.time()
+ test(result)
+ stopTime = time.time()
+ timeTaken = float(stopTime - startTime)
+ result.printErrors()
+ self.stream.writeln(result.separator2)
+ run = result.testsRun
+ self.stream.writeln("Ran %d test%s in %.3fs" %
+ (run, run == 1 and "" or "s", timeTaken))
+ self.stream.writeln()
+ if not result.wasSuccessful():
+ self.stream.write("FAILED (")
+ failed, errored = map(len, (result.failures, result.errors))
+ if failed:
+ self.stream.write("failures=%d" % failed)
+ if errored:
+ if failed: self.stream.write(", ")
+ self.stream.write("errors=%d" % errored)
+ self.stream.writeln(")")
+ else:
+ self.stream.writeln("OK")
+ return result
+
+
+
+##############################################################################
+# Facilities for running tests from the command line
+##############################################################################
+
+class TestProgram:
+ """A command-line program that runs a set of tests; this is primarily
+ for making test modules conveniently executable.
+ """
+ USAGE = """\
+Usage: %(progName)s [options] [test] [...]
+
+Options:
+ -h, --help Show this message
+ -v, --verbose Verbose output
+ -q, --quiet Minimal output
+
+Examples:
+ %(progName)s - run default set of tests
+ %(progName)s MyTestSuite - run suite 'MyTestSuite'
+ %(progName)s MyTestCase.testSomething - run MyTestCase.testSomething
+ %(progName)s MyTestCase - run all 'test*' test methods
+ in MyTestCase
+"""
+ def __init__(self, module='__main__', defaultTest=None,
+ argv=None, testRunner=None, testLoader=defaultTestLoader):
+ if type(module) == type(''):
+ self.module = __import__(module)
+ for part in string.split(module,'.')[1:]:
+ self.module = getattr(self.module, part)
+ else:
+ self.module = module
+ if argv is None:
+ argv = sys.argv
+ self.verbosity = 1
+ self.defaultTest = defaultTest
+ self.testRunner = testRunner
+ self.testLoader = testLoader
+ self.progName = os.path.basename(argv[0])
+ self.parseArgs(argv)
+ self.runTests()
+
+ def usageExit(self, msg=None):
+ if msg: print msg
+ print self.USAGE % self.__dict__
+ sys.exit(2)
+
+ def parseArgs(self, argv):
+ import getopt
+ try:
+ options, args = getopt.getopt(argv[1:], 'hHvq',
+ ['help','verbose','quiet'])
+ for opt, value in options:
+ if opt in ('-h','-H','--help'):
+ self.usageExit()
+ if opt in ('-q','--quiet'):
+ self.verbosity = 0
+ if opt in ('-v','--verbose'):
+ self.verbosity = 2
+ if len(args) == 0 and self.defaultTest is None:
+ self.test = self.testLoader.loadTestsFromModule(self.module)
+ return
+ if len(args) > 0:
+ self.testNames = args
+ else:
+ self.testNames = (self.defaultTest,)
+ self.createTests()
+ except getopt.error, msg:
+ self.usageExit(msg)
+
+ def createTests(self):
+ self.test = self.testLoader.loadTestsFromNames(self.testNames,
+ self.module)
+
+ def runTests(self):
+ if self.testRunner is None:
+ self.testRunner = TextTestRunner(verbosity=self.verbosity)
+ result = self.testRunner.run(self.test)
+ sys.exit(not result.wasSuccessful())
+
+main = TestProgram
+
+
+##############################################################################
+# Executing this module from the command line
+##############################################################################
+
+if __name__ == "__main__":
+ main(module=None)
diff --git a/lib/jython/Lib/urllib.py b/lib/jython/Lib/urllib.py new file mode 100644 index 000000000..4120d342f --- /dev/null +++ b/lib/jython/Lib/urllib.py @@ -0,0 +1,1383 @@ +"""Open an arbitrary URL.
+
+See the following document for more info on URLs:
+"Names and Addresses, URIs, URLs, URNs, URCs", at
+http://www.w3.org/pub/WWW/Addressing/Overview.html
+
+See also the HTTP spec (from which the error codes are derived):
+"HTTP - Hypertext Transfer Protocol", at
+http://www.w3.org/pub/WWW/Protocols/
+
+Related standards and specs:
+- RFC1808: the "relative URL" spec. (authoritative status)
+- RFC1738 - the "URL standard". (authoritative status)
+- RFC1630 - the "URI spec". (informational status)
+
+The object returned by URLopener().open(file) will differ per
+protocol. All you know is that is has methods read(), readline(),
+readlines(), fileno(), close() and info(). The read*(), fileno()
+and close() methods work like those of open files.
+The info() method returns a mimetools.Message object which can be
+used to query various info about the object, if available.
+(mimetools.Message objects are queried with the getheader() method.)
+"""
+
+import string
+import socket
+import os
+import sys
+import types
+
+__all__ = ["urlopen", "URLopener", "FancyURLopener", "urlretrieve",
+ "urlcleanup", "quote", "quote_plus", "unquote", "unquote_plus",
+ "urlencode", "url2pathname", "pathname2url", "splittag",
+ "localhost", "thishost", "ftperrors", "basejoin", "unwrap",
+ "splittype", "splithost", "splituser", "splitpasswd", "splitport",
+ "splitnport", "splitquery", "splitattr", "splitvalue",
+ "splitgophertype", "getproxies"]
+
+__version__ = '1.15' # XXX This version is not always updated :-(
+
+MAXFTPCACHE = 10 # Trim the ftp cache beyond this size
+
+# Helper for non-unix systems
+if os.name == 'mac':
+ from macurl2path import url2pathname, pathname2url
+elif os.name == 'nt':
+ from nturl2path import url2pathname, pathname2url
+elif os.name == 'riscos':
+ from rourl2path import url2pathname, pathname2url
+else:
+ def url2pathname(pathname):
+ return unquote(pathname)
+ def pathname2url(pathname):
+ return quote(pathname)
+
+# This really consists of two pieces:
+# (1) a class which handles opening of all sorts of URLs
+# (plus assorted utilities etc.)
+# (2) a set of functions for parsing URLs
+# XXX Should these be separated out into different modules?
+
+
+# Shortcut for basic usage
+_urlopener = None
+def urlopen(url, data=None):
+ """urlopen(url [, data]) -> open file-like object"""
+ global _urlopener
+ if not _urlopener:
+ _urlopener = FancyURLopener()
+ if data is None:
+ return _urlopener.open(url)
+ else:
+ return _urlopener.open(url, data)
+def urlretrieve(url, filename=None, reporthook=None, data=None):
+ global _urlopener
+ if not _urlopener:
+ _urlopener = FancyURLopener()
+ return _urlopener.retrieve(url, filename, reporthook, data)
+def urlcleanup():
+ if _urlopener:
+ _urlopener.cleanup()
+
+
+ftpcache = {}
+class URLopener:
+ """Class to open URLs.
+ This is a class rather than just a subroutine because we may need
+ more than one set of global protocol-specific options.
+ Note -- this is a base class for those who don't want the
+ automatic handling of errors type 302 (relocated) and 401
+ (authorization needed)."""
+
+ __tempfiles = None
+
+ version = "Python-urllib/%s" % __version__
+
+ # Constructor
+ def __init__(self, proxies=None, **x509):
+ if proxies is None:
+ proxies = getproxies()
+ assert hasattr(proxies, 'has_key'), "proxies must be a mapping"
+ self.proxies = proxies
+ self.key_file = x509.get('key_file')
+ self.cert_file = x509.get('cert_file')
+ self.addheaders = [('User-agent', self.version)]
+ self.__tempfiles = []
+ self.__unlink = os.unlink # See cleanup()
+ self.tempcache = None
+ # Undocumented feature: if you assign {} to tempcache,
+ # it is used to cache files retrieved with
+ # self.retrieve(). This is not enabled by default
+ # since it does not work for changing documents (and I
+ # haven't got the logic to check expiration headers
+ # yet).
+ self.ftpcache = ftpcache
+ # Undocumented feature: you can use a different
+ # ftp cache by assigning to the .ftpcache member;
+ # in case you want logically independent URL openers
+ # XXX This is not threadsafe. Bah.
+
+ def __del__(self):
+ self.close()
+
+ def close(self):
+ self.cleanup()
+
+ def cleanup(self):
+ # This code sometimes runs when the rest of this module
+ # has already been deleted, so it can't use any globals
+ # or import anything.
+ if self.__tempfiles:
+ for file in self.__tempfiles:
+ try:
+ self.__unlink(file)
+ except:
+ pass
+ del self.__tempfiles[:]
+ if self.tempcache:
+ self.tempcache.clear()
+
+ def addheader(self, *args):
+ """Add a header to be used by the HTTP interface only
+ e.g. u.addheader('Accept', 'sound/basic')"""
+ self.addheaders.append(args)
+
+ # External interface
+ def open(self, fullurl, data=None):
+ """Use URLopener().open(file) instead of open(file, 'r')."""
+ fullurl = unwrap(toBytes(fullurl))
+ if self.tempcache and self.tempcache.has_key(fullurl):
+ filename, headers = self.tempcache[fullurl]
+ fp = open(filename, 'rb')
+ return addinfourl(fp, headers, fullurl)
+ urltype, url = splittype(fullurl)
+ if not urltype:
+ urltype = 'file'
+ if self.proxies.has_key(urltype):
+ proxy = self.proxies[urltype]
+ urltype, proxyhost = splittype(proxy)
+ host, selector = splithost(proxyhost)
+ url = (host, fullurl) # Signal special case to open_*()
+ else:
+ proxy = None
+ name = 'open_' + urltype
+ self.type = urltype
+ if '-' in name:
+ # replace - with _
+ name = '_'.join(name.split('-'))
+ if not hasattr(self, name):
+ if proxy:
+ return self.open_unknown_proxy(proxy, fullurl, data)
+ else:
+ return self.open_unknown(fullurl, data)
+ try:
+ if data is None:
+ return getattr(self, name)(url)
+ else:
+ return getattr(self, name)(url, data)
+ except socket.error, msg:
+ raise IOError, ('socket error', msg), sys.exc_info()[2]
+
+ def open_unknown(self, fullurl, data=None):
+ """Overridable interface to open unknown URL type."""
+ type, url = splittype(fullurl)
+ raise IOError, ('url error', 'unknown url type', type)
+
+ def open_unknown_proxy(self, proxy, fullurl, data=None):
+ """Overridable interface to open unknown URL type."""
+ type, url = splittype(fullurl)
+ raise IOError, ('url error', 'invalid proxy for %s' % type, proxy)
+
+ # External interface
+ def retrieve(self, url, filename=None, reporthook=None, data=None):
+ """retrieve(url) returns (filename, None) for a local object
+ or (tempfilename, headers) for a remote object."""
+ url = unwrap(toBytes(url))
+ if self.tempcache and self.tempcache.has_key(url):
+ return self.tempcache[url]
+ type, url1 = splittype(url)
+ if not filename and (not type or type == 'file'):
+ try:
+ fp = self.open_local_file(url1)
+ hdrs = fp.info()
+ del fp
+ return url2pathname(splithost(url1)[1]), hdrs
+ except IOError, msg:
+ pass
+ fp = self.open(url, data)
+ headers = fp.info()
+ if not filename:
+ import tempfile
+ garbage, path = splittype(url)
+ garbage, path = splithost(path or "")
+ path, garbage = splitquery(path or "")
+ path, garbage = splitattr(path or "")
+ suffix = os.path.splitext(path)[1]
+ filename = tempfile.mktemp(suffix)
+ self.__tempfiles.append(filename)
+ result = filename, headers
+ if self.tempcache is not None:
+ self.tempcache[url] = result
+ tfp = open(filename, 'wb')
+ bs = 1024*8
+ size = -1
+ blocknum = 1
+ if reporthook:
+ if headers.has_key("content-length"):
+ size = int(headers["Content-Length"])
+ reporthook(0, bs, size)
+ block = fp.read(bs)
+ if reporthook:
+ reporthook(1, bs, size)
+ while block:
+ tfp.write(block)
+ block = fp.read(bs)
+ blocknum = blocknum + 1
+ if reporthook:
+ reporthook(blocknum, bs, size)
+ fp.close()
+ tfp.close()
+ del fp
+ del tfp
+ return result
+
+ # Each method named open_<type> knows how to open that type of URL
+
+ def open_http(self, url, data=None):
+ """Use HTTP protocol."""
+ import httplib
+ user_passwd = None
+ if type(url) is types.StringType:
+ host, selector = splithost(url)
+ if host:
+ user_passwd, host = splituser(host)
+ host = unquote(host)
+ realhost = host
+ else:
+ host, selector = url
+ urltype, rest = splittype(selector)
+ url = rest
+ user_passwd = None
+ if urltype.lower() != 'http':
+ realhost = None
+ else:
+ realhost, rest = splithost(rest)
+ if realhost:
+ user_passwd, realhost = splituser(realhost)
+ if user_passwd:
+ selector = "%s://%s%s" % (urltype, realhost, rest)
+ #print "proxy via http:", host, selector
+ if not host: raise IOError, ('http error', 'no host given')
+ if user_passwd:
+ import base64
+ auth = base64.encodestring(user_passwd).strip()
+ else:
+ auth = None
+ h = httplib.HTTP(host)
+ if data is not None:
+ h.putrequest('POST', selector)
+ h.putheader('Content-type', 'application/x-www-form-urlencoded')
+ h.putheader('Content-length', '%d' % len(data))
+ else:
+ h.putrequest('GET', selector)
+ if auth: h.putheader('Authorization', 'Basic %s' % auth)
+ if realhost: h.putheader('Host', realhost)
+ for args in self.addheaders: apply(h.putheader, args)
+ h.endheaders()
+ if data is not None:
+ h.send(data)
+ errcode, errmsg, headers = h.getreply()
+ fp = h.getfile()
+ if errcode == 200:
+ return addinfourl(fp, headers, "http:" + url)
+ else:
+ if data is None:
+ return self.http_error(url, fp, errcode, errmsg, headers)
+ else:
+ return self.http_error(url, fp, errcode, errmsg, headers, data)
+
+ def http_error(self, url, fp, errcode, errmsg, headers, data=None):
+ """Handle http errors.
+ Derived class can override this, or provide specific handlers
+ named http_error_DDD where DDD is the 3-digit error code."""
+ # First check if there's a specific handler for this error
+ name = 'http_error_%d' % errcode
+ if hasattr(self, name):
+ method = getattr(self, name)
+ if data is None:
+ result = method(url, fp, errcode, errmsg, headers)
+ else:
+ result = method(url, fp, errcode, errmsg, headers, data)
+ if result: return result
+ return self.http_error_default(url, fp, errcode, errmsg, headers)
+
+ def http_error_default(self, url, fp, errcode, errmsg, headers):
+ """Default error handler: close the connection and raise IOError."""
+ void = fp.read()
+ fp.close()
+ raise IOError, ('http error', errcode, errmsg, headers)
+
+ if hasattr(socket, "ssl"):
+ def open_https(self, url, data=None):
+ """Use HTTPS protocol."""
+ import httplib
+ user_passwd = None
+ if type(url) is types.StringType:
+ host, selector = splithost(url)
+ if host:
+ user_passwd, host = splituser(host)
+ host = unquote(host)
+ realhost = host
+ else:
+ host, selector = url
+ urltype, rest = splittype(selector)
+ url = rest
+ user_passwd = None
+ if urltype.lower() != 'https':
+ realhost = None
+ else:
+ realhost, rest = splithost(rest)
+ if realhost:
+ user_passwd, realhost = splituser(realhost)
+ if user_passwd:
+ selector = "%s://%s%s" % (urltype, realhost, rest)
+ #print "proxy via https:", host, selector
+ if not host: raise IOError, ('https error', 'no host given')
+ if user_passwd:
+ import base64
+ auth = base64.encodestring(user_passwd).strip()
+ else:
+ auth = None
+ h = httplib.HTTPS(host, 0,
+ key_file=self.key_file,
+ cert_file=self.cert_file)
+ if data is not None:
+ h.putrequest('POST', selector)
+ h.putheader('Content-type',
+ 'application/x-www-form-urlencoded')
+ h.putheader('Content-length', '%d' % len(data))
+ else:
+ h.putrequest('GET', selector)
+ if auth: h.putheader('Authorization: Basic %s' % auth)
+ if realhost: h.putheader('Host', realhost)
+ for args in self.addheaders: apply(h.putheader, args)
+ h.endheaders()
+ if data is not None:
+ h.send(data)
+ errcode, errmsg, headers = h.getreply()
+ fp = h.getfile()
+ if errcode == 200:
+ return addinfourl(fp, headers, url)
+ else:
+ if data is None:
+ return self.http_error(url, fp, errcode, errmsg, headers)
+ else:
+ return self.http_error(url, fp, errcode, errmsg, headers,
+ data)
+
+ def open_gopher(self, url):
+ """Use Gopher protocol."""
+ import gopherlib
+ host, selector = splithost(url)
+ if not host: raise IOError, ('gopher error', 'no host given')
+ host = unquote(host)
+ type, selector = splitgophertype(selector)
+ selector, query = splitquery(selector)
+ selector = unquote(selector)
+ if query:
+ query = unquote(query)
+ fp = gopherlib.send_query(selector, query, host)
+ else:
+ fp = gopherlib.send_selector(selector, host)
+ return addinfourl(fp, noheaders(), "gopher:" + url)
+
+ def open_file(self, url):
+ """Use local file or FTP depending on form of URL."""
+ if url[:2] == '//' and url[2:3] != '/':
+ return self.open_ftp(url)
+ else:
+ return self.open_local_file(url)
+
+ def open_local_file(self, url):
+ """Use local file."""
+ import mimetypes, mimetools, StringIO
+ mtype = mimetypes.guess_type(url)[0]
+ headers = mimetools.Message(StringIO.StringIO(
+ 'Content-Type: %s\n' % (mtype or 'text/plain')))
+ host, file = splithost(url)
+ if not host:
+ urlfile = file
+ if file[:1] == '/':
+ urlfile = 'file://' + file
+ return addinfourl(open(url2pathname(file), 'rb'),
+ headers, urlfile)
+ host, port = splitport(host)
+ if not port \
+ and socket.gethostbyname(host) in (localhost(), thishost()):
+ urlfile = file
+ if file[:1] == '/':
+ urlfile = 'file://' + file
+ return addinfourl(open(url2pathname(file), 'rb'),
+ headers, urlfile)
+ raise IOError, ('local file error', 'not on local host')
+
+ def open_ftp(self, url):
+ """Use FTP protocol."""
+ host, path = splithost(url)
+ if not host: raise IOError, ('ftp error', 'no host given')
+ host, port = splitport(host)
+ user, host = splituser(host)
+ if user: user, passwd = splitpasswd(user)
+ else: passwd = None
+ host = unquote(host)
+ user = unquote(user or '')
+ passwd = unquote(passwd or '')
+ host = socket.gethostbyname(host)
+ if not port:
+ import ftplib
+ port = ftplib.FTP_PORT
+ else:
+ port = int(port)
+ path, attrs = splitattr(path)
+ path = unquote(path)
+ dirs = path.split('/')
+ dirs, file = dirs[:-1], dirs[-1]
+ if dirs and not dirs[0]: dirs = dirs[1:]
+ if dirs and not dirs[0]: dirs[0] = '/'
+ key = user, host, port, '/'.join(dirs)
+ # XXX thread unsafe!
+ if len(self.ftpcache) > MAXFTPCACHE:
+ # Prune the cache, rather arbitrarily
+ for k in self.ftpcache.keys():
+ if k != key:
+ v = self.ftpcache[k]
+ del self.ftpcache[k]
+ v.close()
+ try:
+ if not self.ftpcache.has_key(key):
+ self.ftpcache[key] = \
+ ftpwrapper(user, passwd, host, port, dirs)
+ if not file: type = 'D'
+ else: type = 'I'
+ for attr in attrs:
+ attr, value = splitvalue(attr)
+ if attr.lower() == 'type' and \
+ value in ('a', 'A', 'i', 'I', 'd', 'D'):
+ type = value.upper()
+ (fp, retrlen) = self.ftpcache[key].retrfile(file, type)
+ if retrlen is not None and retrlen >= 0:
+ import mimetools, StringIO
+ headers = mimetools.Message(StringIO.StringIO(
+ 'Content-Length: %d\n' % retrlen))
+ else:
+ headers = noheaders()
+ return addinfourl(fp, headers, "ftp:" + url)
+ except ftperrors(), msg:
+ raise IOError, ('ftp error', msg), sys.exc_info()[2]
+
+ def open_data(self, url, data=None):
+ """Use "data" URL."""
+ # ignore POSTed data
+ #
+ # syntax of data URLs:
+ # dataurl := "data:" [ mediatype ] [ ";base64" ] "," data
+ # mediatype := [ type "/" subtype ] *( ";" parameter )
+ # data := *urlchar
+ # parameter := attribute "=" value
+ import StringIO, mimetools, time
+ try:
+ [type, data] = url.split(',', 1)
+ except ValueError:
+ raise IOError, ('data error', 'bad data URL')
+ if not type:
+ type = 'text/plain;charset=US-ASCII'
+ semi = type.rfind(';')
+ if semi >= 0 and '=' not in type[semi:]:
+ encoding = type[semi+1:]
+ type = type[:semi]
+ else:
+ encoding = ''
+ msg = []
+ msg.append('Date: %s'%time.strftime('%a, %d %b %Y %T GMT',
+ time.gmtime(time.time())))
+ msg.append('Content-type: %s' % type)
+ if encoding == 'base64':
+ import base64
+ data = base64.decodestring(data)
+ else:
+ data = unquote(data)
+ msg.append('Content-length: %d' % len(data))
+ msg.append('')
+ msg.append(data)
+ msg = '\n'.join(msg)
+ f = StringIO.StringIO(msg)
+ headers = mimetools.Message(f, 0)
+ f.fileno = None # needed for addinfourl
+ return addinfourl(f, headers, url)
+
+
+class FancyURLopener(URLopener):
+ """Derived class with handlers for errors we can handle (perhaps)."""
+
+ def __init__(self, *args):
+ apply(URLopener.__init__, (self,) + args)
+ self.auth_cache = {}
+ self.tries = 0
+ self.maxtries = 10
+
+ def http_error_default(self, url, fp, errcode, errmsg, headers):
+ """Default error handling -- don't raise an exception."""
+ return addinfourl(fp, headers, "http:" + url)
+
+ def http_error_302(self, url, fp, errcode, errmsg, headers, data=None):
+ """Error 302 -- relocated (temporarily)."""
+ self.tries += 1
+ if self.maxtries and self.tries >= self.maxtries:
+ if hasattr(self, "http_error_500"):
+ meth = self.http_error_500
+ else:
+ meth = self.http_error_default
+ self.tries = 0
+ return meth(url, fp, 500,
+ "Internal Server Error: Redirect Recursion", headers)
+ result = self.redirect_internal(url, fp, errcode, errmsg, headers,
+ data)
+ self.tries = 0
+ return result
+
+ def redirect_internal(self, url, fp, errcode, errmsg, headers, data):
+ if headers.has_key('location'):
+ newurl = headers['location']
+ elif headers.has_key('uri'):
+ newurl = headers['uri']
+ else:
+ return
+ void = fp.read()
+ fp.close()
+ # In case the server sent a relative URL, join with original:
+ newurl = basejoin(self.type + ":" + url, newurl)
+ if data is None:
+ return self.open(newurl)
+ else:
+ return self.open(newurl, data)
+
+ def http_error_301(self, url, fp, errcode, errmsg, headers, data=None):
+ """Error 301 -- also relocated (permanently)."""
+ return self.http_error_302(url, fp, errcode, errmsg, headers, data)
+
+ def http_error_401(self, url, fp, errcode, errmsg, headers, data=None):
+ """Error 401 -- authentication required.
+ See this URL for a description of the basic authentication scheme:
+ http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-v10-spec-00.txt"""
+ if not headers.has_key('www-authenticate'):
+ URLopener.http_error_default(self, url, fp,
+ errmsg, headers)
+ stuff = headers['www-authenticate']
+ import re
+ match = re.match('[ \t]*([^ \t]+)[ \t]+realm="([^"]*)"', stuff)
+ if not match:
+ URLopener.http_error_default(self, url, fp,
+ errcode, errmsg, headers)
+ scheme, realm = match.groups()
+ if scheme.lower() != 'basic':
+ URLopener.http_error_default(self, url, fp,
+ errcode, errmsg, headers)
+ name = 'retry_' + self.type + '_basic_auth'
+ if data is None:
+ return getattr(self,name)(url, realm)
+ else:
+ return getattr(self,name)(url, realm, data)
+
+ def retry_http_basic_auth(self, url, realm, data=None):
+ host, selector = splithost(url)
+ i = host.find('@') + 1
+ host = host[i:]
+ user, passwd = self.get_user_passwd(host, realm, i)
+ if not (user or passwd): return None
+ host = quote(user, safe='') + ':' + quote(passwd, safe='') + '@' + host
+ newurl = 'http://' + host + selector
+ if data is None:
+ return self.open(newurl)
+ else:
+ return self.open(newurl, data)
+
+ def retry_https_basic_auth(self, url, realm, data=None):
+ host, selector = splithost(url)
+ i = host.find('@') + 1
+ host = host[i:]
+ user, passwd = self.get_user_passwd(host, realm, i)
+ if not (user or passwd): return None
+ host = quote(user, safe='') + ':' + quote(passwd, safe='') + '@' + host
+ newurl = '//' + host + selector
+ return self.open_https(newurl, data)
+
+ def get_user_passwd(self, host, realm, clear_cache = 0):
+ key = realm + '@' + host.lower()
+ if self.auth_cache.has_key(key):
+ if clear_cache:
+ del self.auth_cache[key]
+ else:
+ return self.auth_cache[key]
+ user, passwd = self.prompt_user_passwd(host, realm)
+ if user or passwd: self.auth_cache[key] = (user, passwd)
+ return user, passwd
+
+ def prompt_user_passwd(self, host, realm):
+ """Override this in a GUI environment!"""
+ import getpass
+ try:
+ user = raw_input("Enter username for %s at %s: " % (realm,
+ host))
+ passwd = getpass.getpass("Enter password for %s in %s at %s: " %
+ (user, realm, host))
+ return user, passwd
+ except KeyboardInterrupt:
+ print
+ return None, None
+
+
+# Utility functions
+
+_localhost = None
+def localhost():
+ """Return the IP address of the magic hostname 'localhost'."""
+ global _localhost
+ if not _localhost:
+ _localhost = socket.gethostbyname('localhost')
+ return _localhost
+
+_thishost = None
+def thishost():
+ """Return the IP address of the current host."""
+ global _thishost
+ if not _thishost:
+ _thishost = socket.gethostbyname(socket.gethostname())
+ return _thishost
+
+_ftperrors = None
+def ftperrors():
+ """Return the set of errors raised by the FTP class."""
+ global _ftperrors
+ if not _ftperrors:
+ import ftplib
+ _ftperrors = ftplib.all_errors
+ return _ftperrors
+
+_noheaders = None
+def noheaders():
+ """Return an empty mimetools.Message object."""
+ global _noheaders
+ if not _noheaders:
+ import mimetools
+ import StringIO
+ _noheaders = mimetools.Message(StringIO.StringIO(), 0)
+ _noheaders.fp.close() # Recycle file descriptor
+ return _noheaders
+
+
+# Utility classes
+
+class ftpwrapper:
+ """Class used by open_ftp() for cache of open FTP connections."""
+
+ def __init__(self, user, passwd, host, port, dirs):
+ self.user = user
+ self.passwd = passwd
+ self.host = host
+ self.port = port
+ self.dirs = dirs
+ self.init()
+
+ def init(self):
+ import ftplib
+ self.busy = 0
+ self.ftp = ftplib.FTP()
+ self.ftp.connect(self.host, self.port)
+ self.ftp.login(self.user, self.passwd)
+ for dir in self.dirs:
+ self.ftp.cwd(dir)
+
+ def retrfile(self, file, type):
+ import ftplib
+ self.endtransfer()
+ if type in ('d', 'D'): cmd = 'TYPE A'; isdir = 1
+ else: cmd = 'TYPE ' + type; isdir = 0
+ try:
+ self.ftp.voidcmd(cmd)
+ except ftplib.all_errors:
+ self.init()
+ self.ftp.voidcmd(cmd)
+ conn = None
+ if file and not isdir:
+ # Use nlst to see if the file exists at all
+ try:
+ self.ftp.nlst(file)
+ except ftplib.error_perm, reason:
+ raise IOError, ('ftp error', reason), sys.exc_info()[2]
+ # Restore the transfer mode!
+ self.ftp.voidcmd(cmd)
+ # Try to retrieve as a file
+ try:
+ cmd = 'RETR ' + file
+ conn = self.ftp.ntransfercmd(cmd)
+ except ftplib.error_perm, reason:
+ if str(reason)[:3] != '550':
+ raise IOError, ('ftp error', reason), sys.exc_info()[2]
+ if not conn:
+ # Set transfer mode to ASCII!
+ self.ftp.voidcmd('TYPE A')
+ # Try a directory listing
+ if file: cmd = 'LIST ' + file
+ else: cmd = 'LIST'
+ conn = self.ftp.ntransfercmd(cmd)
+ self.busy = 1
+ # Pass back both a suitably decorated object and a retrieval length
+ return (addclosehook(conn[0].makefile('rb'),
+ self.endtransfer), conn[1])
+ def endtransfer(self):
+ if not self.busy:
+ return
+ self.busy = 0
+ try:
+ self.ftp.voidresp()
+ except ftperrors():
+ pass
+
+ def close(self):
+ self.endtransfer()
+ try:
+ self.ftp.close()
+ except ftperrors():
+ pass
+
+class addbase:
+ """Base class for addinfo and addclosehook."""
+
+ def __init__(self, fp):
+ self.fp = fp
+ self.read = self.fp.read
+ self.readline = self.fp.readline
+ if hasattr(self.fp, "readlines"): self.readlines = self.fp.readlines
+ if hasattr(self.fp, "fileno"): self.fileno = self.fp.fileno
+
+ def __repr__(self):
+ return '<%s at %s whose fp = %s>' % (self.__class__.__name__,
+ `id(self)`, `self.fp`)
+
+ def close(self):
+ self.read = None
+ self.readline = None
+ self.readlines = None
+ self.fileno = None
+ if self.fp: self.fp.close()
+ self.fp = None
+
+class addclosehook(addbase):
+ """Class to add a close hook to an open file."""
+
+ def __init__(self, fp, closehook, *hookargs):
+ addbase.__init__(self, fp)
+ self.closehook = closehook
+ self.hookargs = hookargs
+
+ def close(self):
+ addbase.close(self)
+ if self.closehook:
+ apply(self.closehook, self.hookargs)
+ self.closehook = None
+ self.hookargs = None
+
+class addinfo(addbase):
+ """class to add an info() method to an open file."""
+
+ def __init__(self, fp, headers):
+ addbase.__init__(self, fp)
+ self.headers = headers
+
+ def info(self):
+ return self.headers
+
+class addinfourl(addbase):
+ """class to add info() and geturl() methods to an open file."""
+
+ def __init__(self, fp, headers, url):
+ addbase.__init__(self, fp)
+ self.headers = headers
+ self.url = url
+
+ def info(self):
+ return self.headers
+
+ def geturl(self):
+ return self.url
+
+
+def basejoin(base, url):
+ """Utility to combine a URL with a base URL to form a new URL."""
+ type, path = splittype(url)
+ if type:
+ # if url is complete (i.e., it contains a type), return it
+ return url
+ host, path = splithost(path)
+ type, basepath = splittype(base) # inherit type from base
+ if host:
+ # if url contains host, just inherit type
+ if type: return type + '://' + host + path
+ else:
+ # no type inherited, so url must have started with //
+ # just return it
+ return url
+ host, basepath = splithost(basepath) # inherit host
+ basepath, basetag = splittag(basepath) # remove extraneous cruft
+ basepath, basequery = splitquery(basepath) # idem
+ if path[:1] != '/':
+ # non-absolute path name
+ if path[:1] in ('#', '?'):
+ # path is just a tag or query, attach to basepath
+ i = len(basepath)
+ else:
+ # else replace last component
+ i = basepath.rfind('/')
+ if i < 0:
+ # basepath not absolute
+ if host:
+ # host present, make absolute
+ basepath = '/'
+ else:
+ # else keep non-absolute
+ basepath = ''
+ else:
+ # remove last file component
+ basepath = basepath[:i+1]
+ # Interpret ../ (important because of symlinks)
+ while basepath and path[:3] == '../':
+ path = path[3:]
+ i = basepath[:-1].rfind('/')
+ if i > 0:
+ basepath = basepath[:i+1]
+ elif i == 0:
+ basepath = '/'
+ break
+ else:
+ basepath = ''
+
+ path = basepath + path
+ if host and path and path[0] != '/':
+ path = '/' + path
+ if type and host: return type + '://' + host + path
+ elif type: return type + ':' + path
+ elif host: return '//' + host + path # don't know what this means
+ else: return path
+
+
+# Utilities to parse URLs (most of these return None for missing parts):
+# unwrap('<URL:type://host/path>') --> 'type://host/path'
+# splittype('type:opaquestring') --> 'type', 'opaquestring'
+# splithost('//host[:port]/path') --> 'host[:port]', '/path'
+# splituser('user[:passwd]@host[:port]') --> 'user[:passwd]', 'host[:port]'
+# splitpasswd('user:passwd') -> 'user', 'passwd'
+# splitport('host:port') --> 'host', 'port'
+# splitquery('/path?query') --> '/path', 'query'
+# splittag('/path#tag') --> '/path', 'tag'
+# splitattr('/path;attr1=value1;attr2=value2;...') ->
+# '/path', ['attr1=value1', 'attr2=value2', ...]
+# splitvalue('attr=value') --> 'attr', 'value'
+# splitgophertype('/Xselector') --> 'X', 'selector'
+# unquote('abc%20def') -> 'abc def'
+# quote('abc def') -> 'abc%20def')
+
+def toBytes(url):
+ """toBytes(u"URL") --> 'URL'."""
+ # Most URL schemes require ASCII. If that changes, the conversion
+ # can be relaxed
+ if type(url) is types.UnicodeType:
+ try:
+ url = url.encode("ASCII")
+ except UnicodeError:
+ raise UnicodeError("URL " + repr(url) +
+ " contains non-ASCII characters")
+ return url
+
+def unwrap(url):
+ """unwrap('<URL:type://host/path>') --> 'type://host/path'."""
+ url = url.strip()
+ if url[:1] == '<' and url[-1:] == '>':
+ url = url[1:-1].strip()
+ if url[:4] == 'URL:': url = url[4:].strip()
+ return url
+
+_typeprog = None
+def splittype(url):
+ """splittype('type:opaquestring') --> 'type', 'opaquestring'."""
+ global _typeprog
+ if _typeprog is None:
+ import re
+ _typeprog = re.compile('^([^/:]+):')
+
+ match = _typeprog.match(url)
+ if match:
+ scheme = match.group(1)
+ return scheme.lower(), url[len(scheme) + 1:]
+ return None, url
+
+_hostprog = None
+def splithost(url):
+ """splithost('//host[:port]/path') --> 'host[:port]', '/path'."""
+ global _hostprog
+ if _hostprog is None:
+ import re
+ _hostprog = re.compile('^//([^/]*)(.*)$')
+
+ match = _hostprog.match(url)
+ if match: return match.group(1, 2)
+ return None, url
+
+_userprog = None
+def splituser(host):
+ """splituser('user[:passwd]@host[:port]') --> 'user[:passwd]', 'host[:port]'."""
+ global _userprog
+ if _userprog is None:
+ import re
+ _userprog = re.compile('^([^@]*)@(.*)$')
+
+ match = _userprog.match(host)
+ if match: return map(unquote, match.group(1, 2))
+ return None, host
+
+_passwdprog = None
+def splitpasswd(user):
+ """splitpasswd('user:passwd') -> 'user', 'passwd'."""
+ global _passwdprog
+ if _passwdprog is None:
+ import re
+ _passwdprog = re.compile('^([^:]*):(.*)$')
+
+ match = _passwdprog.match(user)
+ if match: return match.group(1, 2)
+ return user, None
+
+# splittag('/path#tag') --> '/path', 'tag'
+_portprog = None
+def splitport(host):
+ """splitport('host:port') --> 'host', 'port'."""
+ global _portprog
+ if _portprog is None:
+ import re
+ _portprog = re.compile('^(.*):([0-9]+)$')
+
+ match = _portprog.match(host)
+ if match: return match.group(1, 2)
+ return host, None
+
+_nportprog = None
+def splitnport(host, defport=-1):
+ """Split host and port, returning numeric port.
+ Return given default port if no ':' found; defaults to -1.
+ Return numerical port if a valid number are found after ':'.
+ Return None if ':' but not a valid number."""
+ global _nportprog
+ if _nportprog is None:
+ import re
+ _nportprog = re.compile('^(.*):(.*)$')
+
+ match = _nportprog.match(host)
+ if match:
+ host, port = match.group(1, 2)
+ try:
+ if not port: raise ValueError, "no digits"
+ nport = int(port)
+ except ValueError:
+ nport = None
+ return host, nport
+ return host, defport
+
+_queryprog = None
+def splitquery(url):
+ """splitquery('/path?query') --> '/path', 'query'."""
+ global _queryprog
+ if _queryprog is None:
+ import re
+ _queryprog = re.compile('^(.*)\?([^?]*)$')
+
+ match = _queryprog.match(url)
+ if match: return match.group(1, 2)
+ return url, None
+
+_tagprog = None
+def splittag(url):
+ """splittag('/path#tag') --> '/path', 'tag'."""
+ global _tagprog
+ if _tagprog is None:
+ import re
+ _tagprog = re.compile('^(.*)#([^#]*)$')
+
+ match = _tagprog.match(url)
+ if match: return match.group(1, 2)
+ return url, None
+
+def splitattr(url):
+ """splitattr('/path;attr1=value1;attr2=value2;...') ->
+ '/path', ['attr1=value1', 'attr2=value2', ...]."""
+ words = url.split(';')
+ return words[0], words[1:]
+
+_valueprog = None
+def splitvalue(attr):
+ """splitvalue('attr=value') --> 'attr', 'value'."""
+ global _valueprog
+ if _valueprog is None:
+ import re
+ _valueprog = re.compile('^([^=]*)=(.*)$')
+
+ match = _valueprog.match(attr)
+ if match: return match.group(1, 2)
+ return attr, None
+
+def splitgophertype(selector):
+ """splitgophertype('/Xselector') --> 'X', 'selector'."""
+ if selector[:1] == '/' and selector[1:2]:
+ return selector[1], selector[2:]
+ return None, selector
+
+def unquote(s):
+ """unquote('abc%20def') -> 'abc def'."""
+ mychr = chr
+ myatoi = int
+ list = s.split('%')
+ res = [list[0]]
+ myappend = res.append
+ del list[0]
+ for item in list:
+ if item[1:2]:
+ try:
+ myappend(mychr(myatoi(item[:2], 16))
+ + item[2:])
+ except:
+ myappend('%' + item)
+ else:
+ myappend('%' + item)
+ return "".join(res)
+
+def unquote_plus(s):
+ """unquote('%7e/abc+def') -> '~/abc def'"""
+ if '+' in s:
+ # replace '+' with ' '
+ s = ' '.join(s.split('+'))
+ return unquote(s)
+
+always_safe = ('ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ 'abcdefghijklmnopqrstuvwxyz'
+ '0123456789' '_.-')
+
+_fast_safe_test = always_safe + '/'
+_fast_safe = None
+
+def _fast_quote(s):
+ global _fast_safe
+ if _fast_safe is None:
+ _fast_safe = {}
+ for c in _fast_safe_test:
+ _fast_safe[c] = c
+ res = list(s)
+ for i in range(len(res)):
+ c = res[i]
+ if not _fast_safe.has_key(c):
+ res[i] = '%%%02X' % ord(c)
+ return ''.join(res)
+
+def quote(s, safe = '/'):
+ """quote('abc def') -> 'abc%20def'
+
+ Each part of a URL, e.g. the path info, the query, etc., has a
+ different set of reserved characters that must be quoted.
+
+ RFC 2396 Uniform Resource Identifiers (URI): Generic Syntax lists
+ the following reserved characters.
+
+ reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
+ "$" | ","
+
+ Each of these characters is reserved in some component of a URL,
+ but not necessarily in all of them.
+
+ By default, the quote function is intended for quoting the path
+ section of a URL. Thus, it will not encode '/'. This character
+ is reserved, but in typical usage the quote function is being
+ called on a path where the existing slash characters are used as
+ reserved characters.
+ """
+ safe = always_safe + safe
+ if _fast_safe_test == safe:
+ return _fast_quote(s)
+ res = list(s)
+ for i in range(len(res)):
+ c = res[i]
+ if c not in safe:
+ res[i] = '%%%02X' % ord(c)
+ return ''.join(res)
+
+def quote_plus(s, safe = ''):
+ """Quote the query fragment of a URL; replacing ' ' with '+'"""
+ if ' ' in s:
+ l = s.split(' ')
+ for i in range(len(l)):
+ l[i] = quote(l[i], safe)
+ return '+'.join(l)
+ else:
+ return quote(s, safe)
+
+def urlencode(query,doseq=0):
+ """Encode a sequence of two-element tuples or dictionary into a URL query string.
+
+ If any values in the query arg are sequences and doseq is true, each
+ sequence element is converted to a separate parameter.
+
+ If the query arg is a sequence of two-element tuples, the order of the
+ parameters in the output will match the order of parameters in the
+ input.
+ """
+
+ if hasattr(query,"items"):
+ # mapping objects
+ query = query.items()
+ else:
+ # it's a bother at times that strings and string-like objects are
+ # sequences...
+ try:
+ # non-sequence items should not work with len()
+ x = len(query)
+ # non-empty strings will fail this
+ if len(query) and type(query[0]) != types.TupleType:
+ raise TypeError
+ # zero-length sequences of all types will get here and succeed,
+ # but that's a minor nit - since the original implementation
+ # allowed empty dicts that type of behavior probably should be
+ # preserved for consistency
+ except TypeError:
+ ty,va,tb = sys.exc_info()
+ raise TypeError, "not a valid non-string sequence or mapping object", tb
+
+ l = []
+ if not doseq:
+ # preserve old behavior
+ for k, v in query:
+ k = quote_plus(str(k))
+ v = quote_plus(str(v))
+ l.append(k + '=' + v)
+ else:
+ for k, v in query:
+ k = quote_plus(str(k))
+ if type(v) == types.StringType:
+ v = quote_plus(v)
+ l.append(k + '=' + v)
+ elif type(v) == types.UnicodeType:
+ # is there a reasonable way to convert to ASCII?
+ # encode generates a string, but "replace" or "ignore"
+ # lose information and "strict" can raise UnicodeError
+ v = quote_plus(v.encode("ASCII","replace"))
+ l.append(k + '=' + v)
+ else:
+ try:
+ # is this a sufficient test for sequence-ness?
+ x = len(v)
+ except TypeError:
+ # not a sequence
+ v = quote_plus(str(v))
+ l.append(k + '=' + v)
+ else:
+ # loop over the sequence
+ for elt in v:
+ l.append(k + '=' + quote_plus(str(elt)))
+ return '&'.join(l)
+
+# Proxy handling
+def getproxies_environment():
+ """Return a dictionary of scheme -> proxy server URL mappings.
+
+ Scan the environment for variables named <scheme>_proxy;
+ this seems to be the standard convention. If you need a
+ different way, you can pass a proxies dictionary to the
+ [Fancy]URLopener constructor.
+
+ """
+ proxies = {}
+ for name, value in os.environ.items():
+ name = name.lower()
+ if value and name[-6:] == '_proxy':
+ proxies[name[:-6]] = value
+ return proxies
+
+if os.name == 'mac':
+ def getproxies():
+ """Return a dictionary of scheme -> proxy server URL mappings.
+
+ By convention the mac uses Internet Config to store
+ proxies. An HTTP proxy, for instance, is stored under
+ the HttpProxy key.
+
+ """
+ try:
+ import ic
+ except ImportError:
+ return {}
+
+ try:
+ config = ic.IC()
+ except ic.error:
+ return {}
+ proxies = {}
+ # HTTP:
+ if config.has_key('UseHTTPProxy') and config['UseHTTPProxy']:
+ try:
+ value = config['HTTPProxyHost']
+ except ic.error:
+ pass
+ else:
+ proxies['http'] = 'http://%s' % value
+ # FTP: XXXX To be done.
+ # Gopher: XXXX To be done.
+ return proxies
+
+elif os.name == 'nt':
+ def getproxies_registry():
+ """Return a dictionary of scheme -> proxy server URL mappings.
+
+ Win32 uses the registry to store proxies.
+
+ """
+ proxies = {}
+ try:
+ import _winreg
+ except ImportError:
+ # Std module, so should be around - but you never know!
+ return proxies
+ try:
+ internetSettings = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER,
+ r'Software\Microsoft\Windows\CurrentVersion\Internet Settings')
+ proxyEnable = _winreg.QueryValueEx(internetSettings,
+ 'ProxyEnable')[0]
+ if proxyEnable:
+ # Returned as Unicode but problems if not converted to ASCII
+ proxyServer = str(_winreg.QueryValueEx(internetSettings,
+ 'ProxyServer')[0])
+ if '=' in proxyServer:
+ # Per-protocol settings
+ for p in proxyServer.split(';'):
+ protocol, address = p.split('=', 1)
+ proxies[protocol] = '%s://%s' % (protocol, address)
+ else:
+ # Use one setting for all protocols
+ if proxyServer[:5] == 'http:':
+ proxies['http'] = proxyServer
+ else:
+ proxies['http'] = 'http://%s' % proxyServer
+ proxies['ftp'] = 'ftp://%s' % proxyServer
+ internetSettings.Close()
+ except (WindowsError, ValueError, TypeError):
+ # Either registry key not found etc, or the value in an
+ # unexpected format.
+ # proxies already set up to be empty so nothing to do
+ pass
+ return proxies
+
+ def getproxies():
+ """Return a dictionary of scheme -> proxy server URL mappings.
+
+ Returns settings gathered from the environment, if specified,
+ or the registry.
+
+ """
+ return getproxies_environment() or getproxies_registry()
+else:
+ # By default use environment variables
+ getproxies = getproxies_environment
+
+
+# Test and time quote() and unquote()
+def test1():
+ import time
+ s = ''
+ for i in range(256): s = s + chr(i)
+ s = s*4
+ t0 = time.time()
+ qs = quote(s)
+ uqs = unquote(qs)
+ t1 = time.time()
+ if uqs != s:
+ print 'Wrong!'
+ print `s`
+ print `qs`
+ print `uqs`
+ print round(t1 - t0, 3), 'sec'
+
+
+def reporthook(blocknum, blocksize, totalsize):
+ # Report during remote transfers
+ print "Block number: %d, Block size: %d, Total size: %d" % (
+ blocknum, blocksize, totalsize)
+
+# Test program
+def test(args=[]):
+ if not args:
+ args = [
+ '/etc/passwd',
+ 'file:/etc/passwd',
+ 'file://localhost/etc/passwd',
+ 'ftp://ftp.python.org/etc/passwd',
+## 'gopher://gopher.micro.umn.edu/1/',
+ 'http://www.python.org/index.html',
+ ]
+ if hasattr(URLopener, "open_https"):
+ args.append('https://synergy.as.cmu.edu/~geek/')
+ try:
+ for url in args:
+ print '-'*10, url, '-'*10
+ fn, h = urlretrieve(url, None, reporthook)
+ print fn
+ if h:
+ print '======'
+ for k in h.keys(): print k + ':', h[k]
+ print '======'
+ fp = open(fn, 'rb')
+ data = fp.read()
+ del fp
+ if '\r' in data:
+ table = string.maketrans("", "")
+ data = data.translate(table, "\r")
+ print data
+ fn, h = None, None
+ print '-'*40
+ finally:
+ urlcleanup()
+
+def main():
+ import getopt, sys
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "th")
+ except getopt.error, msg:
+ print msg
+ print "Use -h for help"
+ return
+ t = 0
+ for o, a in opts:
+ if o == '-t':
+ t = t + 1
+ if o == '-h':
+ print "Usage: python urllib.py [-t] [url ...]"
+ print "-t runs self-test;",
+ print "otherwise, contents of urls are printed"
+ return
+ if t:
+ if t > 1:
+ test1()
+ test(args)
+ else:
+ if not args:
+ print "Use -h for help"
+ for url in args:
+ print urlopen(url).read(),
+
+# Run test program when run as a script
+if __name__ == '__main__':
+ main()
diff --git a/lib/jython/Lib/urlparse.py b/lib/jython/Lib/urlparse.py new file mode 100644 index 000000000..84fff6930 --- /dev/null +++ b/lib/jython/Lib/urlparse.py @@ -0,0 +1,261 @@ +"""Parse (absolute and relative) URLs.
+
+See RFC 1808: "Relative Uniform Resource Locators", by R. Fielding,
+UC Irvine, June 1995.
+"""
+
+__all__ = ["urlparse", "urlunparse", "urljoin"]
+
+# A classification of schemes ('' means apply by default)
+uses_relative = ['ftp', 'http', 'gopher', 'nntp', 'wais', 'file',
+ 'https', 'shttp',
+ 'prospero', 'rtsp', 'rtspu', '']
+uses_netloc = ['ftp', 'http', 'gopher', 'nntp', 'telnet', 'wais',
+ 'file',
+ 'https', 'shttp', 'snews',
+ 'prospero', 'rtsp', 'rtspu', '']
+non_hierarchical = ['gopher', 'hdl', 'mailto', 'news', 'telnet', 'wais',
+ 'snews', 'sip',
+ ]
+uses_params = ['ftp', 'hdl', 'prospero', 'http',
+ 'https', 'shttp', 'rtsp', 'rtspu', 'sip',
+ '']
+uses_query = ['http', 'wais',
+ 'https', 'shttp',
+ 'gopher', 'rtsp', 'rtspu', 'sip',
+ '']
+uses_fragment = ['ftp', 'hdl', 'http', 'gopher', 'news', 'nntp', 'wais',
+ 'https', 'shttp', 'snews',
+ 'file', 'prospero', '']
+
+# Characters valid in scheme names
+scheme_chars = ('abcdefghijklmnopqrstuvwxyz'
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ '0123456789'
+ '+-.')
+
+MAX_CACHE_SIZE = 20
+_parse_cache = {}
+
+def clear_cache():
+ """Clear the parse cache."""
+ global _parse_cache
+ _parse_cache = {}
+
+
+def urlparse(url, scheme = '', allow_fragments = 1):
+ """Parse a URL into 6 components:
+ <scheme>://<netloc>/<path>;<params>?<query>#<fragment>
+ Return a 6-tuple: (scheme, netloc, path, params, query, fragment).
+ Note that we don't break the components up in smaller bits
+ (e.g. netloc is a single string) and we don't expand % escapes."""
+ key = url, scheme, allow_fragments
+ cached = _parse_cache.get(key, None)
+ if cached:
+ return cached
+ if len(_parse_cache) >= MAX_CACHE_SIZE: # avoid runaway growth
+ clear_cache()
+ netloc = path = params = query = fragment = ''
+ i = url.find(':')
+ if i > 0:
+ if url[:i] == 'http': # optimize the common case
+ scheme = url[:i].lower()
+ url = url[i+1:]
+ if url[:2] == '//':
+ i = url.find('/', 2)
+ if i < 0:
+ i = len(url)
+ netloc = url[2:i]
+ url = url[i:]
+ if allow_fragments:
+ i = url.rfind('#')
+ if i >= 0:
+ fragment = url[i+1:]
+ url = url[:i]
+ i = url.find('?')
+ if i >= 0:
+ query = url[i+1:]
+ url = url[:i]
+ i = url.find(';')
+ if i >= 0:
+ params = url[i+1:]
+ url = url[:i]
+ tuple = scheme, netloc, url, params, query, fragment
+ _parse_cache[key] = tuple
+ return tuple
+ for c in url[:i]:
+ if c not in scheme_chars:
+ break
+ else:
+ scheme, url = url[:i].lower(), url[i+1:]
+ if scheme in uses_netloc:
+ if url[:2] == '//':
+ i = url.find('/', 2)
+ if i < 0:
+ i = len(url)
+ netloc, url = url[2:i], url[i:]
+ if allow_fragments and scheme in uses_fragment:
+ i = url.rfind('#')
+ if i >= 0:
+ url, fragment = url[:i], url[i+1:]
+ if scheme in uses_query:
+ i = url.find('?')
+ if i >= 0:
+ url, query = url[:i], url[i+1:]
+ if scheme in uses_params:
+ i = url.find(';')
+ if i >= 0:
+ url, params = url[:i], url[i+1:]
+ tuple = scheme, netloc, url, params, query, fragment
+ _parse_cache[key] = tuple
+ return tuple
+
+def urlunparse((scheme, netloc, url, params, query, fragment)):
+ """Put a parsed URL back together again. This may result in a
+ slightly different, but equivalent URL, if the URL that was parsed
+ originally had redundant delimiters, e.g. a ? with an empty query
+ (the draft states that these are equivalent)."""
+ if netloc or (scheme in uses_netloc and url[:2] == '//'):
+ if url and url[:1] != '/': url = '/' + url
+ url = '//' + (netloc or '') + url
+ if scheme:
+ url = scheme + ':' + url
+ if params:
+ url = url + ';' + params
+ if query:
+ url = url + '?' + query
+ if fragment:
+ url = url + '#' + fragment
+ return url
+
+def urljoin(base, url, allow_fragments = 1):
+ """Join a base URL and a possibly relative URL to form an absolute
+ interpretation of the latter."""
+ if not base:
+ return url
+ if not url:
+ return base
+ bscheme, bnetloc, bpath, bparams, bquery, bfragment = \
+ urlparse(base, '', allow_fragments)
+ scheme, netloc, path, params, query, fragment = \
+ urlparse(url, bscheme, allow_fragments)
+ if scheme != bscheme or scheme not in uses_relative:
+ return url
+ if scheme in uses_netloc:
+ if netloc:
+ return urlunparse((scheme, netloc, path,
+ params, query, fragment))
+ netloc = bnetloc
+ if path[:1] == '/':
+ return urlunparse((scheme, netloc, path,
+ params, query, fragment))
+ if not path:
+ if not params:
+ params = bparams
+ if not query:
+ query = bquery
+ return urlunparse((scheme, netloc, bpath,
+ params, query, fragment))
+ segments = bpath.split('/')[:-1] + path.split('/')
+ # XXX The stuff below is bogus in various ways...
+ if segments[-1] == '.':
+ segments[-1] = ''
+ while '.' in segments:
+ segments.remove('.')
+ while 1:
+ i = 1
+ n = len(segments) - 1
+ while i < n:
+ if (segments[i] == '..'
+ and segments[i-1] not in ('', '..')):
+ del segments[i-1:i+1]
+ break
+ i = i+1
+ else:
+ break
+ if segments == ['', '..']:
+ segments[-1] = ''
+ elif len(segments) >= 2 and segments[-1] == '..':
+ segments[-2:] = ['']
+ return urlunparse((scheme, netloc, '/'.join(segments),
+ params, query, fragment))
+
+def urldefrag(url):
+ """Removes any existing fragment from URL.
+
+ Returns a tuple of the defragmented URL and the fragment. If
+ the URL contained no fragments, the second element is the
+ empty string.
+ """
+ s, n, p, a, q, frag = urlparse(url)
+ defrag = urlunparse((s, n, p, a, q, ''))
+ return defrag, frag
+
+
+test_input = """
+ http://a/b/c/d
+
+ g:h = <URL:g:h>
+ http:g = <URL:http://a/b/c/g>
+ http: = <URL:http://a/b/c/d>
+ g = <URL:http://a/b/c/g>
+ ./g = <URL:http://a/b/c/g>
+ g/ = <URL:http://a/b/c/g/>
+ /g = <URL:http://a/g>
+ //g = <URL:http://g>
+ ?y = <URL:http://a/b/c/d?y>
+ g?y = <URL:http://a/b/c/g?y>
+ g?y/./x = <URL:http://a/b/c/g?y/./x>
+ . = <URL:http://a/b/c/>
+ ./ = <URL:http://a/b/c/>
+ .. = <URL:http://a/b/>
+ ../ = <URL:http://a/b/>
+ ../g = <URL:http://a/b/g>
+ ../.. = <URL:http://a/>
+ ../../g = <URL:http://a/g>
+ ../../../g = <URL:http://a/../g>
+ ./../g = <URL:http://a/b/g>
+ ./g/. = <URL:http://a/b/c/g/>
+ /./g = <URL:http://a/./g>
+ g/./h = <URL:http://a/b/c/g/h>
+ g/../h = <URL:http://a/b/c/h>
+ http:g = <URL:http://a/b/c/g>
+ http: = <URL:http://a/b/c/d>
+ http:?y = <URL:http://a/b/c/d?y>
+ http:g?y = <URL:http://a/b/c/g?y>
+ http:g?y/./x = <URL:http://a/b/c/g?y/./x>
+"""
+# XXX The result for //g is actually http://g/; is this a problem?
+
+def test():
+ import sys
+ base = ''
+ if sys.argv[1:]:
+ fn = sys.argv[1]
+ if fn == '-':
+ fp = sys.stdin
+ else:
+ fp = open(fn)
+ else:
+ import StringIO
+ fp = StringIO.StringIO(test_input)
+ while 1:
+ line = fp.readline()
+ if not line: break
+ words = line.split()
+ if not words:
+ continue
+ url = words[0]
+ parts = urlparse(url)
+ print '%-10s : %s' % (url, parts)
+ abs = urljoin(base, url)
+ if not base:
+ base = abs
+ wrapped = '<URL:%s>' % abs
+ print '%-10s = %s' % (url, wrapped)
+ if len(words) == 3 and words[1] == '=':
+ if wrapped != words[2]:
+ print 'EXPECTED', words[2], '!!!!!!!!!!'
+
+if __name__ == '__main__':
+ test()
diff --git a/lib/jython/Lib/user.py b/lib/jython/Lib/user.py new file mode 100644 index 000000000..cfae42458 --- /dev/null +++ b/lib/jython/Lib/user.py @@ -0,0 +1,43 @@ +"""Hook to allow user-specified customization code to run.
+
+As a policy, Python doesn't run user-specified code on startup of
+Python programs (interactive sessions execute the script specified in
+the PYTHONSTARTUP environment variable if it exists).
+
+However, some programs or sites may find it convenient to allow users
+to have a standard customization file, which gets run when a program
+requests it. This module implements such a mechanism. A program
+that wishes to use the mechanism must execute the statement
+
+ import user
+
+The user module looks for a file .pythonrc.py in the user's home
+directory and if it can be opened, execfile()s it in its own global
+namespace. Errors during this phase are not caught; that's up to the
+program that imports the user module, if it wishes.
+
+The user's .pythonrc.py could conceivably test for sys.version if it
+wishes to do different things depending on the Python version.
+
+"""
+
+import os
+
+home = os.curdir # Default
+if os.environ.has_key('HOME'):
+ home = os.environ['HOME']
+elif os.name == 'nt': # Contributed by Jeff Bauer
+ if os.environ.has_key('HOMEPATH'):
+ if os.environ.has_key('HOMEDRIVE'):
+ home = os.environ['HOMEDRIVE'] + os.environ['HOMEPATH']
+ else:
+ home = os.environ['HOMEPATH']
+
+pythonrc = os.path.join(home, ".pythonrc.py")
+try:
+ f = open(pythonrc)
+except IOError:
+ pass
+else:
+ f.close()
+ execfile(pythonrc)
diff --git a/lib/jython/Lib/warnings.py b/lib/jython/Lib/warnings.py new file mode 100644 index 000000000..2a0e79873 --- /dev/null +++ b/lib/jython/Lib/warnings.py @@ -0,0 +1,251 @@ +"""Python part of the warnings subsystem."""
+
+import sys, re, types
+
+__all__ = ["warn", "showwarning", "formatwarning", "filterwarnings",
+ "resetwarnings"]
+
+defaultaction = "default"
+filters = []
+onceregistry = {}
+
+def warn(message, category=None, stacklevel=1):
+ """Issue a warning, or maybe ignore it or raise an exception."""
+ # Check category argument
+ if category is None:
+ category = UserWarning
+ assert issubclass(category, Warning)
+ # Get context information
+ try:
+ caller = sys._getframe(stacklevel)
+ except ValueError:
+ globals = sys.__dict__
+ lineno = 1
+ else:
+ globals = caller.f_globals
+ lineno = caller.f_lineno
+ module = globals['__name__']
+ filename = globals.get('__file__')
+ if filename:
+ fnl = filename.lower()
+ if fnl.endswith(".pyc") or fnl.endswith(".pyo"):
+ filename = filename[:-1]
+ else:
+ if module == "__main__":
+ filename = sys.argv[0]
+ if not filename:
+ filename = module
+ registry = globals.setdefault("__warningregistry__", {})
+ warn_explicit(message, category, filename, lineno, module, registry)
+
+def warn_explicit(message, category, filename, lineno,
+ module=None, registry=None):
+ if module is None:
+ module = filename
+ if module[-3:].lower() == ".py":
+ module = module[:-3] # XXX What about leading pathname?
+ if registry is None:
+ registry = {}
+ key = (message, category, lineno)
+ # Quick test for common case
+ if registry.get(key):
+ return
+ # Search the filters
+ for item in filters:
+ action, msg, cat, mod, ln = item
+ if (msg.match(message) and
+ issubclass(category, cat) and
+ mod.match(module) and
+ (ln == 0 or lineno == ln)):
+ break
+ else:
+ action = defaultaction
+ # Early exit actions
+ if action == "ignore":
+ registry[key] = 1
+ return
+ if action == "error":
+ raise category(message)
+ # Other actions
+ if action == "once":
+ registry[key] = 1
+ oncekey = (message, category)
+ if onceregistry.get(oncekey):
+ return
+ onceregistry[oncekey] = 1
+ elif action == "always":
+ pass
+ elif action == "module":
+ registry[key] = 1
+ altkey = (message, category, 0)
+ if registry.get(altkey):
+ return
+ registry[altkey] = 1
+ elif action == "default":
+ registry[key] = 1
+ else:
+ # Unrecognized actions are errors
+ raise RuntimeError(
+ "Unrecognized action (%s) in warnings.filters:\n %s" %
+ (`action`, str(item)))
+ # Print message and context
+ showwarning(message, category, filename, lineno)
+
+def showwarning(message, category, filename, lineno, file=None):
+ """Hook to write a warning to a file; replace if you like."""
+ if file is None:
+ file = sys.stderr
+ file.write(formatwarning(message, category, filename, lineno))
+
+def formatwarning(message, category, filename, lineno):
+ """Function to format a warning the standard way."""
+ import linecache
+ s = "%s:%s: %s: %s\n" % (filename, lineno, category.__name__, message)
+ line = linecache.getline(filename, lineno).strip()
+ if line:
+ s = s + " " + line + "\n"
+ return s
+
+def filterwarnings(action, message="", category=Warning, module="", lineno=0,
+ append=0):
+ """Insert an entry into the list of warnings filters (at the front).
+
+ Use assertions to check that all arguments have the right type."""
+ assert action in ("error", "ignore", "always", "default", "module",
+ "once"), "invalid action: %s" % `action`
+ assert isinstance(message, types.StringType), "message must be a string"
+ assert isinstance(category, types.ClassType), "category must be a class"
+ assert issubclass(category, Warning), "category must be a Warning subclass"
+ assert type(module) is types.StringType, "module must be a string"
+ assert type(lineno) is types.IntType and lineno >= 0, \
+ "lineno must be an int >= 0"
+ item = (action, re.compile(message, re.I), category,
+ re.compile(module), lineno)
+ if append:
+ filters.append(item)
+ else:
+ filters.insert(0, item)
+
+def resetwarnings():
+ """Reset the list of warnings filters to its default state."""
+ filters[:] = []
+
+class _OptionError(Exception):
+ """Exception used by option processing helpers."""
+ pass
+
+# Helper to process -W options passed via sys.warnoptions
+def _processoptions(args):
+ for arg in args:
+ try:
+ _setoption(arg)
+ except _OptionError, msg:
+ print >>sys.stderr, "Invalid -W option ignored:", msg
+
+# Helper for _processoptions()
+def _setoption(arg):
+ parts = arg.split(':')
+ if len(parts) > 5:
+ raise _OptionError("too many fields (max 5): %s" % `arg`)
+ while len(parts) < 5:
+ parts.append('')
+ action, message, category, module, lineno = [s.strip()
+ for s in parts]
+ action = _getaction(action)
+ message = re.escape(message)
+ category = _getcategory(category)
+ module = re.escape(module)
+ if module:
+ module = module + '$'
+ if lineno:
+ try:
+ lineno = int(lineno)
+ if lineno < 0:
+ raise ValueError
+ except (ValueError, OverflowError):
+ raise _OptionError("invalid lineno %s" % `lineno`)
+ else:
+ lineno = 0
+ filterwarnings(action, message, category, module, lineno)
+
+# Helper for _setoption()
+def _getaction(action):
+ if not action:
+ return "default"
+ if action == "all": return "always" # Alias
+ for a in ['default', 'always', 'ignore', 'module', 'once', 'error']:
+ if a.startswith(action):
+ return a
+ raise _OptionError("invalid action: %s" % `action`)
+
+# Helper for _setoption()
+def _getcategory(category):
+ if not category:
+ return Warning
+ if re.match("^[a-zA-Z0-9_]+$", category):
+ try:
+ cat = eval(category)
+ except NameError:
+ raise _OptionError("unknown warning category: %s" % `category`)
+ else:
+ i = category.rfind(".")
+ module = category[:i]
+ klass = category[i+1:]
+ try:
+ m = __import__(module, None, None, [klass])
+ except ImportError:
+ raise _OptionError("invalid module name: %s" % `module`)
+ try:
+ cat = getattr(m, klass)
+ except AttributeError:
+ raise _OptionError("unknown warning category: %s" % `category`)
+ if (not isinstance(cat, types.ClassType) or
+ not issubclass(cat, Warning)):
+ raise _OptionError("invalid warning category: %s" % `category`)
+ return cat
+
+# Self-test
+def _test():
+ import getopt
+ testoptions = []
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "W:")
+ except getopt.error, msg:
+ print >>sys.stderr, msg
+ return
+ for o, a in opts:
+ testoptions.append(a)
+ try:
+ _processoptions(testoptions)
+ except _OptionError, msg:
+ print >>sys.stderr, msg
+ return
+ for item in filters: print item
+ hello = "hello world"
+ warn(hello); warn(hello); warn(hello); warn(hello)
+ warn(hello, UserWarning)
+ warn(hello, DeprecationWarning)
+ for i in range(3):
+ warn(hello)
+ filterwarnings("error", "", Warning, "", 0)
+ try:
+ warn(hello)
+ except Exception, msg:
+ print "Caught", msg.__class__.__name__ + ":", msg
+ else:
+ print "No exception"
+ resetwarnings()
+ try:
+ filterwarnings("booh", "", Warning, "", 0)
+ except Exception, msg:
+ print "Caught", msg.__class__.__name__ + ":", msg
+ else:
+ print "No exception"
+
+# Module initialization
+if __name__ == "__main__":
+ import __main__
+ sys.modules['warnings'] = __main__
+ _test()
+else:
+ _processoptions(sys.warnoptions)
diff --git a/lib/jython/Lib/weakref.py b/lib/jython/Lib/weakref.py new file mode 100644 index 000000000..fb32e5757 --- /dev/null +++ b/lib/jython/Lib/weakref.py @@ -0,0 +1,183 @@ +"""Weak reference support for Python.
+
+This module is an implementation of PEP 205:
+
+http://python.sourceforge.net/peps/pep-0205.html
+"""
+
+import UserDict
+
+from _weakref import \
+ getweakrefcount, \
+ getweakrefs, \
+ ref, \
+ proxy, \
+ ReferenceError, \
+ CallableProxyType, \
+ ProxyType, \
+ ReferenceType
+
+ProxyTypes = (ProxyType, CallableProxyType)
+
+__all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs",
+ "WeakKeyDictionary", "ReferenceType", "ProxyType",
+ "CallableProxyType", "ProxyTypes", "WeakValueDictionary"]
+
+class WeakValueDictionary(UserDict.UserDict):
+
+ # We inherit the constructor without worrying about the input
+ # dictionary; since it uses our .update() method, we get the right
+ # checks (if the other dictionary is a WeakValueDictionary,
+ # objects are unwrapped on the way out, and we always wrap on the
+ # way in).
+
+ def __getitem__(self, key):
+ o = self.data.get(key)()
+ if o is None:
+ raise KeyError, key
+ else:
+ return o
+
+ def __repr__(self):
+ return "<WeakValueDictionary at %s>" % id(self)
+
+ def __setitem__(self, key, value):
+ def remove(o, data=self.data, key=key):
+ del data[key]
+ self.data[key] = ref(value, remove)
+
+ def copy(self):
+ new = WeakValueDictionary()
+ for key, ref in self.data.items():
+ o = ref()
+ if o is not None:
+ new[key] = o
+ return new
+
+ def get(self, key, default=None):
+ try:
+ ref = self.data[key]
+ except KeyError:
+ return default
+ else:
+ o = ref()
+ if o is None:
+ # This should only happen
+ return default
+ else:
+ return o
+
+ def items(self):
+ L = []
+ for key, ref in self.data.items():
+ o = ref()
+ if o is not None:
+ L.append((key, o))
+ return L
+
+ def popitem(self):
+ while 1:
+ key, ref = self.data.popitem()
+ o = ref()
+ if o is not None:
+ return key, o
+
+ def setdefault(self, key, default):
+ try:
+ ref = self.data[key]
+ except KeyError:
+ def remove(o, data=self.data, key=key):
+ del data[key]
+ ref = ref(default, remove)
+ self.data[key] = ref
+ return default
+ else:
+ return ref()
+
+ def update(self, dict):
+ d = self.data
+ L = []
+ for key, o in dict.items():
+ def remove(o, data=d, key=key):
+ del data[key]
+ L.append((key, ref(o, remove)))
+ for key, r in L:
+ d[key] = r
+
+ def values(self):
+ L = []
+ for ref in self.data.values():
+ o = ref()
+ if o is not None:
+ L.append(o)
+ return L
+
+
+class WeakKeyDictionary(UserDict.UserDict):
+
+ def __init__(self, dict=None):
+ self.data = {}
+ if dict is not None: self.update(dict)
+ def remove(k, data=self.data):
+ del data[k]
+ self._remove = remove
+
+ def __getitem__(self, key):
+ return self.data[ref(key)]
+
+ def __repr__(self):
+ return "<WeakKeyDictionary at %s>" % id(self)
+
+ def __setitem__(self, key, value):
+ self.data[ref(key, self._remove)] = value
+
+ def copy(self):
+ new = WeakKeyDictionary()
+ for key, value in self.data.items():
+ o = key()
+ if o is not None:
+ new[o] = value
+ return new
+
+ def get(self, key, default=None):
+ return self.data.get(ref(key),default)
+
+ def has_key(self, key):
+ return self.data.has_key(ref(key))
+
+ def items(self):
+ L = []
+ for key, value in self.data.items():
+ o = key()
+ if o is not None:
+ L.append((o, value))
+ return L
+
+ def keys(self):
+ L = []
+ for ref in self.data.keys():
+ o = ref()
+ if o is not None:
+ L.append(o)
+ return L
+
+ def popitem(self):
+ while 1:
+ key, value = self.data.popitem()
+ o = key()
+ if o is not None:
+ return o, value
+
+ def setdefault(self, key, default):
+ return self.data.setdefault(ref(key, self._remove),default)
+
+ def update(self, dict):
+ d = self.data
+ L = []
+ for key, value in dict.items():
+ L.append((ref(key, self._remove), value))
+ for key, r in L:
+ d[key] = r
+
+# no longer needed
+del UserDict
diff --git a/lib/jython/Lib/whichdb.py b/lib/jython/Lib/whichdb.py new file mode 100644 index 000000000..2bbc296fd --- /dev/null +++ b/lib/jython/Lib/whichdb.py @@ -0,0 +1,88 @@ +"""Guess which db package to use to open a db file."""
+
+import os
+
+if os.sep==".":
+ endsep = "/"
+else:
+ endsep = "."
+
+def whichdb(filename):
+ """Guess which db package to use to open a db file.
+
+ Return values:
+
+ - None if the database file can't be read;
+ - empty string if the file can be read but can't be recognized
+ - the module name (e.g. "dbm" or "gdbm") if recognized.
+
+ Importing the given module may still fail, and opening the
+ database using that module may still fail.
+ """
+
+ import struct
+
+ # Check for dbm first -- this has a .pag and a .dir file
+ try:
+ f = open(filename + endsep + "pag", "rb")
+ f.close()
+ f = open(filename + endsep + "dir", "rb")
+ f.close()
+ return "dbm"
+ except IOError:
+ pass
+
+ # Check for dumbdbm next -- this has a .dir and and a .dat file
+ try:
+ f = open(filename + endsep + "dat", "rb")
+ f.close()
+ f = open(filename + endsep + "dir", "rb")
+ try:
+ if f.read(1) in ["'", '"']:
+ return "dumbdbm"
+ finally:
+ f.close()
+ except IOError:
+ pass
+
+ # See if the file exists, return None if not
+ try:
+ f = open(filename, "rb")
+ except IOError:
+ return None
+
+ # Read the start of the file -- the magic number
+ s16 = f.read(16)
+ f.close()
+ s = s16[0:4]
+
+ # Return "" if not at least 4 bytes
+ if len(s) != 4:
+ return ""
+
+ # Convert to 4-byte int in native byte order -- return "" if impossible
+ try:
+ (magic,) = struct.unpack("=l", s)
+ except struct.error:
+ return ""
+
+ # Check for GNU dbm
+ if magic == 0x13579ace:
+ return "gdbm"
+
+ # Check for BSD hash
+ if magic in (0x00061561, 0x61150600):
+ return "dbhash"
+
+ # BSD hash v2 has a 12-byte NULL pad in front of the file type
+ try:
+ (magic,) = struct.unpack("=l", s16[-4:])
+ except struct.error:
+ return ""
+
+ # Check for BSD hash
+ if magic in (0x00061561, 0x61150600):
+ return "dbhash"
+
+ # Unknown
+ return ""
diff --git a/lib/jython/Lib/whrandom.py b/lib/jython/Lib/whrandom.py new file mode 100644 index 000000000..f841e2d67 --- /dev/null +++ b/lib/jython/Lib/whrandom.py @@ -0,0 +1,140 @@ +"""Wichman-Hill random number generator.
+
+Wichmann, B. A. & Hill, I. D. (1982)
+Algorithm AS 183:
+An efficient and portable pseudo-random number generator
+Applied Statistics 31 (1982) 188-190
+
+see also:
+ Correction to Algorithm AS 183
+ Applied Statistics 33 (1984) 123
+
+ McLeod, A. I. (1985)
+ A remark on Algorithm AS 183
+ Applied Statistics 34 (1985),198-200
+
+
+USE:
+whrandom.random() yields double precision random numbers
+ uniformly distributed between 0 and 1.
+
+whrandom.seed(x, y, z) must be called before whrandom.random()
+ to seed the generator
+
+There is also an interface to create multiple independent
+random generators, and to choose from other ranges.
+
+
+
+Multi-threading note: the random number generator used here is not
+thread-safe; it is possible that nearly simultaneous calls in
+different theads return the same random value. To avoid this, you
+have to use a lock around all calls. (I didn't want to slow this
+down in the serial case by using a lock here.)
+"""
+
+# Translated by Guido van Rossum from C source provided by
+# Adrian Baddeley.
+
+
+class whrandom:
+ def __init__(self, x = 0, y = 0, z = 0):
+ """Initialize an instance.
+ Without arguments, initialize from current time.
+ With arguments (x, y, z), initialize from them."""
+ self.seed(x, y, z)
+
+ def seed(self, x = 0, y = 0, z = 0):
+ """Set the seed from (x, y, z).
+ These must be integers in the range [0, 256)."""
+ if not type(x) == type(y) == type(z) == type(0):
+ raise TypeError, 'seeds must be integers'
+ if not (0 <= x < 256 and 0 <= y < 256 and 0 <= z < 256):
+ raise ValueError, 'seeds must be in range(0, 256)'
+ if 0 == x == y == z:
+ # Initialize from current time
+ import time
+ t = long(time.time() * 256)
+ t = int((t&0xffffff) ^ (t>>24))
+ t, x = divmod(t, 256)
+ t, y = divmod(t, 256)
+ t, z = divmod(t, 256)
+ # Zero is a poor seed, so substitute 1
+ self._seed = (x or 1, y or 1, z or 1)
+
+ def random(self):
+ """Get the next random number in the range [0.0, 1.0)."""
+ # This part is thread-unsafe:
+ # BEGIN CRITICAL SECTION
+ x, y, z = self._seed
+ #
+ x = (171 * x) % 30269
+ y = (172 * y) % 30307
+ z = (170 * z) % 30323
+ #
+ self._seed = x, y, z
+ # END CRITICAL SECTION
+ #
+ return (x/30269.0 + y/30307.0 + z/30323.0) % 1.0
+
+ def uniform(self, a, b):
+ """Get a random number in the range [a, b)."""
+ return a + (b-a) * self.random()
+
+ def randint(self, a, b):
+ """Get a random integer in the range [a, b] including
+ both end points.
+
+ (Deprecated; use randrange below.)"""
+ return self.randrange(a, b+1)
+
+ def choice(self, seq):
+ """Choose a random element from a non-empty sequence."""
+ return seq[int(self.random() * len(seq))]
+
+ def randrange(self, start, stop=None, step=1, int=int, default=None):
+ """Choose a random item from range(start, stop[, step]).
+
+ This fixes the problem with randint() which includes the
+ endpoint; in Python this is usually not what you want.
+ Do not supply the 'int' and 'default' arguments."""
+ # This code is a bit messy to make it fast for the
+ # common case while still doing adequate error checking
+ istart = int(start)
+ if istart != start:
+ raise ValueError, "non-integer arg 1 for randrange()"
+ if stop is default:
+ if istart > 0:
+ return int(self.random() * istart)
+ raise ValueError, "empty range for randrange()"
+ istop = int(stop)
+ if istop != stop:
+ raise ValueError, "non-integer stop for randrange()"
+ if step == 1:
+ if istart < istop:
+ return istart + int(self.random() *
+ (istop - istart))
+ raise ValueError, "empty range for randrange()"
+ istep = int(step)
+ if istep != step:
+ raise ValueError, "non-integer step for randrange()"
+ if istep > 0:
+ n = (istop - istart + istep - 1) / istep
+ elif istep < 0:
+ n = (istop - istart + istep + 1) / istep
+ else:
+ raise ValueError, "zero step for randrange()"
+
+ if n <= 0:
+ raise ValueError, "empty range for randrange()"
+ return istart + istep*int(self.random() * n)
+
+
+# Initialize from the current time
+_inst = whrandom()
+seed = _inst.seed
+random = _inst.random
+uniform = _inst.uniform
+randint = _inst.randint
+choice = _inst.choice
+randrange = _inst.randrange
diff --git a/lib/jython/Lib/xdrlib.py b/lib/jython/Lib/xdrlib.py new file mode 100644 index 000000000..e957c7556 --- /dev/null +++ b/lib/jython/Lib/xdrlib.py @@ -0,0 +1,281 @@ +"""Implements (a subset of) Sun XDR -- eXternal Data Representation.
+
+See: RFC 1014
+
+"""
+
+import struct
+
+__all__ = ["Error", "Packer", "Unpacker", "ConversionError"]
+
+# exceptions
+class Error:
+ """Exception class for this module. Use:
+
+ except xdrlib.Error, var:
+ # var has the Error instance for the exception
+
+ Public ivars:
+ msg -- contains the message
+
+ """
+ def __init__(self, msg):
+ self.msg = msg
+ def __repr__(self):
+ return repr(self.msg)
+ def __str__(self):
+ return str(self.msg)
+
+
+class ConversionError(Error):
+ pass
+
+
+
+class Packer:
+ """Pack various data representations into a buffer."""
+
+ def __init__(self):
+ self.reset()
+
+ def reset(self):
+ self.__buf = ''
+
+ def get_buffer(self):
+ return self.__buf
+ # backwards compatibility
+ get_buf = get_buffer
+
+ def pack_uint(self, x):
+ self.__buf = self.__buf + struct.pack('>L', x)
+
+ pack_int = pack_uint
+ pack_enum = pack_int
+
+ def pack_bool(self, x):
+ if x: self.__buf = self.__buf + '\0\0\0\1'
+ else: self.__buf = self.__buf + '\0\0\0\0'
+
+ def pack_uhyper(self, x):
+ self.pack_uint(x>>32 & 0xffffffffL)
+ self.pack_uint(x & 0xffffffffL)
+
+ pack_hyper = pack_uhyper
+
+ def pack_float(self, x):
+ try: self.__buf = self.__buf + struct.pack('>f', x)
+ except struct.error, msg:
+ raise ConversionError, msg
+
+ def pack_double(self, x):
+ try: self.__buf = self.__buf + struct.pack('>d', x)
+ except struct.error, msg:
+ raise ConversionError, msg
+
+ def pack_fstring(self, n, s):
+ if n < 0:
+ raise ValueError, 'fstring size must be nonnegative'
+ n = ((n+3)/4)*4
+ data = s[:n]
+ data = data + (n - len(data)) * '\0'
+ self.__buf = self.__buf + data
+
+ pack_fopaque = pack_fstring
+
+ def pack_string(self, s):
+ n = len(s)
+ self.pack_uint(n)
+ self.pack_fstring(n, s)
+
+ pack_opaque = pack_string
+ pack_bytes = pack_string
+
+ def pack_list(self, list, pack_item):
+ for item in list:
+ self.pack_uint(1)
+ pack_item(item)
+ self.pack_uint(0)
+
+ def pack_farray(self, n, list, pack_item):
+ if len(list) != n:
+ raise ValueError, 'wrong array size'
+ for item in list:
+ pack_item(item)
+
+ def pack_array(self, list, pack_item):
+ n = len(list)
+ self.pack_uint(n)
+ self.pack_farray(n, list, pack_item)
+
+
+
+class Unpacker:
+ """Unpacks various data representations from the given buffer."""
+
+ def __init__(self, data):
+ self.reset(data)
+
+ def reset(self, data):
+ self.__buf = data
+ self.__pos = 0
+
+ def get_position(self):
+ return self.__pos
+
+ def set_position(self, position):
+ self.__pos = position
+
+ def get_buffer(self):
+ return self.__buf
+
+ def done(self):
+ if self.__pos < len(self.__buf):
+ raise Error('unextracted data remains')
+
+ def unpack_uint(self):
+ i = self.__pos
+ self.__pos = j = i+4
+ data = self.__buf[i:j]
+ if len(data) < 4:
+ raise EOFError
+ x = struct.unpack('>L', data)[0]
+ try:
+ return int(x)
+ except OverflowError:
+ return x
+
+ def unpack_int(self):
+ i = self.__pos
+ self.__pos = j = i+4
+ data = self.__buf[i:j]
+ if len(data) < 4:
+ raise EOFError
+ return struct.unpack('>l', data)[0]
+
+ unpack_enum = unpack_int
+ unpack_bool = unpack_int
+
+ def unpack_uhyper(self):
+ hi = self.unpack_uint()
+ lo = self.unpack_uint()
+ return long(hi)<<32 | lo
+
+ def unpack_hyper(self):
+ x = self.unpack_uhyper()
+ if x >= 0x8000000000000000L:
+ x = x - 0x10000000000000000L
+ return x
+
+ def unpack_float(self):
+ i = self.__pos
+ self.__pos = j = i+4
+ data = self.__buf[i:j]
+ if len(data) < 4:
+ raise EOFError
+ return struct.unpack('>f', data)[0]
+
+ def unpack_double(self):
+ i = self.__pos
+ self.__pos = j = i+8
+ data = self.__buf[i:j]
+ if len(data) < 8:
+ raise EOFError
+ return struct.unpack('>d', data)[0]
+
+ def unpack_fstring(self, n):
+ if n < 0:
+ raise ValueError, 'fstring size must be nonnegative'
+ i = self.__pos
+ j = i + (n+3)/4*4
+ if j > len(self.__buf):
+ raise EOFError
+ self.__pos = j
+ return self.__buf[i:i+n]
+
+ unpack_fopaque = unpack_fstring
+
+ def unpack_string(self):
+ n = self.unpack_uint()
+ return self.unpack_fstring(n)
+
+ unpack_opaque = unpack_string
+ unpack_bytes = unpack_string
+
+ def unpack_list(self, unpack_item):
+ list = []
+ while 1:
+ x = self.unpack_uint()
+ if x == 0: break
+ if x != 1:
+ raise ConversionError, '0 or 1 expected, got ' + `x`
+ item = unpack_item()
+ list.append(item)
+ return list
+
+ def unpack_farray(self, n, unpack_item):
+ list = []
+ for i in range(n):
+ list.append(unpack_item())
+ return list
+
+ def unpack_array(self, unpack_item):
+ n = self.unpack_uint()
+ return self.unpack_farray(n, unpack_item)
+
+
+# test suite
+def _test():
+ p = Packer()
+ packtest = [
+ (p.pack_uint, (9,)),
+ (p.pack_bool, (None,)),
+ (p.pack_bool, ('hello',)),
+ (p.pack_uhyper, (45L,)),
+ (p.pack_float, (1.9,)),
+ (p.pack_double, (1.9,)),
+ (p.pack_string, ('hello world',)),
+ (p.pack_list, (range(5), p.pack_uint)),
+ (p.pack_array, (['what', 'is', 'hapnin', 'doctor'], p.pack_string)),
+ ]
+ succeedlist = [1] * len(packtest)
+ count = 0
+ for method, args in packtest:
+ print 'pack test', count,
+ try:
+ apply(method, args)
+ print 'succeeded'
+ except ConversionError, var:
+ print 'ConversionError:', var.msg
+ succeedlist[count] = 0
+ count = count + 1
+ data = p.get_buffer()
+ # now verify
+ up = Unpacker(data)
+ unpacktest = [
+ (up.unpack_uint, (), lambda x: x == 9),
+ (up.unpack_bool, (), lambda x: not x),
+ (up.unpack_bool, (), lambda x: x),
+ (up.unpack_uhyper, (), lambda x: x == 45L),
+ (up.unpack_float, (), lambda x: 1.89 < x < 1.91),
+ (up.unpack_double, (), lambda x: 1.89 < x < 1.91),
+ (up.unpack_string, (), lambda x: x == 'hello world'),
+ (up.unpack_list, (up.unpack_uint,), lambda x: x == range(5)),
+ (up.unpack_array, (up.unpack_string,),
+ lambda x: x == ['what', 'is', 'hapnin', 'doctor']),
+ ]
+ count = 0
+ for method, args, pred in unpacktest:
+ print 'unpack test', count,
+ try:
+ if succeedlist[count]:
+ x = apply(method, args)
+ print pred(x) and 'succeeded' or 'failed', ':', x
+ else:
+ print 'skipping'
+ except ConversionError, var:
+ print 'ConversionError:', var.msg
+ count = count + 1
+
+
+if __name__ == '__main__':
+ _test()
diff --git a/lib/jython/Lib/xml/__init__.py b/lib/jython/Lib/xml/__init__.py new file mode 100644 index 000000000..5249d88f4 --- /dev/null +++ b/lib/jython/Lib/xml/__init__.py @@ -0,0 +1,42 @@ +"""Core XML support for Python.
+
+This package contains three sub-packages:
+
+dom -- The W3C Document Object Model. This supports DOM Level 1 +
+ Namespaces.
+
+parsers -- Python wrappers for XML parsers (currently only supports Expat).
+
+sax -- The Simple API for XML, developed by XML-Dev, led by David
+ Megginson and ported to Python by Lars Marius Garshol. This
+ supports the SAX 2 API.
+"""
+
+
+__all__ = ["dom", "parsers", "sax"]
+
+# When being checked-out without options, this has the form
+# "<dollar>Revision: x.y </dollar>"
+# When exported using -kv, it is "x.y".
+__version__ = "$Revision: 1.11 $".split()[-2:][0]
+
+
+_MINIMUM_XMLPLUS_VERSION = (0, 6, 1)
+
+
+try:
+ import _xmlplus
+except ImportError:
+ pass
+else:
+ try:
+ v = _xmlplus.version_info
+ except AttributeError:
+ # _xmlplue is too old; ignore it
+ pass
+ else:
+ if v >= _MINIMUM_XMLPLUS_VERSION:
+ import sys
+ sys.modules[__name__] = _xmlplus
+ else:
+ del v
diff --git a/lib/jython/Lib/xml/dom/Attr.py b/lib/jython/Lib/xml/dom/Attr.py new file mode 100644 index 000000000..a5b73bb2f --- /dev/null +++ b/lib/jython/Lib/xml/dom/Attr.py @@ -0,0 +1,134 @@ +########################################################################
+#
+# File Name: Attr.py
+#
+# Documentation: http://docs.4suite.com/4DOM/Attr.py.html
+#
+"""
+DOM Level 2 Attribute Node
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+from xml.dom import Node
+from DOMImplementation import implementation
+from FtNode import FtNode
+from Event import MutationEvent
+
+class Attr(FtNode):
+ nodeType = Node.ATTRIBUTE_NODE
+ _allowedChildren = [Node.TEXT_NODE,
+ Node.ENTITY_REFERENCE_NODE
+ ]
+
+ def __init__(self, ownerDocument, name, namespaceURI, prefix, localName):
+ FtNode.__init__(self, ownerDocument, namespaceURI, prefix, localName)
+ self.__dict__['__nodeName'] = name
+ self._ownerElement = None
+
+ ### Attribute Methods ###
+
+ def _get_name(self):
+ return self.__dict__['__nodeName']
+
+ def _get_specified(self):
+ #True if this attribute was explicitly given a value in the document
+ return self._get_value() != ''
+
+ def _get_value(self):
+ return reduce(lambda value, child:
+ value + child.nodeValue,
+ self.childNodes, '')
+
+ def _set_value(self, value):
+ old_value = self.value
+ if value != old_value or len(self.childNodes) > 1:
+ # Remove previous childNodes
+ while self.firstChild:
+ self.removeChild(self.firstChild)
+ if value:
+ self.appendChild(self.ownerDocument.createTextNode(value))
+ owner = self._ownerElement
+ if owner:
+ owner._4dom_fireMutationEvent('DOMAttrModified',
+ relatedNode=self,
+ prevValue=old_value,
+ newValue=value,
+ attrName=self.name,
+ attrChange=MutationEvent.MODIFICATION)
+ owner._4dom_fireMutationEvent('DOMSubtreeModified')
+
+
+ def _get_ownerElement(self):
+ return self._ownerElement
+
+ ### Overridden Methods ###
+
+ def _get_nodeValue(self):
+ return self._get_value()
+
+ def _set_nodeValue(self, value):
+ self._set_value(value)
+
+ def __repr__(self):
+ return '<Attribute Node at %x: Name="%s", Value="%s">' % (
+ id(self),
+ self.name,
+ self.value
+ )
+
+ ### Helper Functions For Cloning ###
+
+ def _4dom_clone(self, owner):
+ a = self.__class__(owner,
+ self.nodeName,
+ self.namespaceURI,
+ self.prefix,
+ self.localName)
+ for child in self.childNodes:
+ a.appendChild(child._4dom_clone(owner))
+ return a
+
+ def __getinitargs__(self):
+ return (self.ownerDocument,
+ self.nodeName,
+ self.namespaceURI,
+ self.prefix,
+ self.localName
+ )
+
+ def __getstate__(self):
+ return self.childNodes
+
+ def __setstate__(self, children):
+ self.childNodes.extend(list(children))
+ for i in range(1, len(children)):
+ children[i]._4dom_setHierarchy(self, children[i-1], None)
+
+ ### Internal Methods ###
+
+ def _4dom_setOwnerElement(self, owner):
+ self.__dict__['_ownerElement'] = owner
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = FtNode._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ 'name':_get_name,
+ 'specified':_get_specified,
+ 'ownerElement':_get_ownerElement,
+ 'value':_get_value,
+ 'nodeValue':_get_value
+ })
+
+ _writeComputedAttrs = FtNode._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ 'value':_set_value,
+ 'nodeValue':_set_value
+ })
+
+ # Create the read-only list of attributes
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ FtNode._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/CDATASection.py b/lib/jython/Lib/xml/dom/CDATASection.py new file mode 100644 index 000000000..d16f96df7 --- /dev/null +++ b/lib/jython/Lib/xml/dom/CDATASection.py @@ -0,0 +1,23 @@ +########################################################################
+#
+# File Name: CDATASection.py
+#
+# Documentation: http://docs.4suite.com/4DOM/CDATASection.py.html
+#
+"""
+Implementation of DOM Level 2 CDATASection interface
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+from xml.dom import Node
+from Text import Text
+
+class CDATASection(Text):
+ nodeType = Node.CDATA_SECTION_NODE
+
+ def __init__(self, ownerDocument, data):
+ Text.__init__(self, ownerDocument, data)
+ self.__dict__['__nodeName'] = "#cdata-section"
diff --git a/lib/jython/Lib/xml/dom/CharacterData.py b/lib/jython/Lib/xml/dom/CharacterData.py new file mode 100644 index 000000000..7f7ea4d9e --- /dev/null +++ b/lib/jython/Lib/xml/dom/CharacterData.py @@ -0,0 +1,136 @@ +########################################################################
+#
+# File Name: CharacterData.py
+#
+# Documentation: http://docs.4suite.com/4DOM/CharacterData.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+from xml.dom import Node
+from DOMImplementation import implementation
+from FtNode import FtNode
+
+from ext import IsDOMString
+
+from xml.dom import IndexSizeErr
+from xml.dom import SyntaxErr
+
+class CharacterData(FtNode):
+ def __init__(self, ownerDocument, data):
+ FtNode.__init__(self, ownerDocument)
+ self.__dict__['__nodeValue'] = data
+ self._length = len(data)
+
+ ### Attribute Methods ###
+
+ def _get_data(self):
+ return self.__dict__['__nodeValue']
+
+ def _set_data(self, data):
+ if not IsDOMString(data):
+ raise SyntaxErr()
+ old_value = self.__dict__['__nodeValue']
+ self.__dict__['__nodeValue'] = data
+ self._length = len(data)
+ self._4dom_fireMutationEvent('DOMCharacterDataModified',
+ prevValue=old_value,
+ newValue=data)
+
+ def _get_length(self):
+ return self._length
+
+ ### Methods ###
+
+ def appendData(self, arg):
+ if len(arg):
+ self._set_data(self.__dict__['__nodeValue'] + arg)
+ self._4dom_fireMutationEvent('DOMSubtreeModified')
+ return
+
+ def deleteData(self, offset, count):
+ if count < 0 or offset < 0 or offset > self._length:
+ raise IndexSizeErr()
+ data = self.__dict__['__nodeValue']
+ data = data[:int(offset)] + data[int(offset+count):]
+ self._set_data(data)
+ self._4dom_fireMutationEvent('DOMSubtreeModified')
+ return
+
+ def insertData(self, offset, arg):
+ if offset < 0 or offset > self._length:
+ raise IndexSizeErr()
+ if not IsDOMString(arg):
+ raise SyntaxErr()
+ data = self.__dict__['__nodeValue']
+ data = data[:int(offset)] + arg + data[int(offset):]
+ self._set_data(data)
+ self._4dom_fireMutationEvent('DOMSubtreeModified')
+ return
+
+ def replaceData(self, offset, count, arg):
+ if not IsDOMString(arg):
+ raise SyntaxErr()
+ if count < 0 or offset < 0 or offset > self._length:
+ raise IndexSizeErr()
+ data = self.__dict__['__nodeValue']
+ data = data[:int(offset)] + arg + data[int(offset+count):]
+ self._set_data(data)
+ self._4dom_fireMutationEvent('DOMSubtreeModified')
+ return
+
+ def substringData(self, offset, count):
+ if count < 0 or offset < 0 or offset > self._length:
+ raise IndexSizeErr()
+ return self.data[int(offset):int(offset+count)]
+
+ ### Helper Functions For Cloning ###
+
+ def _4dom_clone(self, owner):
+ return self.__class__(owner, self.data)
+
+ def __getinitargs__(self):
+ return (self.ownerDocument,
+ self.data
+ )
+
+ ### Overridden Methods ###
+
+ def __repr__(self):
+ # Trim to a managable size
+ if len(self.data) > 20:
+ data = self.data[:20] + '...'
+ else:
+ data = self.data
+
+ # Escape unprintable chars
+ import string
+ for ws in ['\t','\n','\r']:
+ data = string.replace(data, ws, '\\0x%x' % ord(ws))
+
+ return "<%s Node at %x: %s>" % (
+ self.__class__.__name__,
+ id(self),
+ repr(data))
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = FtNode._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ 'length':_get_length,
+ 'data':_get_data
+ })
+
+
+ _writeComputedAttrs = FtNode._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ 'data':_set_data
+ })
+
+ # Create the read-only list of attributes
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ FtNode._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/Comment.py b/lib/jython/Lib/xml/dom/Comment.py new file mode 100644 index 000000000..7541e00b3 --- /dev/null +++ b/lib/jython/Lib/xml/dom/Comment.py @@ -0,0 +1,22 @@ +########################################################################
+#
+# File Name: Comment.py
+#
+# Documentation: http://docs.4suite.org/4DOM/Comment.py.html
+#
+"""
+WWW: http://4suite.org/4DOM e-mail: support@4suite.org
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.org/COPYRIGHT for license and copyright information
+"""
+
+from xml.dom import Node
+from CharacterData import CharacterData
+
+class Comment(CharacterData):
+ nodeType = Node.COMMENT_NODE
+
+ def __init__(self,ownerDocument,data):
+ CharacterData.__init__(self, ownerDocument, data)
+ self.__dict__['__nodename'] = '#comment'
diff --git a/lib/jython/Lib/xml/dom/DOMImplementation.py b/lib/jython/Lib/xml/dom/DOMImplementation.py new file mode 100644 index 000000000..6fca1b9c4 --- /dev/null +++ b/lib/jython/Lib/xml/dom/DOMImplementation.py @@ -0,0 +1,69 @@ +########################################################################
+#
+# File Name: DOMImplementation.py
+#
+# Documentation: http://docs.4suite.com/4DOM/DOMImplementation.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+
+FEATURES_MAP = {'CORE':2.0,
+ 'XML':2.0,
+ 'TRAVERSAL':2.0,
+ 'EVENTS':2.0,
+ 'MUTATIONEVENTS':2.0,
+ }
+
+try:
+ import Range
+except:
+ pass
+else:
+ FEATURES_MAP['RANGE'] = 2.0
+
+class DOMImplementation:
+
+ def __init__(self):
+ pass
+
+ def hasFeature(self, feature, version=''):
+ featureVersion = FEATURES_MAP.get(string.upper(feature))
+ if featureVersion:
+ if version and float(version) != featureVersion:
+ return 0
+ return 1
+ return 0
+
+ def createDocumentType(self, qualifiedName, publicId, systemId):
+ import DocumentType
+ dt = DocumentType.DocumentType(qualifiedName,
+ self._4dom_createNamedNodeMap(),
+ self._4dom_createNamedNodeMap(),
+ publicId,
+ systemId)
+ return dt
+
+ def createDocument(self, namespaceURI, qualifiedName, doctype):
+ import Document
+ doc = Document.Document(doctype)
+ if qualifiedName:
+ el = doc.createElementNS(namespaceURI, qualifiedName)
+ doc.appendChild(el)
+ return doc
+
+ def _4dom_createNodeList(self, list=None):
+ import NodeList
+ return NodeList.NodeList(list)
+
+ def _4dom_createNamedNodeMap(self, owner=None):
+ import NamedNodeMap
+ return NamedNodeMap.NamedNodeMap(owner)
+
+implementation = DOMImplementation()
+getDOMImplementation = DOMImplementation
diff --git a/lib/jython/Lib/xml/dom/Document.py b/lib/jython/Lib/xml/dom/Document.py new file mode 100644 index 000000000..fb5e2435e --- /dev/null +++ b/lib/jython/Lib/xml/dom/Document.py @@ -0,0 +1,329 @@ +########################################################################
+#
+# File Name: Document.py
+#
+# Documentation: http://docs.4suite.com/4DOM/Document.py.html
+#
+"""
+
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import re, string
+
+
+from DOMImplementation import implementation
+from FtNode import FtNode
+from ext import SplitQName
+
+from xml.dom import Node
+from xml.dom import XML_NAMESPACE
+from xml.dom import XMLNS_NAMESPACE
+from xml.dom import HierarchyRequestErr
+from xml.dom import InvalidCharacterErr
+from xml.dom import NotSupportedErr
+from xml.dom import NamespaceErr
+
+#FIXME: should allow combining characters: fix when Python gets Unicode
+g_namePattern = re.compile('[a-zA-Z_:][\w\.\-_:]*\Z')
+
+class Document(FtNode):
+ #Base node type for this class
+ nodeType = Node.DOCUMENT_NODE
+ nodeName = "#document"
+
+ #This is for validation that the proper nodes are added
+ _allowedChildren = [Node.PROCESSING_INSTRUCTION_NODE,
+ Node.COMMENT_NODE,
+ Node.ELEMENT_NODE,
+ Node.DOCUMENT_TYPE_NODE
+ ]
+
+ def __init__(self, doctype):
+ FtNode.__init__(self, None)
+ self.__dict__['__doctype'] = None
+ self.__dict__['__implementation'] = implementation
+ self.__dict__['__documentElement'] = None
+ self.__dict__['_singleChildren'] = {Node.ELEMENT_NODE:'__documentElement',
+ Node.DOCUMENT_TYPE_NODE:'__doctype'
+ }
+ self._4dom_setDocumentType(doctype)
+
+ ### Attribute Methods ###
+
+ def _get_doctype(self):
+ return self.__dict__['__doctype']
+
+ def _get_implementation(self):
+ return self.__dict__['__implementation']
+
+ def _get_documentElement(self):
+ return self.__dict__['__documentElement']
+
+ def _get_ownerDocument(self):
+ return self
+
+ ### Methods ###
+
+ def createAttribute(self, name):
+ if not g_namePattern.match(name):
+ raise InvalidCharacterErr()
+ import Attr
+ return Attr.Attr(self, name, None, None, None)
+
+ def createCDATASection(self, data):
+ from CDATASection import CDATASection
+ return CDATASection(self, data)
+
+ def createComment(self, data):
+ from Comment import Comment
+ return Comment(self, data)
+
+ def createDocumentFragment(self):
+ from DocumentFragment import DocumentFragment
+ return DocumentFragment(self)
+
+ def createElement(self, tagname):
+ if not g_namePattern.match(tagname):
+ raise InvalidCharacterErr()
+ from Element import Element
+ return Element(self, tagname, None, None, None)
+
+ def createEntityReference(self, name):
+ if not g_namePattern.match(name):
+ raise InvalidCharacterErr()
+ from EntityReference import EntityReference
+ return EntityReference(self, name)
+
+ def createProcessingInstruction(self, target, data):
+ if not g_namePattern.match(target):
+ raise InvalidCharacterErr()
+
+ #FIXME: Unicode support
+ # Technically, chacters from the unicode surrogate blocks are illegal.
+ #for c in target:
+ # if c in unicode_surrogate_blocks:
+ # raise InvalidCharacterErr()
+
+ from ProcessingInstruction import ProcessingInstruction
+ return ProcessingInstruction(self, target, data);
+
+ def createTextNode(self, data):
+ from Text import Text
+ return Text(self, data)
+
+ def getElementById(self, elementId):
+ #FIXME: Must be implemented in the parser first
+ return None
+
+ def getElementsByTagName(self, tagName):
+ nodeList = implementation._4dom_createNodeList([])
+ root = self.documentElement
+ if root:
+ if tagName == '*' or root.tagName == tagName:
+ nodeList.append(root)
+ nodeList.extend(list(root.getElementsByTagName(tagName)))
+ return nodeList
+
+
+ ### DOM Level 2 Methods ###
+
+ def createAttributeNS(self, namespaceURI, qualifiedName):
+ if not g_namePattern.match(qualifiedName):
+ raise InvalidCharacterErr()
+ from Attr import Attr
+ (prefix, localName) = SplitQName(qualifiedName)
+ if prefix == 'xml' and namespaceURI != XML_NAMESPACE:
+ raise NamespaceErr()
+ if localName == 'xmlns':
+ if namespaceURI != XMLNS_NAMESPACE:
+ raise NamespaceErr()
+ return Attr(self, qualifiedName, XMLNS_NAMESPACE, 'xmlns', prefix)
+ else:
+ if (not namespaceURI and prefix) or (not prefix and namespaceURI):
+ raise NamespaceErr()
+ return Attr(self, qualifiedName, namespaceURI, prefix, localName)
+
+ def importNode(self, importedNode, deep):
+ importType = importedNode.nodeType
+
+ # No import allow per spec
+ if importType in [Node.DOCUMENT_NODE, Node.DOCUMENT_TYPE_NODE]:
+ raise NotSupportedErr()
+
+ # Only the EntRef itself is copied since the source and destination
+ # documents might have defined the entity differently
+ #FIXME: If the document being imported into provides a definition for
+ # this entity name, its value is assigned.
+ # Need entity support for this!!
+ elif importType == Node.ENTITY_REFERENCE_NODE:
+ deep = 0
+
+ return importedNode.cloneNode(deep, newOwner=self)
+
+ def createElementNS(self, namespaceURI, qualifiedName):
+ from Element import Element
+ if not g_namePattern.match(qualifiedName):
+ raise InvalidCharacterErr()
+ (prefix, localName) = SplitQName(qualifiedName)
+ if prefix == 'xml' and namespaceURI != XML_NAMESPACE:
+ raise NamespaceErr()
+ if prefix and not namespaceURI:
+ raise NamespaceErr()
+ return Element(self, qualifiedName, namespaceURI, prefix, localName)
+
+ def getElementsByTagNameNS(self,namespaceURI,localName):
+ nodeList = implementation._4dom_createNodeList([])
+ root = self.documentElement
+ if root:
+ if ((namespaceURI == '*' or namespaceURI == root.namespaceURI) and
+ (localName == '*' or localName == root.localName)):
+ nodeList.append(root)
+ nodeList.extend(list(root.getElementsByTagNameNS(namespaceURI,
+ localName)))
+ return nodeList
+
+ ### Document Traversal Factory Functions ###
+
+ def createNodeIterator(self, root, whatToShow, filter, entityReferenceExpansion):
+ from NodeIterator import NodeIterator
+ return NodeIterator(root, whatToShow, filter, entityReferenceExpansion)
+
+ def createTreeWalker(self, root, whatToShow, filter, entityReferenceExpansion):
+ from TreeWalker import TreeWalker
+ return TreeWalker(root, whatToShow, filter, entityReferenceExpansion)
+
+ ### Document Event Factory Functions ###
+
+ def createEvent(self,eventType):
+ import Event
+ if eventType in Event.supportedEvents:
+ #Only mutation events are supported
+ return Event.MutationEvent(eventType)
+ else:
+ raise NotSupportedErr()
+
+ ### Document Range Factory Functions ###
+ def createRange(self):
+ if not self.implementation.hasFeature('RANGE','2.0'):
+ raise NotSupportedErr()
+ import Range
+ return Range.Range(self)
+
+ ### Overridden Methods ###
+
+ def appendChild(self, newChild):
+ self._4dom_addSingle(newChild)
+ return FtNode.appendChild(self, newChild)
+
+ def insertBefore(self, newChild, oldChild):
+ self._4dom_addSingle(newChild)
+ return FtNode.insertBefore(self, newChild, oldChild)
+
+ def replaceChild(self, newChild, oldChild):
+ if newChild.nodeType != Node.DOCUMENT_FRAGMENT_NODE:
+ root = self.__dict__['__documentElement']
+ if root in [oldChild, newChild]:
+ self.__dict__['__documentElement'] = None
+ else:
+ raise HierarchyRequestErr()
+ replaced = FtNode.replaceChild(self, newChild, oldChild)
+ if newChild.nodeType == Node.ELEMENT_NODE:
+ self.__dict__['__documentElement'] = newChild
+ if self.__dict__['__doctype']:
+ self.__dict__['__doctype']._4dom_setName(newChild.nodeName)
+ return replaced
+
+ def removeChild(self,oldChild):
+ node = FtNode.removeChild(self, oldChild)
+ if self.documentElement == node:
+ self.__dict__['__documentElement'] = None
+ if self.__dict__['__doctype'] == node:
+ self.__dict__['__doctype'] = None
+ return node
+
+ def cloneNode(self, deep):
+ doc = self.__class__(None)
+ if deep:
+ for child in self.childNodes:
+ clone = child.cloneNode(deep, newOwner=doc)
+ if child.nodeType == Node.DOCUMENT_TYPE_NODE:
+ doc._4dom_setDocumentType(clone)
+ else:
+ doc.appendChild(clone)
+ return doc
+
+ def __repr__(self):
+ return "<%s Document at %x>" % (
+ (self.isXml() and 'XML' or 'HTML'),
+ id(self)
+ )
+
+ ### Internal Methods ###
+
+ def _4dom_createEntity(self, publicId, systemId, notationName):
+ from Entity import Entity
+ return Entity(self, publicId, systemId, notationName)
+
+ def _4dom_createNotation(self, publicId, systemId, name):
+ from Notation import Notation
+ return Notation(self, publicId, systemId, name)
+
+ def _4dom_setDocumentType(self, doctype):
+ if not self.__dict__['__doctype'] and doctype is not None:
+ self.__dict__['__doctype'] = doctype
+ doctype._4dom_setOwnerDocument(self)
+ return FtNode.appendChild(self, doctype)
+
+ def _4dom_addSingle(self, node):
+ '''Make sure only one Element node is added to a Document'''
+ if node.nodeType == Node.ELEMENT_NODE:
+ self._4dom_validateNode(node)
+ if node.parentNode != None:
+ node.parentNode.removeChild(node)
+ if self.__dict__['__documentElement']:
+ raise HierarchyRequestErr()
+ self.__dict__['__documentElement'] = node
+ if self.__dict__['__doctype']:
+ self.__dict__['__doctype']._4dom_setName(node.nodeName)
+
+ ### Helper Functions for Pickling ###
+
+ def __getinitargs__(self):
+ return (None,)
+
+ def __getstate__(self):
+ return (self.childNodes, self.doctype, self.documentElement)
+
+ def __setstate__(self, (children, doctype, root)):
+ FtNode.__setstate__(self, children)
+ self.__dict__['__doctype'] = doctype
+ self.__dict__['__documentElement'] = root
+ return
+
+ ### Convenience Functions ###
+
+ def isXml(self):
+ return 1
+
+ def isHtml(self):
+ return 0
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = FtNode._readComputedAttrs.copy()
+ _readComputedAttrs.update({'doctype':_get_doctype,
+ 'implementation':_get_implementation,
+ 'documentElement':_get_documentElement,
+ 'ownerDocument':_get_ownerDocument,
+ })
+
+
+ _writeComputedAttrs = FtNode._writeComputedAttrs.copy()
+
+ # Create the read-only list of attributes
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ FtNode._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/DocumentFragment.py b/lib/jython/Lib/xml/dom/DocumentFragment.py new file mode 100644 index 000000000..331efb046 --- /dev/null +++ b/lib/jython/Lib/xml/dom/DocumentFragment.py @@ -0,0 +1,45 @@ +########################################################################
+#
+# File Name: DocumentFragment.py
+#
+# Documentation: http://docs.4suite.com/4DOM/DocumentFragment.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+from xml.dom import Node
+from FtNode import FtNode
+
+class DocumentFragment(FtNode):
+ nodeType = Node.DOCUMENT_FRAGMENT_NODE
+ _allowedChildren = [Node.ELEMENT_NODE,
+ Node.PROCESSING_INSTRUCTION_NODE,
+ Node.COMMENT_NODE,
+ Node.TEXT_NODE,
+ Node.CDATA_SECTION_NODE,
+ Node.ENTITY_REFERENCE_NODE]
+
+ def __init__(self, ownerDocument):
+ FtNode.__init__(self, ownerDocument)
+ self.__dict__['__nodeName'] = '#document-fragment'
+
+ ### Overridden Methods ###
+
+ def __repr__(self):
+ return '<DocumentFragment Node at %x: with %d children>' % (
+ id(self),
+ len(self.childNodes),
+ )
+
+ ### Helper Functions For Cloning ###
+
+ def _4dom_clone(self, owner):
+ return self.__class__(owner)
+
+ def __getinitargs__(self):
+ return (self.ownerDocument,
+ )
diff --git a/lib/jython/Lib/xml/dom/DocumentType.py b/lib/jython/Lib/xml/dom/DocumentType.py new file mode 100644 index 000000000..68e9a00c9 --- /dev/null +++ b/lib/jython/Lib/xml/dom/DocumentType.py @@ -0,0 +1,109 @@ +########################################################################
+#
+# File Name: DocumentType.py
+#
+# Documentation: http://docs.4suite.org/4DOM/DocumentType.py.html
+#
+"""
+WWW: http://4suite.org/4DOM e-mail: support@4suite.org
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.org/COPYRIGHT for license and copyright information
+"""
+
+from xml.dom import Node
+from DOMImplementation import implementation
+from FtNode import FtNode
+
+class DocumentType(FtNode):
+ nodeType = Node.DOCUMENT_TYPE_NODE
+
+ def __init__(self, name, entities, notations, publicId, systemId):
+ FtNode.__init__(self, None)
+ self.__dict__['__nodeName'] = name
+ self._entities = entities
+ self._notations = notations
+ self._publicId = publicId
+ self._systemId = systemId
+ #FIXME: Text repr of the entities
+ self._internalSubset = ''
+
+ ### Attribute Methods ###
+
+ def _get_name(self):
+ return self.__dict__['__nodeName']
+
+ def _get_entities(self):
+ return self._entities
+
+ def _get_notations(self):
+ return self._notations
+
+ def _get_publicId(self):
+ return self._publicId
+
+ def _get_systemId(self):
+ return self._systemId
+
+ def _get_internalSubset(self):
+ return self._internalSubset
+
+ ### Overridden Methods ###
+
+ def __repr__(self):
+ return "<DocumentType Node at %x: Name='%s' with %d entities and %d notations>" % (
+ id(self),
+ self.nodeName,
+ len(self._entities),
+ len(self._notations)
+ )
+
+ ### Internal Methods ###
+
+ # Behind the back setting of doctype's ownerDocument
+ # Also sets the owner of the NamedNodeMaps
+ def _4dom_setOwnerDocument(self, newOwner):
+ self.__dict__['__ownerDocument'] = newOwner
+ #self._entities._4dom_setOwnerDocument(newOwner)
+ #self._notations._4dom_setOwnerDocument(newOwner)
+
+ def _4dom_setName(self, name):
+ # Used to keep the root element and doctype in sync
+ self.__dict__['__nodeName'] = name
+
+ ### Helper Functions For Cloning ###
+
+ def _4dom_clone(self, owner):
+ return self.__class__(self.name,
+ self.entities._4dom_clone(owner),
+ self.notations._4dom_clone(owner),
+ self._publicId,
+ self._systemId)
+
+ def __getinitargs__(self):
+ return (self.nodeName,
+ self._entities,
+ self._notations,
+ self._publicId,
+ self._systemId
+ )
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = FtNode._readComputedAttrs.copy()
+ _readComputedAttrs.update({'name':_get_name,
+ 'entities':_get_entities,
+ 'notations':_get_notations,
+ 'publicId':_get_publicId,
+ 'systemId':_get_systemId,
+ 'internalSubset':_get_internalSubset
+ })
+
+
+ _writeComputedAttrs = FtNode._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ })
+
+ # Create the read-only list of attributes
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ FtNode._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/Element.py b/lib/jython/Lib/xml/dom/Element.py new file mode 100644 index 000000000..db7e61cc0 --- /dev/null +++ b/lib/jython/Lib/xml/dom/Element.py @@ -0,0 +1,267 @@ +########################################################################
+#
+# File Name: Element.py
+#
+# Documentation: http://docs.4suite.com/4DOM/Element.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+from DOMImplementation import implementation
+from FtNode import FtNode
+
+import Event
+from xml.dom import Node
+from xml.dom import XML_NAMESPACE
+from xml.dom import InvalidCharacterErr
+from xml.dom import WrongDocumentErr
+from xml.dom import InuseAttributeErr
+from xml.dom import NotFoundErr
+from xml.dom import SyntaxErr
+
+from ext import SplitQName, IsDOMString
+
+import re, string
+#FIXME: should allow combining characters: fix when Python gets Unicode
+g_namePattern = re.compile('[a-zA-Z_:][\w\.\-_:]*\Z')
+
+class Element(FtNode):
+ nodeType = Node.ELEMENT_NODE
+ _allowedChildren = [Node.ELEMENT_NODE,
+ Node.TEXT_NODE,
+ Node.COMMENT_NODE,
+ Node.PROCESSING_INSTRUCTION_NODE,
+ Node.CDATA_SECTION_NODE,
+ Node.ENTITY_REFERENCE_NODE
+ ]
+
+ def __init__(self, ownerDocument, nodeName, namespaceURI, prefix, localName):
+ FtNode.__init__(self, ownerDocument, namespaceURI, prefix, localName);
+ #Set our attributes
+ self.__dict__['__attributes'] = implementation._4dom_createNamedNodeMap(ownerDocument)
+ self.__dict__['__nodeName'] = nodeName
+
+ ### Attribute Methods ###
+
+ def _get_tagName(self):
+ return self.__dict__['__nodeName']
+
+ ### Methods ###
+
+ def getAttribute(self, name):
+ att = self.attributes.getNamedItem(name)
+ return att and att.value or ''
+
+ def getAttributeNode(self, name):
+ return self.attributes.getNamedItem(name)
+
+ def getElementsByTagName(self, tagName):
+ nodeList = implementation._4dom_createNodeList()
+ elements = filter(lambda node, type=Node.ELEMENT_NODE:
+ node.nodeType == type,
+ self.childNodes)
+ for element in elements:
+ if tagName == '*' or element.tagName == tagName:
+ nodeList.append(element)
+ nodeList.extend(list(element.getElementsByTagName(tagName)))
+ return nodeList
+
+ def hasAttribute(self, name):
+ return self.attributes.getNamedItem(name) is not None
+
+ def removeAttribute(self, name):
+ # Return silently if no node
+ node = self.attributes.getNamedItem(name)
+ if node:
+ self.removeAttributeNode(node)
+
+ def removeAttributeNode(self, node):
+ # NamedNodeMap will raise exception if needed
+ if node.namespaceURI is None:
+ self.attributes.removeNamedItem(node.name)
+ else:
+ self.attributes.removeNamedItemNS(node.namespaceURI, node.localName)
+ node._4dom_setOwnerElement(None)
+ self._4dom_fireMutationEvent('DOMAttrModified',
+ relatedNode=node,
+ attrName=node.name,
+ attrChange=Event.MutationEvent.REMOVAL)
+ self._4dom_fireMutationEvent('DOMSubtreeModified')
+ return node
+
+ def setAttribute(self, name, value):
+ if not IsDOMString(value):
+ raise SyntaxErr()
+ if not g_namePattern.match(name):
+ raise InvalidCharacterErr()
+ attr = self.attributes.getNamedItem(name)
+ if attr:
+ attr.value = value
+ else:
+ attr = self.ownerDocument.createAttribute(name)
+ attr.value = value
+ self.setAttributeNode(attr)
+ # the mutation event is fired in Attr.py
+
+ def setAttributeNode(self, node):
+ if node.ownerDocument != self.ownerDocument:
+ raise WrongDocumentErr()
+ if node.ownerElement != None:
+ raise InuseAttributeErr()
+
+ old = self.attributes.getNamedItem(node.name)
+ if old:
+ self._4dom_fireMutationEvent('DOMAttrModified',
+ relatedNode=old,
+ prevValue=old.value,
+ attrName=old.name,
+ attrChange=Event.MutationEvent.REMOVAL)
+ self.attributes.setNamedItem(node)
+ node._4dom_setOwnerElement(self)
+ self._4dom_fireMutationEvent('DOMAttrModified',
+ relatedNode=node,
+ newValue=node.value,
+ attrName=node.name,
+ attrChange=Event.MutationEvent.ADDITION)
+ self._4dom_fireMutationEvent('DOMSubtreeModified')
+ return old
+
+ ### DOM Level 2 Methods ###
+
+ def getAttributeNS(self, namespaceURI, localName):
+ attr = self.attributes.getNamedItemNS(namespaceURI, localName)
+ return attr and attr.value or ''
+
+ def getAttributeNodeNS(self, namespaceURI, localName):
+ return self.attributes.getNamedItemNS(namespaceURI, localName)
+
+ def getElementsByTagNameNS(self, namespaceURI, localName):
+ nodeList = implementation._4dom_createNodeList()
+ elements = filter(lambda node, type=Node.ELEMENT_NODE:
+ node.nodeType == type,
+ self.childNodes)
+ for element in elements:
+ if ((namespaceURI == '*' or element.namespaceURI == namespaceURI)
+ and (localName == '*' or element.localName == localName)):
+ nodeList.append(element)
+ nodeList.extend(list(element.getElementsByTagNameNS(namespaceURI,
+ localName)))
+ return nodeList
+
+ def hasAttributeNS(self, namespaceURI, localName):
+ return self.attributes.getNamedItemNS(namespaceURI, localName) != None
+
+ def removeAttributeNS(self, namespaceURI, localName):
+ # Silently return if not attribute
+ node = self.attributes.getNamedItemNS(namespaceURI, localName)
+ if node:
+ self.removeAttributeNode(node)
+ return
+
+ def setAttributeNS(self, namespaceURI, qualifiedName, value):
+ if not IsDOMString(value):
+ raise SyntaxErr()
+ if not g_namePattern.match(qualifiedName):
+ raise InvalidCharacterErr()
+
+ prefix, localName = SplitQName(qualifiedName)
+ attr = self.attributes.getNamedItemNS(namespaceURI, localName)
+ if attr:
+ attr.value = value
+ else:
+ attr = self.ownerDocument.createAttributeNS(namespaceURI, qualifiedName)
+ attr.value = value
+ self.setAttributeNodeNS(attr)
+ return
+
+ def setAttributeNodeNS(self, node):
+ if self.ownerDocument != node.ownerDocument:
+ raise WrongDocumentErr()
+ if node.ownerElement != None:
+ raise InuseAttributeErr()
+
+ old = self.attributes.getNamedItemNS(node.namespaceURI, node.localName)
+ if old:
+ self._4dom_fireMutationEvent('DOMAttrModified',
+ relatedNode=old,
+ prevValue=old.value,
+ attrName=old.name,
+ attrChange=Event.MutationEvent.REMOVAL)
+ self.attributes.setNamedItemNS(node)
+ node._4dom_setOwnerElement(self)
+ self._4dom_fireMutationEvent('DOMAttrModified',
+ relatedNode=node,
+ newValue=node.value,
+ attrName=node.name,
+ attrChange=Event.MutationEvent.ADDITION)
+ self._4dom_fireMutationEvent('DOMSubtreeModified')
+ return old
+
+ ### Overridden Methods ###
+
+ def __repr__(self):
+ return "<Element Node at %x: Name='%s' with %d attributes and %d children>" % (
+ id(self),
+ self.nodeName,
+ len(self.attributes),
+ len(self.childNodes)
+ )
+
+ # Behind the back setting of element's ownerDocument
+ # Also sets the owner of the NamedNodeMaps
+ def _4dom_setOwnerDocument(self, newOwner):
+ self.__dict__['__ownerDocument'] = newOwner
+ self.__dict__['__attributes']._4dom_setOwnerDocument(newOwner)
+
+ ### Helper Functions For Cloning ###
+
+ def _4dom_clone(self, owner):
+ e = self.__class__(owner,
+ self.nodeName,
+ self.namespaceURI,
+ self.prefix,
+ self.localName)
+ for attr in self.attributes:
+ clone = attr._4dom_clone(owner)
+ if clone.localName is None:
+ e.attributes.setNamedItem(clone)
+ else:
+ e.attributes.setNamedItemNS(clone)
+ clone._4dom_setOwnerElement(self)
+ return e
+
+ def __getinitargs__(self):
+ return (self.ownerDocument,
+ self.nodeName,
+ self.namespaceURI,
+ self.prefix,
+ self.localName
+ )
+
+ def __getstate__(self):
+ return (self.childNodes, self.attributes)
+
+ def __setstate__(self, (children, attrs)):
+ FtNode.__setstate__(self, children)
+ self.__dict__['__attributes'] = attrs
+ for attr in attrs:
+ attr._4dom_setOwnerElement(self)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = FtNode._readComputedAttrs.copy()
+ _readComputedAttrs.update({'tagName':_get_tagName,
+ })
+
+
+ _writeComputedAttrs = FtNode._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ })
+
+ # Create the read-only list of attributes
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ FtNode._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/Entity.py b/lib/jython/Lib/xml/dom/Entity.py new file mode 100644 index 000000000..874b42e67 --- /dev/null +++ b/lib/jython/Lib/xml/dom/Entity.py @@ -0,0 +1,84 @@ +########################################################################
+#
+# File Name: Entity.py
+#
+# Documentation: http://docs.4suite.com/4DOM/Entity.py.html
+#
+"""
+Implementation of DOM Level 2 Entity interface
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+from xml.dom import Node
+from DOMImplementation import implementation
+from FtNode import FtNode
+
+class Entity(FtNode):
+ nodeType = Node.ENTITY_NODE
+ _allowedChildren = [Node.ELEMENT_NODE,
+ Node.PROCESSING_INSTRUCTION_NODE,
+ Node.COMMENT_NODE,
+ Node.TEXT_NODE,
+ Node.CDATA_SECTION_NODE,
+ Node.ENTITY_REFERENCE_NODE
+ ]
+
+ def __init__(self, ownerDocument, publicId, systemId, notationName):
+ FtNode.__init__(self, ownerDocument)
+ self.__dict__['__nodeName'] = '#entity'
+ self.__dict__['publicId'] = publicId
+ self.__dict__['systemId'] = systemId
+ self.__dict__['notationName'] = notationName
+
+ ### Attribute Methods ###
+
+ def _get_systemId(self):
+ return self.systemId
+
+ def _get_publicId(self):
+ return self.publicId
+
+ def _get_notationName(self):
+ return self.notationName
+
+ ### Overridden Methods ###
+
+ def __repr__(self):
+ return '<Entity Node at %x: Public="%s" System="%s" Notation="%s">' % (
+ id(self),
+ self.publicId,
+ self.systemId,
+ self.notationName)
+
+ ### Helper Functions For Cloning ###
+
+ def _4dom_clone(self, owner):
+ return self.__class__(owner,
+ self.publicId,
+ self.systemId,
+ self.notationName)
+
+ def __getinitargs__(self):
+ return (self.ownerDocument,
+ self.publicId,
+ self.systemId,
+ self.notationName
+ )
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = FtNode._readComputedAttrs.copy()
+ _readComputedAttrs.update({'publicId':_get_publicId,
+ 'systemId':_get_systemId,
+ 'notationName':_get_notationName
+ })
+
+
+ _writeComputedAttrs = FtNode._writeComputedAttrs.copy()
+
+ # Create the read-only list of attributes
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ FtNode._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/EntityReference.py b/lib/jython/Lib/xml/dom/EntityReference.py new file mode 100644 index 000000000..e850f06b8 --- /dev/null +++ b/lib/jython/Lib/xml/dom/EntityReference.py @@ -0,0 +1,47 @@ +########################################################################
+#
+# File Name: EntityReference.py
+#
+# Documentation: http://docs.4suite.com/4DOM/EntityReference.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+from xml.dom import Node
+from DOMImplementation import implementation
+from FtNode import FtNode
+
+class EntityReference(FtNode):
+ nodeType = Node.ENTITY_REFERENCE_NODE
+ _allowedChildren = [Node.ELEMENT_NODE,
+ Node.PROCESSING_INSTRUCTION_NODE,
+ Node.COMMENT_NODE,
+ Node.TEXT_NODE,
+ Node.CDATA_SECTION_NODE,
+ Node.ENTITY_REFERENCE_NODE,
+ ]
+
+ def __init__(self, ownerDocument, name):
+ #Note: the Entity's name is treated as nodeName
+ FtNode.__init__(self, ownerDocument)
+ self.__dict__['__nodeName'] = name
+
+ ### Helper Functions For Cloning ###
+
+ def _4dom_clone(self, owner):
+ return self.__class__(owner, self.nodeName)
+
+ def __getinitargs__(self):
+ return (self.ownerDocument,
+ self.nodeName
+ )
+
+ def __repr__(self):
+ return '<EntityReference Node at %x: %s>' % (
+ id(self),
+ repr(self.nodeName)
+ )
diff --git a/lib/jython/Lib/xml/dom/Event.py b/lib/jython/Lib/xml/dom/Event.py new file mode 100644 index 000000000..96f1f8518 --- /dev/null +++ b/lib/jython/Lib/xml/dom/Event.py @@ -0,0 +1,130 @@ +########################################################################
+#
+# File Name: Event.py
+#
+# Documentation: http://docs.4suite.com/4DOM/Event.py.html
+#
+"""
+Implements DOM level 2 Mutation Events
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+
+supportedEvents = [
+ "DOMSubtreeModified",
+ "DOMNodeInserted",
+ "DOMNodeRemoved",
+ "DOMNodeRemovedFromDocument",
+ "DOMNodeInsertedIntoDocument",
+ "DOMAttrModified",
+ "DOMCharacterDataModified"
+ ]
+
+#Event Exception code
+UNSPECIFIED_EVENT_TYPE_ERR = 0
+
+class EventException:
+ def __init__(self, code):
+ self.code = code
+
+
+class EventTarget:
+ """
+ """
+ def __init__(self):
+ self.listeners = {}
+ self.capture_listeners = {}
+ for etype in supportedEvents:
+ self.listeners[etype] = []
+ self.capture_listeners[etype] = []
+ return
+
+ def addEventListener(self, etype, listener, useCapture):
+ if useCapture:
+ if listener not in self.capture_listeners[etype]:
+ self.capture_listeners[etype].append(listener)
+ else:
+ if listener not in self.listeners[etype]:
+ self.listeners[etype].append(listener)
+
+ return
+
+ def removeEventListener(self, etype, listener, useCapture):
+ self.listeners[etype].remove(listener)
+ return
+
+ def dispatchEvent(self, evt):
+ # The actual work is done in the implementing class
+ # since EventTarget has no idea of the DOM hierarchy
+ pass
+
+
+class EventListener:
+ def __init__(self):
+ pass
+
+ def handleEvent(evt):
+ pass
+
+
+class Event:
+ CAPTURING_PHASE = 1
+ AT_TARGET = 2
+ BUBBLING_PHASE = 3
+
+ def __init__(self, eventType):
+ self.target = None
+ self.currentTarget = None
+ self.eventPhase = Event.CAPTURING_PHASE
+ self.type = eventType
+ self.timeStamp = 0
+ return
+
+ def stopPropagation(self):
+ self._4dom_propagate = 0
+
+ def preventDefault(self):
+ self._4dom_preventDefaultCalled = 1
+
+ def initEvent(self, eventTypeArg, canBubbleArg, cancelableArg):
+ self.type = eventTypeArg
+ self.bubbles = canBubbleArg
+ self.cancelable = cancelableArg
+ self._4dom_preventDefaultCalled = 0
+ self._4dom_propagate = 1
+ return
+
+
+class MutationEvent(Event):
+ #Whether or not the event bubbles
+ MODIFICATION = 1
+ ADDITION = 2
+ REMOVAL = 3
+ eventSpec = {
+ "DOMSubtreeModified": 1,
+ "DOMNodeInserted": 1,
+ "DOMNodeRemoved": 1,
+ "DOMNodeRemovedFromDocument": 0,
+ "DOMNodeInsertedIntoDocument": 0,
+ "DOMAttrModified": 1,
+ "DOMCharacterDataModified": 1
+ }
+
+ def __init__(self, eventType):
+ Event.__init__(self,eventType)
+ return
+
+ def initMutationEvent(self, eventTypeArg, canBubbleArg, cancelableArg,
+ relatedNodeArg, prevValueArg, newValueArg, attrNameArg):
+ Event.initEvent(self,eventTypeArg, canBubbleArg, cancelableArg)
+ # FIXME : make these attributes readonly
+ self.relatedNode = relatedNodeArg
+ self.prevValue = prevValueArg
+ self.newValue = newValueArg
+ self.attrName = attrNameArg
+ #No mutation events are cancelable
+ self.cancelable = 0
+ return
diff --git a/lib/jython/Lib/xml/dom/FtNode.py b/lib/jython/Lib/xml/dom/FtNode.py new file mode 100644 index 000000000..bb9905606 --- /dev/null +++ b/lib/jython/Lib/xml/dom/FtNode.py @@ -0,0 +1,447 @@ +########################################################################
+#
+# File Name: Node.py
+#
+# Documentation: http://docs.4suite.com/4DOM/Node.py.html
+#
+"""
+Implements the basic tree structure of DOM
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+from DOMImplementation import implementation
+import Event
+
+from xml.dom import Node
+from xml.dom import NoModificationAllowedErr
+from xml.dom import NamespaceErr
+from xml.dom import NotFoundErr
+from xml.dom import NotSupportedErr
+from xml.dom import HierarchyRequestErr
+from xml.dom import WrongDocumentErr
+from xml.dom import InvalidCharacterErr
+from xml.dom import UnspecifiedEventTypeErr
+from xml.dom import XML_NAMESPACE
+
+import re, copy
+#FIXME: should allow combining characters: fix when Python gets Unicode
+g_namePattern = re.compile(r'[a-zA-Z_:][\w\.\-_:]*\Z')
+g_pattPrefix = re.compile(r'[a-zA-Z_][\w\.\-_]*\Z')
+
+class FtNode(Event.EventTarget, Node):
+ """
+ Encapsulates the pieces that DOM builds on the basic tree structure,
+ Which is implemented by composition of TreeNode
+ """
+
+ nodeType = None
+
+ # Children that this node is allowed to have
+ _allowedChildren = []
+
+ def __init__(self,
+ ownerDocument,
+ namespaceURI=None,
+ prefix=None,
+ localName=None):
+ Event.EventTarget.__init__(self)
+ self.__dict__['__nodeName'] = None
+ self.__dict__['__nodeValue'] = None
+ self.__dict__['__parentNode'] = None
+ self.__dict__['__childNodes'] = None
+ self.__dict__['__previousSibling'] = None
+ self.__dict__['__nextSibling'] = None
+ self.__dict__['__attributes'] = None
+ self.__dict__['__ownerDocument'] = ownerDocument
+ self.__dict__['__namespaceURI'] = namespaceURI
+ self.__dict__['__prefix'] = prefix
+ self.__dict__['__localName'] = localName
+ self.__dict__['__childNodes'] = implementation._4dom_createNodeList([])
+ self.__dict__['__readOnly'] = 0
+
+ ### Attribute Access Methods -- Node.attr ###
+
+ def __getattr__(self, name):
+ attrFunc = self._readComputedAttrs.get(name)
+ if attrFunc:
+ return attrFunc(self)
+ else:
+ return getattr(FtNode, name)
+
+ def __setattr__(self, name, value):
+ #Make sure attribute is not read-only
+ if name in self.__class__._readOnlyAttrs:
+ raise NoModificationAllowedErr()
+ #If it's computed execute that function
+ attrFunc = self.__class__._writeComputedAttrs.get(name)
+ if attrFunc:
+ attrFunc(self, value)
+ #Otherwise, just set the attribute
+ else:
+ self.__dict__[name] = value
+
+ ### Attribute Methods -- Node._get_attr() ###
+
+ def _get_nodeName(self):
+ return self.__dict__['__nodeName']
+
+ def _get_nodeValue(self):
+ return self.__dict__['__nodeValue']
+
+ def _set_nodeValue(self,value):
+ self.__dict__['__nodeValue'] = value
+
+ def _get_nodeType(self):
+ return getattr(self.__class__, 'nodeType')
+
+ def _get_parentNode(self):
+ return self.__dict__['__parentNode']
+
+ def _get_childNodes(self):
+ return self.__dict__['__childNodes']
+
+ def _get_firstChild(self):
+ cn = self.__dict__['__childNodes']
+ return cn and cn[0] or None
+
+ def _get_lastChild(self):
+ cn = self.__dict__['__childNodes']
+ return cn and cn[-1] or None
+
+ def _get_previousSibling(self):
+ return self.__dict__['__previousSibling']
+
+ def _get_nextSibling(self):
+ return self.__dict__['__nextSibling']
+
+ def _get_ownerDocument(self):
+ return self.__dict__['__ownerDocument']
+
+ def _get_attributes(self):
+ return self.__dict__['__attributes']
+
+ def _get_namespaceURI(self):
+ return self.__dict__['__namespaceURI']
+
+ def _get_prefix(self):
+ return self.__dict__['__prefix']
+
+ def _set_prefix(self, value):
+ # Check for invalid characters
+ if not g_namePattern.match(value):
+ raise InvalidCharacterErr()
+ if (self.__dict__['__namespaceURI'] is None or
+ ':' in value or
+ (value == 'xml' and
+ self.__dict__['__namespaceURI'] != XML_NAMESPACE)):
+ raise NamespaceErr()
+ self.__dict__['__prefix'] = value
+ self.__dict__['__nodeName'] = '%s:%s' % (
+ value,
+ self.__dict__['__localName'])
+
+ def _get_localName(self):
+ return self.__dict__['__localName']
+
+ ### Methods ###
+
+ def insertBefore(self, newChild, refChild):
+ if refChild is None:
+ return self.appendChild(newChild)
+ elif newChild.nodeType == Node.DOCUMENT_FRAGMENT_NODE:
+ while newChild.firstChild:
+ self.insertBefore(newChild.firstChild, refChild)
+ else:
+ #Make sure the newChild is all it is cracked up to be
+ self._4dom_validateNode(newChild)
+
+ #Make sure the refChild is indeed our child
+ try:
+ index = self.__dict__['__childNodes'].index(refChild)
+ except:
+ raise NotFoundErr()
+
+ #Remove from old parent
+ if newChild.parentNode != None:
+ newChild.parentNode.removeChild(newChild);
+
+ #Insert it
+ self.__dict__['__childNodes'].insert(index, newChild)
+
+ #Update the child caches
+ newChild._4dom_setHierarchy(self, refChild.previousSibling, refChild)
+
+ newChild._4dom_fireMutationEvent('DOMNodeInserted',relatedNode=self)
+ self._4dom_fireMutationEvent('DOMSubtreeModified')
+ return newChild
+
+ def replaceChild(self, newChild, oldChild):
+ if newChild.nodeType == Node.DOCUMENT_FRAGMENT_NODE:
+ refChild = oldChild.nextSibling
+ self.removeChild(oldChild)
+ self.insertBefore(newChild, refChild)
+ else:
+ self._4dom_validateNode(newChild)
+ #Make sure the oldChild is indeed our child
+ try:
+ index = self.__dict__['__childNodes'].index(oldChild)
+ except:
+ raise NotFoundErr()
+
+ self.__dict__['__childNodes'][index] = newChild
+ if newChild.parentNode is not None:
+ newChild.parentNode.removeChild(newChild)
+
+ newChild._4dom_setHierarchy(self,
+ oldChild.previousSibling,
+ oldChild.nextSibling)
+
+ oldChild._4dom_fireMutationEvent('DOMNodeRemoved',relatedNode=self)
+ oldChild._4dom_setHierarchy(None, None, None)
+
+ newChild._4dom_fireMutationEvent('DOMNodeInserted',relatedNode=self)
+ self._4dom_fireMutationEvent('DOMSubtreeModified')
+ return oldChild
+
+ def removeChild(self, childNode):
+ #Make sure the childNode is indeed our child
+ #FIXME: more efficient using list.remove()
+ try:
+ self.__dict__['__childNodes'].remove(childNode)
+ except:
+ raise NotFoundErr()
+ childNode._4dom_fireMutationEvent('DOMNodeRemoved',relatedNode=self)
+ self._4dom_fireMutationEvent('DOMSubtreeModified')
+
+ # Adjust caches
+ prev = childNode.previousSibling
+ next = childNode.nextSibling
+ if prev:
+ prev.__dict__['__nextSibling'] = next
+ if next:
+ next.__dict__['__previousSibling'] = prev
+
+ childNode._4dom_setHierarchy(None, None, None)
+ return childNode
+
+ def appendChild(self, newChild):
+ if newChild.nodeType == Node.DOCUMENT_FRAGMENT_NODE:
+ while newChild.childNodes:
+ self.appendChild(newChild.childNodes[0])
+ else:
+ self._4dom_validateNode(newChild)
+ # Remove from old parent
+ if newChild.parentNode != None:
+ newChild.parentNode.removeChild(newChild);
+
+ last = self.lastChild
+ self.childNodes.append(newChild)
+ newChild._4dom_setHierarchy(self, last, None)
+
+ newChild._4dom_fireMutationEvent('DOMNodeInserted',relatedNode=self)
+ self._4dom_fireMutationEvent('DOMSubtreeModified')
+ return newChild
+
+ def hasChildNodes(self):
+ return self.__dict__['__childNodes'].length != 0
+
+ def cloneNode(self, deep, newOwner=None, readOnly=0):
+ # Get constructor values
+ clone = self._4dom_clone(newOwner or self.ownerDocument)
+
+ # Set when cloning EntRef children
+ readOnly and clone._4dom_setReadOnly(readOnly)
+
+ # Copy the child nodes if deep
+ if deep and self.nodeType != Node.ATTRIBUTE_NODE:
+ # Children of EntRefs are cloned readOnly
+ if self.nodeType == Node.ENTITY_REFERENCE_NODE:
+ readOnly = 1
+
+ for child in self.childNodes:
+ new_child = child.cloneNode(1, newOwner, readOnly)
+ clone.appendChild(new_child)
+
+ return clone
+
+ def normalize(self):
+ # This one needs to join all adjacent text nodes
+ node = self.firstChild
+ while node:
+ if node.nodeType == Node.TEXT_NODE:
+ next = node.nextSibling
+ while next and next.nodeType == Node.TEXT_NODE:
+ node.appendData(next.data)
+ node.parentNode.removeChild(next)
+ next = node.nextSibling
+ if not node.length:
+ # Remove any empty text nodes
+ node.parentNode.removeChild(node)
+ elif node.nodeType == Node.ELEMENT_NODE:
+ for attr in node.attributes:
+ attr.normalize()
+ node.normalize()
+ node = node.nextSibling
+
+ def supports(self, feature, version):
+ return implementation.hasFeature(feature,version)
+
+ #
+ # Event Target interface implementation
+ #
+ def dispatchEvent(self, evt):
+ if not evt.type:
+ raise UnspecifiedEventTypeErr()
+
+ # the list of my ancestors for capture or bubbling
+ # we are lazy, so we initialize this list only if required
+ if evt._4dom_propagate and \
+ (evt.eventPhase == evt.CAPTURING_PHASE or evt.bubbles):
+ ancestors = [self]
+ while ancestors[-1].parentNode :
+ ancestors.append(ancestors[-1].parentNode)
+
+ # event capture
+ if evt._4dom_propagate and evt.eventPhase == evt.CAPTURING_PHASE :
+ ancestors.reverse()
+ for a in ancestors[:-1]:
+ evt.currentTarget = a
+ for captor in a.capture_listeners[evt.type]:
+ captor.handleEvent(evt)
+ if not evt._4dom_propagate:
+ break
+ # let's put back the list in the right order
+ # and move on to the next phase
+ ancestors.reverse()
+ evt.eventPhase = evt.AT_TARGET
+
+
+ # event handling by the target
+ if evt._4dom_propagate and evt.eventPhase == evt.AT_TARGET :
+ evt.currentTarget = self
+ for listener in self.listeners[evt.type]:
+ listener.handleEvent(evt)
+ # prepare for the next phase, if necessary
+ if evt.bubbles:
+ evt.eventPhase = evt.BUBBLING_PHASE
+
+ # event bubbling
+ if evt._4dom_propagate and evt.eventPhase == evt.BUBBLING_PHASE :
+ for a in ancestors[1:]:
+ evt.currentTarget = a
+ for listener in a.listeners[evt.type]:
+ listener.handleEvent(evt)
+ if not evt._4dom_propagate:
+ break
+
+ return evt._4dom_preventDefaultCalled
+
+
+ ### Unsupported, undocumented DOM Level 3 methods ###
+ ### documented in the Python binding ###
+
+ def isSameNode(self, other):
+ return self == other
+
+ ### Internal Methods ###
+
+ #Functions not defined in the standard
+ #All are fourthought internal functions
+ #and should only be called by you if you specifically
+ #don't want your program to run :)
+
+ def _4dom_setattr(self, name, value):
+ self.__dict__[name] = value
+
+ def _4dom_fireMutationEvent(self,eventType,target=None,
+ relatedNode=None,prevValue=None,
+ newValue=None,attrName=None,attrChange=None):
+ if self.supports('MutationEvents', 2.0):
+ evt = self.ownerDocument.createEvent(eventType)
+ evt.target = target or self
+ evt.initMutationEvent(eventType,evt.eventSpec[eventType],0,
+ relatedNode,prevValue,newValue,attrName)
+ evt.attrChange = attrChange
+ evt.target.dispatchEvent(evt)
+
+ def _4dom_validateNode(self, newNode):
+ if not newNode.nodeType in self.__class__._allowedChildren:
+ raise HierarchyRequestErr()
+ if self.ownerDocument != newNode.ownerDocument:
+ raise WrongDocumentErr()
+
+ def _4dom_setHierarchy(self, parent, previous, next):
+ self.__dict__['__parentNode'] = parent
+ if previous:
+ previous.__dict__['__nextSibling'] = self
+ self.__dict__['__previousSibling'] = previous
+ self.__dict__['__nextSibling'] = next
+ if next:
+ next.__dict__['__previousSibling'] = self
+ return
+
+ def _4dom_setParentNode(self, parent):
+ self.__dict__['__parentNode'] = parent
+
+ def _4dom_setNextSibling(self,next):
+ self.__dict__['__nextSibling'] = next
+
+ def _4dom_setPreviousSibling(self,prev):
+ self.__dict__['__previousSibling'] = prev
+
+ def _4dom_setOwnerDocument(self, owner):
+ self.__dict__['__ownerDocument'] = owner
+
+ def _4dom_setReadOnly(self, flag):
+ self.__dict__['__readOnly'] = flag
+
+ ### Helper Functions For Cloning ###
+
+ def _4dom_clone(self, owner):
+ raise NotSupportedErr('Subclass must override')
+
+ def __getinitargs__(self):
+ return (self.__dict__['__ownerDocument'],
+ self.__dict__['__namespaceURI'],
+ self.__dict__['__prefix'],
+ self.__dict__['__localName']
+ )
+
+ def __getstate__(self):
+ return self.__dict__['__childNodes']
+
+ def __setstate__(self, children):
+ self.__dict__['__childNodes'].extend(list(children))
+ prev = None
+ for child in children:
+ child._4dom_setHierarchy(self, prev, None)
+ prev = child
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = {'nodeName':_get_nodeName,
+ 'nodeValue':_get_nodeValue,
+ 'nodeType':_get_nodeType,
+ 'parentNode':_get_parentNode,
+ 'childNodes':_get_childNodes,
+ 'firstChild':_get_firstChild,
+ 'lastChild':_get_lastChild,
+ 'previousSibling':_get_previousSibling,
+ 'nextSibling':_get_nextSibling,
+ 'attributes':_get_attributes,
+ 'ownerDocument':_get_ownerDocument,
+ 'namespaceURI':_get_namespaceURI,
+ 'prefix':_get_prefix,
+ 'localName':_get_localName
+ }
+
+ _writeComputedAttrs = {'nodeValue':_set_nodeValue,
+ 'prefix':_set_prefix
+ }
+
+ # Create the read-only list of attributes
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/MessageSource.py b/lib/jython/Lib/xml/dom/MessageSource.py new file mode 100644 index 000000000..f4ca4fb3b --- /dev/null +++ b/lib/jython/Lib/xml/dom/MessageSource.py @@ -0,0 +1,55 @@ +# DOMException
+from xml.dom import INDEX_SIZE_ERR, DOMSTRING_SIZE_ERR , HIERARCHY_REQUEST_ERR
+from xml.dom import WRONG_DOCUMENT_ERR, INVALID_CHARACTER_ERR, NO_DATA_ALLOWED_ERR
+from xml.dom import NO_MODIFICATION_ALLOWED_ERR, NOT_FOUND_ERR, NOT_SUPPORTED_ERR
+from xml.dom import INUSE_ATTRIBUTE_ERR, INVALID_STATE_ERR, SYNTAX_ERR
+from xml.dom import INVALID_MODIFICATION_ERR, NAMESPACE_ERR, INVALID_ACCESS_ERR
+
+# EventException
+from xml.dom import UNSPECIFIED_EVENT_TYPE_ERR
+
+#Range Exceptions
+from xml.dom import BAD_BOUNDARYPOINTS_ERR
+from xml.dom import INVALID_NODE_TYPE_ERR
+
+# Fourthought Exceptions
+from xml.dom import XML_PARSE_ERR
+
+try:
+ import os, gettext
+ locale_dir = os.path.split(__file__)[0]
+ gettext.install('4Suite', locale_dir)
+except (ImportError, AttributeError, IOError):
+ def _(msg):
+ return msg
+
+DOMExceptionStrings = {
+ INDEX_SIZE_ERR: _("Index error accessing NodeList or NamedNodeMap"),
+ DOMSTRING_SIZE_ERR: _("DOMString exceeds maximum size"),
+ HIERARCHY_REQUEST_ERR: _("Node manipulation results in invalid parent/child relationship."),
+ WRONG_DOCUMENT_ERR: _("Node is from a different document"),
+ INVALID_CHARACTER_ERR: _("Invalid or illegal character"),
+ NO_DATA_ALLOWED_ERR: _("Node does not support data"),
+ NO_MODIFICATION_ALLOWED_ERR: _("Attempt to modify a read-only object"),
+ NOT_FOUND_ERR: _("Node does not exist in this context"),
+ NOT_SUPPORTED_ERR: _("Object or operation not supported"),
+ INUSE_ATTRIBUTE_ERR: _("Attribute already in use by an element"),
+ INVALID_STATE_ERR: _("Object is not, or is no longer, usable"),
+ SYNTAX_ERR: _("Specified string is invalid or illegal"),
+ INVALID_MODIFICATION_ERR: _("Attempt to modify the type of a node"),
+ NAMESPACE_ERR: _("Invalid or illegal namespace operation"),
+ INVALID_ACCESS_ERR: _("Object does not support this operation or parameter"),
+ }
+
+EventExceptionStrings = {
+ UNSPECIFIED_EVENT_TYPE_ERR : _("Uninitialized type in Event object"),
+ }
+
+FtExceptionStrings = {
+ XML_PARSE_ERR : _("XML parse error at line %d, column %d: %s"),
+ }
+
+RangeExceptionStrings = {
+ BAD_BOUNDARYPOINTS_ERR : _("Invalid Boundary Points specified for Range"),
+ INVALID_NODE_TYPE_ERR : _("Invalid Container Node")
+ }
diff --git a/lib/jython/Lib/xml/dom/NamedNodeMap.py b/lib/jython/Lib/xml/dom/NamedNodeMap.py new file mode 100644 index 000000000..a2442e6d0 --- /dev/null +++ b/lib/jython/Lib/xml/dom/NamedNodeMap.py @@ -0,0 +1,149 @@ +########################################################################
+#
+# File Name: NamedNodeMap.py
+#
+# Documentation: http://docs.4suite.com/4DOM/NamedNodeMap.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import UserDict
+
+class _NamedNodeMapIter:
+ """Iterator class for Python 2.2. The iterator function
+ is .next, the stop-iterator element is the iterator itself."""
+ def __init__(self,map):
+ self.pos = 0
+ self.map = map
+
+ def next(self):
+ try:
+ res = self.map[self.pos]
+ self.pos = self.pos + 1
+ return res
+ except IndexError:
+ return self
+
+from xml.dom import Node
+from xml.dom import NoModificationAllowedErr
+from xml.dom import NotFoundErr
+from xml.dom import NotSupportedErr
+from xml.dom import WrongDocumentErr
+from xml.dom import InuseAttributeErr
+
+class NamedNodeMap(UserDict.UserDict):
+ def __init__(self, ownerDoc=None):
+ UserDict.UserDict.__init__(self)
+ self._ownerDocument = ownerDoc
+ self._positions = []
+
+ ### Attribute Access Methods ###
+
+ def __getattr__(self, name):
+ if name == 'length':
+ return len(self)
+ return getattr(NamedNodeMap, name)
+
+ def __setattr__(self, name, value):
+ if name == 'length':
+ raise NoModificationAllowedErr()
+ self.__dict__[name] = value
+
+ ### Attribute Methods ###
+
+ def _get_length(self):
+ return len(self)
+
+ ### Methods ###
+
+ def item(self, index):
+ if 0 <= index < len(self):
+ return self[self._positions[int(index)]]
+ return None
+
+ def getNamedItem(self, name):
+ return self.get(name)
+
+ def removeNamedItem(self, name):
+ old = self.get(name)
+ if not old:
+ raise NotFoundErr()
+ del self[name]
+ self._positions.remove(name)
+ return old
+
+ def setNamedItem(self, arg):
+ if self._ownerDocument != arg.ownerDocument:
+ raise WrongDocumentErr()
+ if arg.nodeType == Node.ATTRIBUTE_NODE and arg.ownerElement != None:
+ raise InuseAttributeErr()
+ name = arg.nodeName
+ retval = self.get(name)
+ UserDict.UserDict.__setitem__(self, name, arg)
+ if not retval:
+ self._positions.append(name)
+ return retval
+
+ def getNamedItemNS(self, namespaceURI, localName):
+ return self.get((namespaceURI, localName))
+
+ def setNamedItemNS(self, arg):
+ if self._ownerDocument != arg.ownerDocument:
+ raise WrongDocumentErr()
+ if arg.nodeType == Node.ATTRIBUTE_NODE and arg.ownerElement != None:
+ raise InuseAttributeErr()
+ name = (arg.namespaceURI, arg.localName)
+ retval = self.get(name)
+ UserDict.UserDict.__setitem__(self, name, arg)
+ if not retval:
+ self._positions.append(name)
+ return retval
+
+ def removeNamedItemNS(self, namespaceURI, localName):
+ name = (namespaceURI, localName)
+ old = self.get(name)
+ if not old:
+ raise NotFoundErr()
+ del self[name]
+ self._positions.remove(name)
+ return old
+
+ ### Overridden Methods ###
+
+ def __getitem__(self, index):
+ if type(index) == type(0):
+ index = self._positions[index]
+ return UserDict.UserDict.__getitem__(self, index)
+
+ def __setitem__(self, index, item):
+ raise NotSupportedErr()
+
+ def __iter__(self):
+ i = _NamedNodeMapIter(self)
+ return iter(i.next, i)
+
+ def __repr__(self):
+ st = "<NamedNodeMap at %x: {" % (id(self))
+ for k in self.keys():
+ st = st + repr(k) + ': ' + repr(self[k]) + ', '
+ if len(self):
+ st = st[:-2]
+ return st + '}>'
+
+ ### Internal Methods ###
+
+ def _4dom_setOwnerDocument(self, newOwner):
+ self._ownerDocument = newOwner
+
+ def _4dom_clone(self, owner):
+ nnm = self.__class__(owner)
+ for item in self:
+ if item.localName:
+ nnm.setNamedItemNS(item._4dom_clone(owner))
+ else:
+ nnm.setNamedItem(item._4dom_clone(owner))
+ return nnm
diff --git a/lib/jython/Lib/xml/dom/NodeFilter.py b/lib/jython/Lib/xml/dom/NodeFilter.py new file mode 100644 index 000000000..3ae225b4d --- /dev/null +++ b/lib/jython/Lib/xml/dom/NodeFilter.py @@ -0,0 +1,38 @@ +########################################################################
+#
+# File Name: NodeFilter.py
+#
+# Documentation: http://docs.4suite.com/4DOM/NodeFilter.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+class NodeFilter:
+ """
+ This class is really just an abstract base.
+ All implementation must be provided in a derived class
+ """
+ FILTER_ACCEPT = 1
+ FILTER_REJECT = 2
+ FILTER_SKIP = 3
+
+ SHOW_ALL = 0xFFFFFFFF
+ SHOW_ELEMENT = 0x00000001
+ SHOW_ATTRIBUTE = 0x00000002
+ SHOW_TEXT = 0x00000004
+ SHOW_CDATA_SECTION = 0x00000008
+ SHOW_ENTITY_REFERENCE = 0x00000010
+ SHOW_ENTITY = 0x00000020
+ SHOW_PROCESSING_INSTRUCTION = 0x00000040
+ SHOW_COMMENT = 0x00000080
+ SHOW_DOCUMENT = 0x00000100
+ SHOW_DOCUMENT_TYPE = 0x00000200
+ SHOW_DOCUMENT_FRAGMENT = 0x00000400
+ SHOW_NOTATION = 0x00000800
+
+ def acceptNode(self, node):
+ raise TypeError("Please define and use a subclass.")
diff --git a/lib/jython/Lib/xml/dom/NodeIterator.py b/lib/jython/Lib/xml/dom/NodeIterator.py new file mode 100644 index 000000000..bd87ed19b --- /dev/null +++ b/lib/jython/Lib/xml/dom/NodeIterator.py @@ -0,0 +1,129 @@ +########################################################################
+#
+# File Name: NodeIterator.py
+#
+# Documentation: http://docs.4suite.com/4DOM/NodeIterator.py.html
+#
+"""
+Node Iterators from DOM Level 2. Allows "flat" iteration over nodes.
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+from NodeFilter import NodeFilter
+
+from xml.dom import NoModificationAllowedErr
+from xml.dom import InvalidStateErr
+
+class NodeIterator:
+
+ def __init__(self, root, whatToShow, filter, expandEntityReferences):
+ self.__dict__['root'] = root
+ self.__dict__['filter'] = filter
+ self.__dict__['expandEntityReferences'] = expandEntityReferences
+ self.__dict__['whatToShow'] = whatToShow
+ self.__dict__['_atStart'] = 1
+ self.__dict__['_atEnd'] = 0
+ self.__dict__['_current'] = root
+ self.__dict__['_nodeStack'] = []
+ self.__dict__['_detached'] = 0
+
+ def __setattr__(self, name, value):
+ if name in ['root', 'filter', 'expandEntityReferences', 'whatToShow']:
+ raise NoModificationAllowedErr()
+ self.__dict__[name] = value
+
+ def _get_root(self):
+ return self.root
+
+ def _get_filter(self):
+ return self.filter
+
+ def _get_expandEntityReferences(self):
+ return self.expandEntityReferences
+
+ def _get_whatToShow(self):
+ return self.whatToShow
+
+ def nextNode(self):
+ if self._detached:
+ raise InvalidStateErr()
+ next_node = self._advance()
+ while (next_node and not (
+ self._checkWhatToShow(next_node) and
+ self._checkFilter(next_node) == NodeFilter.FILTER_ACCEPT)):
+ next_node = self._advance()
+ return next_node
+
+ def previousNode(self):
+ if self._detached:
+ raise InvalidStateErr()
+ prev_node = self._regress()
+ while (prev_node and not (
+ self._checkWhatToShow(prev_node) and
+ self._checkFilter(prev_node) == NodeFilter.FILTER_ACCEPT)):
+ prev_node = self._regress()
+ return prev_node
+
+ def detach(self):
+ self._detached = 1
+
+ def _advance(self):
+ node = None
+ if self._atStart:
+ # First time through
+ self._atStart = 0
+ node = self._current
+ elif not self._atEnd:
+ current = self._current
+ if current.firstChild:
+ # Do children first
+ node = current.firstChild
+ else:
+ # Now try the siblings
+ while current is not self.root:
+ if current.nextSibling:
+ node = current.nextSibling
+ break
+ # We are at the end of a branch, starting going back up
+ current = current.parentNode
+ else:
+ node = None
+ if node:
+ self._current = node
+ else:
+ self._atEnd = 1
+ return node
+
+ def _regress(self):
+ node = None
+ if self._atEnd:
+ self._atEnd = 0
+ node = self._current
+ elif not self._atStart:
+ current = self._current
+ if current is self.root:
+ node = None
+ elif current.previousSibling:
+ node = current.previousSibling
+ if node.lastChild:
+ node = node.lastChild
+ else:
+ node = current.parentNode
+ if node:
+ self._current = node
+ else:
+ self._atStart = 1
+ return node
+
+ def _checkWhatToShow(self, node):
+ show_bit = 1 << (node.nodeType - 1)
+ return self.whatToShow & show_bit
+
+ def _checkFilter(self, node):
+ if self.filter:
+ return self.filter.acceptNode(node)
+ else:
+ return NodeFilter.FILTER_ACCEPT
diff --git a/lib/jython/Lib/xml/dom/NodeList.py b/lib/jython/Lib/xml/dom/NodeList.py new file mode 100644 index 000000000..c7027981e --- /dev/null +++ b/lib/jython/Lib/xml/dom/NodeList.py @@ -0,0 +1,60 @@ +########################################################################
+#
+# File Name: NodeList.py
+#
+# Documentation: http://docs.4suite.com/4DOM/NodeList.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import UserList
+
+from xml.dom import NoModificationAllowedErr
+
+class NodeList(UserList.UserList):
+ def __init__(self, list=None):
+ UserList.UserList.__init__(self, list)
+ return
+
+ ### Attribute Access Methods ###
+
+ def __getattr__(self, name):
+ if name == 'length':
+ return len(self)
+ #Pass-through
+ return getattr(NodeList, name)
+
+ def __setattr__(self, name, value):
+ if name == 'length':
+ raise NoModificationAllowedErr()
+ #Pass-through
+ self.__dict__[name] = value
+
+ ### Attribute Methods ###
+
+ def _get_length(self):
+ return len(self)
+
+ ### Methods ###
+
+ def item(self, index):
+ if 0 <= index < len(self):
+ return self[int(index)]
+ return None
+
+ #Not defined in the standard
+ def contains(self, node):
+ return node in self
+
+ def __repr__(self):
+ st = "<NodeList at %x: [" % id(self)
+ if len(self):
+ for i in self[:-1]:
+ st = st + repr(i) + ', '
+ st = st + repr(self[-1])
+ st = st + ']>'
+ return st
diff --git a/lib/jython/Lib/xml/dom/Notation.py b/lib/jython/Lib/xml/dom/Notation.py new file mode 100644 index 000000000..699cfad7f --- /dev/null +++ b/lib/jython/Lib/xml/dom/Notation.py @@ -0,0 +1,71 @@ +########################################################################
+#
+# File Name: Notation.py
+#
+# Documentation: http://docs.4suite.org/4DOM/Notation.py.html
+#
+"""
+Implementation of DOM Level 2 Notation interface
+WWW: http://4suite.org/4DOM e-mail: support@4suite.org
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.org/COPYRIGHT for license and copyright information
+"""
+
+from xml.dom import Node
+from FtNode import FtNode
+
+class Notation(FtNode):
+ nodeType = Node.NOTATION_NODE
+
+ def __init__(self, ownerDocument, publicId, systemId, name):
+ FtNode.__init__(self, ownerDocument)
+ self.__dict__['__nodeName'] = name
+ self.__dict__['publicId'] = publicId
+ self.__dict__['systemId'] = systemId
+
+ ### Attribute Methods ###
+
+ def _get_systemId(self):
+ return self.systemId
+
+ def _get_publicId(self):
+ return self.publicId
+
+ ### Overridden Methods ###
+
+ def __repr__(self):
+ return '<Notation Node at %x: PublicId="%s" SystemId="%s" Name="%s">' % (
+ id(self),
+ self.publicId,
+ self.systemId,
+ self.nodeName)
+
+ ### Helper Functions For Cloning ###
+
+ def _4dom_clone(self, owner):
+ return self.__class__(owner,
+ self.publicId,
+ self.systemId,
+ self.nodeName)
+
+ def __getinitargs__(self):
+ return (self.ownerDocument,
+ self.publicId,
+ self.systemId,
+ self.nodeName
+ )
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = FtNode._readComputedAttrs.copy()
+ _readComputedAttrs.update({'publicId':_get_publicId,
+ 'systemId':_get_systemId
+ })
+
+
+ _writeComputedAttrs = FtNode._writeComputedAttrs.copy()
+
+ # Create the read-only list of attributes
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ FtNode._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/ProcessingInstruction.py b/lib/jython/Lib/xml/dom/ProcessingInstruction.py new file mode 100644 index 000000000..9b7f91d96 --- /dev/null +++ b/lib/jython/Lib/xml/dom/ProcessingInstruction.py @@ -0,0 +1,71 @@ +########################################################################
+#
+# File Name: ProcessingInstruction.py
+#
+# Documentation: http://docs.4suite.com/4DOM/ProcessingInstruction.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+from xml.dom import Node
+from FtNode import FtNode
+
+class ProcessingInstruction(FtNode):
+ nodeType = Node.PROCESSING_INSTRUCTION_NODE
+
+ def __init__(self,ownerDocument,target,data):
+ FtNode.__init__(self,ownerDocument,'','','')
+ self.__dict__['__nodeName'] = target
+ self.__dict__['__nodeValue'] = data
+
+ def _get_target(self):
+ return self.__dict__['__nodeName']
+
+ def _get_data(self):
+ return self.__dict__['__nodeValue']
+
+ def _set_data(self, newData):
+ self.__dict__['__nodeValue'] = newData
+
+ ### Overridden Methods ###
+
+ def __repr__(self):
+ data = self.data
+ if len(data) > 20:
+ data = data[20:] + '...'
+ return "<ProcessingInstruction at %x: target='%s' data='%s'>" % (
+ id(self),
+ self.target,
+ data
+ )
+
+ ### Helper Functions For Cloning ###
+
+ def _4dom_clone(self, owner):
+ return self.__class__(owner, self.target, self.data)
+
+ def __getinitargs__(self):
+ return (self.ownerDocument,
+ self.target,
+ self.data
+ )
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = FtNode._readComputedAttrs.copy()
+ _readComputedAttrs.update({'target':_get_target,
+ 'data':_get_data
+ })
+
+
+ _writeComputedAttrs = FtNode._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({'data':_set_data
+ })
+
+ # Create the read-only list of attributes
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ FtNode._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/Range.py b/lib/jython/Lib/xml/dom/Range.py new file mode 100644 index 000000000..0b7a2802e --- /dev/null +++ b/lib/jython/Lib/xml/dom/Range.py @@ -0,0 +1,1099 @@ +########################################################################
+#
+# File Name: Range.py
+#
+# Documentation: http://docs.4suite.com/4DOM/Range.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+
+from xml.dom import InvalidStateErr
+from xml.dom import InvalidNodeTypeErr
+from xml.dom import BadBoundaryPointsErr
+from xml.dom import IndexSizeErr
+from xml.dom import WrongDocumentErr
+
+from xml.dom import Node
+
+
+class Range:
+ readOnly =['startContainer',
+ 'startOffset',
+ 'endContainer',
+ 'endOffset',
+ 'collapsed',
+ 'commonAncestorContainer',
+ ]
+
+ POSITION_EQUAL = 1
+ POSITION_LESS_THAN = 2
+ POSITION_GREATER_THAN = 3
+
+ START_TO_START = 0
+ START_TO_END = 1
+ END_TO_END = 2
+ END_TO_START = 3
+
+ def __init__(self,ownerDocument):
+ self._ownerDocument = ownerDocument
+
+ self.__dict__['startContainer'] = ownerDocument
+ self.__dict__['startOffset'] = 0
+ self.__dict__['endContainer'] = ownerDocument
+ self.__dict__['endOffset'] = 0
+ self.__dict__['collapsed'] = 1
+ self.__dict__['commonAncestorContainer'] = ownerDocument
+
+ self.__dict__['detached'] = 0
+
+
+
+ def __setattr__(self,name,value):
+ if name in self.readOnly:
+ raise AttributeError, name
+ self.__dict__[name] = value
+
+ def __getattr__(self,name):
+ if name in self.readOnly:
+ #Means we are detached
+ raise InvalidStateErr()
+ raise AttributeError, name
+
+
+
+
+
+ def cloneContents(self):
+ """Clone the contents defined by this range"""
+
+ if self.detached:
+ raise InvalidStateErr()
+
+ df = self._ownerDocument.createDocumentFragment()
+
+ if self.startContainer == self.endContainer:
+ if self.startOffset == self.endOffset:
+ return df
+ if self.startContainer.nodeType in [Node.TEXT_NODE,
+ Node.COMMENT_NODE,
+ Node.PROCESSING_INSTRUCTION_NODE]:
+ #Adjust the character data
+ data = self.startContainer.substringData(self.startOffset,1+self.endOffset-self.startOffset)
+ tx = self._ownerDocument.createTextNode(data)
+ df.appendChild(tx)
+
+ else:
+ #Clone a set number of children
+ numDel = self.endOffset - self.startOffset+1
+ for ctr in range(numDel):
+ c = self.startContainer.childNodes[self.startOffset+ctr].cloneNode(1)
+ df.appendChild(c)
+
+ elif self.startContainer == self.commonAncestorContainer:
+ #Clone up the endContainer
+ #From the start to the end
+ lastKids = []
+ copyData = None
+ if self.endContainer.nodeType in [Node.TEXT_NODE,
+ Node.COMMENT_NODE,
+ Node.PROCESSING_INSTRUCTION_NODE]:
+ #Adjust the character data
+ copyData = self.endContainer.substringData(0,self.endOffset)
+ else:
+ numDel = self.endOffset
+ for ctr in range(numDel):
+ lastKids.append(self.endContainer.childNodes[ctr].cloneNode(1))
+
+ cur = self.endContainer
+ while cur.parentNode != self.commonAncestorContainer:
+
+ #Clone all of the way up
+ newCur = cur.cloneNode(0)
+ if copyData:
+ newCur.data = copyData
+ copyData = None
+ for k in lastKids:
+ newCur.appendChild(k)
+
+ lastKids = []
+ index = cur.parentNode.childNodes.index(cur)
+ for ctr in range(index):
+ lastKids.append(cur.parentNode.childNodes[ctr].cloneNode(1))
+ lastKids.append(newCur)
+ cur = cur.parentNode
+
+ newEnd = cur.cloneNode(0)
+ for k in lastKids:
+ newEnd.appendChild(k)
+
+ endAncestorChild = cur
+
+ #Extract up to the ancestor of end
+ for c in self.startContainer.childNodes:
+ if c == endAncestorChild:
+ break
+ df.appendChild(c.cloneNode(1))
+ df.appendChild(newEnd)
+
+ elif self.endContainer == self.commonAncestorContainer:
+ lastKids = []
+ copyData = None
+ if self.startContainer.nodeType in [Node.TEXT_NODE,
+ Node.COMMENT_NODE,
+ Node.PROCESSING_INSTRUCTION_NODE]:
+ #Adjust the character data
+
+ copyData = self.startContainer.substringData(self.startOffset,1+len(self.startContainer.data)-self.startOffset)
+ else:
+ numDel = len(self.startContainer.childNodes) - self.startOffset
+ for ctr in range(numDel):
+ c = self.startContainer.childNodes[self.startOffset+ctr].cloneNode(1)
+ lastKids.append(c)
+
+ cur = self.startContainer
+ while cur.parentNode != self.commonAncestorContainer:
+ #Clone all of the way up
+ newCur = cur.cloneNode(0)
+ if copyData:
+ newCur.data = copyData
+ copyData = None
+ for k in lastKids:
+ newCur.appendChild(k)
+ lastKids = [newCur]
+
+ index = cur.parentNode.childNodes.index(cur)
+ for ctr in range(index+1,len(cur.parentNode.childNodes)):
+ lastKids.append(cur.parentNode.childNodes[ctr].cloneNode(1))
+ cur = cur.parentNode
+
+ startAncestorChild = cur
+ newStart = cur.cloneNode(0)
+ for k in lastKids:
+ newStart.appendChild(k)
+
+ df.appendChild(newStart)
+
+
+ #Extract up to the ancestor of start
+ startAncestorChild = cur
+ startIndex = self.endContainer.childNodes.index(cur)
+ lastAdded = None
+ for ctr in range(startIndex+1,self.endOffset+1):
+ c = self.endContainer.childNodes[ctr].cloneNode(1)
+ df.insertBefore(c,lastAdded)
+ lastAdded = c
+
+ else:
+ #From the start to the end
+ lastStartKids = []
+ startCopyData = None
+ if self.startContainer.nodeType in [Node.TEXT_NODE,
+ Node.COMMENT_NODE,
+ Node.PROCESSING_INSTRUCTION_NODE]:
+ #Adjust the character data
+
+ startCopyData = self.startContainer.substringData(self.startOffset,1+len(self.startContainer.data)-self.startOffset)
+ else:
+ numDel = len(self.startContainer.childNodes) - self.startOffset
+ for ctr in range(numDel):
+ c = self.startContainer.childNodes[self.startOffset+ctr].cloneNode(1)
+ lastStartKids.append(c)
+
+ cur = self.startContainer
+ while cur.parentNode != self.commonAncestorContainer:
+ #Clone all of the way up
+ newCur = cur.cloneNode(0)
+ if startCopyData:
+ newCur.data = startCopyData
+ startCopyData = None
+ for k in lastStartKids:
+ newCur.appendChild(k)
+ lastStartKids = [newCur]
+
+
+ index = cur.parentNode.childNodes.index(cur)
+ for ctr in range(index+1,len(cur.parentNode.childNodes)):
+ lastStartKids.append(cur.parentNode.childNodes[ctr].cloneNode(1))
+ cur = cur.parentNode
+
+ startAncestorChild = cur
+
+ newStart = cur.cloneNode(0)
+ for k in lastStartKids:
+ newStart.appendChild(k)
+
+ df.appendChild(newStart)
+
+
+ lastEndKids = []
+ endCopyData = None
+ #Delete up the endContainer
+ #From the start to the end
+ if self.endContainer.nodeType in [Node.TEXT_NODE,
+ Node.COMMENT_NODE,
+ Node.PROCESSING_INSTRUCTION_NODE]:
+ #Adjust the character data
+ endCopyData = self.endContainer.substringData(0,self.endOffset)
+ else:
+ numDel = self.endOffset
+ for ctr in range(numDel):
+ c = self.endContainer.childNodes[ctr].cloneNode(1)
+ lastEndKids.append(c)
+
+ cur = self.endContainer
+ while cur.parentNode != self.commonAncestorContainer:
+ newCur = cur.cloneNode(0)
+ if endCopyData:
+ newCur.data = endCopyData
+ endCopyData = None
+ for k in lastEndKids:
+ newCur.appendChild(k)
+
+ lastEndKids = []
+ index = cur.parentNode.childNodes.index(cur)
+ for ctr in range(index):
+ lastEndKids.append(cur.parentNode.childNodes[ctr].cloneNode(1))
+ lastEndKids.append(newCur)
+ cur = cur.parentNode
+
+ endAncestorChild = cur
+
+ newEnd = cur.cloneNode(0)
+ for k in lastEndKids:
+ newEnd.appendChild(k)
+
+
+ cur = startAncestorChild
+ #Extract everything between us
+ startIndex = startAncestorChild.parentNode.childNodes.index(startAncestorChild)
+ endIndex = endAncestorChild.parentNode.childNodes.index(endAncestorChild)
+ for ctr in range(startIndex+1,endIndex):
+ c = startAncestorChild.parentNode.childNodes[ctr]
+ df.appendChild(c.cloneNode(1))
+ df.appendChild(newEnd)
+
+
+ #Adjust the containers
+ #FIXME What the heck is the spec talking about??
+ self.__dict__['endContainer'] = self.startContainer
+ self.__dict__['endOffset'] = self.startContainer
+ self.__dict__['commonAncestorContainer'] = self.startContainer
+ self.__dict__['collapsed'] = 1
+
+
+
+ return df
+
+
+ def cloneRange(self):
+ if self.detached:
+ raise InvalidStateErr()
+
+ newRange = Range(self._ownerDocument)
+ newRange.setStart(self.startContainer,self.startOffset)
+ newRange.setEnd(self.endContainer,self.endOffset)
+ return newRange
+
+ def collapse(self,toStart):
+ """Collapse the range"""
+ if self.detached:
+ raise InvalidStateErr()
+
+ if toStart:
+ self.__dict__['endContainer'] = self.startContainer
+ self.__dict__['endOffset'] = self.startOffset
+ else:
+ self.__dict__['startContainer'] = self.endContainer
+ self.__dict__['startOffset'] = self.endOffset
+
+ self.__dict__['collapsed'] = 1
+ self.__dict__['commonAncestorContainer'] = self.startContainer
+
+
+ def compareBoundaryPoints(self,how,sourceRange):
+ if self.detached:
+ raise InvalidStateErr()
+
+ if not hasattr(sourceRange,'_ownerDocument') or sourceRange._ownerDocument != self._ownerDocument or not isinstance(sourceRange,Range):
+ raise WrongDocumentErr()
+
+ if how == self.START_TO_START:
+ ac = self.startContainer
+ ao = self.startOffset
+ bc = sourceRange.startContainer
+ bo = sourceRange.startOffset
+ elif how == self.START_TO_END:
+ ac = self.startContainer
+ ao = self.startOffset
+ bc = sourceRange.endContainer
+ bo = sourceRange.endOffset
+ elif how == self.END_TO_END:
+ ac = self.endContainer
+ ao = self.endOffset
+ bc = sourceRange.endContainer
+ bo = sourceRange.endOffset
+ elif how == self.END_TO_START:
+ ac = self.endContainer
+ ao = self.endOffset
+ bc = sourceRange.startContainer
+ bo = sourceRange.startOffset
+ else:
+ raise TypeError, how
+
+ pos = self.__comparePositions(ac,ao,bc,bo)
+ if pos == self.POSITION_EQUAL:
+ return 0
+ elif pos == self.POSITION_LESS_THAN:
+ return -1
+ return 1
+
+ def deleteContents(self):
+ """Delete the contents defined by this range"""
+
+
+ #NOTE Use 4DOM ReleaseNode cause it is interface safe
+ from xml.dom.ext import ReleaseNode
+
+ if self.detached:
+ raise InvalidStateErr()
+
+ if self.startContainer == self.endContainer:
+ if self.startOffset == self.endOffset:
+ return
+ if self.startContainer.nodeType in [Node.TEXT_NODE,
+ Node.COMMENT_NODE,
+ Node.PROCESSING_INSTRUCTION_NODE]:
+ #Adjust the character data
+ self.startContainer.deleteData(self.startOffset,1+self.endOffset-self.startOffset)
+
+ else:
+ #Delete a set number of children
+ numDel = self.endOffset - self.startOffset+1
+ for ctr in range(numDel):
+ c = self.startContainer.removeChild(self.startContainer.childNodes[self.startOffset])
+ ReleaseNode(c)
+
+ self.__dict__['endContainer'] = self.startContainer
+ self.__dict__['endOffset'] = self.endContainer
+ self.__dict__['commonAncestorContainer'] = self.endContainer
+ self.__dict__['collapsed'] = 1
+
+ elif self.startContainer == self.commonAncestorContainer:
+ #Delete up the endContainer
+ #From the start to the end
+ if self.endContainer.nodeType in [Node.TEXT_NODE,
+ Node.COMMENT_NODE,
+ Node.PROCESSING_INSTRUCTION_NODE]:
+ #Adjust the character data
+ self.endContainer.deleteData(0,self.endOffset)
+ else:
+ numDel = self.endOffset
+ for ctr in range(numDel):
+ c = self.endContainer.removeChild(self.endContainer.childNodes[0])
+ ReleaseNode(c)
+
+ cur = self.endContainer
+ while cur.parentNode != self.commonAncestorContainer:
+ while cur.previousSibling:
+ c = cur.parentNode.removeChild(cur.previousSibling)
+ ReleaseNode(c)
+ cur = cur.parentNode
+
+ #Delete up to the ancestor of end
+ endAncestorChild = cur
+ while self.startContainer.firstChild != endAncestorChild:
+ c = self.startContainer.removeChild(self.startContainer.firstChild)
+ ReleaseNode(c)
+ elif self.endContainer == self.commonAncestorContainer:
+ if self.startContainer.nodeType in [Node.TEXT_NODE,
+ Node.COMMENT_NODE,
+ Node.PROCESSING_INSTRUCTION_NODE]:
+ #Adjust the character data
+ self.startContainer.deleteData(self.startOffset,1+len(self.startContainer.data)-self.startOffset)
+ else:
+ numDel = len(self.startContainer.childNodes) - self.startOffset
+ for ctr in range(numDel):
+ c = self.startContainer.removeChild(self.startContainer.childNodes[self.startOffset])
+ ReleaseNode(c)
+
+ cur = self.startContainer
+ while cur.parentNode != self.commonAncestorContainer:
+ while cur.nextSibling:
+ c = cur.parentNode.removeChild(cur.nextSibling)
+ ReleaseNode(c)
+ cur = cur.parentNode
+
+ startAncestorChild = cur
+
+ #Delete up to the ancestor of start
+ startAncestorChild = cur
+ startIndex = self.endContainer.childNodes.index(cur)
+ numDel = self.endOffset - startIndex
+ for ctr in range(numDel):
+ c = self.endContainer.removeChild(startAncestorChild.nextSibling)
+ ReleaseNode(c)
+
+ else:
+ #From the start to the end
+ if self.startContainer.nodeType in [Node.TEXT_NODE,
+ Node.COMMENT_NODE,
+ Node.PROCESSING_INSTRUCTION_NODE]:
+ #Adjust the character data
+ self.startContainer.deleteData(self.startOffset,1+len(self.startContainer.data)-self.startOffset)
+ else:
+ numDel = len(self.startContainer.childNodes) - self.startOffset
+ for ctr in range(numDel):
+ c = self.startContainer.removeChild(self.startContainer.childNodes[self.startOffset])
+ ReleaseNode(c)
+
+ cur = self.startContainer
+ while cur.parentNode != self.commonAncestorContainer:
+ while cur.nextSibling:
+ c = cur.parentNode.removeChild(cur.nextSibling)
+ ReleaseNode(c)
+ cur = cur.parentNode
+
+ startAncestorChild = cur
+ #Delete up the endContainer
+ #From the start to the end
+ if self.endContainer.nodeType in [Node.TEXT_NODE,
+ Node.COMMENT_NODE,
+ Node.PROCESSING_INSTRUCTION_NODE]:
+ #Adjust the character data
+ self.endContainer.deleteData(0,self.endOffset)
+ else:
+ numDel = self.endOffset
+ for ctr in range(numDel):
+ c = self.endContainer.removeChild(self.endContainer.childNodes[0])
+ ReleaseNode(c)
+
+ cur = self.endContainer
+ while cur.parentNode != self.commonAncestorContainer:
+ while cur.previousSibling:
+ c = cur.parentNode.removeChild(cur.previousSibling)
+ ReleaseNode(c)
+ cur = cur.parentNode
+
+ endAncestorChild = cur
+
+ cur = startAncestorChild
+ #Delete everything between us
+ while cur.nextSibling != endAncestorChild:
+ c = cur.parentNode.removeChild(cur.nextSibling)
+ ReleaseNode(c)
+
+ #Adjust the containers
+ #FIXME What the heck is the spec talking about??
+ self.__dict__['endContainer'] = self.startContainer
+ self.__dict__['endOffset'] = self.startContainer
+ self.__dict__['commonAncestorContainer'] = self.startContainer
+ self.__dict__['collapsed'] = 1
+
+ return None
+
+ def detach(self):
+ self.detached = 1
+ del self.startContainer
+ del self.endContainer
+ del self.startOffset
+ del self.endOffset
+ del self.collapsed
+ del self.commonAncestorContainer
+
+ def extractContents(self):
+ """Extract the contents defined by this range"""
+
+
+ if self.detached:
+ raise InvalidStateErr()
+
+ df = self._ownerDocument.createDocumentFragment()
+
+ if self.startContainer == self.endContainer:
+ if self.startOffset == self.endOffset:
+ return df
+ if self.startContainer.nodeType in [Node.TEXT_NODE,
+ Node.COMMENT_NODE,
+ Node.PROCESSING_INSTRUCTION_NODE]:
+ #Adjust the character data
+ data = self.startContainer.substringData(self.startOffset,1+self.endOffset-self.startOffset)
+ self.startContainer.deleteData(self.startOffset,1+self.endOffset-self.startOffset)
+
+ tx = self._ownerDocument.createTextNode(data)
+ df.appendChild(tx)
+
+ else:
+ #Extrace a set number of children
+
+ numDel = self.endOffset - self.startOffset+1
+ for ctr in range(numDel):
+ c = self.startContainer.removeChild(self.startContainer.childNodes[self.startOffset])
+ df.appendChild(c)
+
+ elif self.startContainer == self.commonAncestorContainer:
+ #Delete up the endContainer
+ #From the start to the end
+ lastKids = []
+ copyData = None
+ #Delete up the endContainer
+ #From the start to the end
+ if self.endContainer.nodeType in [Node.TEXT_NODE,
+ Node.COMMENT_NODE,
+ Node.PROCESSING_INSTRUCTION_NODE]:
+ #Adjust the character data
+ copyData = self.endContainer.substringData(0,self.endOffset)
+ self.endContainer.deleteData(0,self.endOffset)
+ else:
+ numDel = self.endOffset
+ for ctr in range(numDel):
+ c = self.endContainer.removeChild(self.endContainer.childNodes[0])
+ lastKids.append(c)
+
+ cur = self.endContainer
+ while cur.parentNode != self.commonAncestorContainer:
+
+ #Clone all of the way up
+ newCur = cur.cloneNode(0)
+ if copyData:
+ newCur.data = copyData
+ copyData = None
+ for k in lastKids:
+ newCur.appendChild(k)
+ lastKids = [newCur]
+
+ while cur.previousSibling:
+ c = cur.parentNode.removeChild(cur.previousSibling)
+ lastKids = [c] + lastKids
+ cur = cur.parentNode
+
+ newEnd = cur.cloneNode(0)
+ for k in lastKids:
+ newEnd.appendChild(k)
+
+ endAncestorChild = cur
+
+ #Extract up to the ancestor of end
+ while self.startContainer.firstChild != endAncestorChild:
+ c = self.startContainer.removeChild(self.startContainer.firstChild)
+ df.appendChild(c)
+ df.appendChild(newEnd)
+
+ elif self.endContainer == self.commonAncestorContainer:
+ lastKids = []
+ copyData = None
+ if self.startContainer.nodeType in [Node.TEXT_NODE,
+ Node.COMMENT_NODE,
+ Node.PROCESSING_INSTRUCTION_NODE]:
+ #Adjust the character data
+
+ copyData = self.startContainer.substringData(self.startOffset,1+len(self.startContainer.data)-self.startOffset)
+ self.startContainer.deleteData(self.startOffset,1+len(self.startContainer.data)-self.startOffset)
+ else:
+ numDel = len(self.startContainer.childNodes) - self.startOffset
+ for ctr in range(numDel):
+ c = self.startContainer.removeChild(self.startContainer.childNodes[self.startOffset])
+ lastKids.append(c)
+
+ cur = self.startContainer
+ while cur.parentNode != self.commonAncestorContainer:
+ #Clone all of the way up
+ newCur = cur.cloneNode(0)
+ if copyData:
+ newCur.data = copyData
+ copyData = None
+ for k in lastKids:
+ newCur.appendChild(k)
+ lastKids = [newCur]
+
+ while cur.nextSibling:
+ c = cur.parentNode.removeChild(cur.nextSibling)
+ lastKids.append(c)
+ cur = cur.parentNode
+
+ startAncestorChild = cur
+ newStart = cur.cloneNode(0)
+ for k in lastKids:
+ newStart.appendChild(k)
+
+ df.appendChild(newStart)
+
+
+ #Extract up to the ancestor of start
+ startAncestorChild = cur
+ startIndex = self.endContainer.childNodes.index(cur)
+ lastAdded = None
+ numDel = self.endOffset - startIndex
+ for ctr in range(numDel):
+ c = self.endContainer.removeChild(startAncestorChild.nextSibling)
+ df.insertBefore(c,lastAdded)
+ lastAdded = c
+
+ else:
+ #From the start to the end
+ lastStartKids = []
+ startCopyData = None
+ if self.startContainer.nodeType in [Node.TEXT_NODE,
+ Node.COMMENT_NODE,
+ Node.PROCESSING_INSTRUCTION_NODE]:
+ #Adjust the character data
+
+ startCopyData = self.startContainer.substringData(self.startOffset,1+len(self.startContainer.data)-self.startOffset)
+ self.startContainer.deleteData(self.startOffset,1+len(self.startContainer.data)-self.startOffset)
+ else:
+ numDel = len(self.startContainer.childNodes) - self.startOffset
+ for ctr in range(numDel):
+ c = self.startContainer.removeChild(self.startContainer.childNodes[self.startOffset])
+ lastStartKids.append(c)
+
+ cur = self.startContainer
+ while cur.parentNode != self.commonAncestorContainer:
+ #Clone all of the way up
+ newCur = cur.cloneNode(0)
+ if startCopyData:
+ newCur.data = startCopyData
+ startCopyData = None
+ for k in lastStartKids:
+ newCur.appendChild(k)
+ lastStartKids = [newCur]
+
+ while cur.nextSibling:
+ c = cur.parentNode.removeChild(cur.nextSibling)
+ lastStartKids.append(c)
+ cur = cur.parentNode
+
+ startAncestorChild = cur
+
+ newStart = cur.cloneNode(0)
+ for k in lastStartKids:
+ newStart.appendChild(k)
+
+ df.appendChild(newStart)
+
+
+ lastEndKids = []
+ endCopyData = None
+ #Delete up the endContainer
+ #From the start to the end
+ if self.endContainer.nodeType in [Node.TEXT_NODE,
+ Node.COMMENT_NODE,
+ Node.PROCESSING_INSTRUCTION_NODE]:
+ #Adjust the character data
+ endCopyData = self.endContainer.substringData(0,self.endOffset)
+ self.endContainer.deleteData(0,self.endOffset)
+ else:
+ numDel = self.endOffset
+ for ctr in range(numDel):
+ c = self.endContainer.removeChild(self.endContainer.childNodes[0])
+ lastEndKids.append(c)
+
+ cur = self.endContainer
+ while cur.parentNode != self.commonAncestorContainer:
+ newCur = cur.cloneNode(0)
+ if endCopyData:
+ newCur.data = endCopyData
+ endCopyData = None
+ for k in lastEndKids:
+ newCur.appendChild(k)
+ lastEndKids = [newCur]
+ while cur.previousSibling:
+ c = cur.parentNode.removeChild(cur.previousSibling)
+ lastEndKids = [c] + lastEndKids
+ cur = cur.parentNode
+
+ endAncestorChild = cur
+
+ newEnd = cur.cloneNode(0)
+ for k in lastEndKids:
+ newEnd.appendChild(k)
+
+
+ cur = startAncestorChild
+ #Extract everything between us
+ while cur.nextSibling != endAncestorChild:
+ c = cur.parentNode.removeChild(cur.nextSibling)
+ df.appendChild(c)
+ df.appendChild(newEnd)
+
+
+ #Adjust the containers
+ #FIXME What the heck is the spec talking about??
+ self.__dict__['endContainer'] = self.startContainer
+ self.__dict__['endOffset'] = self.startContainer
+ self.__dict__['commonAncestorContainer'] = self.startContainer
+ self.__dict__['collapsed'] = 1
+
+
+
+ return df
+
+
+ def insertNode(self,newNode):
+ """Insert a node at the starting point"""
+
+ if self.detached:
+ raise InvalidStateErr()
+
+ if newNode.nodeType in [Node.ATTRIBUTE_NODE,
+ Node.ENTITY_NODE,
+ Node.NOTATION_NODE,
+ Node.DOCUMENT_NODE,
+ ]:
+ raise InvalidNodeTypeErr()
+
+ if self.startContainer.nodeType == Node.TEXT_NODE:
+ #Split the text at the boundary. Insert the node after this
+ otherText = self.startContainer.substringData(self.startOffset,len(self.startContainer.data))
+ self.startContainer.deleteData(self.startOffset,len(self.startContainer.data))
+ newText = self._ownerDocument.createTextNode(otherText)
+ self.startContainer.parentNode.insertBefore(newText,self.startContainer.nextSibling)
+
+ newText.parentNode.insertBefore(newNode,newText)
+ elif self.startContainer.nodeType in [Node.COMMENT_NODE,
+ Node.PROCESSING_INSTRUCTION_NODE]:
+ raise HierarchyRequestErr()
+ else:
+ curNode = self.startContainer.childNodes[self.startOffset]
+ self.startContainer.insertBefore(newNode,curNode.nextSibling)
+
+
+
+ def selectNode(self,refNode):
+ """Select a node"""
+ if self.detached:
+ raise InvalidStateErr()
+
+ self.__validateRefNode(refNode)
+
+ self.__dict__['startContainer'] = refNode.parentNode
+ self.__dict__['endContainer'] = refNode.parentNode
+
+
+ index = refNode.parentNode.childNodes.index(refNode)
+ self.__dict__['startOffset'] = index
+ self.__dict__['endOffset'] = index+1
+
+ self.__dict__['collapsed'] = 0
+ self.__dict__['commonAncestorContainer'] = refNode.parentNode
+
+
+ def selectNodeContents(self,refNode):
+ """Select a node"""
+ if self.detached:
+ raise InvalidStateErr()
+
+ self.__validateBoundary(refNode,0)
+
+
+ self.__dict__['startContainer'] = refNode
+ self.__dict__['endContainer'] = refNode
+
+
+ self.__dict__['startOffset'] = 0
+ self.__dict__['endOffset'] = len(refNode.childNodes)
+
+ self.__dict__['collapsed'] = self.startOffset == self.endOffset
+ self.__dict__['commonAncestorContainer'] = refNode
+
+
+
+ def setEnd(self,parent,offset):
+ """Set the ranges end container and offset"""
+
+ #Check for errors
+ if self.detached:
+ raise InvalidStateErr()
+
+ self.__validateBoundary(parent,offset)
+
+ self.__dict__['endContainer'] = parent
+ self.__dict__['endOffset'] = offset
+
+ self.__dict__['collapsed'] = 0
+
+ pos = self.__comparePositions(parent,offset,self.startContainer,self.startOffset)
+ self.__dict__['collapsed'] = (pos == self.POSITION_EQUAL)
+ if pos == self.POSITION_LESS_THAN:
+ self.__dict__['startContainer'] = parent
+ self.__dict__['startOffset'] = offset
+ self.__dict__['collapsed'] = 1
+
+ self.__calculateCommonAncestor()
+
+ def setEndAfter(self,node):
+
+ self.__validateRefNode(node)
+
+ cont = node.parentNode
+ index = cont.childNodes.index(node)
+ self.setEnd(cont,index+1)
+
+ def setEndBefore(self,node):
+
+ self.__validateRefNode(node)
+
+ cont = node.parentNode
+ index = cont.childNodes.index(node)
+ self.setEnd(cont,index)
+
+
+
+ def setStart(self,parent,offset):
+ """Set the ranges start container and offset"""
+
+ #Check for errors
+ if self.detached:
+ raise InvalidStateErr()
+
+ self.__validateBoundary(parent,offset)
+
+ self.__dict__['startContainer'] = parent
+ self.__dict__['startOffset'] = offset
+
+
+ pos = self.__comparePositions(parent,offset,self.endContainer,self.endOffset)
+ self.__dict__['collapsed'] = (pos == self.POSITION_EQUAL)
+
+ if pos == self.POSITION_GREATER_THAN:
+ self.__dict__['endContainer'] = parent
+ self.__dict__['endOffset'] = offset
+ self.__dict__['collapsed'] = 1
+
+ self.__calculateCommonAncestor()
+
+ def setStartAfter(self,node):
+
+ self.__validateRefNode(node)
+
+ cont = node.parentNode
+ index = cont.childNodes.index(node)
+ self.setStart(cont,index+1)
+
+ def setStartBefore(self,node):
+
+ self.__validateRefNode(node)
+
+ cont = node.parentNode
+ index = cont.childNodes.index(node)
+ self.setStart(cont,index)
+
+ def surrondContents(self,newParent):
+ """Surrond the range with this node"""
+ if self.detached:
+ raise InvalidStateErr()
+
+ if newParent.nodeType in [Node.ATTRIBUTE_NODE,
+ Node.ENTITY_NODE,
+ Node.DOCUMENT_TYPE_NODE,
+ Node.NOTATION_NODE,
+ Node.DOCUMENT_NODE,
+ Node.DOCUMENT_FRAGMENT_NODE]:
+ raise InvalidNodeTypeErr()
+
+ #See is we have element nodes that are partially selected
+ if self.startContainer.nodeType not in [Node.TEXT_NODE,
+ Node.COMMENT_NODE,
+ Node.PROCESSING_INSTRUCTION_NODE]:
+ if self.commonAncestorContainer not in [self.startContainer,self.startContainer.parentNode]:
+ #This is partially selected because our parent is not the common ancestor
+ raise BadBoundaryPointsErr()
+ if self.endContainer.nodeType not in [Node.TEXT_NODE,
+ Node.COMMENT_NODE,
+ Node.PROCESSING_INSTRUCTION_NODE]:
+ if self.commonAncestorContainer not in [self.endContainer,self.endContainer.parentNode]:
+ #This is partially selected because our parent is not the common ancestor
+ raise BadBoundaryPointsErr()
+
+ #All good, do the insert
+ #Remove children from newPArent
+ for c in newParent.childNodes:
+ newParent.removeChild(c)
+
+ df = self.extractContents()
+
+ self.insertNode(newParent)
+
+ newParent.appendChild(df)
+
+ self.selectNode(newParent)
+
+
+ def toString(self):
+ if self.detached:
+ raise InvalidStateErr()
+
+ df = self.cloneContents()
+
+
+ res = self.__recurseToString(df)
+
+
+ from xml.dom.ext import ReleaseNode
+ ReleaseNode(df)
+
+ return res
+
+ #Internal Functions#
+
+
+ def __validateBoundary(self,node,offset):
+ """Make sure the node is a legal boundary"""
+
+ if not hasattr(node,'nodeType'):
+ raise InvalidNodeTypeErr()
+
+
+ #Check for proper node type
+ curNode = node
+ while curNode:
+ if curNode.nodeType in [Node.ENTITY_NODE,
+ Node.NOTATION_NODE,
+ Node.DOCUMENT_TYPE_NODE,
+ ]:
+ raise InvalidNodeTypeErr()
+ curNode = curNode.parentNode
+
+ #Check number of cild units
+ if offset < 0:
+ raise IndexSizeErr()
+
+ if node.nodeType in [Node.TEXT_NODE,
+ Node.COMMENT_NODE,
+ Node.PROCESSING_INSTRUCTION_NODE]:
+ #Child units are characters
+ if offset > len(node.data):
+ raise IndexSizeErr()
+ else:
+ if offset > len(node.childNodes):
+ raise IndexSizeErr()
+
+ def __validateRefNode(self,node):
+
+ if not hasattr(node,'nodeType'):
+ raise InvalidNodeTypeErr()
+
+ cur = node
+ while cur.parentNode:
+ cur = cur.parentNode
+ if cur.nodeType not in [Node.ATTRIBUTE_NODE,
+ Node.DOCUMENT_NODE,
+ Node.DOCUMENT_FRAGMENT_NODE,
+ ]:
+ raise InvalidNodeTypeErr()
+
+ if node.nodeType in [Node.DOCUMENT_NODE,
+ Node.DOCUMENT_FRAGMENT_NODE,
+ Node.ATTRIBUTE_NODE,
+ Node.ENTITY_NODE,
+ Node.NOTATION_NODE,
+ ]:
+
+ raise InvalidNodeTypeErr()
+
+
+ def __comparePositions(self,aContainer,aOffset,bContainer,bOffset):
+ """Compare Boundary Positions Section 2.5"""
+
+ if aContainer == bContainer:
+ #CASE 1
+ if aOffset == bOffset:
+ return self.POSITION_EQUAL
+ elif aOffset < bOffset:
+ return self.POSITION_LESS_THAN
+ else:
+ return self.POSITION_GREATER_THAN
+ #CASE 2
+ bAncestors = []
+ cur = bContainer
+ while cur:
+ bAncestors.append(cur)
+ cur = cur.parentNode
+
+ for ctr in range(len(aContainer.childNodes)):
+ c = aContainer.childNodes[ctr]
+ if c in bAncestors:
+ if aOffset <= ctr:
+ return self.POSITION_LESS_THAN
+ else:
+ return self.POSITION_GREATER_THAN
+
+ #CASE 3
+ aAncestors = []
+ cur = aContainer
+ while cur:
+ aAncestors.append(cur)
+ cur = cur.parentNode
+
+ for ctr in range(len(bContainer.childNodes)):
+ c = bContainer.childNodes[ctr]
+ if c in aAncestors:
+ if ctr < bOffset:
+ return self.POSITION_LESS_THAN
+ else:
+ return self.POSITION_GREATER_THAN
+
+
+
+ #CASE 4
+ #Check the "Following axis" of A.
+ #If B is in the axis, then A is before B
+
+ curr = aContainer
+ while curr != aContainer.ownerDocument:
+ sibling = curr.nextSibling
+ while sibling:
+ if curr == bContainer:
+ return self.POSITION_LESS_THAN
+ rt = self.__checkDescendants(sibling,bContainer)
+ if rt:
+ return self.POSITION_LESS_THAN
+ sibling = sibling.nextSibling
+ curr = ((curr.nodeType == Node.ATTRIBUTE_NODE) and
+ curr.ownerElement or curr.parentNode)
+
+ #Not in the following, return POSITION_LESS_THAN
+ return self.POSITION_GREATER_THAN
+
+ def __checkDescendants(self,sib,b):
+ for c in sib.childNodes:
+ if c == b: return 1
+ if self.__checkDescendants(c,b): return 1
+ return 0
+
+
+ def __calculateCommonAncestor(self):
+
+ if self.startContainer == self.endContainer:
+ self.__dict__['commonAncestorContainer'] = self.startContainer
+
+ startAncestors = []
+ cur = self.startContainer
+ while cur:
+ startAncestors.append(cur)
+ cur = cur.parentNode
+
+ cur = self.endContainer
+ while cur:
+ if cur in startAncestors:
+ self.__dict__['commonAncestorContainer'] = cur
+ return
+ cur = cur.parentNode
+
+ #Hmm no ancestor
+ raise BadBoundaryPointsErr()
+
+
+ def __recurseToString(self,node):
+
+ if node.nodeType in [Node.TEXT_NODE,
+ Node.CDATA_SECTION_NODE]:
+ return node.data
+ else:
+ res = ""
+ for c in node.childNodes:
+ res = res + self.__recurseToString(c)
+ return res
diff --git a/lib/jython/Lib/xml/dom/Text.py b/lib/jython/Lib/xml/dom/Text.py new file mode 100644 index 000000000..e59021c3b --- /dev/null +++ b/lib/jython/Lib/xml/dom/Text.py @@ -0,0 +1,43 @@ +########################################################################
+#
+# File Name: Text.py
+#
+# Documentation: http://docs.4suite.com/4DOM/Text.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+from CharacterData import CharacterData
+
+from xml.dom import Node
+from xml.dom import IndexSizeErr
+
+class Text(CharacterData):
+ nodeType = Node.TEXT_NODE
+
+ def __init__(self, ownerDocument, data):
+ CharacterData.__init__(self, ownerDocument, data)
+ self.__dict__['__nodeName'] = '#text'
+
+ ### Methods ###
+
+ def splitText(self, offset):
+ if not (0 < offset < self.length):
+ raise IndexSizeErr()
+ data = self.data
+ first = data[:int(offset)]
+ second = data[int(offset):]
+ node = self.ownerDocument.createTextNode(second)
+ self._set_data(first)
+ parent = self.parentNode
+ if parent:
+ sibling = self.nextSibling
+ if sibling:
+ parent.insertBefore(node, self.nextSibling)
+ else:
+ parent.appendChild(node)
+ return node
diff --git a/lib/jython/Lib/xml/dom/TreeWalker.py b/lib/jython/Lib/xml/dom/TreeWalker.py new file mode 100644 index 000000000..9dbd97f3f --- /dev/null +++ b/lib/jython/Lib/xml/dom/TreeWalker.py @@ -0,0 +1,183 @@ +########################################################################
+#
+# File Name: TreeWalker.py
+#
+# Documentation: http://docs.4suite.com/4DOM/TreeWalker.py.html
+#
+"""
+Tree Walker from DOM Level 2. Allows multi-directional iteration over nodes.
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+from NodeFilter import NodeFilter
+
+from xml.dom import NoModificationAllowedErr
+from xml.dom import NotSupportedErr
+
+class TreeWalker:
+ def __init__(self, root, whatToShow, filter, expandEntityReferences):
+ self.__dict__['__root'] = root
+ self.__dict__['__whatToShow'] = whatToShow
+ self.__dict__['__filter'] = filter
+ self.__dict__['__expandEntityReferences'] = expandEntityReferences
+ self.__dict__['__currentNode'] = root
+
+ ### Attribute Access Methods -- xxx.attr ###
+
+ def __getattr__(self, name):
+ attrFunc = self._readComputedAttrs.get(name)
+ if attrFunc:
+ return attrFunc(self)
+
+ def __setattr__(self, name, value):
+ #Make sure attribute is not read-only
+ if name in self.__class__._readOnlyAttrs:
+ raise NoModificationAllowedErr()
+ #If it's computed execute that function
+ attrFunc = self.__class__._writeComputedAttrs.get(name)
+ if attrFunc:
+ attrFunc(self, value)
+ #Otherwise, just set the attribute
+ else:
+ self.__dict__[name] = value
+
+ ### Attribute Methods -- xxx._get_attr() ###
+
+ def _get_root(self):
+ return self.__dict__['__root']
+
+ def _get_filter(self):
+ return self.__dict__['__filter']
+
+ def _get_whatToShow(self):
+ return self.__dict__['__whatToShow']
+
+ def _get_expandEntityReferences(self):
+ return self.__dict__['__expandEntityReferences']
+
+ def _get_currentNode(self):
+ return self.__dict__['__currentNode']
+
+ def _set_currentNode(self, value):
+ if value == None:
+ raise NotSupportedErr()
+ self.__dict__['__currentNode'] = value
+
+ ### Methods ###
+
+ def parentNode(self):
+ next_node = None
+ if self.__dict__['__currentNode'] != self.__dict__['__root']:
+ next_node = self.__dict__['__currentNode']._get_parentNode()
+ while next_node and next_node != self.__dict__['__root'] \
+ and not (self.__checkWhatToShow(next_node) \
+ and self.__checkFilter(next_node) == NodeFilter.FILTER_ACCEPT):
+ next_node = next_node._get_parentNode()
+ if next_node:
+ self.__dict__['__currentNode'] = next_node
+ return next_node
+
+ def firstChild(self):
+ next_node = None
+ if self.__checkFilter(self.__dict__['__currentNode']) != NodeFilter.FILTER_REJECT:
+ next_node = self.__dict__['__currentNode']._get_firstChild()
+ while next_node and not (self.__checkWhatToShow(next_node) \
+ and self.__checkFilter(next_node) == NodeFilter.FILTER_ACCEPT):
+ next_node = next_node._get_nextSibling()
+ if next_node:
+ self.__dict__['__currentNode'] = next_node
+ return next_node
+
+ def lastChild(self):
+ next_node = None
+ if self.__checkFilter(self.__dict__['__currentNode']) != NodeFilter.FILTER_REJECT:
+ next_node = self.__dict__['__currentNode']._get_lastChild()
+ while next_node and not (self.__checkWhatToShow(next_node) \
+ and self.__checkFilter(next_node) == NodeFilter.FILTER_ACCEPT):
+ next_node = next_node._get_previousSibling()
+ if next_node:
+ self.__dict__['__currentNode'] = next_node
+ return next_node
+
+ def previousSibling(self):
+ prev_node = None
+ if self.__dict__['__currentNode'] != self.__root:
+ prev_node = self.__dict__['__currentNode']._get_previousSibling()
+ while prev_node and not (self.__checkWhatToShow(prev_node) \
+ and self.__checkFilter(prev_node) == NodeFilter.FILTER_ACCEPT):
+ prev_node = prev_node._get_previousSibling()
+ if prev_node:
+ self.__dict__['__currentNode'] = prev_node
+ return prev_node
+
+ def nextSibling(self):
+ next_node = None
+ if self.__dict__['__currentNode'] != self.__root:
+ next_node = self.__dict__['__currentNode']._get_nextSibling()
+ while next_node and not (self.__checkWhatToShow(next_node) and self.__checkFilter(next_node) == NodeFilter.FILTER_ACCEPT):
+ next_node = next_node._get_nextSibling()
+ if next_node:
+ self.__dict__['__currentNode'] = next_node
+ return next_node
+
+
+ def nextNode(self):
+ next_node = self.__advance()
+ while next_node and not (self.__checkWhatToShow(next_node) and self.__checkFilter(next_node) == NodeFilter.FILTER_ACCEPT):
+ next_node = self.__advance()
+ return next_node
+
+ def previousNode(self):
+ prev_node = self.__regress()
+ while prev_node and not (self.__checkWhatToShow(prev_node) and self.__checkFilter(prev_node) == NodeFilter.FILTER_ACCEPT):
+ prev_node = self.__regress()
+ return prev_node
+
+
+ def __advance(self):
+ if self.firstChild():
+ return self.__dict__['__currentNode']
+ if self.nextSibling():
+ return self.__dict__['__currentNode']
+ if self.parentNode():
+ return self.nextSibling()
+ return None
+
+
+ def __regress(self):
+ if self.previousSibling():
+ self.lastChild()
+ return self.__dict__['__currentNode']
+ if self.parentNode():
+ return self.__dict__['__currentNode']
+ return None
+
+
+ def __checkWhatToShow(self, node):
+ show_bit = 1 << (node._get_nodeType() - 1)
+ return self.__dict__['__whatToShow'] & show_bit
+
+ def __checkFilter(self, node):
+ if self.__dict__['__filter']:
+ return self.__dict__['__filter'].acceptNode(node)
+ else:
+ return NodeFilter.FILTER_ACCEPT
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = {'root':_get_root,
+ 'whatToShow':_get_whatToShow,
+ 'filter':_get_filter,
+ 'expandEntityReferences':_get_expandEntityReferences,
+ 'currentNode':_get_currentNode
+ }
+
+ _writeComputedAttrs = {'currentNode': _set_currentNode
+ }
+
+ # Create the read-only list of attributes
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/__init__.py b/lib/jython/Lib/xml/dom/__init__.py new file mode 100644 index 000000000..f443544ea --- /dev/null +++ b/lib/jython/Lib/xml/dom/__init__.py @@ -0,0 +1,197 @@ +########################################################################
+#
+# File Name: __init__.py
+#
+# Documentation: http://docs.4suite.com/4DOM/__init__.py.html
+#
+"""
+WWW: http://4suite.org/4DOM e-mail: support@4suite.org
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.org/COPYRIGHT for license and copyright information
+"""
+
+
+class Node:
+ """Class giving the NodeType constants."""
+
+ # DOM implementations may use this as a base class for their own
+ # Node implementations. If they don't, the constants defined here
+ # should still be used as the canonical definitions as they match
+ # the values given in the W3C recommendation. Client code can
+ # safely refer to these values in all tests of Node.nodeType
+ # values.
+
+ ELEMENT_NODE = 1
+ ATTRIBUTE_NODE = 2
+ TEXT_NODE = 3
+ CDATA_SECTION_NODE = 4
+ ENTITY_REFERENCE_NODE = 5
+ ENTITY_NODE = 6
+ PROCESSING_INSTRUCTION_NODE = 7
+ COMMENT_NODE = 8
+ DOCUMENT_NODE = 9
+ DOCUMENT_TYPE_NODE = 10
+ DOCUMENT_FRAGMENT_NODE = 11
+ NOTATION_NODE = 12
+
+
+# DOMException codes
+INDEX_SIZE_ERR = 1
+DOMSTRING_SIZE_ERR = 2
+HIERARCHY_REQUEST_ERR = 3
+WRONG_DOCUMENT_ERR = 4
+INVALID_CHARACTER_ERR = 5
+NO_DATA_ALLOWED_ERR = 6
+NO_MODIFICATION_ALLOWED_ERR = 7
+NOT_FOUND_ERR = 8
+NOT_SUPPORTED_ERR = 9
+INUSE_ATTRIBUTE_ERR = 10
+INVALID_STATE_ERR = 11
+SYNTAX_ERR = 12
+INVALID_MODIFICATION_ERR = 13
+NAMESPACE_ERR = 14
+INVALID_ACCESS_ERR = 15
+
+# EventException codes
+UNSPECIFIED_EVENT_TYPE_ERR = 0
+
+# Fourthought specific codes
+FT_EXCEPTION_BASE = 1000
+XML_PARSE_ERR = FT_EXCEPTION_BASE + 1
+
+#RangeException codes
+BAD_BOUNDARYPOINTS_ERR = 1
+INVALID_NODE_TYPE_ERR = 2
+
+
+class DOMException(Exception):
+ def __init__(self, code, msg=''):
+ self.code = code
+ self.msg = msg or DOMExceptionStrings[code]
+
+ def __str__(self):
+ return self.msg
+
+class EventException(Exception):
+ def __init__(self, code, msg=''):
+ self.code = code
+ self.msg = msg or EventExceptionStrings[code]
+ return
+
+ def __str__(self):
+ return self.msg
+
+class RangeException(Exception):
+ def __init__(self, code, msg):
+ self.code = code
+ self.msg = msg or RangeExceptionStrings[code]
+ Exception.__init__(self, self.msg)
+
+class FtException(Exception):
+ def __init__(self, code, *args):
+ self.code = code
+ self.msg = FtExceptionStrings[code] % args
+ return
+
+ def __str__(self):
+ return self.msg
+
+class IndexSizeErr(DOMException):
+ def __init__(self, msg=''):
+ DOMException.__init__(self, INDEX_SIZE_ERR, msg)
+
+class DOMStringSizeErr(DOMException):
+ def __init__(self, msg=''):
+ DOMException.__init__(self, DOMSTRING_SIZE_ERR, msg)
+
+class HierarchyRequestErr(DOMException):
+ def __init__(self, msg=''):
+ DOMException.__init__(self, HIERARCHY_REQUEST_ERR, msg)
+
+class WrongDocumentErr(DOMException):
+ def __init__(self, msg=''):
+ DOMException.__init__(self, WRONG_DOCUMENT_ERR, msg)
+
+class InvalidCharacterErr(DOMException):
+ def __init__(self, msg=''):
+ DOMException.__init__(self, INVALID_CHARACTER_ERR, msg)
+
+class NoDataAllowedErr(DOMException):
+ def __init__(self, msg=''):
+ DOMException.__init__(self, NO_DATA_ALLOWED_ERR, msg)
+
+class NoModificationAllowedErr(DOMException):
+ def __init__(self, msg=''):
+ DOMException.__init__(self, NO_MODIFICATION_ALLOWED_ERR, msg)
+
+class NotFoundErr(DOMException):
+ def __init__(self, msg=''):
+ DOMException.__init__(self, NOT_FOUND_ERR, msg)
+
+class NotSupportedErr(DOMException):
+ def __init__(self, msg=''):
+ DOMException.__init__(self, NOT_SUPPORTED_ERR, msg)
+
+class InuseAttributeErr(DOMException):
+ def __init__(self, msg=''):
+ DOMException.__init__(self, INUSE_ATTRIBUTE_ERR, msg)
+
+class InvalidStateErr(DOMException):
+ def __init__(self, msg=''):
+ DOMException.__init__(self, INVALID_STATE_ERR, msg)
+
+class SyntaxErr(DOMException):
+ def __init__(self, msg=''):
+ DOMException.__init__(self, SYNTAX_ERR, msg)
+
+class InvalidModificationErr(DOMException):
+ def __init__(self, msg=''):
+ DOMException.__init__(self, INVALID_MODIFICATION_ERR, msg)
+
+class NamespaceErr(DOMException):
+ def __init__(self, msg=''):
+ DOMException.__init__(self, NAMESPACE_ERR, msg)
+
+class InvalidAccessErr(DOMException):
+ def __init__(self, msg=''):
+ DOMException.__init__(self, INVALID_ACCESS_ERR, msg)
+
+class UnspecifiedEventTypeErr(EventException):
+ def __init__(self, msg=''):
+ EventException.__init__(self, UNSPECIFIED_EVENT_TYPE_ERR, msg)
+
+class XmlParseErr(FtException):
+ def __init__(self, msg=''):
+ FtException.__init__(self, XML_PARSE_ERR, msg)
+
+#Specific Range Exceptions
+class BadBoundaryPointsErr(RangeException):
+ def __init__(self, msg=''):
+ RangeException.__init__(self, BAD_BOUNDARYPOINTS_ERR, msg)
+
+class InvalidNodeTypeErr(RangeException):
+ def __init__(self, msg=''):
+ RangeException.__init__(self, INVALID_NODE_TYPE_ERR, msg)
+
+from xml.dom import DOMImplementation
+
+try:
+ from xml.dom.html import HTMLDOMImplementation
+ implementation = HTMLDOMImplementation.HTMLDOMImplementation()
+ HTMLDOMImplementation.implementation = implementation
+except ImportError:
+ implementation = DOMImplementation.DOMImplementation()
+DOMImplementation.implementation = implementation
+
+XML_NAMESPACE = "http://www.w3.org/XML/1998/namespace"
+XMLNS_NAMESPACE = "http://www.w3.org/2000/xmlns/"
+XHTML_NAMESPACE = "http://www.w3.org/1999/xhtml"
+
+import MessageSource
+DOMExceptionStrings = MessageSource.__dict__['DOMExceptionStrings']
+EventExceptionStrings = MessageSource.__dict__['EventExceptionStrings']
+FtExceptionStrings = MessageSource.__dict__['FtExceptionStrings']
+RangeExceptionStrings = MessageSource.__dict__['RangeExceptionStrings']
+
+from domreg import getDOMImplementation,registerDOMImplementation
diff --git a/lib/jython/Lib/xml/dom/domreg.py b/lib/jython/Lib/xml/dom/domreg.py new file mode 100644 index 000000000..3b52787a8 --- /dev/null +++ b/lib/jython/Lib/xml/dom/domreg.py @@ -0,0 +1,76 @@ +"""Registration facilities for DOM. This module should not be used
+directly. Instead, the functions getDOMImplementation and
+registerDOMImplementation should be imported from xml.dom."""
+
+# This is a list of well-known implementations. Well-known names
+# should be published by posting to xml-sig@python.org, and are
+# subsequently recorded in this file.
+
+well_known_implementations = {
+ 'minidom':'xml.dom.minidom',
+ '4DOM': 'xml.dom.DOMImplementation',
+ }
+
+# DOM implementations not officially registered should register
+# themselves with their
+
+registered = {}
+
+def registerDOMImplementation(name, factory):
+ """registerDOMImplementation(name, factory)
+
+ Register the factory function with the name. The factory function
+ should return an object which implements the DOMImplementation
+ interface. The factory function can either return the same object,
+ or a new one (e.g. if that implementation supports some
+ customization)."""
+
+ registered[name] = factory
+
+def _good_enough(dom, features):
+ "_good_enough(dom, features) -> Return 1 if the dom offers the features"
+ for f,v in features:
+ if not dom.hasFeature(f,v):
+ return 0
+ return 1
+
+def getDOMImplementation(name = None, features = ()):
+ """getDOMImplementation(name = None, features = ()) -> DOM implementation.
+
+ Return a suitable DOM implementation. The name is either
+ well-known, the module name of a DOM implementation, or None. If
+ it is not None, imports the corresponding module and returns
+ DOMImplementation object if the import succeeds.
+
+ If name is not given, consider the available implementations to
+ find one with the required feature set. If no implementation can
+ be found, raise an ImportError. The features list must be a sequence
+ of (feature, version) pairs which are passed to hasFeature."""
+
+ import os
+ creator = None
+ mod = well_known_implementations.get(name)
+ if mod:
+ mod = __import__(mod, {}, {}, ['getDOMImplementation'])
+ return mod.getDOMImplementation()
+ elif name:
+ return registered[name]()
+ elif os.environ.has_key("PYTHON_DOM"):
+ return getDOMImplementation(name = os.environ["PYTHON_DOM"])
+
+ # User did not specify a name, try implementations in arbitrary
+ # order, returning the one that has the required features
+ for creator in registered.values():
+ dom = creator()
+ if _good_enough(dom, features):
+ return dom
+
+ for creator in well_known_implementations.keys():
+ try:
+ dom = getDOMImplementation(name = creator)
+ except StandardError: # typically ImportError, or AttributeError
+ continue
+ if _good_enough(dom, features):
+ return dom
+
+ raise ImportError,"no suitable DOM implementation found"
diff --git a/lib/jython/Lib/xml/dom/ext/Printer.py b/lib/jython/Lib/xml/dom/ext/Printer.py new file mode 100644 index 000000000..d37ef4abc --- /dev/null +++ b/lib/jython/Lib/xml/dom/ext/Printer.py @@ -0,0 +1,384 @@ +########################################################################
+#
+# File Name: Printer.py
+#
+# Documentation: http://docs.4suite.com/4DOM/Printer.py.html
+#
+"""
+The printing sub-system.
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string, re
+from xml.dom import Node
+from xml.dom.ext.Visitor import Visitor, WalkerInterface
+from xml.dom import ext, XMLNS_NAMESPACE, XML_NAMESPACE, XHTML_NAMESPACE
+from xml.dom.html import TranslateHtmlCdata
+from xml.dom.html import HTML_4_TRANSITIONAL_INLINE
+from xml.dom.html import HTML_FORBIDDEN_END
+from xml.dom.html import HTML_BOOLEAN_ATTRS
+
+ILLEGAL_LOW_CHARS = '[\x01-\x08\x0B-\x0C\x0E-\x1F]'
+SURROGATE_BLOCK = '[\xF0-\xF7][\x80-\xBF][\x80-\xBF][\x80-\xBF]'
+ILLEGAL_HIGH_CHARS = '\xEF\xBF[\xBE\xBF]'
+#Note: Prolly fuzzy on this, but it looks as if characters from the surrogate block are allowed if in scalar form, which is encoded in UTF8 the same was as in surrogate block form
+XML_ILLEGAL_CHAR_PATTERN = re.compile('%s|%s'%(ILLEGAL_LOW_CHARS, ILLEGAL_HIGH_CHARS))
+
+g_utf8TwoBytePattern = re.compile('([\xC0-\xC3])([\x80-\xBF])')
+g_cdataCharPattern = re.compile('[&<]|]]>')
+g_charToEntity = {
+ '&': '&',
+ '<': '<',
+ ']]>': ']]>',
+ }
+
+try:
+ #The following stanza courtesy Martin von Loewis
+ import codecs # Python 1.6+ only
+ from types import UnicodeType
+ def utf8_to_code(text, encoding):
+ encoder = codecs.lookup(encoding)[0] # encode,decode,reader,writer
+ if type(text) is not UnicodeType:
+ text = unicode(text, "utf-8")
+ return encoder(text)[0] # result,size
+ def strobj_to_utf8str(text, encoding):
+ if string.upper(encoding) not in ["UTF-8", "ISO-8859-1", "LATIN-1"]:
+ raise ValueError("Invalid encoding: %s"%encoding)
+ encoder = codecs.lookup(encoding)[0] # encode,decode,reader,writer
+ if type(text) is not UnicodeType:
+ text = unicode(text, "utf-8")
+ #FIXME
+ return str(encoder(text)[0])
+except ImportError:
+ def utf8_to_code(text, encoding):
+ encoding = string.upper(encoding)
+ if encoding == 'UTF-8':
+ return text
+ from xml.unicode.iso8859 import wstring
+ wstring.install_alias('ISO-8859-1', 'ISO_8859-1:1987')
+ #Note: Pass through to wstrop. This means we don't play nice and
+ #Escape characters that are not in the target encoding.
+ ws = wstring.from_utf8(text)
+ text = ws.encode(encoding)
+ #This version would skip all untranslatable chars: see wstrop.c
+ #text = ws.encode(encoding, 1)
+ return text
+ strobj_to_utf8str = utf8_to_code
+
+
+def TranslateCdataAttr(characters):
+ '''Handles normalization and some intelligence about quoting'''
+ if not characters:
+ return '', "'"
+ if "'" in characters:
+ delimiter = '"'
+ new_chars = re.sub('"', '"', characters)
+ else:
+ delimiter = "'"
+ new_chars = re.sub("'", ''', characters)
+ #FIXME: There's more to normalization
+ #Convert attribute new-lines to character entity
+ # characters is possibly shorter than new_chars (no entities)
+ if "\n" in characters:
+ new_chars = re.sub('\n', ' ', new_chars)
+ return new_chars, delimiter
+
+
+#Note: Unicode object only for now
+def TranslateCdata(characters, encoding='UTF-8', prev_chars='', markupSafe=0,
+ charsetHandler=utf8_to_code):
+ """
+ charsetHandler is a function that takes a string or unicode object as the
+ first argument, representing the string to be procesed, and an encoding
+ specifier as the second argument. It must return a string or unicode
+ object
+ """
+ if not characters:
+ return ''
+ if not markupSafe:
+ if g_cdataCharPattern.search(characters):
+ new_string = g_cdataCharPattern.subn(
+ lambda m, d=g_charToEntity: d[m.group()],
+ characters)[0]
+ else:
+ new_string = characters
+ if prev_chars[-2:] == ']]' and characters[0] == '>':
+ new_string = '>' + new_string[1:]
+ else:
+ new_string = characters
+ #Note: use decimal char entity rep because some browsers are broken
+ #FIXME: This will bomb for high characters. Should, for instance, detect
+ #The UTF-8 for 0xFFFE and put out 
+ if XML_ILLEGAL_CHAR_PATTERN.search(new_string):
+ new_string = XML_ILLEGAL_CHAR_PATTERN.subn(
+ lambda m: '&#%i;' % ord(m.group()),
+ new_string)[0]
+ new_string = charsetHandler(new_string, encoding)
+ return new_string
+
+
+class PrintVisitor(Visitor):
+ def __init__(self, stream, encoding, indent='', plainElements=None,
+ nsHints=None, isXhtml=0, force8bit=0):
+ self.stream = stream
+ self.encoding = encoding
+ # Namespaces
+ self._namespaces = [{}]
+ self._nsHints = nsHints or {}
+ # PrettyPrint
+ self._indent = indent
+ self._depth = 0
+ self._inText = 0
+ self._plainElements = plainElements or []
+ # HTML support
+ self._html = None
+ self._isXhtml = isXhtml
+ self.force8bit = force8bit
+ return
+
+ def _write(self, text):
+ if self.force8bit:
+ obj = strobj_to_utf8str(text, self.encoding)
+ else:
+ obj = utf8_to_code(text, self.encoding)
+ self.stream.write(obj)
+ return
+
+ def _tryIndent(self):
+ if not self._inText and self._indent:
+ self._write('\n' + self._indent*self._depth)
+ return
+
+ def visit(self, node):
+ if self._html is None:
+ # Set HTMLDocument flag here for speed
+ self._html = hasattr(node.ownerDocument, 'getElementsByName')
+
+ nodeType = node.nodeType
+ if node.nodeType == Node.ELEMENT_NODE:
+ return self.visitElement(node)
+
+ elif node.nodeType == Node.ATTRIBUTE_NODE:
+ return self.visitAttr(node)
+
+ elif node.nodeType == Node.TEXT_NODE:
+ return self.visitText(node)
+
+ elif node.nodeType == Node.CDATA_SECTION_NODE:
+ return self.visitCDATASection(node)
+
+ elif node.nodeType == Node.ENTITY_REFERENCE_NODE:
+ return self.visitEntityReference(node)
+
+ elif node.nodeType == Node.ENTITY_NODE:
+ return self.visitEntity(node)
+
+ elif node.nodeType == Node.PROCESSING_INSTRUCTION_NODE:
+ return self.visitProcessingInstruction(node)
+
+ elif node.nodeType == Node.COMMENT_NODE:
+ return self.visitComment(node)
+
+ elif node.nodeType == Node.DOCUMENT_NODE:
+ return self.visitDocument(node)
+
+ elif node.nodeType == Node.DOCUMENT_TYPE_NODE:
+ return self.visitDocumentType(node)
+
+ elif node.nodeType == Node.DOCUMENT_FRAGMENT_NODE:
+ return self.visitDocumentFragment(node)
+
+ elif node.nodeType == Node.NOTATION_NODE:
+ return self.visitNotation(node)
+
+ # It has a node type, but we don't know how to handle it
+ raise Exception("Unknown node type: %s" % repr(node))
+
+ def visitNodeList(self, node, exclude=None):
+ for curr in node:
+ curr is not exclude and self.visit(curr)
+ return
+
+ def visitNamedNodeMap(self, node):
+ for item in node.values():
+ self.visit(item)
+ return
+
+ def visitAttr(self, node):
+ if node.namespaceURI == XMLNS_NAMESPACE:
+ # Skip namespace declarations
+ return
+ self._write(' ' + node.name)
+ value = node.value
+ if value or not self._html:
+ text = TranslateCdata(value, self.encoding)
+ text, delimiter = TranslateCdataAttr(text)
+ self._write("=%s%s%s" % (delimiter, text, delimiter))
+ return
+
+ def visitProlog(self):
+ self._write("<?xml version='1.0' encoding='%s'?>" % (
+ self.encoding or 'utf-8'
+ ))
+ self._inText = 0
+ return
+
+ def visitDocument(self, node):
+ not self._html and self.visitProlog()
+ node.doctype and self.visitDocumentType(node.doctype)
+ self.visitNodeList(node.childNodes, exclude=node.doctype)
+ return
+
+ def visitDocumentFragment(self, node):
+ self.visitNodeList(node.childNodes)
+ return
+
+ def visitElement(self, node):
+ self._namespaces.append(self._namespaces[-1].copy())
+ inline = node.tagName in self._plainElements
+ not inline and self._tryIndent()
+ self._write('<%s' % node.tagName)
+ if self._isXhtml or not self._html:
+ namespaces = ''
+ if self._isXhtml:
+ nss = {'xml': XML_NAMESPACE, '': XHTML_NAMESPACE}
+ else:
+ nss = ext.GetAllNs(node)
+ if self._nsHints:
+ self._nsHints.update(nss)
+ nss = self._nsHints
+ self._nsHints = {}
+ del nss['xml']
+ for prefix in nss.keys():
+ if not self._namespaces[-1].has_key(prefix) or self._namespaces[-1][prefix] != nss[prefix]:
+ if prefix:
+ xmlns = " xmlns:%s='%s'" % (prefix, nss[prefix])
+ else:
+ xmlns = " xmlns='%s'" % nss[prefix]
+ namespaces = namespaces + xmlns
+
+ self._namespaces[-1][prefix] = nss[prefix]
+ self._write(namespaces)
+ for attr in node.attributes.values():
+ self.visitAttr(attr)
+ if len(node.childNodes):
+ self._write('>')
+ self._depth = self._depth + 1
+ self.visitNodeList(node.childNodes)
+ self._depth = self._depth - 1
+ if not self._html or (node.tagName not in HTML_FORBIDDEN_END):
+ not (self._inText and inline) and self._tryIndent()
+ self._write('</%s>' % node.tagName)
+ elif not self._html:
+ self._write('/>')
+ elif node.tagName not in HTML_FORBIDDEN_END:
+ self._write('></%s>' % node.tagName)
+ else:
+ self._write('>')
+ del self._namespaces[-1]
+ self._inText = 0
+ return
+
+ def visitText(self, node):
+ text = node.data
+ if self._indent:
+ text = string.strip(text) and text
+ if text:
+ if self._html:
+ text = TranslateHtmlCdata(text, self.encoding)
+ else:
+ text = TranslateCdata(text, self.encoding)
+ self.stream.write(text)
+ self._inText = 1
+ return
+
+ def visitDocumentType(self, doctype):
+ self._tryIndent()
+ self._write('<!DOCTYPE %s' % doctype.name)
+ if doctype.systemId and '"' in doctype.systemId:
+ system = "'%s'" % doctype.systemId
+ else:
+ system = '"%s"' % doctype.systemId
+ if doctype.publicId and '"' in doctype.publicId:
+ # We should probably throw an error
+ # Valid characters: <space> | <newline> | <linefeed> |
+ # [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%]
+ public = "'%s'" % doctype.publicId
+ else:
+ public = '"%s"' % doctype.publicId
+ if doctype.publicId and doctype.systemId:
+ self._write(' PUBLIC %s %s' % (public, system))
+ elif doctype.systemId:
+ self._write(' SYSTEM %s' % system)
+ if doctype.entities or doctype.notations:
+ self._write(' [')
+ self._depth = self._depth + 1
+ self.visitNamedNodeMap(doctype.entities)
+ self.visitNamedNodeMap(doctype.notations)
+ self._depth = self._depth - 1
+ self._tryIndent()
+ self._write(']>')
+ else:
+ self._write('>')
+ self._inText = 0
+ return
+
+ def visitEntity(self, node):
+ """Visited from a NamedNodeMap in DocumentType"""
+ self._tryIndent()
+ self._write('<!ENTITY %s' % (node.nodeName))
+ node.publicId and self._write(' PUBLIC %s' % node.publicId)
+ node.systemId and self._write(' SYSTEM %s' % node.systemId)
+ node.notationName and self._write(' NDATA %s' % node.notationName)
+ self._write('>')
+ return
+
+ def visitNotation(self, node):
+ """Visited from a NamedNodeMap in DocumentType"""
+ self._tryIndent()
+ self._write('<!NOTATION %s' % node.nodeName)
+ node.publicId and self._write(' PUBLIC %s' % node.publicId)
+ node.systemId and self._write(' SYSTEM %s' % node.systemId)
+ self._write('>')
+ return
+
+ def visitCDATASection(self, node):
+ self._tryIndent()
+ self._write('<![CDATA[%s]]>' % (node.data))
+ self._inText = 0
+ return
+
+ def visitComment(self, node):
+ self._tryIndent()
+ self._write('<!--%s-->' % (node.data))
+ self._inText = 0
+ return
+
+ def visitEntityReference(self, node):
+ self._write('&%s;' % node.nodeName)
+ self._inText = 1
+ return
+
+ def visitProcessingInstruction(self, node):
+ self._tryIndent()
+ self._write('<?%s %s?>' % (node.target, node.data))
+ self._inText = 0
+ return
+
+
+class PrintWalker(WalkerInterface):
+ def __init__(self, visitor, startNode):
+ WalkerInterface.__init__(self, visitor)
+ self.start_node = startNode
+ return
+
+ def step(self):
+ """There is really no step to printing. It prints the whole thing"""
+ self.visitor.visit(self.start_node)
+ return
+
+ def run(self):
+ return self.step()
diff --git a/lib/jython/Lib/xml/dom/ext/Visitor.py b/lib/jython/Lib/xml/dom/ext/Visitor.py new file mode 100644 index 000000000..4bad5a670 --- /dev/null +++ b/lib/jython/Lib/xml/dom/ext/Visitor.py @@ -0,0 +1,73 @@ +########################################################################
+#
+# File Name: Visitor.py
+#
+# Documentation: http://docs.4suite.com/4DOM/Visitor.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+class Visitor:
+ def visit(self, node):
+ """Default behavior for the visitor is simply to print an informational message"""
+ print "Visiting %s node %s\n"%(node.nodeType, node.nodeName)
+ return None
+
+class WalkerInterface:
+ def __init__(self, visitor):
+ self.visitor = visitor
+ pass
+
+ def step(self):
+ """Advance to the next item in order, visit, and then pause"""
+ pass
+
+ def run(self):
+ """Continue advancing from the current position through the last leaf node without pausing."""
+ pass
+
+
+class PreOrderWalker(WalkerInterface):
+ def __init__(self, visitor, startNode):
+ WalkerInterface.__init__(self, visitor)
+ self.node_stack = []
+ self.node_stack.append(startNode)
+
+ def step(self):
+ """
+ Visits the current node, and then advances to its first child,
+ if any, else the next sibling.
+ returns a tuple completed, ret_val
+ completed -- flags whether or not we've traversed the entire tree
+ ret_val -- return value from the visitor
+ """
+ completed = 0
+ ret_val = self.visitor.visit(self.node_stack[-1])
+ if (self.node_stack[-1].hasChildNodes()):
+ self.node_stack.append(self.node_stack[-1].firstChild)
+ else:
+ #Back-track until we can find a node with an unprocessed sibling
+ next_sib = None
+ while not next_sib and not completed:
+ next_sib = self.node_stack[-1].nextSibling
+ del self.node_stack[-1]
+ if next_sib:
+ self.node_stack.append(next_sib)
+ else:
+ if not len(self.node_stack):
+ completed = 1
+ return completed, ret_val
+
+ def run(self):
+ completed = 0
+ while not completed:
+ completed, ret_val = self.step()
+
+
+#Set the default Walker class to the PreOrderWalker.
+#User can change this according to preferences
+Walker = PreOrderWalker
diff --git a/lib/jython/Lib/xml/dom/ext/XHtml2HtmlPrinter.py b/lib/jython/Lib/xml/dom/ext/XHtml2HtmlPrinter.py new file mode 100644 index 000000000..4754f0590 --- /dev/null +++ b/lib/jython/Lib/xml/dom/ext/XHtml2HtmlPrinter.py @@ -0,0 +1,48 @@ +import string
+import Printer
+from xml.dom import XHTML_NAMESPACE
+from xml.dom.html import HTML_FORBIDDEN_END
+
+class HtmlDocType:
+ name = 'HTML'
+ publicId = "-//W3C//DTD HTML 4.0//EN"
+ systemId = "http://www.w3.org/TR/REC-html40/strict.dtd"
+ entities = notations = []
+
+class HtmlAttr:
+ def __init__(self, node):
+ self.namespaceURI = None
+ self.name = string.upper(node.localName or node.nodeName)
+ self.value = node.value
+ return
+
+class HtmlElement:
+ def __init__(self, node):
+ self.tagName = string.upper(node.localName or node.nodeName)
+ self.childNodes = node.childNodes
+ self.attributes = node.attributes
+ return
+
+class XHtml2HtmlPrintVisitor(Printer.PrintVisitor):
+ def __init__(self, stream, encoding, indent='', plainElements=None):
+ Printer.PrintVisitor.__init__(self,stream,encoding,indent,plainElements)
+ self._html = 1
+ return
+
+ def visitDocument(self, doc):
+ self.visitDocumentType(HtmlDocType)
+ self.visitNodeList(doc.childNodes, exclude=doc.doctype)
+ return
+
+ def visitAttr(self, node):
+ if node.namespaceURI and node.namespaceURI != XHTML_NAMESPACE:
+ return
+ Printer.PrintVisitor.visitAttr(self,HtmlAttr(node))
+
+ def visitElement(self, node):
+ if node.namespaceURI and node.namespaceURI != XHTML_NAMESPACE:
+ return
+ htmlElement = HtmlElement(node)
+ if htmlElement.tagName == 'XHTML':
+ htmlElement.tagName = 'HTML'
+ Printer.PrintVisitor.visitElement(self,htmlElement)
diff --git a/lib/jython/Lib/xml/dom/ext/XHtmlPrinter.py b/lib/jython/Lib/xml/dom/ext/XHtmlPrinter.py new file mode 100644 index 000000000..b57c9db30 --- /dev/null +++ b/lib/jython/Lib/xml/dom/ext/XHtmlPrinter.py @@ -0,0 +1,55 @@ +import string
+import Printer
+from xml.dom import XHTML_NAMESPACE
+
+# Wrapper classes to convert nodes from HTML to XHTML
+
+class XHtmlDocType:
+ def __init__(self, doctype):
+ self.name = 'html'
+ self.publicId = "-//W3C//DTD XHTML 1.0 Strict//EN"
+ self.systemId = "DTD/xhtml1-strict.dtd"
+ self.entities = doctype and doctype.entities or []
+ self.notations = doctype and doctype.notation or []
+ return
+
+class XHtmlAttr:
+ def __init__(self, node):
+ self.namespaceURI = XHTML_NAMESPACE
+ self.name = string.lower(node.name)
+ self.node = node
+ return
+
+ def __getattr__(self, key):
+ return getattr(self.node, key)
+
+class XHtmlElement:
+ def __init__(self, node):
+ self.tagName = string.lower(node.tagName)
+ self.node = node
+ return
+
+ def __getattr__(self, key):
+ return getattr(self.node, key)
+
+class XHtmlPrintVisitor(Printer.PrintVisitor):
+ def __init__(self, stream, encoding, indent):
+ xhtml = {None: 'http://www.w3.org/1999/xhtml'}
+ Printer.PrintVisitor.__init__(self, stream, encoding, indent, nsHints=xhtml)
+ self._html = 0
+ return
+
+ def visitDocument(self,node):
+ self.visitProlog()
+ self._tryIndent()
+ self.visitDocumentType(XHtmlDocType(node.doctype))
+ self.visitNodeList(node.childNodes, exclude=node.doctype)
+ return
+
+ def visitAttr(self, node):
+ Printer.PrintVisitor.visitAttr(self, XHtmlAttr(node))
+ return
+
+ def visitElement(self, node):
+ Printer.PrintVisitor.visitElement(self, XHtmlElement(node))
+ return
diff --git a/lib/jython/Lib/xml/dom/ext/__init__.py b/lib/jython/Lib/xml/dom/ext/__init__.py new file mode 100644 index 000000000..cd0522e27 --- /dev/null +++ b/lib/jython/Lib/xml/dom/ext/__init__.py @@ -0,0 +1,289 @@ +########################################################################
+#
+# File Name: __init__.py
+#
+# Documentation: http://docs.4suite.com/4DOM/__init__.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+"""Some Helper functions: 4DOM/PyXML-specific Extensions to the DOM,
+and DOM-related utilities."""
+
+import sys,string
+
+from xml.dom import Node
+from xml.dom.NodeFilter import NodeFilter
+from xml.dom import XML_NAMESPACE, XMLNS_NAMESPACE, DOMException
+from xml.dom.html import HTML_4_TRANSITIONAL_INLINE
+from c14n import Canonicalize
+import re
+
+
+import types
+if (sys.hexversion >> 8) > 0x10502:
+ IsDOMString = lambda s: type(s) in [types.StringType, types.UnicodeType]
+else:
+ IsDOMString = lambda s: type(s) == types.StringType
+
+class FtDomException(DOMException):
+ def __init__(self, *args):
+ apply(DOMException.__init__,(self,)+ args)
+ return
+
+
+NodeTypeDict = {
+ Node.ELEMENT_NODE : "Element",
+ Node.ATTRIBUTE_NODE : "Attr",
+ Node.TEXT_NODE : "Text",
+ Node.CDATA_SECTION_NODE : "CDATASection",
+ Node.ENTITY_REFERENCE_NODE : "EntityReference",
+ Node.ENTITY_NODE : "Entity",
+ Node.PROCESSING_INSTRUCTION_NODE : "ProcessingInstruction",
+ Node.COMMENT_NODE : "Comment",
+ Node.DOCUMENT_NODE : "Document",
+ Node.DOCUMENT_TYPE_NODE : "DocumentType",
+ Node.DOCUMENT_FRAGMENT_NODE : "DocumentFragment",
+ Node.NOTATION_NODE : "Notation"
+ }
+
+
+def NodeTypeToClassName(nodeType):
+ return NodeTypeDict[nodeType]
+
+
+def Print(root, stream=sys.stdout, encoding='UTF-8'):
+ if not hasattr(root, "nodeType"):
+ return
+ from xml.dom.ext import Printer
+ nss = SeekNss(root)
+ visitor = Printer.PrintVisitor(stream, encoding, nsHints=nss)
+ Printer.PrintWalker(visitor, root).run()
+ return
+
+
+def PrettyPrint(root, stream=sys.stdout, encoding='UTF-8', indent=' ',
+ preserveElements=None):
+ if not hasattr(root, "nodeType"):
+ return
+ from xml.dom.ext import Printer
+ nss_hints = SeekNss(root)
+ preserveElements = preserveElements or []
+ owner_doc = root.ownerDocument or root
+ if hasattr(owner_doc, 'getElementsByName'):
+ #We don't want to insert any whitespace into HTML inline elements
+ preserveElements = preserveElements + HTML_4_TRANSITIONAL_INLINE
+ visitor = Printer.PrintVisitor(stream, encoding, indent,
+ preserveElements, nss_hints)
+ Printer.PrintWalker(visitor, root).run()
+ stream.write('\n')
+ return
+
+
+def XHtmlPrettyPrint(root, stream=sys.stdout, encoding='UTF-8', indent=' '):
+ if not hasattr(root, "nodeType"):
+ return
+
+ from xml.dom.ext import XHtmlPrinter
+ visitor = XHtmlPrinter.XHtmlPrintVisitor(stream, encoding, indent)
+ Printer.PrintWalker(visitor, root).run()
+ stream.write('\n')
+ return
+
+
+def XHtmlPrint(root, stream=sys.stdout, encoding='UTF-8'):
+ XHtmlPrettyPrint(root, stream, encoding, '')
+
+
+def ReleaseNode(node):
+ cn = node.childNodes[:]
+ for child in cn:
+ if child.nodeType == Node.ELEMENT_NODE:
+ ReleaseNode(child)
+ node.removeChild(child)
+
+ if node.nodeType == Node.ELEMENT_NODE:
+ for ctr in range(node.attributes.length):
+ attr = node.attributes.item(0)
+ node.removeAttributeNode(attr)
+ ReleaseNode(attr)
+
+
+def StripHtml(startNode, preserveElements=None):
+ '''
+ Remove all text nodes in a given tree that do not have at least one
+ non-whitespace character, taking into account special HTML elements
+ '''
+ preserveElements = preserveElements or []
+ preserveElements = preserveElements + HTML_4_TRANSITIONAL_INLINE
+ remove_list = []
+ owner_doc = startNode.ownerDocument or startNode
+ snit = owner_doc.createNodeIterator(startNode, NodeFilter.SHOW_TEXT,
+ None, 0)
+ curr_node = snit.nextNode()
+ while curr_node:
+ #first of all make sure it is not inside one of the preserve_elements
+ ancestor = curr_node
+ while ancestor != startNode:
+ if ancestor.nodeType == Node.ELEMENT_NODE:
+ if ancestor.nodeName in preserveElements:
+ break
+ ancestor = ancestor.parentNode
+ else:
+ if not string.strip(curr_node.data):
+ remove_list.append(curr_node)
+ ancestor = ancestor.parentNode
+ curr_node = snit.nextNode()
+ for node_to_remove in remove_list:
+ node_to_remove.parentNode.removeChild(node_to_remove)
+ return startNode
+
+
+def StripXml(startNode, preserveElements=None):
+ '''
+ Remove all text nodes in a given tree that do not have at least one
+ non-whitespace character, taking into account xml:space
+ '''
+ preserveElements = preserveElements or []
+ remove_list = []
+ owner_doc = startNode.ownerDocument or startNode
+ snit = owner_doc.createNodeIterator(startNode, NodeFilter.SHOW_TEXT,
+ None, 0)
+ curr_node = snit.nextNode()
+ while curr_node:
+ #first of all make sure it is not inside xml:space='preserve'
+ if XmlSpaceState(curr_node) != 'preserve':
+ if not string.strip(curr_node.data):
+ #also make sure it is not inside one of the preserve elements
+ ancestor = curr_node
+ while ancestor != startNode:
+ if ancestor.nodeType == Node.ELEMENT_NODE:
+ if ancestor.localName in preserveElements or (ancestor.namespaceURI, ancestor.localName) in preserveElements:
+ break
+ ancestor = ancestor.parentNode
+ else:
+ remove_list.append(curr_node)
+ ancestor = ancestor.parentNode
+ curr_node = snit.nextNode()
+ for node_to_remove in remove_list:
+ node_to_remove.parentNode.removeChild(node_to_remove)
+ return startNode
+
+_id_key = ('', 'ID')
+
+def GetElementById(startNode, targetId):
+ '''
+ Return the element in the given tree with an ID attribute of the given
+ value
+ '''
+ owner_doc = startNode.ownerDocument or startNode
+ snit = owner_doc.createNodeIterator(startNode, NodeFilter.SHOW_ELEMENT,
+ None, 0)
+ curr_node = snit.nextNode()
+ while curr_node:
+ attr = curr_node.attributes.get(_id_key, None)
+ if attr and attr._get_nodeValue() == targetId:
+ return curr_node
+ curr_node = snit.nextNode()
+ return None
+
+
+def XmlSpaceState(node):
+ '''
+ Return the valid value of the xml:space attribute currently in effect
+ '''
+ valid_values = ['', 'preserve', 'default']
+ xml_space_found = 0
+ root_reached = 0
+ xml_space_state = ''
+ while not(xml_space_state or root_reached):
+ if node.nodeType == Node.ELEMENT_NODE:
+ xml_space_state = node.getAttributeNS(XML_NAMESPACE, 'space')
+ if xml_space_state not in valid_values: xml_space_state = ''
+ parent_node = node.parentNode
+ if not (parent_node and parent_node.nodeType == Node.ELEMENT_NODE):
+ root_reached = 1
+ node = parent_node
+ return xml_space_state
+
+
+def GetAllNs(node):
+ #The xml namespace is implicit
+ nss = {'xml': XML_NAMESPACE}
+ if node.nodeType == Node.ATTRIBUTE_NODE and node.ownerElement:
+ return GetAllNs(node.ownerElement)
+ if node.nodeType == Node.ELEMENT_NODE:
+ if node.namespaceURI:
+ nss[node.prefix] = node.namespaceURI
+ for attr in node.attributes.values():
+ if attr.namespaceURI == XMLNS_NAMESPACE:
+ if attr.localName == 'xmlns':
+ nss[''] = attr.value
+ else:
+ nss[attr.localName] = attr.value
+ elif attr.namespaceURI:
+ nss[attr.prefix] = attr.namespaceURI
+ if node.parentNode:
+ #Inner NS/Prefix mappings take precedence over outer ones
+ parent_nss = GetAllNs(node.parentNode)
+ parent_nss.update(nss)
+ nss = parent_nss
+ return nss
+
+
+#FIXME: this dict is a small memory leak: a splay tree that rotates out
+#out of the tree would be perfect.
+#g_splitNames = {}
+def SplitQName(qname):
+ """
+ Input a QName according to XML Namespaces 1.0
+ http://www.w3.org/TR/REC-xml-names
+ Return the name parts according to the spec
+ In the case of namespace declarations the tuple returned
+ is (prefix, 'xmlns')
+ Note that this won't hurt users since prefixes and local parts starting
+ with "xml" are reserved, but it makes ns-aware builders easier to write
+ """
+ #sName = g_splitNames.get(qname)
+ sName = None
+ if sName == None:
+ fields = string.splitfields(qname, ':')
+ if len(fields) == 1:
+ #Note: we could gain a tad more performance by interning 'xmlns'
+ if qname == 'xmlns':
+ sName = ('', 'xmlns')
+ else:
+ sName = ('', qname)
+ elif len(fields) == 2:
+ if fields[0] == 'xmlns':
+ sName = (fields[1], 'xmlns')
+ else:
+ sName = (fields[0], fields[1])
+ else:
+ sname = (None, None)
+ #g_splitNames[qname] = sName
+ return sName
+
+
+def SeekNss(node, nss=None):
+ '''traverses the tree to seek an approximate set of defined namespaces'''
+ nss = nss or {}
+ for child in node.childNodes:
+ if child.nodeType == Node.ELEMENT_NODE:
+ if child.namespaceURI:
+ nss[child.prefix] = child.namespaceURI
+ for attr in child.attributes.values():
+ if attr.namespaceURI == XMLNS_NAMESPACE:
+ if attr.localName == 'xmlns':
+ nss[''] = attr.value
+ else:
+ nss[attr.localName] = attr.value
+ elif attr.namespaceURI:
+ nss[attr.prefix] = attr.namespaceURI
+ SeekNss(child, nss)
+ return nss
+
diff --git a/lib/jython/Lib/xml/dom/ext/c14n.py b/lib/jython/Lib/xml/dom/ext/c14n.py new file mode 100644 index 000000000..251ff278d --- /dev/null +++ b/lib/jython/Lib/xml/dom/ext/c14n.py @@ -0,0 +1,251 @@ +#! /usr/bin/env python
+'''XML Canonicalization
+
+This module generates canonical XML, as defined in
+ http://www.w3.org/TR/xml-c14n
+
+It is limited in that it can only canonicalize an element and all its
+children; general document subsets are not supported.
+'''
+
+_copyright = '''Copyright 2001, Zolera Systems Inc. All Rights Reserved.
+Distributed under the terms of the Python 2.0 Copyright or later.'''
+
+from xml.dom import Node
+from xml.ns import XMLNS
+import re
+try:
+ import cStringIO
+ StringIO = cStringIO
+except:
+ import StringIO
+
+_attrs = lambda E: E.attributes or []
+_children = lambda E: E.childNodes or []
+
+def _sorter(n1, n2):
+ '''Sorting predicate for non-NS attributes.'''
+ i = cmp(n1.namespaceURI, n2.namespaceURI)
+ if i: return i
+ return cmp(n1.localName, n2.localName)
+
+def _sorter_ns(n1, n2):
+ '''Sorting predicate for NS attributes; "xmlns" always comes first.'''
+ if n1.localName == 'xmlns': return -1
+ if n2.localName == 'xmlns': return 1
+ return cmp(n1.localName, n2.localName)
+
+class _implementation:
+ '''Implementation class for C14N.'''
+
+ # Handlers for each node, by node type.
+ handlers = {}
+
+ # pattern/replacement list for whitespace stripping.
+ repats = (
+ ( re.compile(r'[ \t]+'), ' ' ),
+ ( re.compile(r'[\r\n]+'), '\n' ),
+ )
+
+ def __init__(self, node, write, nsdict={}, stripspace=0, nocomments=1):
+ '''Create and run the implementation.'''
+ if node.nodeType != Node.ELEMENT_NODE:
+ raise TypeError, 'Non-element node'
+ self.write, self.stripspace, self.nocomments = \
+ write, stripspace, nocomments
+
+ if nsdict == None or nsdict == {}:
+ nsdict = { 'xml': XMLNS.XML, 'xmlns': XMLNS.BASE }
+ self.ns_stack = [ nsdict ]
+
+ # Collect the initial list of xml:XXX attributes.
+ xmlattrs = []
+ for a in _attrs(node):
+ if a.namespaceURI == XMLNS.XML:
+ n = a.localName
+ xmlattrs.append(n)
+
+ # Walk up and get all xml:XXX attributes we inherit.
+ parent, inherited = node.parentNode, []
+ while parent:
+ if parent.nodeType != Node.ELEMENT_NODE: break
+ for a in _attrs(parent):
+ if a.namespaceURI != XMLNS.XML: continue
+ n = a.localName
+ if n not in xmlattrs:
+ xmlattrs.append(n)
+ inherited.append(a)
+ parent = parent.parentNode
+
+ self._do_element(node, inherited)
+ self.ns_stack.pop()
+
+ def _do_text(self, node):
+ 'Process a text node.'
+ s = node.data \
+ .replace("&", "&") \
+ .replace("<", "<") \
+ .replace(">", ">") \
+ .replace("\015", "
")
+ if self.stripspace:
+ for pat,repl in _implementation.repats: s = re.sub(pat, repl, s)
+ if s: self.write(s)
+ handlers[Node.TEXT_NODE] =_do_text
+ handlers[Node.CDATA_SECTION_NODE] =_do_text
+
+ def _do_pi(self, node):
+ '''Process a PI node. Since we start with an element, we're
+ never a child of the root, so we never write leading or trailing
+ #xA.
+ '''
+ W = self.write
+ W('<?')
+ W(node.nodeName)
+ s = node.data
+ if s:
+ W(' ')
+ W(s)
+ W('?>')
+ handlers[Node.PROCESSING_INSTRUCTION_NODE] =_do_pi
+
+ def _do_comment(self, node):
+ '''Process a comment node. Since we start with an element, we're
+ never a child of the root, so we never write leading or trailing
+ #xA.
+ '''
+ if self.nocomments: return
+ W = self.write
+ W('<!--')
+ W(node.data)
+ W('-->')
+ handlers[Node.COMMENT_NODE] =_do_comment
+
+ def _do_attr(self, n, value):
+ 'Process an attribute.'
+ W = self.write
+ W(' ')
+ W(n)
+ W('="')
+ s = value \
+ .replace("&", "&") \
+ .replace("<", "<") \
+ .replace('"', '"') \
+ .replace('\011', '	') \
+ .replace('\012', '
') \
+ .replace('\015', '
')
+ W(s)
+ W('"')
+
+ def _do_element(self, node, initialattrlist = []):
+ 'Process an element (and its children).'
+ name = node.nodeName
+ W = self.write
+ W('<')
+ W(name)
+
+ # Get parent namespace, make a copy for us to inherit.
+ parent_ns = self.ns_stack[-1]
+ my_ns = parent_ns.copy()
+
+ # Divide attributes into NS definitions and others.
+ nsnodes, others = [], initialattrlist[:]
+ for a in _attrs(node):
+ if a.namespaceURI == XMLNS.BASE:
+ nsnodes.append(a)
+ else:
+ others.append(a)
+
+ # Namespace attributes: update dictionary; if not already
+ # in parent, output it.
+ nsnodes.sort(_sorter_ns)
+ for a in nsnodes:
+ # Some DOMs seem to rename "xmlns='xxx'" strangely
+ n = a.nodeName
+ if n == "xmlns:":
+ key, n = "", "xmlns"
+ else:
+ key = a.localName
+
+ v = my_ns[key] = a.nodeValue
+ pval = parent_ns.get(key, None)
+
+ if n == "xmlns" and v in [ '', XMLNS.BASE ] \
+ and pval in [ '', XMLNS.BASE ]:
+ # Default namespace set to default value.
+ pass
+ elif v != pval:
+ self._do_attr(n, v)
+
+ # Other attributes: sort and output.
+ others.sort(_sorter)
+ for a in others: self._do_attr(a.nodeName, a.value)
+
+ W('>')
+
+ # Push our namespace dictionary, recurse, pop the dicionary.
+ self.ns_stack.append(my_ns)
+ for c in _children(node):
+ _implementation.handlers[c.nodeType](self, c)
+ # XXX Ignore unknown node types?
+ #handler = _implementation.handlers.get(c.nodeType, None)
+ #if handler: handler(self, c)
+ self.ns_stack.pop()
+ W('</%s>' % (name,))
+ handlers[Node.ELEMENT_NODE] =_do_element
+
+def Canonicalize(node, output=None, **kw):
+ '''Canonicalize a DOM element node and everything underneath it.
+ Return the text; if output is specified then output.write will
+ be called to output the text and None will be returned
+ Keyword parameters:
+ stripspace -- remove extra (almost all) whitespace from text nodes
+ nsdict -- a dictionary of prefix:uri namespace entries assumed
+ to exist in the surrounding context
+ comments -- keep comments if non-zero (default is zero)
+ '''
+
+ if not output: s = StringIO.StringIO()
+ _implementation(node,
+ (output and output.write) or s.write,
+ nsdict=kw.get('nsdict', {}),
+ stripspace=kw.get('stripspace', 0),
+ nocomments=kw.get('comments', 0) == 0,
+ )
+ if not output: return s.getvalue()
+
+if __name__ == '__main__':
+ text = '''<SOAP-ENV:Envelope xml:lang='en'
+ xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
+ xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchemaInstance"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchemaZ" xmlns:spare='foo'
+ SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
+ <SOAP-ENV:Body xmlns='test-uri'><?MYPI spenser?>
+ <zzz xsd:foo='xsdfoo' xsi:a='xsi:a'/>
+ <SOAP-ENC:byte>44</SOAP-ENC:byte> <!-- 1 -->
+ <Name xml:lang='en-GB'>This is the name</Name>Some
+content here on two lines.
+ <n2><![CDATA[<greeting>Hello</greeting>]]></n2> <!-- 3 -->
+ <n3 href='z&zz' xsi:type='SOAP-ENC:string'>
+ more content. indented </n3>
+ <a2 xmlns:f='z' xmlns:aa='zz'><i xmlns:f='z'>12</i><t>rich salz</t></a2> <!-- 8 -->
+ </SOAP-ENV:Body>
+ <z xmlns='myns' id='zzz'>The value of n3</z>
+ <zz xmlns:spare='foo' xmlns='myns2' id='tri2'><inner>content</inner></zz>
+</SOAP-ENV:Envelope>'''
+
+ print _copyright
+ from xml.dom.ext.reader import PyExpat
+ reader = PyExpat.Reader()
+ dom = reader.fromString(text)
+ for e in _children(dom):
+ if e.nodeType != Node.ELEMENT_NODE: continue
+ for ee in _children(e):
+ if ee.nodeType != Node.ELEMENT_NODE: continue
+ print '\n', '=' * 60
+ print Canonicalize(ee, nsdict={'spare':'foo'}, stripspace=1)
+ print '-' * 60
+ print Canonicalize(ee, stripspace=0)
+ print '-' * 60
+ print Canonicalize(ee, comments=1)
+ print '=' * 60
diff --git a/lib/jython/Lib/xml/dom/ext/reader/Sax.py b/lib/jython/Lib/xml/dom/ext/reader/Sax.py new file mode 100644 index 000000000..e75d5cc52 --- /dev/null +++ b/lib/jython/Lib/xml/dom/ext/reader/Sax.py @@ -0,0 +1,171 @@ +########################################################################
+#
+# File Name: Sax.py
+#
+# Documentation: http://docs.4suite.com/4DOM/Sax.py.html
+#
+"""
+Components for reading XML files from a SAX producer.
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import sys, string, cStringIO
+from xml.sax import saxlib, saxexts, drivers
+from xml.dom import Entity, DocumentType, Document
+from xml.dom import DocumentType, Document
+from xml.dom import implementation
+from xml.dom.ext import SplitQName, ReleaseNode
+from xml.dom.ext import reader
+
+class XmlDomGenerator(saxlib.HandlerBase):
+ def __init__(self, keepAllWs=0):
+ self._keepAllWs = keepAllWs
+ return
+
+ def initState(self, ownerDoc=None):
+ """
+ If None is passed in as the doc, set up an empty document to act
+ as owner and also add all elements to this document
+ """
+ if ownerDoc == None:
+ dt = implementation.createDocumentType('', '', '')
+ self._ownerDoc = implementation.createDocument('', None, dt)
+ self._rootNode = self._ownerDoc
+ else:
+ self._ownerDoc = ownerDoc
+ #Create a docfrag to hold all the generated nodes.
+ self._rootNode = self._ownerDoc.createDocumentFragment()
+
+ #Set up the stack which keeps track of the nesting of DOM nodes.
+ self._nodeStack = []
+ self._nodeStack.append(self._rootNode)
+ self._currText = ''
+ return
+
+ def getRootNode(self):
+ self._completeTextNode()
+ return self._rootNode
+
+ def _completeTextNode(self):
+ if self._currText:
+ new_text = self._ownerDoc.createTextNode(self._currText)
+ self._nodeStack[-1].appendChild(new_text)
+ self._currText = ''
+
+ #Overridden DTDHandler methods
+ def notationDecl (self, name, publicId, systemId):
+ new_notation = self._ownerDoc.createNotation(self._ownerDoc, publicId, systemId, name)
+ self._ownerDoc.documentType.notations.setNamedItem(new_notation)
+
+ def unparsedEntityDecl (self, name, publicId, systemId, notationName):
+ new_notation = implementation.createEntity(self._ownerDoc, publicId, systemId, notationName)
+ self._ownerDoc.documentType.entities.setNamedItem(new_notation)
+
+ #Overridden DocumentHandler methods
+ def processingInstruction (self, target, data):
+ self._completeTextNode()
+ p = self._ownerDoc.createProcessingInstruction(target,data);
+ self._nodeStack[-1].appendChild(p)
+
+ def startElement(self, name, attribs):
+ self._completeTextNode()
+ new_element = self._ownerDoc.createElement(name)
+
+ for curr_attrib_key in attribs.keys():
+ new_element.setAttribute(
+ curr_attrib_key,
+ attribs[curr_attrib_key]
+ )
+ self._nodeStack.append(new_element)
+
+ def endElement(self, name):
+ self._completeTextNode()
+ new_element = self._nodeStack[-1]
+ del self._nodeStack[-1]
+ self._nodeStack[-1].appendChild(new_element)
+
+ def ignorableWhitespace(self, ch, start, length):
+ """
+ If 'keepAllWs' permits, add ignorable white-space as a text node.
+ A Document node cannot contain text nodes directly.
+ If the white-space occurs outside the root element, there is no place
+ for it in the DOM and it must be discarded.
+ """
+ if self._keepAllWs:
+ self._currText = self._currText + ch[start:start+length]
+
+ def characters(self, ch, start, length):
+ self._currText = self._currText + ch[start:start+length]
+
+ #Overridden ErrorHandler methods
+ #def warning(self, exception):
+ # raise exception
+
+ def error(self, exception):
+ raise exception
+
+ def fatalError(self, exception):
+ raise exception
+
+
+class Reader(reader.Reader):
+ def __init__(self, validate=0, keepAllWs=0, catName=None,
+ saxHandlerClass=XmlDomGenerator, parser=None):
+ #Create an XML DOM from SAX events
+ self.parser = parser or (validate and saxexts.XMLValParserFactory.make_parser()) or saxexts.XMLParserFactory.make_parser()
+ if catName:
+ #set up the catalog, if there is one
+ from xml.parsers.xmlproc import catalog
+ cat_handler = catalog.SAX_catalog(catName, catalog.CatParserFactory())
+ self.parser.setEntityResolver(cat_handler)
+ self.handler = saxHandlerClass(keepAllWs)
+ self.parser.setDocumentHandler(self.handler)
+ self.parser.setDTDHandler(self.handler)
+ self.parser.setErrorHandler(self.handler)
+ return
+
+ def releaseNode(self, node):
+ ReleaseNode(node)
+
+ def fromStream(self, stream, ownerDocument=None):
+ self.handler.initState(ownerDoc=ownerDocument)
+ self.parser.parseFile(stream)
+ return self.handler.getRootNode()
+
+
+########################## Deprecated ##############################
+
+def FromXmlStream(stream, ownerDocument=None, validate=0, keepAllWs=0,
+ catName=None, saxHandlerClass=XmlDomGenerator, parser=None):
+ reader = Reader(validate, keepAllWs, catName, saxHandlerClass, parser)
+ return reader.fromStream(stream, ownerDocument)
+
+
+def FromXml(text, ownerDocument=None, validate=0, keepAllWs=0,
+ catName=None, saxHandlerClass=XmlDomGenerator, parser=None):
+ fp = cStringIO.StringIO(text)
+ rv = FromXmlStream(fp, ownerDocument, validate, keepAllWs, catName,
+ saxHandlerClass, parser)
+ return rv
+
+
+def FromXmlFile(fileName, ownerDocument=None, validate=0, keepAllWs=0,
+ catName=None, saxHandlerClass=XmlDomGenerator, parser=None):
+ fp = open(fileName, 'r')
+ rv = FromXmlStream(fp, ownerDocument, validate, keepAllWs, catName,
+ saxHandlerClass, parser)
+ fp.close()
+ return rv
+
+
+def FromXmlUrl(url, ownerDocument=None, validate=0, keepAllWs=0,
+ catName=None, saxHandlerClass=XmlDomGenerator, parser=None):
+ import urllib
+ fp = urllib.urlopen(url)
+ rv = FromXmlStream(fp, ownerDocument, validate, keepAllWs, catName,
+ saxHandlerClass, parser)
+ fp.close()
+ return rv
diff --git a/lib/jython/Lib/xml/dom/ext/reader/Sax2.py b/lib/jython/Lib/xml/dom/ext/reader/Sax2.py new file mode 100644 index 000000000..c7df92f29 --- /dev/null +++ b/lib/jython/Lib/xml/dom/ext/reader/Sax2.py @@ -0,0 +1,347 @@ +########################################################################
+#
+# File Name: Sax2.py
+#
+# Documentation: http://docs.4suite.com/4DOM/Sax2.py.html
+#
+"""
+Components for reading XML files from a SAX2 producer.
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000, 2001 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import sys, string, cStringIO, os, urllib
+from xml.sax import saxlib, saxutils, sax2exts, handler
+from xml.dom import Entity, DocumentType, Document
+from xml.dom import Node
+from xml.dom import implementation
+from xml.dom.ext import SplitQName, ReleaseNode
+from xml.dom import XML_NAMESPACE, XMLNS_NAMESPACE
+from xml.dom import Element
+from xml.dom import Attr
+from xml.dom.ext import reader
+
+
+class NsHandler:
+ def initState(self, ownerDoc=None):
+ self._namespaces = {'xml': XML_NAMESPACE}
+ self._namespaceStack = []
+ return
+
+ def startElement(self, name, attribs):
+ self._completeTextNode()
+ old_nss = {}
+ del_nss = []
+ for curr_attrib_key, value in attribs.items():
+ (prefix, local) = SplitQName(curr_attrib_key)
+ if local == 'xmlns':
+ if self._namespaces.has_key(prefix):
+ old_nss[prefix] = self._namespaces[prefix]
+ else:
+ del_nss.append(prefix)
+ if (prefix or value):
+ self._namespaces[prefix] = attribs[curr_attrib_key]
+ else:
+ del self._namespaces[prefix]
+
+ self._namespaceStack.append((old_nss, del_nss))
+ (prefix, local) = SplitQName(name)
+ nameSpace = self._namespaces.get(prefix, '')
+
+ if self._ownerDoc:
+ new_element = self._ownerDoc.createElementNS(nameSpace, (prefix and prefix + ':' + local) or local)
+ else:
+ self._initRootNode(nameSpace, name)
+ new_element = self._ownerDoc.documentElement
+
+ for curr_attrib_key,curr_attrib_value in attribs.items():
+ (prefix, local) = SplitQName(curr_attrib_key)
+ if local == 'xmlns':
+ namespace = XMLNS_NAMESPACE
+ attr = self._ownerDoc.createAttributeNS(namespace,
+ local + ':' + prefix)
+ else:
+ namespace = prefix and self._namespaces.get(prefix, '') or ''
+ attr = self._ownerDoc.createAttributeNS(namespace,
+ (prefix and prefix + ':' + local) or local)
+ attr.value = curr_attrib_value
+ new_element.setAttributeNodeNS(attr)
+ self._nodeStack.append(new_element)
+ return
+
+ def endElement(self, name):
+ self._completeTextNode()
+ new_element = self._nodeStack[-1]
+ del self._nodeStack[-1]
+ old_nss, del_nss = self._namespaceStack[-1]
+ del self._namespaceStack[-1]
+ self._namespaces.update(old_nss)
+ for prefix in del_nss:
+ del self._namespaces[prefix]
+ if new_element != self._ownerDoc.documentElement:
+ self._nodeStack[-1].appendChild(new_element)
+ return
+
+
+class XmlDomGenerator(NsHandler, saxlib.HandlerBase, saxlib.LexicalHandler,
+ saxlib.DeclHandler):
+ def __init__(self, keepAllWs=0):
+ self._keepAllWs = keepAllWs
+ return
+
+ def initState(self, ownerDoc=None):
+ self._ownerDoc = None
+ self._rootNode = None
+ #Set up the stack which keeps track of the nesting of DOM nodes.
+ self._nodeStack = []
+ if ownerDoc:
+ self._ownerDoc = ownerDoc
+ #Create a docfrag to hold all the generated nodes.
+ self._rootNode = self._ownerDoc.createDocumentFragment()
+ self._nodeStack.append(self._rootNode)
+ self._dt = None
+ self._xmlDecl = None
+ self._orphanedNodes = []
+ self._currText = ''
+ NsHandler.initState(self, ownerDoc)
+ return
+
+ def _initRootNode(self, docElementUri, docElementName):
+ if not self._dt:
+ self._dt = implementation.createDocumentType(docElementName,'','')
+ self._ownerDoc = implementation.createDocument(docElementUri, docElementName, self._dt)
+ if self._xmlDecl:
+ decl_data = 'version="%s"' % (
+ self._xmlDecl['version']
+ )
+ if self._xmlDecl['encoding']:
+ decl_data = decl_data + ' encoding="%s"'%(
+ self._xmlDecl['encoding']
+ )
+ if self._xmlDecl['standalone']:
+ decl_data = decl_data + ' standalone="%s"'%(
+ self._xmlDecl['standalone']
+ )
+ xml_decl_node = self._ownerDoc.createProcessingInstruction(
+ 'xml',
+ decl_data
+ )
+ self._ownerDoc.insertBefore(xml_decl_node, self._ownerDoc.docType)
+ before_doctype = 1
+ for o_node in self._orphanedNodes:
+ if o_node[0] == 'pi':
+ pi = self._ownerDoc.createProcessingInstruction(
+ o_node[1],
+ o_node[2]
+ )
+ if before_doctype:
+ self._ownerDoc.insertBefore(pi, self._dt)
+ else:
+ self._ownerDoc.appendChild(pi)
+ elif o_node[0] == 'comment':
+ comment = self._ownerDoc.createComment(o_node[1])
+ if before_doctype:
+ self._ownerDoc.insertBefore(comment, self._dt)
+ else:
+ self._ownerDoc.appendChild(comment)
+ elif o_node[0] == 'doctype':
+ before_doctype = 0
+ elif o_node[0] == 'unparsedentitydecl':
+ apply(self.unparsedEntityDecl, o_node[1:])
+ else:
+ raise Exception("Unknown orphaned node:"+o_node[0])
+ self._rootNode = self._ownerDoc
+ self._nodeStack.append(self._rootNode)
+ return
+
+ def _completeTextNode(self):
+ #Note some parsers don't report ignorable white space properly
+ if self._currText and len(self._nodeStack) and self._nodeStack[-1].nodeType != Node.DOCUMENT_NODE:
+ new_text = self._ownerDoc.createTextNode(self._currText)
+ self._nodeStack[-1].appendChild(new_text)
+ self._currText = ''
+ return
+
+ def getRootNode(self):
+ self._completeTextNode()
+ return self._rootNode
+
+ #Overridden DocumentHandler methods
+ def processingInstruction(self, target, data):
+ if self._rootNode:
+ self._completeTextNode()
+ pi = self._ownerDoc.createProcessingInstruction(target, data)
+ self._nodeStack[-1].appendChild(pi)
+ else:
+ self._orphanedNodes.append(('pi', target, data))
+ return
+
+ def startElementNS(self, name, qname, attribs):
+ namespace = name[0]
+ local = name[1]
+ if self._ownerDoc:
+ new_element = self._ownerDoc.createElementNS(namespace, qname)
+ else:
+ self._initRootNode(namespace, qname)
+ new_element = self._ownerDoc.documentElement
+
+ for attr_qname in attribs.getQNames():
+ attr_ns = attribs.getNameByQName(attr_qname)[0]
+ attr = self._ownerDoc.createAttributeNS(attr_ns, attr_qname)
+ attr.value = attribs.getValueByQName(attr_qname)
+ new_element.setAttributeNodeNS(attr)
+ self._nodeStack.append(new_element)
+ return
+
+ def endElementNS(self, name, qname):
+ self._completeTextNode()
+ new_element = self._nodeStack[-1]
+ del self._nodeStack[-1]
+ if new_element != self._ownerDoc.documentElement:
+ self._nodeStack[-1].appendChild(new_element)
+ return
+
+ def ignorableWhitespace(self, chars):
+ """
+ If 'keepAllWs' permits, add ignorable white-space as a text node.
+ A Document node cannot contain text nodes directly.
+ If the white-space occurs outside the root element, there is no place
+ for it in the DOM and it must be discarded.
+ """
+ if self._keepAllWs and self._nodeStack[-1].nodeType != Node.DOCUMENT_NODE:
+ self._currText = self._currText + chars
+ return
+
+ def characters(self, chars):
+ self._currText = self._currText + chars
+ return
+
+ #Overridden LexicalHandler methods
+ def xmlDecl(self, version, encoding, standalone):
+ self._xmlDecl = {'version': version, 'encoding': encoding, 'standalone': standalone}
+ return
+
+ def startDTD(self, doctype, publicID, systemID):
+ self._dt = implementation.createDocumentType(doctype, publicID, systemID)
+ self._orphanedNodes.append(('doctype',))
+ return
+
+ def comment(self, text):
+ if self._rootNode:
+ self._completeTextNode()
+ new_comment = self._ownerDoc.createComment(text)
+ self._nodeStack[-1].appendChild(new_comment)
+ else:
+ self._orphanedNodes.append(('comment', text))
+ return
+
+ def startCDATA(self):
+ self._completeTextNode()
+ return
+
+ def endCDATA(self):
+ #NOTE: this doesn't handle the error where endCDATA is called
+ #Without corresponding startCDATA. Is this a problem?
+ if self._currText:
+ new_text = self._ownerDoc.createCDATASection(self._currText)
+ self._nodeStack[-1].appendChild(new_text)
+ self._currText = ''
+ return
+
+ #Overridden DTDHandler methods
+ def notationDecl (self, name, publicId, systemId):
+ new_notation = self._ownerDoc.getFactory().createNotation(self._ownerDoc, publicId, systemId, name)
+ self._ownerDoc.getDocumentType().getNotations().setNamedItem(new_notation)
+ return
+
+ def unparsedEntityDecl (self, name, publicId, systemId, ndata):
+ if self._ownerDoc:
+ new_notation = self._ownerDoc.getFactory().createEntity(self._ownerDoc, publicId, systemId, name)
+ self._ownerDoc.getDocumentType().getEntities().setNamedItem(new_notation)
+ else:
+ self._orphanedNodes.append(('unparsedentitydecl', name, publicId, systemId, ndata))
+ return
+
+ #Overridden ErrorHandler methods
+ #FIXME: How do we handle warnings?
+
+ def error(self, exception):
+ raise exception
+
+ def fatalError(self, exception):
+ raise exception
+
+
+class Reader(reader.Reader):
+ def __init__(self, validate=0, keepAllWs=0, catName=None,
+ saxHandlerClass=XmlDomGenerator, parser=None):
+ self.parser = parser or (validate and sax2exts.XMLValParserFactory.make_parser()) or sax2exts.XMLParserFactory.make_parser()
+ if catName:
+ #set up the catalog, if there is one
+ from xml.parsers.xmlproc import catalog
+ cat_handler = catalog.SAX_catalog(
+ catName, catalog.CatParserFactory()
+ )
+ self.parser.setEntityResolver(cat_handler)
+ self.handler = saxHandlerClass(keepAllWs)
+ self.parser.setContentHandler(self.handler)
+ self.parser.setDTDHandler(self.handler)
+ self.parser.setErrorHandler(self.handler)
+ try:
+ #FIXME: Maybe raise a warning?
+ self.parser.setProperty(handler.property_lexical_handler, self.handler)
+ self.parser.setProperty(handler.property_declaration_handler, self.handler)
+ except (SystemExit, KeyboardInterrupt):
+ raise
+ except:
+ pass
+ return
+
+ def fromStream(self, stream, ownerDoc=None):
+ self.handler.initState(ownerDoc=ownerDoc)
+ #self.parser.parseFile(stream)
+ s = saxutils.prepare_input_source(stream)
+ self.parser.parse(s)
+ rt = self.handler.getRootNode()
+ #if hasattr(self.parser.parser,'deref'):
+ # self.parser.parser.deref()
+ #self.parser.parser = None
+ #self.parser = None
+ #self.handler = None
+ return rt
+
+########################## Deprecated ##############################
+
+def FromXmlStream(stream, ownerDocument=None, validate=0, keepAllWs=0,
+ catName=None, saxHandlerClass=XmlDomGenerator, parser=None):
+ reader = Reader(validate, keepAllWs, catName, saxHandlerClass, parser)
+ return reader.fromStream(stream, ownerDocument)
+
+
+def FromXml(text, ownerDocument=None, validate=0, keepAllWs=0,
+ catName=None, saxHandlerClass=XmlDomGenerator, parser=None):
+ fp = cStringIO.StringIO(text)
+ rv = FromXmlStream(fp, ownerDocument, validate, keepAllWs, catName,
+ saxHandlerClass, parser)
+ return rv
+
+
+def FromXmlFile(fileName, ownerDocument=None, validate=0, keepAllWs=0,
+ catName=None, saxHandlerClass=XmlDomGenerator, parser=None):
+ fp = open(fileName, 'r')
+ rv = FromXmlStream(fp, ownerDocument, validate, keepAllWs, catName,
+ saxHandlerClass, parser)
+ fp.close()
+ return rv
+
+
+def FromXmlUrl(url, ownerDocument=None, validate=0, keepAllWs=0,
+ catName=None, saxHandlerClass=XmlDomGenerator, parser=None):
+ import urllib
+ fp = urllib.urlopen(url)
+ rv = FromXmlStream(fp, ownerDocument, validate, keepAllWs, catName,
+ saxHandlerClass, parser)
+ fp.close()
+ return rv
diff --git a/lib/jython/Lib/xml/dom/ext/reader/Sax2Lib.py b/lib/jython/Lib/xml/dom/ext/reader/Sax2Lib.py new file mode 100644 index 000000000..a50b2775f --- /dev/null +++ b/lib/jython/Lib/xml/dom/ext/reader/Sax2Lib.py @@ -0,0 +1,282 @@ +"""A Python translation of the SAX2 parser API. This file provides only
+default classes with absolutely minimum functionality, from which
+drivers and applications can be subclassed.
+
+Many of these classes are empty and are included only as documentation
+of the interfaces.
+"""
+
+from xml.sax import saxlib
+
+class LexicalHandler:
+ """
+ Default handler for lexical events
+ Note: All methods can raise SAXException
+ """
+ handlerId = 'http://xml.org/sax/handlers/lexical'
+
+ def xmlDecl(self, version, encoding, standalone):
+ """The XML Declaration"""
+ pass
+
+ def startDTD(self, doctype, publicID, systemID):
+ """Invoked at the beginning of the DOCTYPE declaration"""
+ pass
+
+ def endDTD(self):
+ """
+ Invoked after all components of the DOCTYPE declaration,
+ including both internal and external DTD subsets
+ """
+ pass
+
+ def startEntity(self, name):
+ """
+ Note: If an external DTD subset is read, it will invoke this method
+ with special entity name of "[DTD]"
+ """
+ pass
+
+ def endEntity(self, name):
+ pass
+
+ def comment(self, text):
+ """XML Comment"""
+ pass
+
+ def startCDATA(self):
+ """Beginning of CDATA Section"""
+ pass
+
+ def endCDATA(self):
+ """End of CDATA Section"""
+ pass
+
+
+class AttributeList2(saxlib. AttributeList):
+ def isSpecified(self, id):
+ """
+ Whether the attribute value with the given name or index was
+ explicitly specified in the element, or was determined from the
+ default. Parameter can be either integer index or attribute name.
+ None (the default) signals 'Don't Know', else a boolean return
+ """
+ pass
+
+ def getEntityRefList(self, id):
+ """
+ XML 1,0 parsers are required to report all entity references,
+ even if unexpanded. This includes those in attribute strings.
+ Many parsers and apps ignore this, but for full conformance,
+ This method can be called to get a list of indexes referring
+ to entity references within the attribute value string for the
+ given name or index. Parameter can be either integer index or
+ attribute name.
+ """
+ pass
+
+
+class EntityRefList:
+ """
+ This is the entity-reference list returned by
+ AttributeList2.getEntityRefList(index)
+ """
+ def getLength(self):
+ "Return the number of Entity Ref pointers"
+ pass
+
+ def getEntityName(self, index):
+ "Return the name of the entity reference at the given index"
+ pass
+
+ def getEntityRefStart(self, index):
+ """
+ Return the string start position of the entity reference
+ at the given index
+ """
+ pass
+
+ def getEntityRefEnd(self, index):
+ """
+ Return the string end position of the entity reference
+ at the given index
+ """
+ pass
+
+ def __len__(self):
+ "Alias for getLength."
+ pass
+
+
+class DTDDeclHandler:
+ """
+ A handler for a minimal set of DTD Events
+ """
+ MODEL_ELEMENTS = 1
+ MODEL_MIXED = 2
+ MODEL_ANY = 3
+ MODEL_EMPTY = 4
+ ATTRIBUTE_DEFAULTED = 1
+ ATTRIBUTE_IMPLIED = 2
+ ATTRIBUTE_REQUIRED = 3
+ ATTRIBUTE_FIXED = 4
+
+ handlerId = 'http://xml.org/sax/handlers/dtd-decl'
+
+ def elementDecl(self, name, modelType, model):
+ """
+ Report an element-type declaration.
+ name and model are strings, modelType is an enumerated int from 1 to 4
+ """
+ pass
+
+ def attributeDecl(self,
+ element,
+ name,
+ type,
+ defaultValue,
+ defaultType,
+ entityRefs):
+ """
+ Report an attribute declaration. The first 4 parameters are strings,
+ defaultType is an integer from 1 to 4, entityRefs is an EntityRefList
+ """
+ pass
+
+ def externalEntityDecl(self, name, isParameterEntity, publicId, systemId):
+ """
+ Report an external entity declaration.
+ All parameters are strings except for isParameterEntity,
+ which is 0 or 1
+ """
+ pass
+
+ def internalEntityDecl(self, name, isParameterEntity, value):
+ """
+ Report an external entity declaration.
+ All parameters are strings except for isParameterEntity,
+ which is 0 or 1
+ """
+ pass
+
+
+class NamespaceHandler:
+ """
+ Receive callbacks for the start and end of the scope of each
+ namespace declaration.
+ """
+
+ handlerId = 'http://xml.org/sax/handlers/namespace'
+
+ def startNamespaceDeclScope(self, prefix, uri):
+ """
+ Report the start of the scope of a namespace declaration.
+ This event will be reported before the startElement event
+ for the element containing the namespace declaration. All
+ declarations must be properly nested; if there are multiple
+ declarations in a single element, they must end in the opposite
+ order that they began.
+ both parameters are strings
+ """
+ pass
+
+ def endNamespaceDeclScope(self, prefix):
+ """
+ Report the end of the scope of a namespace declaration.
+ This event will be reported after the endElement event for
+ the element containing the namespace declaration. Namespace
+ scopes must be properly nested.
+ """
+ pass
+
+
+class ModParser(saxlib.Parser):
+ """
+ All methods may raise
+ SAXNotSupportedException
+ """
+ def setFeature(self, featureID, state):
+ """
+ featureId is a string, state a boolean
+ """
+ pass
+
+ def setHandler(self, handlerID, handler):
+ """
+ handlerID is a string, handler a handler instance
+ """
+ pass
+
+ def set(self, propID, value):
+ """
+ propID is a string, value of arbitrary type
+ """
+ pass
+
+ def get(self, propID):
+ pass
+
+
+import sys
+if sys.platform[0:4] == 'java':
+ from exceptions import Exception
+
+class SAXNotSupportedException(Exception):
+ """
+ Indicate that a SAX2 parser interface does not support a particular
+ feature or handler, or property.
+ """
+ pass
+
+
+#Just a few helper lists with the core components
+CoreHandlers = [
+'http://xml.org/sax/handlers/lexical',
+'http://xml.org/sax/handlers/dtd-decl',
+'http://xml.org/sax/handlers/namespace'
+]
+
+CoreProperties = [
+'http://xml.org/sax/properties/namespace-sep',
+#write-only string
+#Set the separator to be used between the URI part of a name and the
+#local part of a name when namespace processing is being performed
+#(see the http://xml.org/sax/features/namespaces feature). By
+#default, the separator is a single space. This property may not be
+#set while a parse is in progress (raises SAXNotSupportedException).
+
+'http://xml.org/sax/properties/dom-node',
+#read-only Node instance
+#Get the DOM node currently being visited, if the SAX parser is
+#iterating over a DOM tree. If the parser recognises and supports
+#this property but is not currently visiting a DOM node, it should
+#return null (this is a good way to check for availability before the
+#parse begins).
+
+'http://xml.org/sax/properties/xml-string'
+#read-only string
+#Get the literal string of characters associated with the current
+#event. If the parser recognises and supports this property but is
+#not currently parsing text, it should return null (this is a good
+#way to check for availability before the parse begins).
+]
+
+CoreFeatures = [
+'http://xml.org/sax/features/validation',
+#Validate (1) or don't validate (0).
+
+'http://xml.org/sax/features/external-general-entities',
+#Expand external general entities (1) or don't expand (0).
+
+'http://xml.org/sax/features/external-parameter-entities',
+#Expand external parameter entities (1) or don't expand (0).
+
+'http://xml.org/sax/features/namespaces',
+#Preprocess namespaces (1) or don't preprocess (0). See also
+
+#the http://xml.org/sax/properties/namespace-sep property.
+'http://xml.org/sax/features/normalize-text'
+#Ensure that all consecutive text is returned in a single callback to
+#DocumentHandler.characters or DocumentHandler.ignorableWhitespace
+#(1) or explicitly do not require it (0).
+]
diff --git a/lib/jython/Lib/xml/dom/ext/reader/__init__.py b/lib/jython/Lib/xml/dom/ext/reader/__init__.py new file mode 100644 index 000000000..66cf874cf --- /dev/null +++ b/lib/jython/Lib/xml/dom/ext/reader/__init__.py @@ -0,0 +1,76 @@ +########################################################################
+#
+# File Name: __init__.py
+#
+# Documentation: http://docs.4suite.org/4DOM/ext/reader/__init__.py.html
+#
+"""
+The 4DOM reader module has routines for deserializing XML and HTML to DOM
+WWW: http://4suite.org/4DOM e-mail: support@4suite.org
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.org/COPYRIGHT for license and copyright information
+"""
+
+import string, urllib, urlparse, cStringIO, os
+from xml.dom.ext import ReleaseNode
+
+try:
+ import codecs
+ from types import UnicodeType
+ encoder = codecs.lookup("utf-8")[0] # encode,decode,reader,writer
+ def StrStream(st):
+ if type(st) is UnicodeType:
+ st = encoder(st)[0]
+ return cStringIO.StringIO(st)
+except ImportError:
+ StrStream = lambda x: cStringIO.StringIO(x)
+
+import string, urlparse, urllib, os
+
+
+class BaseUriResolver:
+ def resolve(self, uri, base=''):
+ #scheme, netloc, path, params, query, fragment
+ scheme = urlparse.urlparse(uri)[0]
+ if scheme in ['', 'http', 'ftp', 'file', 'gopher']:
+ uri = urlparse.urljoin(base, uri)
+ if os.access(uri, os.F_OK):
+ #Hack because urllib breaks on Windows paths
+ stream = open(uri)
+ else:
+ stream = urllib.urlopen(uri)
+ return stream
+
+BASIC_RESOLVER = BaseUriResolver()
+
+class Reader:
+ def clone(self):
+ """Used to create a new copy of this instance"""
+ if hasattr(self,'__getinitargs__'):
+ return apply(self.__class__,self.__getinitargs__())
+ else:
+ return self.__class__()
+
+ def fromStream(self, stream, ownerDoc=None):
+ """Create a DOM from a stream"""
+ raise "NOT OVERIDDEN"
+
+ def fromString(self, str, ownerDoc=None):
+ """Create a DOM from a string"""
+ stream = StrStream(str)
+ try:
+ return self.fromStream(stream, ownerDoc)
+ finally:
+ stream.close()
+
+ def fromUri(self, uri, ownerDoc=None):
+ stream = BASIC_RESOLVER.resolve(uri)
+ try:
+ return self.fromStream(stream, ownerDoc)
+ finally:
+ stream.close()
+
+ def releaseNode(self, node):
+ "Free a DOM tree"
+ node and ReleaseNode(node)
diff --git a/lib/jython/Lib/xml/dom/html/GenerateHtml.py b/lib/jython/Lib/xml/dom/html/GenerateHtml.py new file mode 100644 index 000000000..07ea1fc90 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/GenerateHtml.py @@ -0,0 +1,270 @@ +#!/usr/bin/env python
+import string, os, sys
+try:
+ from xml.dom import Node
+ from xml.dom.ext.reader import Sax
+ Reader = Sax.FromXmlFile
+except ImportError:
+ print 'You need to have PyXML installed to run this program'
+ sys.exit(1)
+
+
+def Generate(fileName,
+ output_dir=None,
+ program_name=None
+ ):
+ output_dir = output_dir or '.'
+
+ dom = Reader(fileName)
+
+ header = CreateHeader(dom, program_name)
+ classes = dom.getElementsByTagName('class')
+ outfiles = []
+ for klass in classes:
+ outfiles.append(GenClassFile(klass, header, output_dir))
+ return outfiles
+
+
+def CreateHeader(dom, prog_name):
+ result = ''
+ header = dom.getElementsByTagName('header')
+ if header:
+ result = result + string.strip(header[0].childNodes[0].data)
+ result = result + '\n\n'
+
+ if prog_name:
+ add_str = ' by ' + prog_name
+ else:
+ add_str = ''
+ result = result + '### This file is automatically generated%s.\n' % add_str
+
+ result = result + '### DO NOT EDIT!\n\n'
+
+ copyright = dom.getElementsByTagName('copyright')
+ if copyright:
+ result = result + '"""\n'
+ result = result + string.strip(copyright[0].childNodes[0].data) + '\n'
+ result = result + '"""\n\n'
+
+ return result
+
+# Helper function for indenting Python
+def indent(count, text, tab=' '*4):
+ return tab*count + text
+
+# Get/Set routines for DOMString attributes
+def stringGetAttr(name, value):
+ return indent(2, 'return self.getAttribute("%s")\n\n' % name)
+
+def stringSetAttr(name):
+ return indent(2, 'self.setAttribute("%s", value)\n\n' % name)
+
+# Routines for boolean attributes
+def boolGetAttr(name, value):
+ return indent(2, 'return self.hasAttribute("%s")\n\n' % name)
+
+def boolSetAttr(name):
+ result = indent(2, 'if value:\n')
+ result = result + indent(3, 'self.setAttribute("%s", "%s")\n' % (name, name))
+ result = result + indent(2, 'else:\n')
+ result = result + indent(3, 'self.removeAttribute("%s")\n\n' % name)
+ return result
+
+# Routines for number attributes
+def longGetAttr(name, value):
+ result = indent(2, 'value = self.getAttribute("%s")\n' % name)
+ result = result + indent(2, 'if value:\n')
+ result = result + indent(3, 'return int(value)\n')
+ result = result + indent(2, 'return 0\n\n')
+ return result
+
+def longSetAttr(name):
+ return indent(2, 'self.setAttribute("%s", str(value))\n\n' % name)
+
+# Routines for value-list attributes
+def listGetAttr(name, value):
+ return indent(2, 'return string.capitalize(self.getAttribute("%s"))\n\n' % name)
+
+# Routines for attributes mapped to Text nodes
+def nodeGetAttr(dummy, value):
+ result = indent(2, 'if not self.firstChild:\n')
+ result = result + indent(3, 'return ''\n')
+ result = result + indent(2, 'if self.firstChild == self.lastChild:\n')
+ result = result + indent(3, 'return self.firstChild.data\n')
+ result = result + indent(2, 'self.normalize()\n')
+ result = result + indent(2, 'text = filter(lambda x: x.nodeType == Node.TEXT_NODE, self.childNodes)\n')
+ result = result + indent(2, 'return text[0].data\n\n')
+ return result
+
+def nodeSetAttr(dummy):
+ result = indent(2, 'text = None\n')
+ result = result + indent(2, 'for node in self.childNodes:\n')
+ result = result + indent(3, 'if not text and node.nodeType == Node.TEXT_NODE:\n')
+ result = result + indent(4, 'text = node\n')
+ result = result + indent(3, 'else:\n')
+ result = result + indent(4, 'self.removeChild(node)\n')
+ result = result + indent(2, 'if text:\n')
+ result = result + indent(3, 'text.data = value\n')
+ result = result + indent(2, 'else:\n')
+ result = result + indent(3, 'text = self.ownerDocument.createTextNode(value)\n')
+ result = result + indent(3, 'self.appendChild(text)\n\n')
+ return result
+
+#Routines for constant attributes
+def constGetAttr(name, value):
+ if not value:
+ value = 'None'
+ else:
+ value = '"%s"' % value
+ return indent(2, 'return %s\n\n' % value)
+
+#Routines for form based classes
+def formGetAttr(dummy,dummy2):
+ result = indent(2, 'parent = self.parentNode\n')
+ result = result + indent(2, 'while parent:\n')
+ result = result + indent(3, 'if parent.nodeName == "FORM":\n')
+ result = result + indent(4, 'return parent\n')
+ result = result + indent(3, 'parent = parent.parentNode\n')
+ result = result + indent(2, 'return None\n\n')
+ return result
+
+
+g_valueTypeMap = {
+ 'bool' : (boolGetAttr, boolSetAttr),
+ 'long' : (longGetAttr, longSetAttr),
+ 'list' : (listGetAttr, stringSetAttr),
+ 'node' : (nodeGetAttr, nodeSetAttr),
+ 'string' : (stringGetAttr, stringSetAttr),
+ 'form' : (formGetAttr, None),
+ 'const' : (constGetAttr, None)
+ }
+
+def GenClassFile(klass, header, output_dir):
+ class_name = 'HTML%sElement' % klass.getAttribute('name')
+ fileName = os.path.join(output_dir,class_name + '.py')
+ file = open(fileName, 'w')
+
+ # General header stuff
+ file.write(string.replace(header, '$FILE$', class_name))
+
+ # Import statements
+ file.write('import string\n')
+ file.write('from xml.dom import Node\n')
+ baseclass = klass.getElementsByTagName('baseclass')[0].getAttribute('name')
+ base_name = string.split(baseclass, '.')[-1]
+ file.write('from %s import %s\n' % (baseclass, base_name))
+ file.write('\n')
+
+ # Class declaration
+ file.write('class %s(%s):\n\n' % (class_name, base_name))
+
+ # Constructor
+ file.write(indent(1, 'def __init__(self, ownerDocument, nodeName'))
+ multiple = klass.getAttribute('multiple')
+ tag_name = klass.getAttribute('tagname')
+ if not multiple:
+ if not tag_name:
+ tag_name = string.upper(klass.getAttribute('name'))
+ file.write('="%s"' % tag_name)
+ file.write('):\n')
+ file.write(indent(2, '%s.__init__(self, ownerDocument, nodeName)\n\n' % base_name))
+
+ # Attributes
+ file.write(indent(1, '### Attribute Methods ###\n\n'))
+ attrs = klass.getElementsByTagName('attribute')
+ read_attrs = []
+ write_attrs = []
+ for attr in attrs:
+ dom_name = attr.getAttribute('name')
+ value_type = attr.getAttribute('type')
+ html_name = attr.getAttribute('htmlname')
+ if not html_name:
+ html_name = string.upper(dom_name)
+ value = attr.getAttribute('value') # for const value-type
+ permissions = attr.getElementsByTagName('permissions')[0]
+ readable = int(permissions.getAttribute('readable'))
+ writeable = int(permissions.getAttribute('writeable'))
+
+ if readable:
+ file.write(indent(1, 'def _get_%s(self):\n' % dom_name))
+ get_func = g_valueTypeMap[value_type][0]
+ file.write(get_func(html_name, value))
+ read_attrs.append(dom_name)
+
+ if writeable:
+ file.write(indent(1, 'def _set_%s(self, value):\n' % dom_name))
+ set_func = g_valueTypeMap[value_type][1]
+ try:
+ file.write(set_func(html_name or value))
+ except:
+ raise "Set function '%s' in class %s, attribute %s" % (value_type, class_name, dom_name)
+ write_attrs.append(dom_name)
+
+ # Methods
+ methods = klass.getElementsByTagName('method')
+ if methods:
+ file.write(indent(1, '### Methods ###\n\n'))
+ for method in methods:
+ method_name = method.getAttribute('name')
+ params = method.getElementsByTagName('params')[0].childNodes
+ param_list = []
+ for param in params:
+ arg = param.getAttribute('name')
+ default = param.firstChild
+ param_list.append((arg,default))
+ file.write(indent(1, 'def %s(self' % method_name))
+ for arg,default in param_list:
+ file.write(', %s' % arg)
+ if default:
+ file.write('=%s' % default.data)
+ file.write('):\n')
+
+ # The function code
+ code = method.getElementsByTagName('code')[0].firstChild
+ if code:
+ lines = string.split(string.strip(code.data), '\n')
+ for line in lines:
+ writeTab(file, 2, line)
+ else:
+ file.write(indent(2, 'pass\n'))
+ file.write('\n')
+
+ # Attribute access control
+ file.write(indent(1, '### Attribute Access Mappings ###\n\n'))
+
+ file.write(indent(1, '_readComputedAttrs = %s._readComputedAttrs.copy()\n' % base_name))
+ if len(read_attrs):
+ file.write(indent(1, '_readComputedAttrs.update({\n'))
+ for attr in read_attrs[:-1]:
+ file.write(indent(2, '"%s" : _get_%s,\n' % (attr, attr)))
+ attr = read_attrs[-1]
+ file.write(indent(2, '"%s" : _get_%s\n' % (attr, attr)))
+ file.write(indent(2, '})\n\n'))
+
+ file.write(indent(1, '_writeComputedAttrs = %s._writeComputedAttrs.copy()\n' % base_name))
+ if len(write_attrs):
+ file.write(indent(1, '_writeComputedAttrs.update({\n'))
+ for attr in write_attrs[:-1]:
+ file.write(indent(2, '"%s" : _set_%s,\n' % (attr, attr)))
+ attr = write_attrs[-1]
+ file.write(indent(2, '"%s" : _set_%s\n' % (attr, attr)))
+ file.write(indent(2, '})\n\n'))
+
+ file.write(indent(1, '_readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),\n'))
+ file.write(indent(1, ' %s._readOnlyAttrs + _readComputedAttrs.keys())\n\n' % base_name))
+
+ return fileName
+
+if __name__ == '__main__':
+ program_name = os.path.basename(sys.argv[0])
+ output_dir = None
+
+ if len(sys.argv) < 2:
+ print 'Usage: %s input_file [output_dir]' % program_name
+ sys.exit(1)
+ elif len(sys.argv) == 3:
+ output_dir = sys.argv[2]
+
+ input_file = sys.argv[1]
+
+ Generate(input_file,output_dir,program_name)
diff --git a/lib/jython/Lib/xml/dom/html/HTMLAnchorElement.py b/lib/jython/Lib/xml/dom/html/HTMLAnchorElement.py new file mode 100644 index 000000000..41eebfb02 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLAnchorElement.py @@ -0,0 +1,147 @@ +########################################################################
+#
+# File Name: HTMLAnchorElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLAnchorElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLAnchorElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="A"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_accessKey(self):
+ return self.getAttribute("ACCESSKEY")
+
+ def _set_accessKey(self, value):
+ self.setAttribute("ACCESSKEY", value)
+
+ def _get_charset(self):
+ return self.getAttribute("CHARSET")
+
+ def _set_charset(self, value):
+ self.setAttribute("CHARSET", value)
+
+ def _get_coords(self):
+ return self.getAttribute("COORDS")
+
+ def _set_coords(self, value):
+ self.setAttribute("COORDS", value)
+
+ def _get_href(self):
+ return self.getAttribute("HREF")
+
+ def _set_href(self, value):
+ self.setAttribute("HREF", value)
+
+ def _get_hreflang(self):
+ return self.getAttribute("HREFLANG")
+
+ def _set_hreflang(self, value):
+ self.setAttribute("HREFLANG", value)
+
+ def _get_name(self):
+ return self.getAttribute("NAME")
+
+ def _set_name(self, value):
+ self.setAttribute("NAME", value)
+
+ def _get_rel(self):
+ return self.getAttribute("REL")
+
+ def _set_rel(self, value):
+ self.setAttribute("REL", value)
+
+ def _get_rev(self):
+ return self.getAttribute("REV")
+
+ def _set_rev(self, value):
+ self.setAttribute("REV", value)
+
+ def _get_shape(self):
+ return string.capitalize(self.getAttribute("SHAPE"))
+
+ def _set_shape(self, value):
+ self.setAttribute("SHAPE", value)
+
+ def _get_tabIndex(self):
+ value = self.getAttribute("TABINDEX")
+ if value:
+ return int(value)
+ return 0
+
+ def _set_tabIndex(self, value):
+ self.setAttribute("TABINDEX", str(value))
+
+ def _get_target(self):
+ return self.getAttribute("TARGET")
+
+ def _set_target(self, value):
+ self.setAttribute("TARGET", value)
+
+ def _get_type(self):
+ return self.getAttribute("TYPE")
+
+ def _set_type(self, value):
+ self.setAttribute("TYPE", value)
+
+ ### Methods ###
+
+ def blur(self):
+ pass
+
+ def focus(self):
+ pass
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "accessKey" : _get_accessKey,
+ "charset" : _get_charset,
+ "coords" : _get_coords,
+ "href" : _get_href,
+ "hreflang" : _get_hreflang,
+ "name" : _get_name,
+ "rel" : _get_rel,
+ "rev" : _get_rev,
+ "shape" : _get_shape,
+ "tabIndex" : _get_tabIndex,
+ "target" : _get_target,
+ "type" : _get_type
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "accessKey" : _set_accessKey,
+ "charset" : _set_charset,
+ "coords" : _set_coords,
+ "href" : _set_href,
+ "hreflang" : _set_hreflang,
+ "name" : _set_name,
+ "rel" : _set_rel,
+ "rev" : _set_rev,
+ "shape" : _set_shape,
+ "tabIndex" : _set_tabIndex,
+ "target" : _set_target,
+ "type" : _set_type
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLAppletElement.py b/lib/jython/Lib/xml/dom/html/HTMLAppletElement.py new file mode 100644 index 000000000..8a15ed156 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLAppletElement.py @@ -0,0 +1,128 @@ +########################################################################
+#
+# File Name: HTMLAppletElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLAppletElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLAppletElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="APPLET"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_align(self):
+ return string.capitalize(self.getAttribute("ALIGN"))
+
+ def _set_align(self, value):
+ self.setAttribute("ALIGN", value)
+
+ def _get_alt(self):
+ return self.getAttribute("ALT")
+
+ def _set_alt(self, value):
+ self.setAttribute("ALT", value)
+
+ def _get_archive(self):
+ return self.getAttribute("ARCHIVE")
+
+ def _set_archive(self, value):
+ self.setAttribute("ARCHIVE", value)
+
+ def _get_code(self):
+ return self.getAttribute("CODE")
+
+ def _set_code(self, value):
+ self.setAttribute("CODE", value)
+
+ def _get_codeBase(self):
+ return self.getAttribute("CODEBASE")
+
+ def _set_codeBase(self, value):
+ self.setAttribute("CODEBASE", value)
+
+ def _get_height(self):
+ return self.getAttribute("HEIGHT")
+
+ def _set_height(self, value):
+ self.setAttribute("HEIGHT", value)
+
+ def _get_hspace(self):
+ return self.getAttribute("HSPACE")
+
+ def _set_hspace(self, value):
+ self.setAttribute("HSPACE", value)
+
+ def _get_name(self):
+ return self.getAttribute("NAME")
+
+ def _set_name(self, value):
+ self.setAttribute("NAME", value)
+
+ def _get_object(self):
+ return self.getAttribute("OBJECT")
+
+ def _set_object(self, value):
+ self.setAttribute("OBJECT", value)
+
+ def _get_vspace(self):
+ return self.getAttribute("VSPACE")
+
+ def _set_vspace(self, value):
+ self.setAttribute("VSPACE", value)
+
+ def _get_width(self):
+ return self.getAttribute("WIDTH")
+
+ def _set_width(self, value):
+ self.setAttribute("WIDTH", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "align" : _get_align,
+ "alt" : _get_alt,
+ "archive" : _get_archive,
+ "code" : _get_code,
+ "codeBase" : _get_codeBase,
+ "height" : _get_height,
+ "hspace" : _get_hspace,
+ "name" : _get_name,
+ "object" : _get_object,
+ "vspace" : _get_vspace,
+ "width" : _get_width
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "align" : _set_align,
+ "alt" : _set_alt,
+ "archive" : _set_archive,
+ "code" : _set_code,
+ "codeBase" : _set_codeBase,
+ "height" : _set_height,
+ "hspace" : _set_hspace,
+ "name" : _set_name,
+ "object" : _set_object,
+ "vspace" : _set_vspace,
+ "width" : _set_width
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLAreaElement.py b/lib/jython/Lib/xml/dom/html/HTMLAreaElement.py new file mode 100644 index 000000000..0634038a8 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLAreaElement.py @@ -0,0 +1,110 @@ +########################################################################
+#
+# File Name: HTMLAreaElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLAreaElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLAreaElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="AREA"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_accessKey(self):
+ return self.getAttribute("ACCESSKEY")
+
+ def _set_accessKey(self, value):
+ self.setAttribute("ACCESSKEY", value)
+
+ def _get_alt(self):
+ return self.getAttribute("ALT")
+
+ def _set_alt(self, value):
+ self.setAttribute("ALT", value)
+
+ def _get_coords(self):
+ return self.getAttribute("COORDS")
+
+ def _set_coords(self, value):
+ self.setAttribute("COORDS", value)
+
+ def _get_href(self):
+ return self.getAttribute("HREF")
+
+ def _set_href(self, value):
+ self.setAttribute("HREF", value)
+
+ def _get_noHref(self):
+ return self.hasAttribute("NOHREF")
+
+ def _set_noHref(self, value):
+ if value:
+ self.setAttribute("NOHREF", "NOHREF")
+ else:
+ self.removeAttribute("NOHREF")
+
+ def _get_shape(self):
+ return string.capitalize(self.getAttribute("SHAPE"))
+
+ def _set_shape(self, value):
+ self.setAttribute("SHAPE", value)
+
+ def _get_tabIndex(self):
+ value = self.getAttribute("TABINDEX")
+ if value:
+ return int(value)
+ return 0
+
+ def _set_tabIndex(self, value):
+ self.setAttribute("TABINDEX", str(value))
+
+ def _get_target(self):
+ return self.getAttribute("TARGET")
+
+ def _set_target(self, value):
+ self.setAttribute("TARGET", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "accessKey" : _get_accessKey,
+ "alt" : _get_alt,
+ "coords" : _get_coords,
+ "href" : _get_href,
+ "noHref" : _get_noHref,
+ "shape" : _get_shape,
+ "tabIndex" : _get_tabIndex,
+ "target" : _get_target
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "accessKey" : _set_accessKey,
+ "alt" : _set_alt,
+ "coords" : _set_coords,
+ "href" : _set_href,
+ "noHref" : _set_noHref,
+ "shape" : _set_shape,
+ "tabIndex" : _set_tabIndex,
+ "target" : _set_target
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLBRElement.py b/lib/jython/Lib/xml/dom/html/HTMLBRElement.py new file mode 100644 index 000000000..0658ab8e2 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLBRElement.py @@ -0,0 +1,48 @@ +########################################################################
+#
+# File Name: HTMLBRElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLBRElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLBRElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="BR"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_clear(self):
+ return string.capitalize(self.getAttribute("CLEAR"))
+
+ def _set_clear(self, value):
+ self.setAttribute("CLEAR", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "clear" : _get_clear
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "clear" : _set_clear
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLBaseElement.py b/lib/jython/Lib/xml/dom/html/HTMLBaseElement.py new file mode 100644 index 000000000..9f80a9c5d --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLBaseElement.py @@ -0,0 +1,56 @@ +########################################################################
+#
+# File Name: HTMLBaseElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLBaseElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLBaseElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="BASE"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_href(self):
+ return self.getAttribute("HREF")
+
+ def _set_href(self, value):
+ self.setAttribute("HREF", value)
+
+ def _get_target(self):
+ return self.getAttribute("TARGET")
+
+ def _set_target(self, value):
+ self.setAttribute("TARGET", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "href" : _get_href,
+ "target" : _get_target
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "href" : _set_href,
+ "target" : _set_target
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLBaseFontElement.py b/lib/jython/Lib/xml/dom/html/HTMLBaseFontElement.py new file mode 100644 index 000000000..8ee4650db --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLBaseFontElement.py @@ -0,0 +1,64 @@ +########################################################################
+#
+# File Name: HTMLBaseFontElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLBaseFontElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLBaseFontElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="BASEFONT"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_color(self):
+ return self.getAttribute("COLOR")
+
+ def _set_color(self, value):
+ self.setAttribute("COLOR", value)
+
+ def _get_face(self):
+ return self.getAttribute("FACE")
+
+ def _set_face(self, value):
+ self.setAttribute("FACE", value)
+
+ def _get_size(self):
+ return self.getAttribute("SIZE")
+
+ def _set_size(self, value):
+ self.setAttribute("SIZE", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "color" : _get_color,
+ "face" : _get_face,
+ "size" : _get_size
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "color" : _set_color,
+ "face" : _set_face,
+ "size" : _set_size
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLBodyElement.py b/lib/jython/Lib/xml/dom/html/HTMLBodyElement.py new file mode 100644 index 000000000..e23b19ee5 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLBodyElement.py @@ -0,0 +1,88 @@ +########################################################################
+#
+# File Name: HTMLBodyElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLBodyElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLBodyElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="BODY"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_aLink(self):
+ return self.getAttribute("ALINK")
+
+ def _set_aLink(self, value):
+ self.setAttribute("ALINK", value)
+
+ def _get_background(self):
+ return self.getAttribute("BACKGROUND")
+
+ def _set_background(self, value):
+ self.setAttribute("BACKGROUND", value)
+
+ def _get_bgColor(self):
+ return self.getAttribute("BGCOLOR")
+
+ def _set_bgColor(self, value):
+ self.setAttribute("BGCOLOR", value)
+
+ def _get_link(self):
+ return self.getAttribute("LINK")
+
+ def _set_link(self, value):
+ self.setAttribute("LINK", value)
+
+ def _get_text(self):
+ return self.getAttribute("TEXT")
+
+ def _set_text(self, value):
+ self.setAttribute("TEXT", value)
+
+ def _get_vLink(self):
+ return self.getAttribute("VLINK")
+
+ def _set_vLink(self, value):
+ self.setAttribute("VLINK", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "aLink" : _get_aLink,
+ "background" : _get_background,
+ "bgColor" : _get_bgColor,
+ "link" : _get_link,
+ "text" : _get_text,
+ "vLink" : _get_vLink
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "aLink" : _set_aLink,
+ "background" : _set_background,
+ "bgColor" : _set_bgColor,
+ "link" : _set_link,
+ "text" : _set_text,
+ "vLink" : _set_vLink
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLButtonElement.py b/lib/jython/Lib/xml/dom/html/HTMLButtonElement.py new file mode 100644 index 000000000..b00288292 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLButtonElement.py @@ -0,0 +1,99 @@ +########################################################################
+#
+# File Name: HTMLButtonElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLButtonElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLButtonElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="BUTTON"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_accessKey(self):
+ return self.getAttribute("ACCESSKEY")
+
+ def _set_accessKey(self, value):
+ self.setAttribute("ACCESSKEY", value)
+
+ def _get_disabled(self):
+ return self.hasAttribute("DISABLED")
+
+ def _set_disabled(self, value):
+ if value:
+ self.setAttribute("DISABLED", "DISABLED")
+ else:
+ self.removeAttribute("DISABLED")
+
+ def _get_form(self):
+ parent = self.parentNode
+ while parent:
+ if parent.nodeName == "FORM":
+ return parent
+ parent = parent.parentNode
+ return None
+
+ def _get_name(self):
+ return self.getAttribute("NAME")
+
+ def _set_name(self, value):
+ self.setAttribute("NAME", value)
+
+ def _get_tabIndex(self):
+ value = self.getAttribute("TABINDEX")
+ if value:
+ return int(value)
+ return 0
+
+ def _set_tabIndex(self, value):
+ self.setAttribute("TABINDEX", str(value))
+
+ def _get_type(self):
+ return self.getAttribute("TYPE")
+
+ def _get_value(self):
+ return self.getAttribute("VALUE")
+
+ def _set_value(self, value):
+ self.setAttribute("VALUE", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "accessKey" : _get_accessKey,
+ "disabled" : _get_disabled,
+ "form" : _get_form,
+ "name" : _get_name,
+ "tabIndex" : _get_tabIndex,
+ "type" : _get_type,
+ "value" : _get_value
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "accessKey" : _set_accessKey,
+ "disabled" : _set_disabled,
+ "name" : _set_name,
+ "tabIndex" : _set_tabIndex,
+ "value" : _set_value
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLCollection.py b/lib/jython/Lib/xml/dom/html/HTMLCollection.py new file mode 100644 index 000000000..23967def2 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLCollection.py @@ -0,0 +1,78 @@ +########################################################################
+#
+# File Name: HTMLCollection.py
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLCollection.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+from xml.dom import Node
+from xml.dom import NoModificationAllowedErr
+from xml.dom.html import HTML_NAME_ALLOWED
+import UserList
+
+class HTMLCollection(UserList.UserList):
+
+ def __init__(self, list=None):
+ UserList.UserList.__init__(self, list or [])
+
+ ### Attribute Access Methods ###
+
+ def __getattr__(self, name):
+ if name == 'length':
+ return self._get_length()
+ # Pass-through
+ return getattr(HTMLCollection, name)
+
+ def __setattr__(self, name, value):
+ if name == 'length':
+ self._set_length(value)
+ # Pass-through
+ self.__dict__[name] = value
+
+ ### Attribute Methods ###
+
+ def _get_length(self):
+ return self.__len__()
+
+ def _set_length(self, value):
+ raise NoModificationAllowedErr()
+
+ ### Methods ###
+
+ def item(self, index):
+ if index >= self.__len__():
+ return None
+ else:
+ return self[int(index)]
+
+ def namedItem(self, name):
+ found_node = None
+ for node in self:
+ # IDs take presedence over NAMEs
+ if node.getAttribute('ID') == name:
+ found_node = node
+ break
+ if not found_node and node.getAttribute('NAME') == name \
+ and node.tagName in HTML_NAME_ALLOWED:
+ # We found a node with NAME attribute, but we have to wait
+ # until all nodes are done (one might have an ID that matches)
+ found_node = node
+ print 'found:', found_node
+ return found_node
+
+ ### Overridden Methods ###
+
+ def __repr__(self):
+ st = "<HTMLCollection at %x: [" % (id(self))
+ if len(self):
+ for i in self[:-1]:
+ st = st + repr(i) + ', '
+ st = st + repr(self[-1])
+ st = st + ']>'
+ return st
diff --git a/lib/jython/Lib/xml/dom/html/HTMLDListElement.py b/lib/jython/Lib/xml/dom/html/HTMLDListElement.py new file mode 100644 index 000000000..90811f226 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLDListElement.py @@ -0,0 +1,51 @@ +########################################################################
+#
+# File Name: HTMLDListElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLDListElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLDListElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="DL"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_compact(self):
+ return self.hasAttribute("COMPACT")
+
+ def _set_compact(self, value):
+ if value:
+ self.setAttribute("COMPACT", "COMPACT")
+ else:
+ self.removeAttribute("COMPACT")
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "compact" : _get_compact
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "compact" : _set_compact
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLDOMImplementation.py b/lib/jython/Lib/xml/dom/html/HTMLDOMImplementation.py new file mode 100644 index 000000000..ea498b8e3 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLDOMImplementation.py @@ -0,0 +1,37 @@ +########################################################################
+#
+# File Name: implementation.py
+#
+# Documentation: http://docs.4suite.com/4DOM/implementation.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+from xml.dom import DOMImplementation
+
+# Add the HTML feature
+DOMImplementation.FEATURES_MAP['HTML'] = 2.0
+
+class HTMLDOMImplementation(DOMImplementation.DOMImplementation):
+
+ def __init__(self):
+ DOMImplementation.DOMImplementation.__init__(self)
+
+ def createHTMLDocument(self, title):
+ from xml.dom.html import HTMLDocument
+ doc = HTMLDocument.HTMLDocument()
+ h = doc.createElement('HTML')
+ doc.appendChild(h)
+ doc._set_title(title)
+ return doc
+
+ def _4dom_createHTMLCollection(self,list=None):
+ if list is None:
+ list = []
+ from xml.dom.html import HTMLCollection
+ hc = HTMLCollection.HTMLCollection(list)
+ return hc
diff --git a/lib/jython/Lib/xml/dom/html/HTMLDirectoryElement.py b/lib/jython/Lib/xml/dom/html/HTMLDirectoryElement.py new file mode 100644 index 000000000..0bdcd657d --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLDirectoryElement.py @@ -0,0 +1,51 @@ +########################################################################
+#
+# File Name: HTMLDirectoryElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLDirectoryElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLDirectoryElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="DIR"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_compact(self):
+ return self.hasAttribute("COMPACT")
+
+ def _set_compact(self, value):
+ if value:
+ self.setAttribute("COMPACT", "COMPACT")
+ else:
+ self.removeAttribute("COMPACT")
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "compact" : _get_compact
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "compact" : _set_compact
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLDivElement.py b/lib/jython/Lib/xml/dom/html/HTMLDivElement.py new file mode 100644 index 000000000..fa8f2b145 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLDivElement.py @@ -0,0 +1,56 @@ +########################################################################
+#
+# File Name: HTMLDivElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLDivElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLDivElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="DIV"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_type(self):
+ return self.getAttribute("TYPE")
+
+ def _set_type(self, value):
+ self.setAttribute("TYPE", value)
+
+ def _get_align(self):
+ return string.capitalize(self.getAttribute("ALIGN"))
+
+ def _set_align(self, value):
+ self.setAttribute("ALIGN", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "type" : _get_type,
+ "align" : _get_align
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "type" : _set_type,
+ "align" : _set_align
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLDocument.py b/lib/jython/Lib/xml/dom/html/HTMLDocument.py new file mode 100644 index 000000000..77af2d78d --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLDocument.py @@ -0,0 +1,355 @@ +########################################################################
+#
+# File Name: HTMLDocument.py
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLDocument.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+from xml.dom import Node
+from xml.dom import NotSupportedErr
+
+from xml.dom.Document import Document
+from xml.dom import implementation
+from xml.dom import ext
+
+import string, sys
+
+from xml.dom.html import HTML_DTD
+
+class HTMLDocument(Document):
+
+ def __init__(self):
+ Document.__init__(self, None)
+ # These only make sense in a browser environment, therefore
+ # they never change
+ self.__dict__['__referrer'] = ''
+ self.__dict__['__domain'] = None
+ self.__dict__['__URL'] = ''
+
+ self.__dict__['__cookie'] = ''
+ self.__dict__['__writable'] = 0
+ self.__dict__['_html'] = vars(sys.modules['xml.dom.html'])
+
+ ### Attribute Methods ###
+
+ def _get_URL(self):
+ return self.__dict__['__URL']
+
+ def _get_anchors(self):
+ anchors = self.getElementsByTagName('A');
+ anchors = filter(lambda x: x._get_name(), anchors)
+ return implementation._4dom_createHTMLCollection(anchors)
+
+ def _get_applets(self):
+ al = self.getElementsByTagName('APPLET')
+ ol = self.getElementsByTagName('OBJECT')
+ ol = filter(lambda x: x._get_code(), ol)
+ return implementation._4dom_createHTMLCollection(al+ol)
+
+ def _get_body(self):
+ body = ''
+ #Try to find the body or FRAMESET
+ elements = self.getElementsByTagName('FRAMESET')
+ if not elements:
+ elements = self.getElementsByTagName('BODY')
+ if elements:
+ body = elements[0]
+ else:
+ #Create a body
+ body = self.createElement('BODY')
+ self.documentElement.appendChild(body)
+ return body
+
+ def _set_body(self, newBody):
+ elements = self.getElementsByTagName('FRAMESET')
+ if not elements:
+ elements = self.getElementsByTagName('BODY')
+ if elements:
+ # Replace the existing one
+ elements[0].parentNode.replaceChild(newBody, elements[0])
+ else:
+ # Add it
+ self.documentElement.appendChild(newBody)
+
+ def _get_cookie(self):
+ return self.__dict__['__cookie']
+
+ def _set_cookie(self, cookie):
+ self.__dict__['__cookie'] = cookie
+
+ def _get_domain(self):
+ return self.__dict__['__domain']
+
+ def _get_forms(self):
+ forms = self.getElementsByTagName('FORM')
+ return implementation._4dom_createHTMLCollection(forms)
+
+ def _get_images(self):
+ images = self.getElementsByTagName('IMG')
+ return implementation._4dom_createHTMLCollection(images)
+
+ def _get_links(self):
+ areas = self.getElementsByTagName('AREA')
+ anchors = self.getElementsByTagName('A')
+ links = filter(lambda x: x._get_href(), areas+anchors)
+ return implementation._4dom_createHTMLCollection(links)
+
+ def _get_referrer(self):
+ return self.__dict__['__referrer']
+
+ def _get_title(self):
+ elements = self.getElementsByTagName('TITLE')
+ if elements:
+ #Take the first
+ title = elements[0]
+ title.normalize()
+ if title.firstChild:
+ return title.firstChild.data
+ return ''
+
+ def _set_title(self, title):
+ # See if we can find the title
+ title_nodes = self.getElementsByTagName('TITLE')
+ if title_nodes:
+ title_node = title_nodes[0]
+ title_node.normalize()
+ if title_node.firstChild:
+ title_node.firstChild.data = title
+ return
+ else:
+ title_node = self.createElement('TITLE')
+ self._4dom_getHead().appendChild(title_node)
+ text = self.createTextNode(title)
+ title_node.appendChild(text)
+
+ ### Methods ###
+
+ def close(self):
+ self.__dict__['__writable'] = 0
+
+ def getElementsByName(self, elementName):
+ return self._4dom_getElementsByAttribute('*', 'NAME', elementName)
+
+ def open(self):
+ #Clear out the doc
+ self.__dict__['__referrer'] = ''
+ self.__dict__['__domain'] = None
+ self.__dict__['__url'] = ''
+ self.__dict__['__cookie'] = ''
+ self.__dict__['__writable'] = 1
+
+ def write(self, st):
+ if not self.__dict__['__writable']:
+ return
+ #We need to parse the string here
+ from xml.dom.ext.reader.HtmlLib import FromHTML
+ d = FromHtml(st, self)
+ if d != self:
+ self.appendChild(d)
+
+ def writeln(self, st):
+ st = st + '\n'
+ self.write(st)
+
+
+ def getElementByID(self, ID):
+ hc = self._4dom_getElementsByAttribute('*','ID',ID)
+ if hc.length != 0:
+ return hc[0]
+ return None
+
+ ### Overridden Methods ###
+
+ def createElement(self, tagName):
+ return self._4dom_createHTMLElement(tagName)
+
+ def createAttribute(self, name):
+ return Document.createAttribute(self, string.upper(name))
+
+ def createCDATASection(*args, **kw):
+ raise NotSupportedErr()
+
+ def createEntityReference(*args, **kw):
+ raise NotSupportedErr()
+
+ def createProcessingInstruction(*args, **kw):
+ raise NotSupportedErr()
+
+ def _4dom_createEntity(*args, **kw):
+ raise NotSupportedErr()
+
+ def _4dom_createNotation(*args, **kw):
+ raise NotSupportedErr()
+
+ ### Internal Methods ###
+
+ def _4dom_getElementsByAttribute(self, tagName, attribute, attrValue=None):
+ nl = self.getElementsByTagName(tagName)
+ hc = implementation._4dom_createHTMLCollection()
+ for elem in nl:
+ attr = elem.getAttribute(attribute)
+ if attrValue == None and attr != '':
+ hc.append(elem)
+ elif attr == attrValue:
+ hc.append(elem)
+ return hc
+
+ def _4dom_getHead(self):
+ nl = self.getElementsByTagName('HEAD')
+ if not nl:
+ head = self.createElement('HEAD')
+ #The head goes in front of the body
+ body = self._get_body()
+ self.documentElement.insertBefore(head, body)
+ else:
+ head = nl[0]
+ return head
+
+ def _4dom_createHTMLElement(self, tagName):
+ lowered = string.lower(tagName)
+ if not HTML_DTD.has_key(lowered):
+ raise TypeError('Unknown HTML Element: %s' % tagName)
+
+ if lowered in NoClassTags:
+ from HTMLElement import HTMLElement
+ return HTMLElement(self, tagName)
+
+ #FIXME: capitalize() broken with unicode in Python 2.0
+ #normTagName = string.capitalize(tagName)
+ capitalized = string.upper(tagName[0]) + lowered[1:]
+ element = HTMLTagMap.get(capitalized, capitalized)
+ module = 'HTML%sElement' % element
+ if not self._html.has_key(module):
+ #Try to import it (should never fail)
+ __import__('xml.dom.html.%s' % module)
+ # Class and module have the same name
+ klass = getattr(self._html[module], module)
+ return klass(self, tagName)
+
+ def cloneNode(self, deep):
+ clone = HTMLDocument()
+ clone.__dict__['__referrer'] = self._get_referrer()
+ clone.__dict__['__domain'] = self._get_domain()
+ clone.__dict__['__URL'] = self._get_URL()
+ clone.__dict__['__cookie'] = self._get_cookie()
+ if deep:
+ if self.doctype is not None:
+ # Cannot have any children, no deep needed
+ dt = self.doctype.cloneNode(0)
+ clone._4dom_setDocumentType(dt)
+ if self.documentElement is not None:
+ # The root element can have children, duh
+ root = self.documentElement.cloneNode(1, newOwner=clone)
+ clone.appendChild(root)
+ return clone
+
+ def isXml(self):
+ return 0
+
+ def isHtml(self):
+ return 1
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = Document._readComputedAttrs.copy()
+ _readComputedAttrs.update ({
+ 'title' : _get_title,
+ 'referrer' : _get_referrer,
+ 'domain' : _get_domain,
+ 'URL' : _get_URL,
+ 'body' : _get_body,
+ 'images' : _get_images,
+ 'applets' : _get_applets,
+ 'links' : _get_links,
+ 'forms' : _get_forms,
+ 'anchors' : _get_anchors,
+ 'cookie' : _get_cookie
+ })
+
+ _writeComputedAttrs = Document._writeComputedAttrs.copy()
+ _writeComputedAttrs.update ({
+ 'title' : _set_title,
+ 'body' : _set_body,
+ 'cookie' : _set_cookie,
+ })
+
+ # Create the read-only list of attributes
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ Document._readOnlyAttrs + _readComputedAttrs.keys())
+
+# HTML tags that don't map directly to a class name
+HTMLTagMap = {'Isindex': 'IsIndex',
+ 'Optgroup': 'OptGroup',
+ 'Textarea': 'TextArea',
+ 'Fieldset': 'FieldSet',
+ 'Ul': 'UList',
+ 'Ol': 'OList',
+ 'Dl': 'DList',
+ 'Dir': 'Directory',
+ 'Li': 'LI',
+ 'P': 'Paragraph',
+ 'H1': 'Heading',
+ 'H2': 'Heading',
+ 'H3': 'Heading',
+ 'H4': 'Heading',
+ 'H5': 'Heading',
+ 'H6': 'Heading',
+ 'Q': 'Quote',
+ 'Blockquote': 'Quote',
+ 'Br': 'BR',
+ 'Basefont': 'BaseFont',
+ 'Hr': 'HR',
+ 'A': 'Anchor',
+ 'Img': 'Image',
+ 'Caption': 'TableCaption',
+ 'Col': 'TableCol',
+ 'Colgroup': 'TableCol',
+ 'Td': 'TableCell',
+ 'Th': 'TableCell',
+ 'Tr': 'TableRow',
+ 'Thead': 'TableSection',
+ 'Tbody': 'TableSection',
+ 'Tfoot': 'TableSection',
+ 'Frameset': 'FrameSet',
+ 'Iframe': 'IFrame',
+ 'Form': 'Form',
+ 'Ins' : 'Mod',
+ 'Del' : 'Mod',
+ }
+
+#HTML Elements with no specific DOM Interface of their own
+NoClassTags = ['sub',
+ 'sup',
+ 'span',
+ 'bdo',
+ 'tt',
+ 'i',
+ 'b',
+ 'u',
+ 's',
+ 'strike',
+ 'big',
+ 'small',
+ 'em',
+ 'strong',
+ 'dfn',
+ 'code',
+ 'samp',
+ 'kbd',
+ 'var',
+ 'cite',
+ 'acronym',
+ 'abbr',
+ 'dd',
+ 'dt',
+ 'noframes',
+ 'noscript',
+ 'address',
+ 'center',
+ ]
diff --git a/lib/jython/Lib/xml/dom/html/HTMLElement.py b/lib/jython/Lib/xml/dom/html/HTMLElement.py new file mode 100644 index 000000000..1b9948132 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLElement.py @@ -0,0 +1,121 @@ +########################################################################
+#
+# File Name: HTMLElement.py
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLElement.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+from xml.dom.Element import Element
+
+import string
+
+class HTMLElement(Element):
+
+ def __init__(self, ownerDocument, nodeName):
+ tagName = string.upper(nodeName)
+ Element.__init__(self, ownerDocument, tagName, '', '',tagName)
+
+ ### Attribute Methods ###
+
+ def _get_id(self):
+ return self.getAttribute('ID')
+
+ def _set_id(self,ID):
+ self.setAttribute('ID',ID)
+
+ def _get_title(self):
+ return self.getAttribute('TITLE')
+
+ def _set_title(self,title):
+ self.setAttribute('TITLE',title)
+
+ def _get_lang(self):
+ return self.getAttribute('LANG')
+
+ def _set_lang(self,lang):
+ self.setAttribute('LANG',lang)
+
+ def _get_dir(self):
+ return self.getAttribute('DIR')
+
+ def _set_dir(self,dir):
+ self.setAttribute('DIR',dir)
+
+ def _get_className(self):
+ return self.getAttribute('CLASSNAME')
+
+ def _set_className(self,className):
+ self.setAttribute('CLASSNAME',className)
+
+ ### Overridden Methods ###
+
+ def getAttribute(self, name):
+ attr = self.attributes.getNamedItem(string.upper(name))
+ return attr and attr.value or ''
+
+ def getAttributeNode(self, name):
+ return self.attributes.getNamedItem(string.upper(name))
+
+ def getElementsByTagName(self, tagName):
+ return Element.getElementsByTagName(self, string.upper(tagName))
+
+ def hasAttribute(self, name):
+ return self.attributes.getNamedItem(string.upper(name)) is not None
+
+ def removeAttribute(self, name):
+ attr = self.attributes.getNamedItem(string.upper(name))
+ attr and self.removeAttributeNode(attr)
+
+ def setAttribute(self, name, value):
+ Element.setAttribute(self, string.upper(name), value)
+
+ def _4dom_validateString(self, value):
+ return value
+
+ ### Helper Functions For Cloning ###
+
+ def _4dom_clone(self, owner):
+ e = self.__class__(owner,
+ self.tagName)
+ for attr in self.attributes:
+ clone = attr._4dom_clone(owner)
+ if clone.localName is None:
+ e.attributes.setNamedItem(clone)
+ else:
+ self.attributes.setNamedItemNS(clone)
+ clone._4dom_setOwnerElement(self)
+ return e
+
+ def __getinitargs__(self):
+ return (self.ownerDocument,
+ self.tagName
+ )
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = Element._readComputedAttrs.copy()
+ _readComputedAttrs.update ({
+ 'id' : _get_id,
+ 'title' : _get_title,
+ 'lang' : _get_lang,
+ 'dir' : _get_dir,
+ 'className' : _get_className,
+ })
+
+ _writeComputedAttrs = Element._writeComputedAttrs.copy()
+ _writeComputedAttrs.update ({
+ 'id' : _set_id,
+ 'title' : _set_title,
+ 'lang' : _set_lang,
+ 'dir' : _set_dir,
+ 'className' : _set_className,
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ Element._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLFieldSetElement.py b/lib/jython/Lib/xml/dom/html/HTMLFieldSetElement.py new file mode 100644 index 000000000..0d822f71f --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLFieldSetElement.py @@ -0,0 +1,46 @@ +########################################################################
+#
+# File Name: HTMLFieldSetElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLFieldSetElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLFieldSetElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="FIELDSET"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_form(self):
+ parent = self.parentNode
+ while parent:
+ if parent.nodeName == "FORM":
+ return parent
+ parent = parent.parentNode
+ return None
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "form" : _get_form
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLFontElement.py b/lib/jython/Lib/xml/dom/html/HTMLFontElement.py new file mode 100644 index 000000000..ca4776907 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLFontElement.py @@ -0,0 +1,64 @@ +########################################################################
+#
+# File Name: HTMLFontElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLFontElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLFontElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="FONT"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_color(self):
+ return self.getAttribute("COLOR")
+
+ def _set_color(self, value):
+ self.setAttribute("COLOR", value)
+
+ def _get_face(self):
+ return self.getAttribute("FACE")
+
+ def _set_face(self, value):
+ self.setAttribute("FACE", value)
+
+ def _get_size(self):
+ return self.getAttribute("SIZE")
+
+ def _set_size(self, value):
+ self.setAttribute("SIZE", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "color" : _get_color,
+ "face" : _get_face,
+ "size" : _get_size
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "color" : _set_color,
+ "face" : _set_face,
+ "size" : _set_size
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLFormElement.py b/lib/jython/Lib/xml/dom/html/HTMLFormElement.py new file mode 100644 index 000000000..2276f4ea0 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLFormElement.py @@ -0,0 +1,120 @@ +#
+# File Name: HTMLFormElement.py
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLFormElement.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import ext
+from xml.dom import implementation
+from xml.dom.html.HTMLElement import HTMLElement
+from xml.dom.html.HTMLCollection import HTMLCollection
+
+FORM_CHILDREN = ['INPUT',
+ 'SELECT',
+ 'OPTGROUP',
+ 'OPTION',
+ 'TEXTAREA',
+ 'LABEL',
+ 'BUTTON',
+ 'FIELDSET',
+ 'LEGEND',
+ 'OBJECT',
+ 'ISINDEX'
+ ]
+
+class HTMLFormElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName='FORM'):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_acceptCharset(self):
+ return self.getAttribute('ACCEPT-CHARSET')
+
+ def _set_acceptCharset(self,acceptcharset):
+ self.setAttribute('ACCEPT-CHARSET',acceptcharset)
+
+ def _get_action(self):
+ return self.getAttribute('ACTION')
+
+ def _set_action(self,action):
+ self.setAttribute('ACTION',action)
+
+ def _get_elements(self):
+ #Make a collection of control elements
+ nl = self.getElementsByTagName('*')
+ l = []
+ for child in nl:
+ if child.tagName in FORM_CHILDREN:
+ l.append(child)
+ return implementation._4dom_createHTMLCollection(l)
+
+ def _get_encType(self):
+ return self.getAttribute('ENCTYPE')
+
+ def _set_encType(self,enctype):
+ self.setAttribute('ENCTYPE',enctype)
+
+ def _get_length(self):
+ return self._get_elements().length
+
+ def _get_method(self):
+ return string.capitalize(self.getAttribute('METHOD'))
+
+ def _set_method(self,method):
+ self.setAttribute('METHOD',method)
+
+ def _get_name(self):
+ return self.getAttribute('NAME')
+
+ def _set_name(self,name):
+ self.setAttribute('NAME',name)
+
+ def _get_target(self):
+ return self.getAttribute('TARGET')
+
+ def _set_target(self,target):
+ self.setAttribute('TARGET',target)
+
+ ### Methods ###
+
+ def reset(self):
+ pass
+
+ def submit(self):
+ pass
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update ({
+ 'acceptCharset' : _get_acceptCharset,
+ 'action' : _get_action,
+ 'elements' : _get_elements,
+ 'encType' : _get_encType,
+ 'length' : _get_length,
+ 'method' : _get_method,
+ 'name' : _get_name,
+ 'target' : _get_target
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update ({
+ 'acceptCharset' : _set_acceptCharset,
+ 'action' : _set_action,
+ 'encType' : _set_encType,
+ 'method' : _set_method,
+ 'name' : _set_name,
+ 'target' : _set_target
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLFrameElement.py b/lib/jython/Lib/xml/dom/html/HTMLFrameElement.py new file mode 100644 index 000000000..cd67e8e08 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLFrameElement.py @@ -0,0 +1,117 @@ +########################################################################
+#
+# File Name: HTMLFrameElement.py
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLFrameElement.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLFrameElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="FRAME"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+ self.__content = None
+
+ ### Attribute Methods ###
+
+ def _get_contentDocument(self):
+ if not self.__content:
+ source = self._get_src()
+ import os.path
+ ext = os.path.splitext(source)
+ if string.find(ext, 'htm') > 0:
+ from xml.dom.ext.reader import HtmlLib
+ self.__content = HtmlLib.FromHtmlUrl(source)
+ elif string.lower(ext) == '.xml':
+ from xml.dom.ext.reader import Sax2
+ self.__content = Sax2.FromXmlUrl(source)
+ return self.__content
+
+ def _get_frameBorder(self):
+ return string.capitalize(self.getAttribute("FRAMEBORDER"))
+
+ def _set_frameBorder(self, value):
+ self.setAttribute("FRAMEBORDER", value)
+
+ def _get_longDesc(self):
+ return self.getAttribute("LONGDESC")
+
+ def _set_longDesc(self, value):
+ self.setAttribute("LONGDESC", value)
+
+ def _get_marginHeight(self):
+ return self.getAttribute("MARGINHEIGHT")
+
+ def _set_marginHeight(self, value):
+ self.setAttribute("MARGINHEIGHT", value)
+
+ def _get_marginWidth(self):
+ return self.getAttribute("MARGINWIDTH")
+
+ def _set_marginWidth(self, value):
+ self.setAttribute("MARGINWIDTH", value)
+
+ def _get_name(self):
+ return self.getAttribute("NAME")
+
+ def _set_name(self, value):
+ self.setAttribute("NAME", value)
+
+ def _get_noResize(self):
+ return self.hasAttribute("NORESIZE")
+
+ def _set_noResize(self, value):
+ if value:
+ self.setAttribute("NORESIZE", "NORESIZE")
+ else:
+ self.removeAttribute("NORESIZE")
+
+ def _get_scrolling(self):
+ return string.capitalize(self.getAttribute("SCROLLING"))
+
+ def _set_scrolling(self, value):
+ self.setAttribute("SCROLLING", value)
+
+ def _get_src(self):
+ return self.getAttribute("SRC")
+
+ def _set_src(self, value):
+ self.setAttribute("SRC", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "contentDocument" : _get_contentDocument,
+ "frameBorder" : _get_frameBorder,
+ "longDesc" : _get_longDesc,
+ "marginHeight" : _get_marginHeight,
+ "marginWidth" : _get_marginWidth,
+ "name" : _get_name,
+ "noResize" : _get_noResize,
+ "scrolling" : _get_scrolling,
+ "src" : _get_src
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "frameBorder" : _set_frameBorder,
+ "longDesc" : _set_longDesc,
+ "marginHeight" : _set_marginHeight,
+ "marginWidth" : _set_marginWidth,
+ "name" : _set_name,
+ "noResize" : _set_noResize,
+ "scrolling" : _set_scrolling,
+ "src" : _set_src
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLFrameSetElement.py b/lib/jython/Lib/xml/dom/html/HTMLFrameSetElement.py new file mode 100644 index 000000000..beb9fb798 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLFrameSetElement.py @@ -0,0 +1,56 @@ +########################################################################
+#
+# File Name: HTMLFrameSetElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLFrameSetElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLFrameSetElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="FRAMESET"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_cols(self):
+ return self.getAttribute("COLS")
+
+ def _set_cols(self, value):
+ self.setAttribute("COLS", value)
+
+ def _get_rows(self):
+ return self.getAttribute("ROWS")
+
+ def _set_rows(self, value):
+ self.setAttribute("ROWS", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "cols" : _get_cols,
+ "rows" : _get_rows
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "cols" : _set_cols,
+ "rows" : _set_rows
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLHRElement.py b/lib/jython/Lib/xml/dom/html/HTMLHRElement.py new file mode 100644 index 000000000..b694a3385 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLHRElement.py @@ -0,0 +1,75 @@ +########################################################################
+#
+# File Name: HTMLHRElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLHRElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLHRElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="HR"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_align(self):
+ return string.capitalize(self.getAttribute("ALIGN"))
+
+ def _set_align(self, value):
+ self.setAttribute("ALIGN", value)
+
+ def _get_noShade(self):
+ return self.hasAttribute("NOSHADE")
+
+ def _set_noShade(self, value):
+ if value:
+ self.setAttribute("NOSHADE", "NOSHADE")
+ else:
+ self.removeAttribute("NOSHADE")
+
+ def _get_size(self):
+ return self.getAttribute("SIZE")
+
+ def _set_size(self, value):
+ self.setAttribute("SIZE", value)
+
+ def _get_width(self):
+ return self.getAttribute("WIDTH")
+
+ def _set_width(self, value):
+ self.setAttribute("WIDTH", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "align" : _get_align,
+ "noShade" : _get_noShade,
+ "size" : _get_size,
+ "width" : _get_width
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "align" : _set_align,
+ "noShade" : _set_noShade,
+ "size" : _set_size,
+ "width" : _set_width
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLHeadElement.py b/lib/jython/Lib/xml/dom/html/HTMLHeadElement.py new file mode 100644 index 000000000..7e1ab0620 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLHeadElement.py @@ -0,0 +1,48 @@ +########################################################################
+#
+# File Name: HTMLHeadElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLHeadElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLHeadElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="HEAD"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_profile(self):
+ return self.getAttribute("PROFILE")
+
+ def _set_profile(self, value):
+ self.setAttribute("PROFILE", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "profile" : _get_profile
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "profile" : _set_profile
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLHeadingElement.py b/lib/jython/Lib/xml/dom/html/HTMLHeadingElement.py new file mode 100644 index 000000000..aad622457 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLHeadingElement.py @@ -0,0 +1,48 @@ +########################################################################
+#
+# File Name: HTMLHeadingElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLHeadingElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLHeadingElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_align(self):
+ return string.capitalize(self.getAttribute("ALIGN"))
+
+ def _set_align(self, value):
+ self.setAttribute("ALIGN", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "align" : _get_align
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "align" : _set_align
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLHtmlElement.py b/lib/jython/Lib/xml/dom/html/HTMLHtmlElement.py new file mode 100644 index 000000000..f1a9916e1 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLHtmlElement.py @@ -0,0 +1,48 @@ +########################################################################
+#
+# File Name: HTMLHtmlElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLHtmlElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLHtmlElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="HTML"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_version(self):
+ return self.getAttribute("VERSION")
+
+ def _set_version(self, value):
+ self.setAttribute("VERSION", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "version" : _get_version
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "version" : _set_version
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLIFrameElement.py b/lib/jython/Lib/xml/dom/html/HTMLIFrameElement.py new file mode 100644 index 000000000..49c2486d4 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLIFrameElement.py @@ -0,0 +1,130 @@ +########################################################################
+#
+# File Name: HTMLIFrameElement.py
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLIFrameElement.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLIFrameElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="IFRAME"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+ self.__content = None
+
+ ### Attribute Methods ###
+
+ def _get_align(self):
+ return string.capitalize(self.getAttribute("ALIGN"))
+
+ def _set_align(self, value):
+ self.setAttribute("ALIGN", value)
+
+ def _get_contentDocument(self):
+ if not self.__content:
+ source = self._get_src()
+ import os.path
+ ext = os.path.splitext(source)
+ if string.find(ext, 'htm') > 0:
+ from xml.dom.ext.reader import HtmlLib
+ self.__content = HtmlLib.FromHtmlUrl(source)
+ elif string.lower(ext) == '.xml':
+ from xml.dom.ext.reader import Sax2
+ self.__content = Sax2.FromXmlUrl(source)
+ return self.__content
+
+ def _get_frameBorder(self):
+ return string.capitalize(self.getAttribute("FRAMEBORDER"))
+
+ def _set_frameBorder(self, value):
+ self.setAttribute("FRAMEBORDER", value)
+
+ def _get_height(self):
+ return self.getAttribute("HEIGHT")
+
+ def _set_height(self, value):
+ self.setAttribute("HEIGHT", value)
+
+ def _get_longDesc(self):
+ return self.getAttribute("LONGDESC")
+
+ def _set_longDesc(self, value):
+ self.setAttribute("LONGDESC", value)
+
+ def _get_marginHeight(self):
+ return self.getAttribute("MARGINHEIGHT")
+
+ def _set_marginHeight(self, value):
+ self.setAttribute("MARGINHEIGHT", value)
+
+ def _get_marginWidth(self):
+ return self.getAttribute("MARGINWIDTH")
+
+ def _set_marginWidth(self, value):
+ self.setAttribute("MARGINWIDTH", value)
+
+ def _get_name(self):
+ return self.getAttribute("NAME")
+
+ def _set_name(self, value):
+ self.setAttribute("NAME", value)
+
+ def _get_scrolling(self):
+ return string.capitalize(self.getAttribute("SCROLLING"))
+
+ def _set_scrolling(self, value):
+ self.setAttribute("SCROLLING", value)
+
+ def _get_src(self):
+ return self.getAttribute("SRC")
+
+ def _set_src(self, value):
+ self.setAttribute("SRC", value)
+
+ def _get_width(self):
+ return self.getAttribute("WIDTH")
+
+ def _set_width(self, value):
+ self.setAttribute("WIDTH", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "align" : _get_align,
+ "contentDocument" : _get_contentDocument,
+ "frameBorder" : _get_frameBorder,
+ "height" : _get_height,
+ "longDesc" : _get_longDesc,
+ "marginHeight" : _get_marginHeight,
+ "marginWidth" : _get_marginWidth,
+ "name" : _get_name,
+ "scrolling" : _get_scrolling,
+ "src" : _get_src,
+ "Width" : _get_width
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "align" : _set_align,
+ "frameBorder" : _set_frameBorder,
+ "height" : _set_height,
+ "longDesc" : _set_longDesc,
+ "marginHeight" : _set_marginHeight,
+ "marginWidth" : _set_marginWidth,
+ "name" : _set_name,
+ "scrolling" : _set_scrolling,
+ "src" : _set_src,
+ "Width" : _set_width
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLImageElement.py b/lib/jython/Lib/xml/dom/html/HTMLImageElement.py new file mode 100644 index 000000000..b5ec390c7 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLImageElement.py @@ -0,0 +1,147 @@ +########################################################################
+#
+# File Name: HTMLImageElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLImageElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLImageElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="IMG"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_lowSrc(self):
+ return self.getAttribute("LOWSRC")
+
+ def _set_lowSrc(self, value):
+ self.setAttribute("LOWSRC", value)
+
+ def _get_name(self):
+ return self.getAttribute("NAME")
+
+ def _set_name(self, value):
+ self.setAttribute("NAME", value)
+
+ def _get_align(self):
+ return string.capitalize(self.getAttribute("ALIGN"))
+
+ def _set_align(self, value):
+ self.setAttribute("ALIGN", value)
+
+ def _get_alt(self):
+ return self.getAttribute("ALT")
+
+ def _set_alt(self, value):
+ self.setAttribute("ALT", value)
+
+ def _get_border(self):
+ return self.getAttribute("BORDER")
+
+ def _set_border(self, value):
+ self.setAttribute("BORDER", value)
+
+ def _get_height(self):
+ return self.getAttribute("HEIGHT")
+
+ def _set_height(self, value):
+ self.setAttribute("HEIGHT", value)
+
+ def _get_hspace(self):
+ return self.getAttribute("HSPACE")
+
+ def _set_hspace(self, value):
+ self.setAttribute("HSPACE", value)
+
+ def _get_isMap(self):
+ return self.hasAttribute("ISMAP")
+
+ def _set_isMap(self, value):
+ if value:
+ self.setAttribute("ISMAP", "ISMAP")
+ else:
+ self.removeAttribute("ISMAP")
+
+ def _get_longDesc(self):
+ return self.getAttribute("LONGDESC")
+
+ def _set_longDesc(self, value):
+ self.setAttribute("LONGDESC", value)
+
+ def _get_src(self):
+ return self.getAttribute("SRC")
+
+ def _set_src(self, value):
+ self.setAttribute("SRC", value)
+
+ def _get_useMap(self):
+ return self.getAttribute("USEMAP")
+
+ def _set_useMap(self, value):
+ self.setAttribute("USEMAP", value)
+
+ def _get_vspace(self):
+ return self.getAttribute("VSPACE")
+
+ def _set_vspace(self, value):
+ self.setAttribute("VSPACE", value)
+
+ def _get_width(self):
+ return self.getAttribute("WIDTH")
+
+ def _set_width(self, value):
+ self.setAttribute("WIDTH", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "lowSrc" : _get_lowSrc,
+ "name" : _get_name,
+ "align" : _get_align,
+ "alt" : _get_alt,
+ "border" : _get_border,
+ "height" : _get_height,
+ "hspace" : _get_hspace,
+ "isMap" : _get_isMap,
+ "longDesc" : _get_longDesc,
+ "src" : _get_src,
+ "useMap" : _get_useMap,
+ "vspace" : _get_vspace,
+ "width" : _get_width
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "lowSrc" : _set_lowSrc,
+ "name" : _set_name,
+ "align" : _set_align,
+ "alt" : _set_alt,
+ "border" : _set_border,
+ "height" : _set_height,
+ "hspace" : _set_hspace,
+ "isMap" : _set_isMap,
+ "longDesc" : _set_longDesc,
+ "src" : _set_src,
+ "useMap" : _set_useMap,
+ "vspace" : _set_vspace,
+ "width" : _set_width
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLInputElement.py b/lib/jython/Lib/xml/dom/html/HTMLInputElement.py new file mode 100644 index 000000000..add6b812d --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLInputElement.py @@ -0,0 +1,225 @@ +########################################################################
+#
+# File Name: HTMLInputElement.py
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLInputElement.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+from xml.dom.html.HTMLElement import HTMLElement
+from xml.dom import InvalidAccessErr
+import string
+
+class HTMLInputElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName='INPUT'):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ def _get_accept(self):
+ return self.getAttribute('ACCEPT')
+
+ def _set_accept(self,accept):
+ self.setAttribute('ACCEPT',accept)
+
+ def _get_accessKey(self):
+ return self.getAttribute('ACCESSKEY')
+
+ def _set_accessKey(self,accessKey):
+ self.setAttribute('ACCESSKEY',accessKey)
+
+ def _get_align(self):
+ return string.capitalize(self.getAttribute('ALIGN'))
+
+ def _set_align(self,align):
+ self.setAttribute('ALIGN',align)
+
+ def _get_alt(self):
+ return self.getAttribute('ALT')
+
+ def _set_alt(self,alt):
+ self.setAttribute('ALT',alt)
+
+ def _get_checked(self):
+ if self._get_type() in ['Radio', 'Checkbox']:
+ return self.hasAttribute('CHECKED')
+ else:
+ raise InvalidAccessErr()
+
+ def _set_checked(self,checked):
+ if self._get_type() in ['Radio','Checkbox']:
+ if checked:
+ self.setAttribute('CHECKED', 'CHECKED')
+ else:
+ self.removeAttribute('CHECKED')
+ else:
+ raise InvalidAccessErr()
+
+ def _get_defaultChecked(self):
+ return self._get_checked()
+
+ def _set_defaultChecked(self,checked):
+ self._set_checked(checked)
+
+ def _get_defaultValue(self):
+ return self._get_value()
+
+ def _set_defaultValue(self,value):
+ self._set_value(value)
+
+ def _get_disabled(self):
+ return self.hasAttribute('DISABLED')
+
+ def _set_disabled(self,disabled):
+ if disabled:
+ self.setAttribute('DISABLED', 'DISABLED')
+ else:
+ self.removeAttribute('DISABLED')
+
+ def _get_form(self):
+ parent = self.parentNode
+ while parent:
+ if parent.nodeName == "FORM":
+ return parent
+ parent = parent.parentNode
+ return None
+
+ def _get_maxLength(self):
+ if self._get_type() in ['Text','Password']:
+ rt = self.getAttribute('MAXLENGTH')
+ if rt:
+ return int(rt)
+ raise InvalidAccessErr()
+
+ def _set_maxLength(self,maxLength):
+ if self._get_type() in ['Text','Password']:
+ self.setAttribute('MAXLENGTH',str(maxLength))
+ else:
+ raise InvalidAccessErr()
+
+ def _get_name(self):
+ return self.getAttribute('NAME')
+
+ def _set_name(self,name):
+ self.setAttribute('NAME',name)
+
+ def _get_readOnly(self):
+ if self._get_type() in ['Text','Password']:
+ return self.hasAttribute('READONLY')
+ raise InvalidAccessErr()
+
+ def _set_readOnly(self,readOnly):
+ if self._get_type() in ['Text','Password']:
+ if readOnly:
+ self.setAttribute('READONLY', 'READONLY')
+ else:
+ self.removeAttribute('READONLY')
+ else:
+ raise InvalidAccessErr()
+
+ def _get_size(self):
+ return self.getAttribute('SIZE')
+
+ def _set_size(self,size):
+ self.setAttribute('SIZE',size)
+
+ def _get_src(self):
+ if self._get_type() == 'Image':
+ return self.getAttribute('SRC')
+ else:
+ raise InvalidAccessErr()
+
+ def _set_src(self,src):
+ if self._get_type() == 'Image':
+ self.setAttribute('SRC',src)
+ else:
+ raise InvalidAccessErr()
+
+ def _get_tabIndex(self):
+ rt = self.getAttribute('TABINDEX')
+ if rt:
+ return int(rt)
+ return -1
+
+ def _set_tabIndex(self,tabIndex):
+ self.setAttribute('TABINDEX',str(tabIndex))
+
+ def _get_type(self):
+ return string.capitalize(self.getAttribute('TYPE'))
+
+ def _get_useMap(self):
+ return self.getAttribute('USEMAP')
+
+ def _set_useMap(self,useMap):
+ self.setAttribute('USEMAP',useMap)
+
+ def _get_value(self):
+ return self.getAttribute('VALUE')
+
+ def _set_value(self,value):
+ self.setAttribute('VALUE',value)
+
+ ### Methods ###
+
+ def blur(self):
+ pass
+
+ def click(self):
+ pass
+
+ def focus(self):
+ pass
+
+ def select(self):
+ pass
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update ({
+ 'accept' : _get_accept,
+ 'accessKey' : _get_accessKey,
+ 'align' : _get_align,
+ 'alt' : _get_alt,
+ 'checked' : _get_checked,
+ 'defaultChecked' : _get_defaultChecked,
+ 'defaultValue' : _get_defaultValue,
+ 'disabled' : _get_disabled,
+ 'form' : _get_form,
+ 'maxLength' : _get_maxLength,
+ 'name' : _get_name,
+ 'readOnly' : _get_readOnly,
+ 'size' : _get_size,
+ 'src' : _get_src,
+ 'tabIndex' : _get_tabIndex,
+ 'type' : _get_type,
+ 'useMap' : _get_useMap,
+ 'value' : _get_value,
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update ({
+ 'accept' : _set_accept,
+ 'accessKey' : _set_accessKey,
+ 'align' : _set_align,
+ 'alt' : _set_alt,
+ 'checked' : _set_checked,
+ 'defaultChecked' : _set_defaultChecked,
+ 'defaultValue' : _set_defaultValue,
+ 'disabled' : _set_disabled,
+ 'maxLength' : _set_maxLength,
+ 'name' : _set_name,
+ 'readOnly' : _set_readOnly,
+ 'size' : _set_size,
+ 'src' : _set_src,
+ 'tabIndex' : _set_tabIndex,
+ 'useMap' : _set_useMap,
+ 'value' : _set_value,
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLIsIndexElement.py b/lib/jython/Lib/xml/dom/html/HTMLIsIndexElement.py new file mode 100644 index 000000000..5f3c34ba7 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLIsIndexElement.py @@ -0,0 +1,57 @@ +########################################################################
+#
+# File Name: HTMLIsIndexElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLIsIndexElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLIsIndexElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="ISINDEX"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_form(self):
+ parent = self.parentNode
+ while parent:
+ if parent.nodeName == "FORM":
+ return parent
+ parent = parent.parentNode
+ return None
+
+ def _get_prompt(self):
+ return self.getAttribute("PROMPT")
+
+ def _set_prompt(self, value):
+ self.setAttribute("PROMPT", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "form" : _get_form,
+ "prompt" : _get_prompt
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "prompt" : _set_prompt
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLLIElement.py b/lib/jython/Lib/xml/dom/html/HTMLLIElement.py new file mode 100644 index 000000000..926fb058b --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLLIElement.py @@ -0,0 +1,59 @@ +########################################################################
+#
+# File Name: HTMLLIElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLLIElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLLIElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="LI"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_type(self):
+ return self.getAttribute("TYPE")
+
+ def _set_type(self, value):
+ self.setAttribute("TYPE", value)
+
+ def _get_value(self):
+ value = self.getAttribute("VALUE")
+ if value:
+ return int(value)
+ return 0
+
+ def _set_value(self, value):
+ self.setAttribute("VALUE", str(value))
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "type" : _get_type,
+ "value" : _get_value
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "type" : _set_type,
+ "value" : _set_value
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLLabelElement.py b/lib/jython/Lib/xml/dom/html/HTMLLabelElement.py new file mode 100644 index 000000000..a1c274c0f --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLLabelElement.py @@ -0,0 +1,65 @@ +########################################################################
+#
+# File Name: HTMLLabelElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLLabelElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLLabelElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="LABEL"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_accessKey(self):
+ return self.getAttribute("ACCESSKEY")
+
+ def _set_accessKey(self, value):
+ self.setAttribute("ACCESSKEY", value)
+
+ def _get_form(self):
+ parent = self.parentNode
+ while parent:
+ if parent.nodeName == "FORM":
+ return parent
+ parent = parent.parentNode
+ return None
+
+ def _get_htmlFor(self):
+ return self.getAttribute("FOR")
+
+ def _set_htmlFor(self, value):
+ self.setAttribute("FOR", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "accessKey" : _get_accessKey,
+ "form" : _get_form,
+ "htmlFor" : _get_htmlFor
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "accessKey" : _set_accessKey,
+ "htmlFor" : _set_htmlFor
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLLegendElement.py b/lib/jython/Lib/xml/dom/html/HTMLLegendElement.py new file mode 100644 index 000000000..1e9b5e065 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLLegendElement.py @@ -0,0 +1,65 @@ +########################################################################
+#
+# File Name: HTMLLegendElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLLegendElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLLegendElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="LEGEND"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_accessKey(self):
+ return self.getAttribute("ACCESSKEY")
+
+ def _set_accessKey(self, value):
+ self.setAttribute("ACCESSKEY", value)
+
+ def _get_align(self):
+ return string.capitalize(self.getAttribute("ALIGN"))
+
+ def _set_align(self, value):
+ self.setAttribute("ALIGN", value)
+
+ def _get_form(self):
+ parent = self.parentNode
+ while parent:
+ if parent.nodeName == "FORM":
+ return parent
+ parent = parent.parentNode
+ return None
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "accessKey" : _get_accessKey,
+ "align" : _get_align,
+ "form" : _get_form
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "accessKey" : _set_accessKey,
+ "align" : _set_align
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLLinkElement.py b/lib/jython/Lib/xml/dom/html/HTMLLinkElement.py new file mode 100644 index 000000000..d8ddad984 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLLinkElement.py @@ -0,0 +1,115 @@ +########################################################################
+#
+# File Name: HTMLLinkElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLLinkElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLLinkElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="LINK"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_disabled(self):
+ return self.hasAttribute("DISABLED")
+
+ def _set_disabled(self, value):
+ if value:
+ self.setAttribute("DISABLED", "DISABLED")
+ else:
+ self.removeAttribute("DISABLED")
+
+ def _get_charset(self):
+ return self.getAttribute("CHARSET")
+
+ def _set_charset(self, value):
+ self.setAttribute("CHARSET", value)
+
+ def _get_href(self):
+ return self.getAttribute("HREF")
+
+ def _set_href(self, value):
+ self.setAttribute("HREF", value)
+
+ def _get_hreflang(self):
+ return self.getAttribute("HREFLANG")
+
+ def _set_hreflang(self, value):
+ self.setAttribute("HREFLANG", value)
+
+ def _get_media(self):
+ return self.getAttribute("MEDIA")
+
+ def _set_media(self, value):
+ self.setAttribute("MEDIA", value)
+
+ def _get_rel(self):
+ return self.getAttribute("REL")
+
+ def _set_rel(self, value):
+ self.setAttribute("REL", value)
+
+ def _get_rev(self):
+ return self.getAttribute("REV")
+
+ def _set_rev(self, value):
+ self.setAttribute("REV", value)
+
+ def _get_target(self):
+ return self.getAttribute("TARGET")
+
+ def _set_target(self, value):
+ self.setAttribute("TARGET", value)
+
+ def _get_type(self):
+ return self.getAttribute("TYPE")
+
+ def _set_type(self, value):
+ self.setAttribute("TYPE", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "disabled" : _get_disabled,
+ "charset" : _get_charset,
+ "href" : _get_href,
+ "hreflang" : _get_hreflang,
+ "media" : _get_media,
+ "rel" : _get_rel,
+ "rev" : _get_rev,
+ "target" : _get_target,
+ "type" : _get_type
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "disabled" : _set_disabled,
+ "charset" : _set_charset,
+ "href" : _set_href,
+ "hreflang" : _set_hreflang,
+ "media" : _set_media,
+ "rel" : _set_rel,
+ "rev" : _set_rev,
+ "target" : _set_target,
+ "type" : _set_type
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLMapElement.py b/lib/jython/Lib/xml/dom/html/HTMLMapElement.py new file mode 100644 index 000000000..c2a13039f --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLMapElement.py @@ -0,0 +1,48 @@ +########################################################################
+#
+# File Name: HTMLMapElement.py
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLMapElement.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+from xml.dom.html.HTMLElement import HTMLElement
+from xml.dom import implementation
+
+class HTMLMapElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName='MAP'):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_areas(self):
+ rt = self.getElementsByTagName('AREA')
+ return implementation._4dom_createHTMLCollection(rt)
+
+ def _get_name(self):
+ return self.getAttribute('NAME')
+
+ def _set_name(self,name):
+ self.setAttribute('NAME',name)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update ({
+ 'areas' : _get_areas,
+ 'name' : _get_name
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update ({
+ 'name' : _set_name
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLMenuElement.py b/lib/jython/Lib/xml/dom/html/HTMLMenuElement.py new file mode 100644 index 000000000..6f7bd2447 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLMenuElement.py @@ -0,0 +1,51 @@ +########################################################################
+#
+# File Name: HTMLMenuElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLMenuElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLMenuElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="MENU"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_compact(self):
+ return self.hasAttribute("COMPACT")
+
+ def _set_compact(self, value):
+ if value:
+ self.setAttribute("COMPACT", "COMPACT")
+ else:
+ self.removeAttribute("COMPACT")
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "compact" : _get_compact
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "compact" : _set_compact
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLMetaElement.py b/lib/jython/Lib/xml/dom/html/HTMLMetaElement.py new file mode 100644 index 000000000..4f2ef6543 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLMetaElement.py @@ -0,0 +1,72 @@ +########################################################################
+#
+# File Name: HTMLMetaElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLMetaElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLMetaElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="META"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_content(self):
+ return self.getAttribute("CONTENT")
+
+ def _set_content(self, value):
+ self.setAttribute("CONTENT", value)
+
+ def _get_httpEquiv(self):
+ return self.getAttribute("HTTP-EQUIV")
+
+ def _set_httpEquiv(self, value):
+ self.setAttribute("HTTP-EQUIV", value)
+
+ def _get_name(self):
+ return self.getAttribute("NAME")
+
+ def _set_name(self, value):
+ self.setAttribute("NAME", value)
+
+ def _get_scheme(self):
+ return self.getAttribute("SCHEME")
+
+ def _set_scheme(self, value):
+ self.setAttribute("SCHEME", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "content" : _get_content,
+ "httpEquiv" : _get_httpEquiv,
+ "name" : _get_name,
+ "scheme" : _get_scheme
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "content" : _set_content,
+ "httpEquiv" : _set_httpEquiv,
+ "name" : _set_name,
+ "scheme" : _set_scheme
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLModElement.py b/lib/jython/Lib/xml/dom/html/HTMLModElement.py new file mode 100644 index 000000000..d6e6aa19c --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLModElement.py @@ -0,0 +1,56 @@ +########################################################################
+#
+# File Name: HTMLModElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLModElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLModElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="MOD"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_cite(self):
+ return self.getAttribute("CITE")
+
+ def _set_cite(self, value):
+ self.setAttribute("CITE", value)
+
+ def _get_dateTime(self):
+ return self.getAttribute("DATETIME")
+
+ def _set_dateTime(self, value):
+ self.setAttribute("DATETIME", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "cite" : _get_cite,
+ "dateTime" : _get_dateTime
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "cite" : _set_cite,
+ "dateTime" : _set_dateTime
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLOListElement.py b/lib/jython/Lib/xml/dom/html/HTMLOListElement.py new file mode 100644 index 000000000..4be860557 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLOListElement.py @@ -0,0 +1,70 @@ +########################################################################
+#
+# File Name: HTMLOListElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLOListElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLOListElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="OL"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_compact(self):
+ return self.hasAttribute("COMPACT")
+
+ def _set_compact(self, value):
+ if value:
+ self.setAttribute("COMPACT", "COMPACT")
+ else:
+ self.removeAttribute("COMPACT")
+
+ def _get_start(self):
+ value = self.getAttribute("START")
+ if value:
+ return int(value)
+ return 0
+
+ def _set_start(self, value):
+ self.setAttribute("START", str(value))
+
+ def _get_type(self):
+ return self.getAttribute("TYPE")
+
+ def _set_type(self, value):
+ self.setAttribute("TYPE", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "compact" : _get_compact,
+ "start" : _get_start,
+ "type" : _get_type
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "compact" : _set_compact,
+ "start" : _set_start,
+ "type" : _set_type
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLObjectElement.py b/lib/jython/Lib/xml/dom/html/HTMLObjectElement.py new file mode 100644 index 000000000..ad5b772e3 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLObjectElement.py @@ -0,0 +1,195 @@ +########################################################################
+#
+# File Name: HTMLObjectElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLObjectElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLObjectElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="OBJECT"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_align(self):
+ return string.capitalize(self.getAttribute("ALIGN"))
+
+ def _set_align(self, value):
+ self.setAttribute("ALIGN", value)
+
+ def _get_archive(self):
+ return self.getAttribute("ARCHIVE")
+
+ def _set_archive(self, value):
+ self.setAttribute("ARCHIVE", value)
+
+ def _get_border(self):
+ return self.getAttribute("BORDER")
+
+ def _set_border(self, value):
+ self.setAttribute("BORDER", value)
+
+ def _get_code(self):
+ return self.getAttribute("CODE")
+
+ def _set_code(self, value):
+ self.setAttribute("CODE", value)
+
+ def _get_codeBase(self):
+ return self.getAttribute("CODEBASE")
+
+ def _set_codeBase(self, value):
+ self.setAttribute("CODEBASE", value)
+
+ def _get_codeType(self):
+ return self.getAttribute("CODETYPE")
+
+ def _set_codeType(self, value):
+ self.setAttribute("CODETYPE", value)
+
+ def _get_contentDocument(self):
+ return "None"
+
+ def _get_data(self):
+ return self.getAttribute("DATA")
+
+ def _set_data(self, value):
+ self.setAttribute("DATA", value)
+
+ def _get_declare(self):
+ return self.hasAttribute("DECLARE")
+
+ def _set_declare(self, value):
+ if value:
+ self.setAttribute("DECLARE", "DECLARE")
+ else:
+ self.removeAttribute("DECLARE")
+
+ def _get_form(self):
+ parent = self.parentNode
+ while parent:
+ if parent.nodeName == "FORM":
+ return parent
+ parent = parent.parentNode
+ return None
+
+ def _get_height(self):
+ return self.getAttribute("HEIGHT")
+
+ def _set_height(self, value):
+ self.setAttribute("HEIGHT", value)
+
+ def _get_hspace(self):
+ return self.getAttribute("HSPACE")
+
+ def _set_hspace(self, value):
+ self.setAttribute("HSPACE", value)
+
+ def _get_name(self):
+ return self.getAttribute("NAME")
+
+ def _set_name(self, value):
+ self.setAttribute("NAME", value)
+
+ def _get_standby(self):
+ return self.getAttribute("STANDBY")
+
+ def _set_standby(self, value):
+ self.setAttribute("STANDBY", value)
+
+ def _get_tabIndex(self):
+ value = self.getAttribute("TABINDEX")
+ if value:
+ return int(value)
+ return 0
+
+ def _set_tabIndex(self, value):
+ self.setAttribute("TABINDEX", str(value))
+
+ def _get_type(self):
+ return self.getAttribute("TYPE")
+
+ def _set_type(self, value):
+ self.setAttribute("TYPE", value)
+
+ def _get_useMap(self):
+ return self.getAttribute("USEMAP")
+
+ def _set_useMap(self, value):
+ self.setAttribute("USEMAP", value)
+
+ def _get_vspace(self):
+ return self.getAttribute("VSPACE")
+
+ def _set_vspace(self, value):
+ self.setAttribute("VSPACE", value)
+
+ def _get_width(self):
+ return self.getAttribute("WIDTH")
+
+ def _set_width(self, value):
+ self.setAttribute("WIDTH", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "align" : _get_align,
+ "archive" : _get_archive,
+ "border" : _get_border,
+ "code" : _get_code,
+ "codeBase" : _get_codeBase,
+ "codeType" : _get_codeType,
+ "contentDocument" : _get_contentDocument,
+ "data" : _get_data,
+ "declare" : _get_declare,
+ "form" : _get_form,
+ "height" : _get_height,
+ "hspace" : _get_hspace,
+ "name" : _get_name,
+ "standby" : _get_standby,
+ "tabIndex" : _get_tabIndex,
+ "type" : _get_type,
+ "useMap" : _get_useMap,
+ "vspace" : _get_vspace,
+ "width" : _get_width
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "align" : _set_align,
+ "archive" : _set_archive,
+ "border" : _set_border,
+ "code" : _set_code,
+ "codeBase" : _set_codeBase,
+ "codeType" : _set_codeType,
+ "data" : _set_data,
+ "declare" : _set_declare,
+ "height" : _set_height,
+ "hspace" : _set_hspace,
+ "name" : _set_name,
+ "standby" : _set_standby,
+ "tabIndex" : _set_tabIndex,
+ "type" : _set_type,
+ "useMap" : _set_useMap,
+ "vspace" : _set_vspace,
+ "width" : _set_width
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLOptGroupElement.py b/lib/jython/Lib/xml/dom/html/HTMLOptGroupElement.py new file mode 100644 index 000000000..ff8fdc998 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLOptGroupElement.py @@ -0,0 +1,59 @@ +########################################################################
+#
+# File Name: HTMLOptGroupElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLOptGroupElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLOptGroupElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="OPTGROUP"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_disabled(self):
+ return self.hasAttribute("DISABLED")
+
+ def _set_disabled(self, value):
+ if value:
+ self.setAttribute("DISABLED", "DISABLED")
+ else:
+ self.removeAttribute("DISABLED")
+
+ def _get_label(self):
+ return self.getAttribute("LABEL")
+
+ def _set_label(self, value):
+ self.setAttribute("LABEL", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "disabled" : _get_disabled,
+ "label" : _get_label
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "disabled" : _set_disabled,
+ "label" : _set_label
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLOptionElement.py b/lib/jython/Lib/xml/dom/html/HTMLOptionElement.py new file mode 100644 index 000000000..addc210cd --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLOptionElement.py @@ -0,0 +1,124 @@ +########################################################################
+#
+# File Name: HTMLOptionElement.py
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLOptionElement.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+from xml.dom.html.HTMLElement import HTMLElement
+from xml.dom import Node
+
+class HTMLOptionElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName='OPTION'):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_defaultSelected(self):
+ return self._get_selected()
+
+ def _set_defaultSelected(self, selected):
+ self._set_selected(selected)
+
+ def _get_disabled(self):
+ return self.getAttributeNode('DISABLED') and 1 or 0
+
+ def _set_disabled(self,disabled):
+ if disabled:
+ self.setAttribute('DISABLED', 'DISABLED')
+ else:
+ self.removeAttribute('DISABLED')
+
+ def _get_form(self):
+ parent = self.parentNode
+ while parent:
+ if parent.nodeName == "FORM":
+ return parent
+ parent = parent.parentNode
+ return None
+
+ def _get_index(self):
+ p = self.parentNode
+ if p.tagName != 'SELECT':
+ return -1
+ options = p._get_options()
+ try:
+ return options.index(self)
+ except:
+ return -1
+
+ def _get_label(self):
+ return self.getAttribute('LABEL')
+
+ def _set_label(self,label):
+ self.setAttribute('LABEL',label)
+
+ def _get_selected(self):
+ return self.hasAttribute('SELECTED')
+
+ def _set_selected(self, selected):
+ if selected:
+ self.setAttribute('SELECTED', 'SELECTED')
+ else:
+ self.removeAttribute('SELECTED')
+
+ def _get_text(self):
+ if not self.firstChild:
+ return
+ if self.firstChild == self.lastChild:
+ return self.firstChild.data
+ self.normalize()
+ text = filter(lambda x: x.nodeType == Node.TEXT_NODE, self.childNodes)
+ return text[0].data
+
+ def _set_text(self, value):
+ text = None
+ for node in self.childNodes:
+ if not text and node.nodeType == Node.TEXT_NODE:
+ text = node
+ else:
+ self.removeChild(node)
+ if text:
+ text.data = value
+ else:
+ text = self.ownerDocument.createTextNode(value)
+ self.appendChild(text)
+
+ def _get_value(self):
+ return self.getAttribute('VALUE')
+
+ def _set_value(self,value):
+ self.setAttribute('VALUE',value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update ({
+ 'defaultSelected' : _get_defaultSelected,
+ 'disabled' : _get_disabled,
+ 'form' : _get_form,
+ 'index' : _get_index,
+ 'label' : _get_label,
+ 'selected' : _get_selected,
+ 'text' : _get_text,
+ 'value' : _get_value,
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update ({
+ 'defaultSelected' : _set_defaultSelected,
+ 'disabled' : _set_disabled,
+ 'label' : _set_label,
+ 'selected' : _set_selected,
+ 'value' : _set_value,
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLParagraphElement.py b/lib/jython/Lib/xml/dom/html/HTMLParagraphElement.py new file mode 100644 index 000000000..20a482956 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLParagraphElement.py @@ -0,0 +1,48 @@ +########################################################################
+#
+# File Name: HTMLParagraphElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLParagraphElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLParagraphElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="P"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_align(self):
+ return string.capitalize(self.getAttribute("ALIGN"))
+
+ def _set_align(self, value):
+ self.setAttribute("ALIGN", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "align" : _get_align
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "align" : _set_align
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLParamElement.py b/lib/jython/Lib/xml/dom/html/HTMLParamElement.py new file mode 100644 index 000000000..9e3204c9e --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLParamElement.py @@ -0,0 +1,72 @@ +########################################################################
+#
+# File Name: HTMLParamElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLParamElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLParamElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="PARAM"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_name(self):
+ return self.getAttribute("NAME")
+
+ def _set_name(self, value):
+ self.setAttribute("NAME", value)
+
+ def _get_type(self):
+ return self.getAttribute("TYPE")
+
+ def _set_type(self, value):
+ self.setAttribute("TYPE", value)
+
+ def _get_value(self):
+ return self.getAttribute("VALUE")
+
+ def _set_value(self, value):
+ self.setAttribute("VALUE", value)
+
+ def _get_valueType(self):
+ return string.capitalize(self.getAttribute("VALUETYPE"))
+
+ def _set_valueType(self, value):
+ self.setAttribute("VALUETYPE", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "name" : _get_name,
+ "type" : _get_type,
+ "value" : _get_value,
+ "valueType" : _get_valueType
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "name" : _set_name,
+ "type" : _set_type,
+ "value" : _set_value,
+ "valueType" : _set_valueType
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLPreElement.py b/lib/jython/Lib/xml/dom/html/HTMLPreElement.py new file mode 100644 index 000000000..5abcc855a --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLPreElement.py @@ -0,0 +1,51 @@ +########################################################################
+#
+# File Name: HTMLPreElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLPreElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLPreElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="PRE"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_width(self):
+ value = self.getAttribute("WIDTH")
+ if value:
+ return int(value)
+ return 0
+
+ def _set_width(self, value):
+ self.setAttribute("WIDTH", str(value))
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "width" : _get_width
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "width" : _set_width
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLQuoteElement.py b/lib/jython/Lib/xml/dom/html/HTMLQuoteElement.py new file mode 100644 index 000000000..48bea5900 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLQuoteElement.py @@ -0,0 +1,48 @@ +########################################################################
+#
+# File Name: HTMLQuoteElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLQuoteElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLQuoteElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_cite(self):
+ return self.getAttribute("CITE")
+
+ def _set_cite(self, value):
+ self.setAttribute("CITE", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "cite" : _get_cite
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "cite" : _set_cite
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLScriptElement.py b/lib/jython/Lib/xml/dom/html/HTMLScriptElement.py new file mode 100644 index 000000000..c5a567d3c --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLScriptElement.py @@ -0,0 +1,115 @@ +########################################################################
+#
+# File Name: HTMLScriptElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLScriptElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLScriptElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="SCRIPT"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_charset(self):
+ return self.getAttribute("CHARSET")
+
+ def _set_charset(self, value):
+ self.setAttribute("CHARSET", value)
+
+ def _get_defer(self):
+ return self.hasAttribute("DEFER")
+
+ def _set_defer(self, value):
+ if value:
+ self.setAttribute("DEFER", "DEFER")
+ else:
+ self.removeAttribute("DEFER")
+
+ def _get_event(self):
+ return self.getAttribute("EVENT")
+
+ def _set_event(self, value):
+ self.setAttribute("EVENT", value)
+
+ def _get_htmlFor(self):
+ return self.getAttribute("FOR")
+
+ def _set_htmlFor(self, value):
+ self.setAttribute("FOR", value)
+
+ def _get_src(self):
+ return self.getAttribute("SRC")
+
+ def _set_src(self, value):
+ self.setAttribute("SRC", value)
+
+ def _get_text(self):
+ if not self.firstChild:
+ return
+ if self.firstChild == self.lastChild:
+ return self.firstChild.data
+ self.normalize()
+ text = filter(lambda x: x.nodeType == Node.TEXT_NODE, self.childNodes)
+ return text[0].data
+
+ def _set_text(self, value):
+ text = None
+ for node in self.childNodes:
+ if not text and node.nodeType == Node.TEXT_NODE:
+ text = node
+ else:
+ self.removeChild(node)
+ if text:
+ text.data = value
+ else:
+ text = self.ownerDocument.createTextNode(value)
+ self.appendChild(text)
+
+ def _get_type(self):
+ return self.getAttribute("TYPE")
+
+ def _set_type(self, value):
+ self.setAttribute("TYPE", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "charset" : _get_charset,
+ "defer" : _get_defer,
+ "event" : _get_event,
+ "htmlFor" : _get_htmlFor,
+ "src" : _get_src,
+ "text" : _get_text,
+ "type" : _get_type
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "charset" : _set_charset,
+ "defer" : _set_defer,
+ "event" : _set_event,
+ "htmlFor" : _set_htmlFor,
+ "src" : _set_src,
+ "text" : _set_text,
+ "type" : _set_type
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLSelectElement.py b/lib/jython/Lib/xml/dom/html/HTMLSelectElement.py new file mode 100644 index 000000000..ec393bf3c --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLSelectElement.py @@ -0,0 +1,161 @@ +########################################################################
+#
+# File Name: HTMLSelectElement.py
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLSelectElement.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+from xml.dom import implementation
+from xml.dom import IndexSizeErr
+from xml.dom.html.HTMLElement import HTMLElement
+import string
+
+class HTMLSelectElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName='SELECT'):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ def _get_type(self):
+ if self._get_multiple():
+ return 'select-multiple'
+ return 'select-one'
+
+ def _get_selectedIndex(self):
+ options = self._get_options()
+ for ctr in range(len(options)):
+ node = options.item(ctr)
+ if node._get_selected() == 1:
+ return ctr
+ return -1
+
+ def _set_selectedIndex(self,index):
+ options = self._get_options()
+ if index < 0 or index >= len(options):
+ raise IndexSizeErr()
+
+ for ctr in range(len(options)):
+ node = options.item(ctr)
+ if ctr == index:
+ node._set_selected(1)
+ else:
+ node._set_selected(0)
+
+ def _get_value(self):
+ options = self._get_options()
+ node = options.item(self._get_selectedIndex())
+ if node.hasAttribute('VALUE'):
+ value = node.getAttribute('VALUE')
+ elif node.firstChild:
+ value = node.firstChild.data
+ else:
+ value = ''
+ return value
+
+ def _set_value(self,value):
+ # This doesn't seem to do anything in browsers
+ pass
+
+ def _get_length(self):
+ return self._get_options()._get_length()
+
+ def _get_options(self):
+ children = self.getElementsByTagName('OPTION')
+ return implementation._4dom_createHTMLCollection(children)
+
+ def _get_disabled(self):
+ if self.getAttributeNode('DISABLED'):
+ return 1
+ return 0
+
+ def _set_disabled(self,disabled):
+ if disabled:
+ self.setAttribute('DISABLED', 'DISABLED')
+ else:
+ self.removeAttribute('DISABLED')
+
+ def _get_multiple(self):
+ if self.getAttributeNode('MULTIPLE'):
+ return 1
+ return 0
+
+ def _set_multiple(self,mult):
+ if mult:
+ self.setAttribute('MULTIPLE', 'MULTIPLE')
+ else:
+ self.removeAttribute('MULTIPLE')
+
+ def _get_name(self):
+ return self.getAttribute('NAME')
+
+ def _set_name(self,name):
+ self.setAttribute('NAME',name)
+
+ def _get_size(self):
+ rt = self.getAttribute('SIZE')
+ if rt != None:
+ return string.atoi(rt)
+ return -1
+
+ def _set_size(self,size):
+ self.setAttribute('SIZE',str(size))
+
+ def _get_tabIndex(self):
+ return string.atoi(self.getAttribute('TABINDEX'))
+
+ def _set_tabIndex(self,tabindex):
+ self.setAttribute('TABINDEX',str(tabindex))
+
+ def add(self,newElement,beforeElement):
+ self.insertBefore(newElement,beforeElement)
+
+ def remove(self,index):
+ if index < 0 or index >= self._get_length:
+ return
+ hc = self._get_options()
+ node = hc.item(index)
+ self.removeChild(node)
+
+ def _get_form(self):
+ parent = self.parentNode
+ while parent:
+ if parent.nodeName == "FORM":
+ return parent
+ parent = parent.parentNode
+ return None
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update ({
+ 'type' : _get_type,
+ 'length' : _get_length,
+ 'options' : _get_options,
+ 'form' : _get_form,
+ 'selectedIndex' : _get_selectedIndex,
+ 'value' : _get_value,
+ 'disabled' : _get_disabled,
+ 'multiple' : _get_multiple,
+ 'name' : _get_name,
+ 'size' : _get_size,
+ 'tabIndex' : _get_tabIndex,
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update ({
+ 'selectedIndex' : _set_selectedIndex,
+ 'value' : _set_value,
+ 'disabled' : _set_disabled,
+ 'multiple' : _set_multiple,
+ 'name' : _set_name,
+ 'size' : _set_size,
+ 'tabIndex' : _set_tabIndex,
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLStyleElement.py b/lib/jython/Lib/xml/dom/html/HTMLStyleElement.py new file mode 100644 index 000000000..807f9fc8c --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLStyleElement.py @@ -0,0 +1,67 @@ +########################################################################
+#
+# File Name: HTMLStyleElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLStyleElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLStyleElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="STYLE"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_disabled(self):
+ return self.hasAttribute("DISABLED")
+
+ def _set_disabled(self, value):
+ if value:
+ self.setAttribute("DISABLED", "DISABLED")
+ else:
+ self.removeAttribute("DISABLED")
+
+ def _get_media(self):
+ return self.getAttribute("MEDIA")
+
+ def _set_media(self, value):
+ self.setAttribute("MEDIA", value)
+
+ def _get_type(self):
+ return self.getAttribute("TYPE")
+
+ def _set_type(self, value):
+ self.setAttribute("TYPE", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "disabled" : _get_disabled,
+ "media" : _get_media,
+ "type" : _get_type
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "disabled" : _set_disabled,
+ "media" : _set_media,
+ "type" : _set_type
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLTableCaptionElement.py b/lib/jython/Lib/xml/dom/html/HTMLTableCaptionElement.py new file mode 100644 index 000000000..b0d9c9970 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLTableCaptionElement.py @@ -0,0 +1,48 @@ +########################################################################
+#
+# File Name: HTMLTableCaptionElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLTableCaptionElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLTableCaptionElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="CAPTION"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_align(self):
+ return string.capitalize(self.getAttribute("ALIGN"))
+
+ def _set_align(self, value):
+ self.setAttribute("ALIGN", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "align" : _get_align
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "align" : _set_align
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLTableCellElement.py b/lib/jython/Lib/xml/dom/html/HTMLTableCellElement.py new file mode 100644 index 000000000..9b99b6575 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLTableCellElement.py @@ -0,0 +1,164 @@ +########################################################################
+#
+# File Name: HTMLTableCellElement.py
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLTableCellElement.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLTableCellElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName='TD'):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_abbr(self):
+ return self.getAttribute('ABBR')
+
+ def _set_abbr(self,abbr):
+ self.setAttribute('ABBR',abbr)
+
+ def _get_align(self):
+ return string.capitalize(self.getAttribute('ALIGN'))
+
+ def _set_align(self, align):
+ self.setAttribute('ALIGN', align)
+
+ def _get_axis(self):
+ return self.getAttribute('AXIS')
+
+ def _set_axis(self, axis):
+ self.setAttribute('AXIS', axis)
+
+ def _get_bgColor(self):
+ return self.getAttribute('BGCOLOR')
+
+ def _set_bgColor(self, color):
+ self.setAttribute('BGCOLOR', color)
+
+ def _get_cellIndex(self):
+ #We need to find the TR we are in
+ if self.parentNode == None:
+ return -1
+ cells = self.parentNode._get_cells()
+ return cells.index(self)
+
+ def _get_ch(self):
+ return self.getAttribute('CHAR')
+
+ def _set_ch(self,ch):
+ self.setAttribute('CHAR',ch)
+
+ def _get_chOff(self):
+ return self.getAttribute('CHAROFF')
+
+ def _set_chOff(self, offset):
+ self.setAttribute('CHAROFF', offset)
+
+ def _get_colSpan(self):
+ value = self.getAttribute('COLSPAN')
+ if value:
+ return int(value)
+ return 1
+
+ def _set_colSpan(self, span):
+ self.setAttribute('COLSPAN',str(span))
+
+ def _get_headers(self):
+ return self.getAttribute('HEADERS')
+
+ def _set_headers(self,headers):
+ self.setAttribute('HEADERS',headers)
+
+ def _get_height(self):
+ return self.getAttribute('HEIGHT')
+
+ def _set_height(self,height):
+ self.setAttribute('HEIGHT',height)
+
+ def _get_noWrap(self):
+ return self.hasAttribute('NOWRAP')
+
+ def _set_noWrap(self,nowrap):
+ if nowrap:
+ self.setAttribute('NOWRAP', 'NOWRAP')
+ else:
+ self.removeAttribute('NOWRAP')
+
+ def _get_rowSpan(self):
+ value = self.getAttribute('ROWSPAN')
+ if value:
+ return int(value)
+ return 1
+
+ def _set_rowSpan(self, span):
+ self.setAttribute('ROWSPAN', str(span))
+
+ def _get_scope(self):
+ return string.capitalize(self.getAttribute('SCOPE'))
+
+ def _set_scope(self, scope):
+ self.setAttribute('SCOPE', scope)
+
+ def _get_vAlign(self):
+ return string.capitalize(self.getAttribute('VALIGN'))
+
+ def _set_vAlign(self, valign):
+ self.setAttribute('VALIGN', valign)
+
+ def _get_width(self):
+ return self.getAttribute('WIDTH')
+
+ def _set_width(self, width):
+ self.setAttribute('WIDTH', width)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update ({
+ 'cellIndex' : _get_cellIndex,
+ 'abbr' : _get_abbr,
+ 'align' : _get_align,
+ 'axis' : _get_axis,
+ 'bgColor' : _get_bgColor,
+ 'ch' : _get_ch,
+ 'chOff' : _get_chOff,
+ 'colSpan' : _get_colSpan,
+ 'headers' : _get_headers,
+ 'height' : _get_height,
+ 'noWrap' : _get_noWrap,
+ 'rowSpan' : _get_rowSpan,
+ 'scope' : _get_scope,
+ 'vAlign' : _get_vAlign,
+ 'width' : _get_width,
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update ({
+ 'abbr' : _set_abbr,
+ 'align' : _set_align,
+ 'axis' : _set_axis,
+ 'bgColor' : _set_bgColor,
+ 'ch' : _set_ch,
+ 'chOff' : _set_chOff,
+ 'colSpan' : _set_colSpan,
+ 'headers' : _set_headers,
+ 'height' : _set_height,
+ 'noWrap' : _set_noWrap,
+ 'rowSpan' : _set_rowSpan,
+ 'scope' : _set_scope,
+ 'vAlign' : _set_vAlign,
+ 'width' : _set_width,
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLTableColElement.py b/lib/jython/Lib/xml/dom/html/HTMLTableColElement.py new file mode 100644 index 000000000..2443a0cbf --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLTableColElement.py @@ -0,0 +1,91 @@ +########################################################################
+#
+# File Name: HTMLTableColElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLTableColElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLTableColElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="COL"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_align(self):
+ return string.capitalize(self.getAttribute("ALIGN"))
+
+ def _set_align(self, value):
+ self.setAttribute("ALIGN", value)
+
+ def _get_ch(self):
+ return self.getAttribute("CHAR")
+
+ def _set_ch(self, value):
+ self.setAttribute("CHAR", value)
+
+ def _get_chOff(self):
+ return self.getAttribute("CHAROFF")
+
+ def _set_chOff(self, value):
+ self.setAttribute("CHAROFF", value)
+
+ def _get_span(self):
+ value = self.getAttribute("SPAN")
+ if value:
+ return int(value)
+ return 0
+
+ def _set_span(self, value):
+ self.setAttribute("SPAN", str(value))
+
+ def _get_vAlign(self):
+ return string.capitalize(self.getAttribute("VALIGN"))
+
+ def _set_vAlign(self, value):
+ self.setAttribute("VALIGN", value)
+
+ def _get_width(self):
+ return self.getAttribute("WIDTH")
+
+ def _set_width(self, value):
+ self.setAttribute("WIDTH", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "align" : _get_align,
+ "ch" : _get_ch,
+ "chOff" : _get_chOff,
+ "span" : _get_span,
+ "vAlign" : _get_vAlign,
+ "width" : _get_width
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "align" : _set_align,
+ "ch" : _set_ch,
+ "chOff" : _set_chOff,
+ "span" : _set_span,
+ "vAlign" : _set_vAlign,
+ "width" : _set_width
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLTableElement.py b/lib/jython/Lib/xml/dom/html/HTMLTableElement.py new file mode 100644 index 000000000..2a0d2a3e1 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLTableElement.py @@ -0,0 +1,281 @@ +########################################################################
+#
+# File Name: HTMLTableElement.py
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLTableElement.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+from xml.dom.html.HTMLElement import HTMLElement
+from xml.dom import IndexSizeErr
+from xml.dom import implementation
+from xml.dom.NodeFilter import NodeFilter
+import string
+
+class HTMLTableElement(HTMLElement):
+ """
+ Operations follow the DOM spec, and the 4.0 DTD for TABLE
+ <!ELEMENT TABLE (CAPTION?, (COL*|COLGROUP*), THEAD?, TFOOT?, TBODY+)>
+ """
+ def __init__(self, ownerDocument, nodeName='TABLE'):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_align(self):
+ return string.capitalize(self.getAttribute('ALIGN'))
+
+ def _set_align(self,align):
+ self.setAttribute('ALIGN',align)
+
+ def _get_bgColor(self):
+ return self.getAttribute('BGCOLOR')
+
+ def _set_bgColor(self,bgcolor):
+ self.setAttribute('BGCOLOR',bgcolor)
+
+ def _get_border(self):
+ return self.getAttribute('BORDER')
+
+ def _set_border(self,border):
+ self.setAttribute('BORDER',border)
+
+ def _get_caption(self):
+ nl = self.getElementsByTagName('CAPTION')
+ if len(nl):
+ return nl[0]
+ return None
+
+ def _set_caption(self,capt):
+ nl = self.getElementsByTagName('CAPTION')
+ if len(nl):
+ self.replaceChild(capt, nl[0])
+ else:
+ self.insertBefore(capt, self.firstChild)
+
+ def _get_cellPadding(self):
+ return self.getAttribute('CELLPADDING')
+
+ def _set_cellPadding(self,cellpadding):
+ self.setAttribute('CELLPADDING',cellpadding)
+
+ def _get_cellSpacing(self):
+ return self.getAttribute('CELLSPACING')
+
+ def _set_cellSpacing(self,cellspacing):
+ self.setAttribute('CELLSPACING',cellspacing)
+
+ def _get_frame(self):
+ return string.capitalize(self.getAttribute('FRAME'))
+
+ def _set_frame(self,frame):
+ self.setAttribute('FRAME',frame)
+
+ def _get_rows(self):
+ rows = []
+ tHead = self._get_tHead()
+ if tHead:
+ rows.extend(list(tHead._get_rows()))
+ tFoot = self._get_tFoot()
+ if tFoot:
+ rows.extend(list(tFoot._get_rows()))
+ for tb in self._get_tBodies():
+ rows.extend(list(tb._get_rows()))
+ return implementation._4dom_createHTMLCollection(rows)
+
+ def _get_rules(self):
+ return string.capitalize(self.getAttribute('RULES'))
+
+ def _set_rules(self,rules):
+ self.setAttribute('RULES',rules)
+
+ def _get_summary(self):
+ return self.getAttribute('SUMMARY')
+
+ def _set_summary(self,summary):
+ self.setAttribute('SUMMARY',summary)
+
+ def _get_tBodies(self):
+ bodies = []
+ for child in self.childNodes:
+ if child.nodeName == 'TBODY':
+ bodies.append(child)
+ return implementation._4dom_createHTMLCollection(bodies)
+
+ def _get_tFoot(self):
+ for child in self.childNodes:
+ if child.nodeName == 'TFOOT':
+ return child
+ return None
+
+ def _set_tFoot(self, newFooter):
+ oldFooter = self._get_tFoot()
+ if not oldFooter:
+ # TFoot goes after THead
+ iter = self.ownerDocument.createNodeIterator(self.firstChild,
+ NodeFilter.SHOW_ELEMENT,
+ None, 0)
+ ref = None
+ node = iter.nextNode()
+ while not ref and node:
+ tagName = node.tagName
+ if tagName == 'THEAD':
+ ref = iter.nextNode()
+ elif tagName == 'TBODY':
+ ref = node
+ node = iter.nextNode()
+ self.insertBefore(newFooter, ref)
+ else:
+ self.replaceChild(newFooter, oldFooter)
+
+ def _get_tHead(self):
+ for child in self.childNodes:
+ if child.nodeName == 'THEAD':
+ return child
+ return None
+
+ def _set_tHead(self, newHead):
+ oldHead = self._get_tHead()
+ if oldHead:
+ self.replaceChild(newHead, oldHead)
+ else:
+ # We need to put the new Thead in the correct spot
+ # Look for a TFOOT or a TBODY
+ iter = self.ownerDocument.createNodeIterator(self.firstChild,
+ NodeFilter.SHOW_ELEMENT,
+ None, 0)
+ ref = None
+ node = iter.nextNode()
+ while not ref and node:
+ tagName = node.tagName
+ if tagName == 'TFOOT':
+ ref = node
+ elif tagName == 'TBODY':
+ ref = node
+ elif tagName in ['COL','COLGROUP']:
+ node = iter.nextNode()
+ while node.tagName == tagName:
+ node = iter.nextNode()
+ ref = node
+ elif tagName == 'CAPTION':
+ ref = iter.nextNode()
+ node = iter.nextNode()
+ self.insertBefore(newHead, ref)
+
+ def _get_width(self):
+ return self.getAttribute('WIDTH')
+
+ def _set_width(self,width):
+ self.setAttribute('WIDTH',width)
+
+ ### Methods ###
+
+ def createCaption(self):
+ #Create a new CAPTION if one does not exist
+ caption = self._get_caption()
+ if not caption:
+ caption = self.ownerDocument.createElement('CAPTION')
+ self._set_caption(caption)
+ return caption
+
+ def createTHead(self):
+ #Create a new THEAD if one does not exist
+ thead = self._get_tHead()
+ if not thead:
+ thead = self.ownerDocument.createElement('THEAD')
+ self._set_tHead(thead)
+ return thead
+
+ def createTFoot(self):
+ #Create a new TFOOT if one does not exist
+ tfoot = self._get_tFoot()
+ if not tfoot:
+ tfoot = self.ownerDocument.createElement('TFOOT')
+ self._set_tFoot(tfoot)
+ return tfoot
+
+ def deleteCaption(self):
+ caption = self._get_caption()
+ if caption:
+ self.removeChild(caption)
+
+ def deleteRow(self,index):
+ rows = self._get_rows()
+ if index < 0 or index >= len(rows):
+ raise IndexSizeErr()
+ rows[index].parentNode.removeChild(rows[index])
+
+ def deleteTHead(self):
+ thead = self._get_tHead()
+ if thead != None:
+ self.removeChild(thead)
+
+ def deleteTFoot(self):
+ tfoot = self._get_tFoot()
+ if tfoot:
+ self.removeChild(tfoot)
+
+ def insertRow(self,index):
+ rows = self._get_rows()
+ if index < 0 or index > len(rows):
+ raise IndexSizeErr()
+ newRow = self.ownerDocument.createElement('TR')
+ if not rows:
+ # An empty table, create a body in which to insert the row
+ body = self.ownerDocument.createElement('TBODY')
+ # The body is the last element according to DTD
+ self.appendChild(body)
+ parent = body
+ ref = None
+ elif index == len(rows):
+ parent = rows[-1].parentNode
+ ref = None
+ else:
+ ref = rows[index]
+ parent = ref.parentNode
+ return parent.insertBefore(newRow, ref)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update ({
+ 'rows' : _get_rows,
+ 'tBodies' : _get_tBodies,
+ 'caption' : _get_caption,
+ 'tHead' : _get_tHead,
+ 'tFoot' : _get_tFoot,
+ 'align' : _get_align,
+ 'bgColor' : _get_bgColor,
+ 'border' : _get_border,
+ 'cellPadding' : _get_cellPadding,
+ 'cellSpacing' : _get_cellSpacing,
+ 'frame' : _get_frame,
+ 'rules' : _get_rules,
+ 'summary' : _get_summary,
+ 'width' : _get_width,
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update ({
+ 'caption' : _set_caption,
+ 'tHead' : _set_tHead,
+ 'tFoot' : _set_tFoot,
+ 'align' : _set_align,
+ 'bgColor' : _set_bgColor,
+ 'border' : _set_border,
+ 'cellPadding' : _set_cellPadding,
+ 'cellSpacing' : _set_cellSpacing,
+ 'frame' : _set_frame,
+ 'rules' : _set_rules,
+ 'summary' : _set_summary,
+ 'width' : _set_width,
+ })
+
+ # Create the read-only list of attributes
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLTableRowElement.py b/lib/jython/Lib/xml/dom/html/HTMLTableRowElement.py new file mode 100644 index 000000000..758a95684 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLTableRowElement.py @@ -0,0 +1,126 @@ +########################################################################
+#
+# File Name: HTMLTableRowElement.py
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLTableRowElement.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import implementation
+from xml.dom import IndexSizeErr
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLTableRowElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName='TR'):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_align(self):
+ return string.capitalize(self.getAttribute('ALIGN'))
+
+ def _set_align(self,align):
+ self.setAttribute('ALIGN', align)
+
+ def _get_bgColor(self):
+ return self.getAttribute('BGCOLOR')
+
+ def _set_bgColor(self, color):
+ self.setAttribute('BGCOLOR', color)
+
+ def _get_cells(self):
+ cells = []
+ for child in self.childNodes:
+ if child.tagName in ['TD','TH']:
+ cells.append(child)
+ return implementation._4dom_createHTMLCollection(cells)
+
+ def _get_ch(self):
+ return self.getAttribute('CHAR')
+
+ def _set_ch(self, ch):
+ self.setAttribute('CHAR', ch)
+
+ def _get_chOff(self):
+ return self.getAttribute('CHAROFF')
+
+ def _set_chOff(self, offset):
+ self.setAttribute('CHAROFF', offset)
+
+ def _get_rowIndex(self):
+ #Get our index in the table
+ section = self.parentNode
+ if section == None:
+ return -1
+ table = section.parentNode
+ if table == None:
+ return -1
+ rows = table._get_rows()
+ return rows.index(self)
+
+ def _get_sectionRowIndex(self):
+ section = self.parentNode
+ if section == None:
+ return -1
+ rows = section._get_rows()
+ return rows.index(self)
+
+ def _get_vAlign(self):
+ return string.capitalize(self.getAttribute('VALIGN'))
+
+ def _set_vAlign(self, valign):
+ self.setAttribute('VALIGN', valign)
+
+ ### Methods ###
+
+ def insertCell(self, index):
+ cells = self._get_cells()
+ if index < 0 or index > len(cells):
+ raise IndexSizeErr()
+ cell = self.ownerDocument.createElement('TD')
+ length = cells.length
+ if index == len(cells):
+ ref = None
+ elif index < len(cells):
+ ref = cells[index]
+ return self.insertBefore(cell, ref)
+
+ def deleteCell(self,index):
+ cells = self._get_cells()
+ if index < 0 or index >= len(cells):
+ raise IndexSizeErr()
+ self.removeChild(cells[index])
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update ({
+ 'rowIndex' : _get_rowIndex,
+ 'sectionRowIndex' : _get_sectionRowIndex,
+ 'cells' : _get_cells,
+ 'align' : _get_align,
+ 'bgColor' : _get_bgColor,
+ 'ch' : _get_ch,
+ 'chOff' : _get_chOff,
+ 'vAlign' : _get_vAlign,
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update ({
+ 'align' : _set_align,
+ 'bgColor' : _set_bgColor,
+ 'ch' : _set_ch,
+ 'chOff' : _set_chOff,
+ 'vAlign' : _set_vAlign,
+ })
+
+ # Create the read-only list of attributes
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLTableSectionElement.py b/lib/jython/Lib/xml/dom/html/HTMLTableSectionElement.py new file mode 100644 index 000000000..09498e8fb --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLTableSectionElement.py @@ -0,0 +1,98 @@ +########################################################################
+#
+# File Name: HTMLTableSectionElement.py
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLTableSectionElement.py.html
+#
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import implementation
+from xml.dom.html.HTMLElement import HTMLElement
+from xml.dom import IndexSizeErr
+
+class HTMLTableSectionElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_align(self):
+ return string.capitalize(self.getAttribute('ALIGN'))
+
+ def _set_align(self,align):
+ self.setAttribute('ALIGN',align)
+
+ def _get_ch(self):
+ return self.getAttribute('CHAR')
+
+ def _set_ch(self,char):
+ self.setAttribute('CHAR',char)
+
+ def _get_chOff(self):
+ return self.getAttribute('CHAROFF')
+
+ def _set_chOff(self,offset):
+ self.setAttribute('CHAROFF',offset)
+
+ def _get_rows(self):
+ rows = []
+ for child in self.childNodes:
+ if child.tagName == 'TR':
+ rows.append(child)
+ return implementation._4dom_createHTMLCollection(rows)
+
+ def _get_vAlign(self):
+ return string.capitalize(self.getAttribute('VALIGN'))
+
+ def _set_vAlign(self,valign):
+ self.setAttribute('VALIGN',valign)
+
+ ### Methods ###
+
+ def deleteRow(self,index):
+ rows = self._get_rows()
+ if index < 0 or index > len(rows):
+ raise IndexSizeErr()
+ rows[index].parentNode.removeChild(rows[index])
+
+ def insertRow(self,index):
+ rows = self._get_rows()
+ if index < 0 or index > len(rows):
+ raise IndexSizeErr()
+ rows = self._get_rows()
+ newRow = self.ownerDocument.createElement('TR')
+ if index == len(rows):
+ ref = None
+ else:
+ ref = rows[index]
+ return self.insertBefore(newRow, ref)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update ({
+ 'rows' : _get_rows,
+ 'align' : _get_align,
+ 'ch' : _get_ch,
+ 'chOff' : _get_chOff,
+ 'vAlign' : _get_vAlign,
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update ({
+ 'align' : _set_align,
+ 'ch' : _set_ch,
+ 'chOff' : _set_chOff,
+ 'vAlign' : _set_vAlign,
+ })
+
+ # Create the read-only list of attributes
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLTextAreaElement.py b/lib/jython/Lib/xml/dom/html/HTMLTextAreaElement.py new file mode 100644 index 000000000..3489f145a --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLTextAreaElement.py @@ -0,0 +1,183 @@ +########################################################################
+#
+# File Name: HTMLTextAreaElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLTextAreaElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLTextAreaElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="TEXTAREA"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_accessKey(self):
+ return self.getAttribute("ACCESSKEY")
+
+ def _set_accessKey(self, value):
+ self.setAttribute("ACCESSKEY", value)
+
+ def _get_cols(self):
+ value = self.getAttribute("COLS")
+ if value:
+ return int(value)
+ return 0
+
+ def _set_cols(self, value):
+ self.setAttribute("COLS", str(value))
+
+ def _get_defaultValue(self):
+ if not self.firstChild:
+ return
+ if self.firstChild == self.lastChild:
+ return self.firstChild.data
+ self.normalize()
+ text = filter(lambda x: x.nodeType == Node.TEXT_NODE, self.childNodes)
+ return text[0].data
+
+ def _set_defaultValue(self, value):
+ text = None
+ for node in self.childNodes:
+ if not text and node.nodeType == Node.TEXT_NODE:
+ text = node
+ else:
+ self.removeChild(node)
+ if text:
+ text.data = value
+ else:
+ text = self.ownerDocument.createTextNode(value)
+ self.appendChild(text)
+
+ def _get_disabled(self):
+ return self.hasAttribute("DISABLED")
+
+ def _set_disabled(self, value):
+ if value:
+ self.setAttribute("DISABLED", "DISABLED")
+ else:
+ self.removeAttribute("DISABLED")
+
+ def _get_form(self):
+ parent = self.parentNode
+ while parent:
+ if parent.nodeName == "FORM":
+ return parent
+ parent = parent.parentNode
+ return None
+
+ def _get_name(self):
+ return self.getAttribute("NAME")
+
+ def _set_name(self, value):
+ self.setAttribute("NAME", value)
+
+ def _get_readonly(self):
+ return self.hasAttribute("READONLY")
+
+ def _set_readonly(self, value):
+ if value:
+ self.setAttribute("READONLY", "READONLY")
+ else:
+ self.removeAttribute("READONLY")
+
+ def _get_rows(self):
+ value = self.getAttribute("ROWS")
+ if value:
+ return int(value)
+ return 0
+
+ def _set_rows(self, value):
+ self.setAttribute("ROWS", str(value))
+
+ def _get_tabIndex(self):
+ value = self.getAttribute("TABINDEX")
+ if value:
+ return int(value)
+ return 0
+
+ def _set_tabIndex(self, value):
+ self.setAttribute("TABINDEX", str(value))
+
+ def _get_type(self):
+ return "textarea"
+
+ def _get_value(self):
+ if not self.firstChild:
+ return
+ if self.firstChild == self.lastChild:
+ return self.firstChild.data
+ self.normalize()
+ text = filter(lambda x: x.nodeType == Node.TEXT_NODE, self.childNodes)
+ return text[0].data
+
+ def _set_value(self, value):
+ text = None
+ for node in self.childNodes:
+ if not text and node.nodeType == Node.TEXT_NODE:
+ text = node
+ else:
+ self.removeChild(node)
+ if text:
+ text.data = value
+ else:
+ text = self.ownerDocument.createTextNode(value)
+ self.appendChild(text)
+
+ ### Methods ###
+
+ def blur(self):
+ pass
+
+ def focus(self):
+ pass
+
+ def select(self):
+ pass
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "accessKey" : _get_accessKey,
+ "cols" : _get_cols,
+ "defaultValue" : _get_defaultValue,
+ "disabled" : _get_disabled,
+ "form" : _get_form,
+ "name" : _get_name,
+ "readonly" : _get_readonly,
+ "rows" : _get_rows,
+ "tabIndex" : _get_tabIndex,
+ "type" : _get_type,
+ "value" : _get_value
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "accessKey" : _set_accessKey,
+ "cols" : _set_cols,
+ "defaultValue" : _set_defaultValue,
+ "disabled" : _set_disabled,
+ "name" : _set_name,
+ "readonly" : _set_readonly,
+ "rows" : _set_rows,
+ "tabIndex" : _set_tabIndex,
+ "value" : _set_value
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLTitleElement.py b/lib/jython/Lib/xml/dom/html/HTMLTitleElement.py new file mode 100644 index 000000000..f1df1e51b --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLTitleElement.py @@ -0,0 +1,64 @@ +########################################################################
+#
+# File Name: HTMLTitleElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLTitleElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLTitleElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="TITLE"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_text(self):
+ if not self.firstChild:
+ return
+ if self.firstChild == self.lastChild:
+ return self.firstChild.data
+ self.normalize()
+ text = filter(lambda x: x.nodeType == Node.TEXT_NODE, self.childNodes)
+ return text[0].data
+
+ def _set_text(self, value):
+ text = None
+ for node in self.childNodes:
+ if not text and node.nodeType == Node.TEXT_NODE:
+ text = node
+ else:
+ self.removeChild(node)
+ if text:
+ text.data = value
+ else:
+ text = self.ownerDocument.createTextNode(value)
+ self.appendChild(text)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "text" : _get_text
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "text" : _set_text
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/HTMLUListElement.py b/lib/jython/Lib/xml/dom/html/HTMLUListElement.py new file mode 100644 index 000000000..077449d84 --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/HTMLUListElement.py @@ -0,0 +1,59 @@ +########################################################################
+#
+# File Name: HTMLUListElement
+#
+# Documentation: http://docs.4suite.com/4DOM/HTMLUListElement.html
+#
+
+### This file is automatically generated by GenerateHtml.py.
+### DO NOT EDIT!
+
+"""
+WWW: http://4suite.com/4DOM e-mail: support@4suite.com
+
+Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved.
+See http://4suite.com/COPYRIGHT for license and copyright information
+"""
+
+import string
+from xml.dom import Node
+from xml.dom.html.HTMLElement import HTMLElement
+
+class HTMLUListElement(HTMLElement):
+
+ def __init__(self, ownerDocument, nodeName="UL"):
+ HTMLElement.__init__(self, ownerDocument, nodeName)
+
+ ### Attribute Methods ###
+
+ def _get_compact(self):
+ return self.hasAttribute("COMPACT")
+
+ def _set_compact(self, value):
+ if value:
+ self.setAttribute("COMPACT", "COMPACT")
+ else:
+ self.removeAttribute("COMPACT")
+
+ def _get_type(self):
+ return string.capitalize(self.getAttribute("TYPE"))
+
+ def _set_type(self, value):
+ self.setAttribute("TYPE", value)
+
+ ### Attribute Access Mappings ###
+
+ _readComputedAttrs = HTMLElement._readComputedAttrs.copy()
+ _readComputedAttrs.update({
+ "compact" : _get_compact,
+ "type" : _get_type
+ })
+
+ _writeComputedAttrs = HTMLElement._writeComputedAttrs.copy()
+ _writeComputedAttrs.update({
+ "compact" : _set_compact,
+ "type" : _set_type
+ })
+
+ _readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),
+ HTMLElement._readOnlyAttrs + _readComputedAttrs.keys())
diff --git a/lib/jython/Lib/xml/dom/html/__init__.py b/lib/jython/Lib/xml/dom/html/__init__.py new file mode 100644 index 000000000..b32467d9c --- /dev/null +++ b/lib/jython/Lib/xml/dom/html/__init__.py @@ -0,0 +1,472 @@ +HTML_4_STRICT_INLINE = ['TT', 'I', 'B', 'BIG', 'SMALL', 'EM', 'STRONG', 'DFN', 'CODE', 'SAMP', 'KBD', 'VAR', 'CITE', 'ABBR', 'ACRONYM', 'A', 'IMG', 'OBJECT', 'SCRIPT', 'MAP', 'Q', 'SUB', 'SUP' 'SPAN', 'BDO', 'INPUT', 'SELECT', 'TEXTAREA', 'LABEL', 'BUTTON']
+
+HTML_4_TRANSITIONAL_INLINE = ['TT', 'I', 'B', 'U', 'S', 'STRIKE', 'BIG', 'SMALL', 'EM', 'STRONG', 'DFN', 'CODE', 'SAMP', 'KBD', 'VAR', 'CITE', 'ABBR', 'ACRONYM', 'A', 'IMG', 'APPLET', 'OBJECT', 'FONT', 'BASEFONT', 'SCRIPT', 'MAP', 'Q', 'SUB', 'SUP', 'SPAN', 'BDO', 'IFRAME', 'INPUT', 'SELECT', 'TEXTAREA', 'LABEL', 'BUTTON']
+
+HTML_FORBIDDEN_END = ['AREA', 'BASE', 'BASEFONT', 'BR', 'COL', 'FRAME', 'HR', 'IMG', 'INPUT', 'ISINDEX', 'LINK', 'META', 'PARAM']
+
+HTML_OPT_END = ['BODY', 'COLGROUP', 'DD', 'DT', 'HEAD', 'HTML', 'LI', 'OPTION', 'P', 'TBODY', 'TD', 'TFOOT', 'TH', 'THEAD', 'TR']
+
+#FIXME: map attrs to the tags that use them
+HTML_BOOLEAN_ATTRS = ['CHECKED', 'COMPACT', 'DECLARE', 'DEFER', 'DISABLED', 'ISMAP', 'MULTIPLE', 'NOHREF', 'NORESIZE', 'NOSHADE', 'NOWRAP', 'READONLY', 'SELECTED']
+
+HTML_CHARACTER_ENTITIES = {
+ # Sect 24.2 -- ISO 8859-1
+ 160: 'nbsp',
+ 161: 'iexcl',
+ 162: 'cent',
+ 163: 'pound',
+ 164: 'curren',
+ 165: 'yen',
+ 166: 'brvbar',
+ 167: 'sect',
+ 168: 'uml',
+ 169: 'copy',
+ 170: 'ordf',
+ 171: 'laquo',
+ 172: 'not',
+ 173: 'shy',
+ 174: 'reg',
+ 175: 'macr',
+ 176: 'deg',
+ 177: 'plusmn',
+ 178: 'sup2',
+ 179: 'sup3',
+ 180: 'acute',
+ 181: 'micro',
+ 182: 'para',
+ 183: 'middot',
+ 184: 'cedil',
+ 185: 'sup1',
+ 186: 'ordm',
+ 187: 'raquo',
+ 188: 'frac14',
+ 189: 'frac12',
+ 190: 'frac34',
+ 191: 'iquest',
+ 192: 'Agrave',
+ 193: 'Aacute',
+ 194: 'Acirc',
+ 195: 'Atilde',
+ 196: 'Auml',
+ 197: 'Aring',
+ 198: 'AElig',
+ 199: 'Ccedil',
+ 200: 'Egrave',
+ 201: 'Eacute',
+ 202: 'Ecirc',
+ 203: 'Euml',
+ 204: 'Igrave',
+ 205: 'Iacute',
+ 206: 'Icirc',
+ 207: 'Iuml',
+ 208: 'ETH',
+ 209: 'Ntilde',
+ 210: 'Ograve',
+ 211: 'Oacute',
+ 212: 'Ocirc',
+ 213: 'Otilde',
+ 214: 'Ouml',
+ 215: 'times',
+ 216: 'Oslash',
+ 217: 'Ugrave',
+ 218: 'Uacute',
+ 219: 'Ucirc',
+ 220: 'Uuml',
+ 221: 'Yacute',
+ 222: 'THORN',
+ 223: 'szlig',
+ 224: 'agrave',
+ 225: 'aacute',
+ 226: 'acirc',
+ 227: 'atilde',
+ 228: 'auml',
+ 229: 'aring',
+ 230: 'aelig',
+ 231: 'ccedil',
+ 232: 'egrave',
+ 233: 'eacute',
+ 234: 'ecirc',
+ 235: 'euml',
+ 236: 'igrave',
+ 237: 'iacute',
+ 238: 'icirc',
+ 239: 'iuml',
+ 240: 'eth',
+ 241: 'ntilde',
+ 242: 'ograve',
+ 243: 'oacute',
+ 244: 'ocirc',
+ 245: 'otilde',
+ 246: 'ouml',
+ 247: 'divide',
+ 248: 'oslash',
+ 249: 'ugrave',
+ 250: 'uacute',
+ 251: 'ucirc',
+ 252: 'uuml',
+ 253: 'yacute',
+ 254: 'thorn',
+ 255: 'yuml',
+
+ # Sect 24.3 -- Symbols, Mathematical Symbols, and Greek Letters
+ # Latin Extended-B
+ 402: 'fnof',
+ # Greek
+ 913: 'Alpha',
+ 914: 'Beta',
+ 915: 'Gamma',
+ 916: 'Delta',
+ 917: 'Epsilon',
+ 918: 'Zeta',
+ 919: 'Eta',
+ 920: 'Theta',
+ 921: 'Iota',
+ 922: 'Kappa',
+ 923: 'Lambda',
+ 924: 'Mu',
+ 925: 'Nu',
+ 926: 'Xi',
+ 927: 'Omicron',
+ 928: 'Pi',
+ 929: 'Rho',
+ 931: 'Sigma',
+ 932: 'Tau',
+ 933: 'Upsilon',
+ 934: 'Phi',
+ 935: 'Chi',
+ 936: 'Psi',
+ 937: 'Omega',
+ 945: 'alpha',
+ 946: 'beta',
+ 947: 'gamma',
+ 948: 'delta',
+ 949: 'epsilon',
+ 950: 'zeta',
+ 951: 'eta',
+ 952: 'theta',
+ 953: 'iota',
+ 954: 'kappa',
+ 955: 'lambda',
+ 956: 'mu',
+ 957: 'nu',
+ 958: 'xi',
+ 959: 'omicron',
+ 960: 'pi',
+ 961: 'rho',
+ 962: 'sigmaf',
+ 963: 'sigma',
+ 964: 'tau',
+ 965: 'upsilon',
+ 966: 'phi',
+ 967: 'chi',
+ 968: 'psi',
+ 969: 'omega',
+ 977: 'thetasym',
+ 978: 'upsih',
+ 982: 'piv',
+ # General Punctuation
+ 8226: 'bull', # bullet
+ 8230: 'hellip', # horizontal ellipsis
+ 8242: 'prime', # prime (minutes/feet)
+ 8243: 'Prime', # double prime (seconds/inches)
+ 8254: 'oline', # overline (spacing overscore)
+ 8250: 'frasl', # fractional slash
+ # Letterlike Symbols
+ 8472: 'weierp', # script capital P (power set/Weierstrass p)
+ 8465: 'image', # blackletter capital I (imaginary part)
+ 8476: 'real', # blackletter capital R (real part)
+ 8482: 'trade', # trademark
+ 8501: 'alefsym', # alef symbol (first transfinite cardinal)
+ # Arrows
+ 8592: 'larr', # leftwards arrow
+ 8593: 'uarr', # upwards arrow
+ 8594: 'rarr', # rightwards arrow
+ 8595: 'darr', # downwards arrow
+ 8596: 'harr', # left right arrow
+ 8629: 'crarr', # downwards arrow with corner leftwards (carriage return)
+ 8656: 'lArr', # leftwards double arrow
+ 8657: 'uArr', # upwards double arrow
+ 8658: 'rArr', # rightwards double arrow
+ 8659: 'dArr', # downwards double arrow
+ 8660: 'hArr', # left right double arrow
+ # Mathematical Operators
+ 8704: 'forall', # for all
+ 8706: 'part', # partial differential
+ 8707: 'exist', # there exists
+ 8709: 'empty', # empty set, null set, diameter
+ 8711: 'nabla', # nabla, backward difference
+ 8712: 'isin', # element of
+ 8713: 'notin', # not an element of
+ 8715: 'ni', # contains as member
+ 8719: 'prod', # n-ary product, product sign
+ 8721: 'sum', # n-ary sumation
+ 8722: 'minus', # minus sign
+ 8727: 'lowast', # asterisk operator
+ 8730: 'radic', # square root, radical sign
+ 8733: 'prop', # proportional to
+ 8734: 'infin', # infinity
+ 8736: 'ang', # angle
+ 8743: 'and', # logical and, wedge
+ 8744: 'or', # logical or, vee
+ 8745: 'cap', # intersection, cap
+ 8746: 'cup', # union, cup
+ 8747: 'int', # integral
+ 8756: 'there4', # therefore
+ 8764: 'sim', # tilde operator, varies with, similar to
+ 8773: 'cong', # approximately equal to
+ 8776: 'asymp', # almost equal to, asymptotic to
+ 8800: 'ne', # not equal to
+ 8801: 'equiv', # identical to
+ 8804: 'le', # less-than or equal to
+ 8805: 'ge', # greater-than or equal to
+ 8834: 'sub', # subset of
+ 8835: 'sup', # superset of
+ 8836: 'nsub', # not subset of
+ 8838: 'sube', # subset of or equal to
+ 8839: 'supe', # superset of or equal to
+ 8853: 'oplus', # circled plus, direct sum
+ 8855: 'otimes', # circled times, vector product
+ 8869: 'perp', # up tack, orthogonal to, perpendicular
+ 8901: 'sdot', # dot operator
+ 8968: 'lceil', # left ceiling, apl upstile
+ 8969: 'rceil', # right ceiling
+ 8970: 'lfloor', # left floor, apl downstile
+ 8971: 'rfloor', # right floor
+ 9001: 'lang', # left-pointing angle bracket, bra
+ 9002: 'rang', # right-pointing angle bracket, ket
+ 9674: 'loz', # lozenge
+ # Miscellaneous Symbols
+ 9824: 'spades',
+ 9827: 'clubs',
+ 9829: 'hearts',
+ 9830: 'diams',
+
+ # Sect 24.4 -- Markup Significant and Internationalization
+ # Latin Extended-A
+ 338: 'OElig', # capital ligature OE
+ 339: 'oelig', # small ligature oe
+ 352: 'Scaron', # capital S with caron
+ 353: 'scaron', # small s with caron
+ 376: 'Yuml', # capital Y with diaeresis
+ # Spacing Modifier Letters
+ 710: 'circ', # circumflexx accent
+ 732: 'tidle', # small tilde
+ # General Punctuation
+ 8194: 'ensp', # en space
+ 8195: 'emsp', # em space
+ 8201: 'thinsp', # thin space
+ 8204: 'zwnj', # zero-width non-joiner
+ 8205: 'zwj', # zero-width joiner
+ 8206: 'lrm', # left-to-right mark
+ 8207: 'rlm', # right-to-left mark
+ 8211: 'ndash', # en dash
+ 8212: 'mdash', # em dash
+ 8216: 'lsquo', # left single quotation mark
+ 8217: 'rsquo', # right single quotation mark
+ 8218: 'sbquo', # single low-9 quotation mark
+ 8220: 'ldquo', # left double quotation mark
+ 8221: 'rdquo', # right double quotation mark
+ 8222: 'bdquo', # double low-9 quotation mark
+ 8224: 'dagger', # dagger
+ 8225: 'Dagger', # double dagger
+ 8240: 'permil', # per mille sign
+ 8249: 'lsaquo', # single left-pointing angle quotation mark
+ 8250: 'rsaquo', # single right-pointing angle quotation mark
+ 8364: 'euro', # euro sign
+ }
+
+HTML_NAME_ALLOWED = ['A',
+ 'APPLET',
+ 'BUTTON',
+ 'FORM',
+ 'FRAME',
+ 'IFRAME',
+ 'IMG',
+ 'INPUT',
+ 'MAP',
+ 'META',
+ 'OBJECT',
+ 'PARAM',
+ 'SELECT',
+ 'TEXTAREA']
+
+# xhtml DTD
+
+HTML_DTD = {
+ 'col': [],
+ 'u': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'p': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'caption': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'q': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'i': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'textarea': [],
+ 'center': ['#PCDATA', 'a', 'abbr', 'acronym', 'address', 'applet', 'b', 'basefont', 'bdo', 'big', 'blockquote', 'br', 'button', 'center', 'cite', 'code', 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'fieldset', 'font', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'iframe', 'img', 'input', 'ins', 'isindex', 'kbd', 'label', 'map', 'menu', 'noframes', 'noscript', 'object', 'ol', 'p', 'pre', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'textarea', 'tt', 'u', 'ul', 'var'],
+ 'script': [],
+ 'ol': ['li'],
+ 'a': ['#PCDATA', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'legend': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'strong': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'address': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'br': [],
+ 'base': [],
+ 'object': ['#PCDATA', 'a', 'abbr', 'acronym', 'address', 'applet', 'b', 'basefont', 'bdo', 'big', 'blockquote', 'br', 'button', 'center', 'cite', 'code', 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'fieldset', 'font', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'iframe', 'img', 'input', 'ins', 'isindex', 'kbd', 'label', 'map', 'menu', 'noframes', 'noscript', 'object', 'ol', 'p', 'param', 'pre', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'textarea', 'tt', 'u', 'ul', 'var'],
+ 'basefont': [],
+ 'map': ['address', 'area', 'blockquote', 'center', 'del', 'dir', 'div', 'dl', 'fieldset', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'ins', 'isindex', 'menu', 'noframes', 'noscript', 'ol', 'p', 'pre', 'script', 'table', 'ul'],
+ 'body': ['#PCDATA', 'a', 'abbr', 'acronym', 'address', 'applet', 'b', 'basefont', 'bdo', 'big', 'blockquote', 'br', 'button', 'center', 'cite', 'code', 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'fieldset', 'font', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'iframe', 'img', 'input', 'ins', 'isindex', 'kbd', 'label', 'map', 'menu', 'noframes', 'noscript', 'object', 'ol', 'p', 'pre', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'textarea', 'tt', 'u', 'ul', 'var'],
+ 'samp': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'dl': ['dd', 'dt'],
+ 'acronym': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'html': ['body', 'frameset', 'head'],
+ 'em': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'label': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'tbody': ['tr'],
+ 'bdo': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'sub': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'meta': [],
+ 'ins': ['#PCDATA', 'a', 'abbr', 'acronym', 'address', 'applet', 'b', 'basefont', 'bdo', 'big', 'blockquote', 'br', 'button', 'center', 'cite', 'code', 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'fieldset', 'font', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'iframe', 'img', 'input', 'ins', 'isindex', 'kbd', 'label', 'map', 'menu', 'noframes', 'noscript', 'object', 'ol', 'p', 'pre', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'textarea', 'tt', 'u', 'ul', 'var'],
+ 'frame': [],
+ 's': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'title': ['#PCDATA'],
+ 'frameset': ['frame', 'frameset', 'noframes'],
+ 'pre': ['#PCDATA', 'a', 'abbr', 'acronym', 'b', 'bdo', 'br', 'button', 'cite', 'code', 'dfn', 'em', 'i', 'input', 'kbd', 'label', 'map', 'q', 's', 'samp', 'select', 'span', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'dir': ['li'],
+ 'div': ['#PCDATA', 'a', 'abbr', 'acronym', 'address', 'applet', 'b', 'basefont', 'bdo', 'big', 'blockquote', 'br', 'button', 'center', 'cite', 'code', 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'fieldset', 'font', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'iframe', 'img', 'input', 'ins', 'isindex', 'kbd', 'label', 'map', 'menu', 'noframes', 'noscript', 'object', 'ol', 'p', 'pre', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'textarea', 'tt', 'u', 'ul', 'var'],
+ 'small': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'iframe': ['#PCDATA', 'a', 'abbr', 'acronym', 'address', 'applet', 'b', 'basefont', 'bdo', 'big', 'blockquote', 'br', 'button', 'center', 'cite', 'code', 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'fieldset', 'font', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'iframe', 'img', 'input', 'ins', 'isindex', 'kbd', 'label', 'map', 'menu', 'noframes', 'noscript', 'object', 'ol', 'p', 'pre', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'textarea', 'tt', 'u', 'ul', 'var'],
+ 'del': ['#PCDATA', 'a', 'abbr', 'acronym', 'address', 'applet', 'b', 'basefont', 'bdo', 'big', 'blockquote', 'br', 'button', 'center', 'cite', 'code', 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'fieldset', 'font', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'iframe', 'img', 'input', 'ins', 'isindex', 'kbd', 'label', 'map', 'menu', 'noframes', 'noscript', 'object', 'ol', 'p', 'pre', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'textarea', 'tt', 'u', 'ul', 'var'],
+ 'applet': ['#PCDATA', 'a', 'abbr', 'acronym', 'address', 'applet', 'b', 'basefont', 'bdo', 'big', 'blockquote', 'br', 'button', 'center', 'cite', 'code', 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'fieldset', 'font', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'iframe', 'img', 'input', 'ins', 'isindex', 'kbd', 'label', 'map', 'menu', 'noframes', 'noscript', 'object', 'ol', 'p', 'param', 'pre', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'textarea', 'tt', 'u', 'ul', 'var'],
+ 'ul': ['li'],
+ 'isindex': [],
+ 'button': ['#PCDATA', 'abbr', 'acronym', 'address', 'applet', 'b', 'basefont', 'bdo', 'big', 'blockquote', 'br', 'center', 'cite', 'code', 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'font', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'img', 'ins', 'kbd', 'map', 'menu', 'noframes', 'noscript', 'object', 'ol', 'p', 'pre', 'q', 's', 'samp', 'script', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'tt', 'u', 'ul', 'var'],
+ 'colgroup': ['col'],
+ 'b': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'table': ['caption', 'col', 'colgroup', 'tbody', 'tfoot', 'thead', 'tr'],
+ 'dt': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'optgroup': ['option'],
+ 'abbr': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'link': [],
+ 'h4': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'dd': ['#PCDATA', 'a', 'abbr', 'acronym', 'address', 'applet', 'b', 'basefont', 'bdo', 'big', 'blockquote', 'br', 'button', 'center', 'cite', 'code', 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'fieldset', 'font', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'iframe', 'img', 'input', 'ins', 'isindex', 'kbd', 'label', 'map', 'menu', 'noframes', 'noscript', 'object', 'ol', 'p', 'pre', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'textarea', 'tt', 'u', 'ul', 'var'],
+ 'big': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'hr': [],
+ 'form': ['#PCDATA', 'a', 'abbr', 'acronym', 'address', 'applet', 'b', 'basefont', 'bdo', 'big', 'blockquote', 'br', 'button', 'center', 'cite', 'code', 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'fieldset', 'font', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'iframe', 'img', 'input', 'ins', 'isindex', 'kbd', 'label', 'map', 'menu', 'noframes', 'noscript', 'object', 'ol', 'p', 'pre', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'textarea', 'tt', 'u', 'ul', 'var'],
+ 'option': [],
+ 'fieldset': ['#PCDATA', 'a', 'abbr', 'acronym', 'address', 'applet', 'b', 'basefont', 'bdo', 'big', 'blockquote', 'br', 'button', 'center', 'cite', 'code', 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'fieldset', 'font', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'iframe', 'img', 'input', 'ins', 'isindex', 'kbd', 'label', 'legend', 'map', 'menu', 'noframes', 'noscript', 'object', 'ol', 'p', 'pre', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'textarea', 'tt', 'u', 'ul', 'var'],
+ 'blockquote': ['#PCDATA', 'a', 'abbr', 'acronym', 'address', 'applet', 'b', 'basefont', 'bdo', 'big', 'blockquote', 'br', 'button', 'center', 'cite', 'code', 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'fieldset', 'font', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'iframe', 'img', 'input', 'ins', 'isindex', 'kbd', 'label', 'map', 'menu', 'noframes', 'noscript', 'object', 'ol', 'p', 'pre', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'textarea', 'tt', 'u', 'ul', 'var'],
+ 'head': ['base', 'isindex', 'link', 'meta', 'object', 'script', 'style', 'title'],
+ 'thead': ['tr'],
+ 'cite': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'td': ['#PCDATA', 'a', 'abbr', 'acronym', 'address', 'applet', 'b', 'basefont', 'bdo', 'big', 'blockquote', 'br', 'button', 'center', 'cite', 'code', 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'fieldset', 'font', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'iframe', 'img', 'input', 'ins', 'isindex', 'kbd', 'label', 'map', 'menu', 'noframes', 'noscript', 'object', 'ol', 'p', 'pre', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'textarea', 'tt', 'u', 'ul', 'var'],
+ 'input': [],
+ 'var': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'th': ['#PCDATA', 'a', 'abbr', 'acronym', 'address', 'applet', 'b', 'basefont', 'bdo', 'big', 'blockquote', 'br', 'button', 'center', 'cite', 'code', 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'fieldset', 'font', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'iframe', 'img', 'input', 'ins', 'isindex', 'kbd', 'label', 'map', 'menu', 'noframes', 'noscript', 'object', 'ol', 'p', 'pre', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'textarea', 'tt', 'u', 'ul', 'var'],
+ 'tfoot': ['tr'],
+ 'dfn': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'li': ['#PCDATA', 'a', 'abbr', 'acronym', 'address', 'applet', 'b', 'basefont', 'bdo', 'big', 'blockquote', 'br', 'button', 'center', 'cite', 'code', 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'fieldset', 'font', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'iframe', 'img', 'input', 'ins', 'isindex', 'kbd', 'label', 'map', 'menu', 'noframes', 'noscript', 'object', 'ol', 'p', 'pre', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'textarea', 'tt', 'u', 'ul', 'var'],
+ 'param': [],
+ 'tr': ['td', 'th'],
+ 'tt': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'menu': ['li'],
+ 'area': [],
+ 'img': [],
+ 'span': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'style': [],
+ 'noscript': ['#PCDATA', 'a', 'abbr', 'acronym', 'address', 'applet', 'b', 'basefont', 'bdo', 'big', 'blockquote', 'br', 'button', 'center', 'cite', 'code', 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'fieldset', 'font', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'iframe', 'img', 'input', 'ins', 'isindex', 'kbd', 'label', 'map', 'menu', 'noframes', 'noscript', 'object', 'ol', 'p', 'pre', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'textarea', 'tt', 'u', 'ul', 'var'],
+ 'noframes': ['#PCDATA', 'a', 'abbr', 'acronym', 'address', 'applet', 'b', 'basefont', 'bdo', 'big', 'blockquote', 'br', 'button', 'center', 'cite', 'code', 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'fieldset', 'font', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'iframe', 'img', 'input', 'ins', 'isindex', 'kbd', 'label', 'map', 'menu', 'noframes', 'noscript', 'object', 'ol', 'p', 'pre', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'textarea', 'tt', 'u', 'ul', 'var'],
+ 'select': ['optgroup', 'option'],
+ 'font': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'strike': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'sup': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'h5': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'kbd': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'h6': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'h1': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'h3': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'h2': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var'],
+ 'code': ['#PCDATA', 'a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var']
+ }
+
+from xml.dom.html import HTMLDOMImplementation
+
+htmlImplementation = HTMLDOMImplementation.HTMLDOMImplementation()
+
+
+#FIXME: all of this can be made much more efficient. Maybe when we leave Python 1.x behind
+try:
+ #The following stanza courtesy Martin von Loewis
+ import codecs # Python 1.6+ only
+ from types import UnicodeType
+ def utf8_to_code(text, encoding):
+ encoder = codecs.lookup(encoding)[0] # encode,decode,reader,writer
+ if type(text) is not UnicodeType:
+ text = unicode(text, "utf-8")
+ return encoder(text)[0] # result,size
+
+ def ConvertChar(m):
+ return '&'+HTML_CHARACTER_ENTITIES[ord(m.group())]+';'
+
+ def UseHtmlCharEntities(text):
+ if type(text) is not UnicodeType:
+ text = unicode(text, "utf-8")
+ new_text, num_subst = re.subn(g_htmlUniCharEntityPattern, ConvertChar,
+ text)
+ return new_text
+
+except ImportError:
+ from xml.unicode.iso8859 import wstring
+ wstring.install_alias('ISO-8859-1', 'ISO_8859-1:1987')
+
+ def utf8_to_code(text, encoding):
+ encoding = string.upper(encoding)
+ if encoding == 'UTF-8':
+ return text
+ #Note: Pass through to wstrop. This means we don't play nice and
+ #Escape characters that are not in the target encoding.
+ ws = wstring.from_utf8(text)
+ text = ws.encode(encoding)
+ #This version would skip all untranslatable chars: see wstrop.c
+ #text = ws.encode(encoding, 1)
+ return text
+
+ def ConvertChar(m):
+ char = ((int(ord(m.group(1))) & 0x03) << 6) | (int(ord(m.group(2))) & 0x3F)
+ if HTML_CHARACTER_ENTITIES.has_key(char):
+ return '&'+HTML_CHARACTER_ENTITIES[char]+';'
+ else:
+ return m.group()
+
+ def UseHtmlCharEntities(text):
+ new_text, num_subst = re.subn(g_utf8TwoBytePattern, ConvertChar, text)
+ return new_text
+
+
+import re, string
+g_xmlIllegalCharPattern = re.compile('[\x01-\x08\x0B-\x0D\x0E-\x1F\x80-\xFF]')
+g_numCharEntityPattern = re.compile('&#(\d+);')
+g_utf8TwoBytePattern = re.compile('([\xC0-\xC3])([\x80-\xBF])')
+g_htmlUniCharEntityPattern = re.compile('[\xa0-\xff]')
+g_cdataCharPattern = re.compile('[&<]|]]>')
+g_charToEntity = {
+ '&': '&',
+ '<': '<',
+ ']]>': ']]>',
+ }
+
+
+def TranslateHtmlCdata(characters, encoding='UTF-8', prev_chars=''):
+ #Translate numerical char entity references with HTML entity equivalents
+ new_string, num_subst = re.subn(
+ g_cdataCharPattern,
+ lambda m, d=g_charToEntity: d[m.group()],
+ characters
+ )
+ if prev_chars[-2:] == ']]' and new_string[0] == '>':
+ new_string = '>' + new_string[1:]
+ new_string = UseHtmlCharEntities(new_string)
+ new_string = utf8_to_code(new_string, encoding)
+ #new_string, num_subst = re.subn(g_xmlIllegalCharPattern, lambda m: '&#%i;'%ord(m.group()), new_string)
+ #Note: use decimal char entity rep because some browsers are broken
+ return new_string
+
+
+SECURE_HTML_ELEMS = ["A", "P", "BR", "B", "I", "DIV", "STRONG", "EM", "BLOCKQUOTE", "UL", "OL", "LI", "DL", "DD", "DT", "TT"]
diff --git a/lib/jython/Lib/xml/dom/javadom.py b/lib/jython/Lib/xml/dom/javadom.py new file mode 100644 index 000000000..1dc064f52 --- /dev/null +++ b/lib/jython/Lib/xml/dom/javadom.py @@ -0,0 +1,696 @@ +"""An adapter for Java DOM implementations that makes it possible to
+access them through the same interface as the Python DOM implementations.
+
+Supports:
+- Sun's Java Project X
+- Xerces
+- David Brownell's SAX 2.0 Utilities / DOM2
+- Indelv DOM
+- SXP
+- OpenXML
+
+$Id: javadom.py,v 1.7 2001/02/19 15:21:50 fdrake Exp $
+"""
+
+# Todo:
+# - extend test suite
+# - start using _set_up_attributes, or give up as too slow?
+# - support level 2
+
+import string
+
+# --- Supported Java DOM implementations
+
+class BaseDomImplementation:
+ """An abstract DomImplementation with some reusable implementations
+ of build* methods that depend on a lower-level _parse_from_source
+ method."""
+
+ def buildDocumentString(self, string):
+ from java.io import StringReader
+ from org.xml.sax import InputSource
+ return self._parse_from_source(InputSource(StringReader(string)))
+
+ def buildDocumentUrl(self, url):
+ return self._parse_from_source(url)
+
+ def buildDocumentFile(self, filename):
+ return self.buildDocumentUrl(filetourl(filename))
+
+class SunDomImplementation:
+
+ def createDocument(self):
+ from com.sun.xml.tree import XmlDocument
+ return Document(XmlDocument())
+
+ def buildDocumentString(self, string):
+ from com.sun.xml.tree import XmlDocumentBuilder
+ return Document(XmlDocumentBuilder.createXmlDocument(string))
+
+ def buildDocumentUrl(self, url):
+ from com.sun.xml.tree import XmlDocument
+ return Document(XmlDocument.createXmlDocument(url))
+
+ def buildDocumentFile(self, filename):
+ return self.buildDocumentUrl(filetourl(filename))
+
+class XercesDomImplementation(BaseDomImplementation):
+
+ def createDocument(self):
+ from org.apache.xerces.dom import DocumentImpl
+ return Document(DocumentImpl())
+
+ def _parse_from_source(self, source):
+ from org.apache.xerces.parsers import DOMParser
+ p = DOMParser()
+ p.parse(source)
+ return Document(p.getDocument())
+
+class BrownellDomImplementation(BaseDomImplementation):
+
+ def createDocument(self):
+ from org.brownell.xml.dom import DomDocument
+ return Document(DomDocument())
+
+ def _parse_from_source(self, source):
+ from org.brownell.xml import DomBuilder
+ return Document(DomBuilder.createDocument(source))
+
+class IndelvDomImplementation(BaseDomImplementation):
+
+ def createDocument(self):
+ from com.indelv.dom import DOMImpl
+ return Document(DOMImpl.createNewDocument())
+
+ def _parse_from_source(self, source):
+ from com.indelv.dom.util import XMLReader
+ from org.xml.sax import InputSource
+ return Document(XMLReader.parseDocument(InputSource(source)))
+
+class SxpDomImplementation(BaseDomImplementation):
+
+ def createDocument(self):
+ from fr.loria.xml import DOMFactory
+ return Document(DOMFactory().createDocument())
+
+ def _parse_from_source(self, source):
+ from fr.loria.xml import DocumentLoader
+ loader = DocumentLoader()
+
+ if type(source) == type(""):
+ doc = loader.loadDocument(source)
+ elif source.getCharacterStream() != None:
+ doc = loader.loadDocument(source.getCharacterStream())
+ elif source.getByteStream() != None:
+ doc = loader.loadDocument(source.getByteStream())
+ elif source.getSystemId() != None:
+ doc = loader.loadDocument(source.getSystemId())
+
+ return Document(doc)
+
+class OpenXmlDomImplementation(BaseDomImplementation):
+
+ def createDocument(self):
+ from org.openxml.dom import DocumentImpl
+ return Document(DocumentImpl())
+
+ def _parse_from_source(self, source):
+ from org.openxml.dom import SAXBuilder
+ from org.openxml.parser import XMLSAXParser
+
+ builder = SAXBuilder()
+ parser = XMLSAXParser()
+ parser.setDocumentHandler(builder)
+ parser.parse(source)
+ return Document(builder.getDocument())
+
+# ===== Utilities
+
+def filetourl(file):
+ # A Python port of James Clark's fileToURL from XMLTest.java.
+ from java.io import File
+ from java.net import URL
+ from java.lang import System
+
+ file = File(file).getAbsolutePath()
+ sep = System.getProperty("file.separator")
+
+ if sep != None and len(sep) == 1:
+ file = file.replace(sep[0], '/')
+
+ if len(file) > 0 and file[0] != '/':
+ file = '/' + file
+
+ return URL('file', None, file).toString()
+
+def _wrap_node(node):
+ if node == None:
+ return None
+
+ return NODE_CLASS_MAP[node.getNodeType()] (node)
+
+# ===== Constants
+
+ELEMENT_NODE = 1
+ATTRIBUTE_NODE = 2
+TEXT_NODE = 3
+CDATA_SECTION_NODE = 4
+ENTITY_REFERENCE_NODE = 5
+ENTITY_NODE = 6
+PROCESSING_INSTRUCTION_NODE = 7
+COMMENT_NODE = 8
+DOCUMENT_NODE = 9
+DOCUMENT_TYPE_NODE = 10
+DOCUMENT_FRAGMENT_NODE = 11
+NOTATION_NODE = 12
+
+# ===== DOMException
+
+try:
+ from org.w3c.dom import DOMException
+except ImportError, e:
+ pass
+
+# ===== DOMImplementation
+
+class DOMImplementation:
+
+ def __init__(self, impl):
+ self._impl = impl
+
+ def hasFeature(self, feature, version):
+ if version == None or version == "1.0":
+ return string.lower(feature) == "xml" and \
+ self._impl.hasFeature(feature, version)
+ else:
+ return 0
+
+ def __repr__(self):
+ return "<DOMImplementation javadom.py, using '%s'>" % self._impl
+
+# ===== Node
+
+class Node:
+
+ def __init__(self, impl):
+ self.__dict__['_impl'] = impl
+
+ # attributes
+
+ def _get_nodeName(self):
+ return self._impl.getNodeName()
+
+ def _get_nodeValue(self):
+ return self._impl.getNodeValue()
+
+ def _get_nodeType(self):
+ return self._impl.getNodeType()
+
+ def _get_parentNode(self):
+ return _wrap_node(self._impl.getParentNode())
+
+ def _get_childNodes(self):
+ children = self._impl.getChildNodes()
+ if children is None:
+ return children
+ else:
+ return NodeList(children)
+
+ def _get_firstChild(self):
+ return _wrap_node(self._impl.getFirstChild())
+
+ def _get_lastChild(self):
+ return _wrap_node(self._impl.getLastChild())
+
+ def _get_previousSibling(self):
+ return _wrap_node(self._impl.getPreviousSibling())
+
+ def _get_nextSibling(self):
+ return _wrap_node(self._impl.getNextSibling())
+
+ def _get_ownerDocument(self):
+ return _wrap_node(self._impl.getOwnerDocument())
+
+ def _get_attributes(self):
+ atts = self._impl.getAttributes()
+ if atts is None:
+ return None
+ else:
+ return NamedNodeMap(atts)
+
+ # methods
+
+ def insertBefore(self, new, neighbour):
+ self._impl.insertBefore(new._impl, neighbour._impl)
+
+ def replaceChild(self, new, old):
+ self._impl.replaceChild(new._impl, old._impl)
+ return old
+
+ def removeChild(self, old):
+ self._impl.removeChild(old._impl)
+ return old
+
+ def appendChild(self, new):
+ return self._impl.appendChild(new._impl)
+
+ def hasChildNodes(self):
+ return self._impl.hasChildNodes()
+
+ def cloneNode(self):
+ return _wrap_node(self._impl.cloneNode())
+
+ # python
+
+ def __getattr__(self, name):
+ if name[ : 5] != '_get_':
+ return getattr(self, '_get_' + name) ()
+
+ raise AttributeError, name
+
+ def __setattr__(self, name, value):
+ getattr(self, '_set_' + name) (value)
+
+# ===== Document
+
+class Document(Node):
+
+ def __init__(self, impl):
+ Node.__init__(self, impl)
+
+ # methods
+
+ def createTextNode(self, data):
+ return Text(self._impl.createTextNode(data))
+
+ def createEntityReference(self, name):
+ return EntityReference(self._impl.createEntityReference(name))
+
+ def createElement(self, name):
+ return Element(self._impl.createElement(name))
+
+ def createDocumentFragment(self):
+ return DocumentFragment(self._impl.createDocumentFragment())
+
+ def createComment(self, data):
+ return Comment(self._impl.createComment(data))
+
+ def createCDATASection(self, data):
+ return CDATASection(self._impl.createCDATASection(data))
+
+ def createProcessingInstruction(self, target, data):
+ return ProcessingInstruction(self._impl.createProcessingInstruction(target, data))
+
+ def createAttribute(self, name):
+ return Attr(self._impl.createAttribute(name))
+
+ def getElementsByTagName(self, name):
+ return NodeList(self._impl.getElementsByTagName(name))
+
+ # attributes
+
+ def _get_doctype(self):
+ return self._impl.getDoctype()
+
+ def _get_implementation(self):
+ return DOMImplementation(self._impl.getImplementation())
+
+ def _get_documentElement(self):
+ return _wrap_node(self._impl.getDocumentElement())
+
+ # python
+
+ def __repr__(self):
+ docelm = self._impl.getDocumentElement()
+ if docelm:
+ return "<Document with root '%s'>" % docelm.getTagName()
+ else:
+ return "<Document with no root>"
+
+# ===== Element
+
+class Element(Node):
+
+ def __init__(self, impl):
+ Node.__init__(self, impl)
+
+ self.__dict__['_get_tagName'] = self._impl.getTagName
+ self.__dict__['getAttribute'] = self._impl.getAttribute
+ self.__dict__['setAttribute'] = self._impl.setAttribute
+ self.__dict__['removeAttribute'] = self._impl.removeAttribute
+ self.__dict__['normalize'] = self._impl.normalize
+
+ # methods
+
+ def getAttributeNode(self, name):
+ node = self._impl.getAttributeNode(name)
+ if node == None:
+ return node
+ else:
+ return Attr(node)
+
+ def setAttributeNode(self, attr):
+ self._impl.setAttributeNode(attr._impl)
+
+ def removeAttributeNode(self, attr):
+ self._impl.removeAttributeNode(attr._impl)
+
+ def getElementsByTagName(self, name):
+ return NodeList(self._impl.getElementsByTagName(name))
+
+ # python
+
+ def __repr__(self):
+ return "<Element '%s' with %d attributes and %d children>" % \
+ (self._impl.getTagName(),
+ self._impl.getAttributes().getLength(),
+ self._impl.getChildNodes().getLength())
+
+# ===== CharacterData
+
+class CharacterData(Node):
+
+ def __init__(self, impl):
+ Node.__init__(self, impl)
+
+ self.__dict__['_get_data'] = self._impl.getData
+ self.__dict__['_set_data'] = self._impl.setData
+ self.__dict__['_get_length'] = self._impl.getLength
+
+ self.__dict__['substringData'] = self._impl.substringData
+ self.__dict__['appendData'] = self._impl.appendData
+ self.__dict__['insertData'] = self._impl.insertData
+ self.__dict__['deleteData'] = self._impl.deleteData
+ self.__dict__['replaceData'] = self._impl.replaceData
+
+# ===== Comment
+
+class Comment(CharacterData):
+
+ def __repr__(self):
+ return "<Comment of length %d>" % self.getLength()
+
+# ===== ProcessingInstruction
+
+class ProcessingInstruction(Node):
+
+ def __init__(self, impl):
+ Node.__init__(self, impl)
+
+ self.__dict__['_get_target'] = self._impl.getTarget
+ self.__dict__['_get_data'] = self._impl.getData
+ self.__dict__['_set_data'] = self._impl.setData
+
+ def __repr__(self):
+ return "<PI with target '%s'>" % self._impl.getTarget()
+
+# ===== Text
+
+class Text(CharacterData):
+
+ def splitText(self, offset):
+ return Text(self._impl.splitText(offset))
+
+ def __repr__(self):
+ return "<Text of length %d>" % self._impl.getLength()
+
+# ===== CDATASection
+
+class CDATASection(Text):
+
+ def __repr__(self):
+ return "<CDATA section of length %d>" % self._impl.getLength()
+
+# ===== Attr
+
+class Attr(Node):
+
+ def __init__(self, impl):
+ Node.__init__(self, impl)
+
+ self.__dict__['_get_name'] = self._impl.getName
+ self.__dict__['_get_specified'] = self._impl.getSpecified
+ self.__dict__['_get_value'] = self._impl.getValue
+ self.__dict__['_set_value'] = self._impl.setValue
+
+ def __repr__(self):
+ return "<Attr '%s'>" % self._impl.getName()
+
+# ===== EntityReference
+
+class EntityReference(Node):
+
+ def __repr__(self):
+ return "<EntityReference '%s'>" % self.getNodeName()
+
+# ===== DocumentType
+
+class DocumentType(Node):
+
+ def __init__(self, impl):
+ Node.__init__(self, impl)
+
+ self.__dict__['_get_name'] = self._impl.getName
+
+ def _get_entities(self):
+ return NamedNodeMap(self._impl.getEntities())
+
+ def _get_notations(self):
+ return NamedNodeMap(self._impl.getNotations())
+
+ def __repr__(self):
+ return "<DocumentType '%s'>" % self._impl.getNodeName()
+
+# ===== Notation
+
+class Notation(Node):
+
+ def __init__(self, impl):
+ Node.__init__(self, impl)
+
+ self.__dict__['_get_publicId'] = self._impl.getPublicId
+ self.__dict__['_get_systemId'] = self._impl.getSystemId
+
+ def __repr__(self):
+ return "<Notation '%s'>" % self._impl.getNodeName()
+
+# ===== Entity
+
+class Entity(Node):
+
+ def __init__(self, impl):
+ Node.__init__(self, impl)
+
+ self.__dict__['_get_publicId'] = self._impl.getPublicId
+ self.__dict__['_get_systemId'] = self._impl.getSystemId
+ self.__dict__['_get_notationName'] = self._impl.getNotationName
+
+ def __repr__(self):
+ return "<Entity '%s'>" % self._impl.getNodeName()
+
+# ===== DocumentFragment
+
+class DocumentFragment(Node):
+
+ def __repr__(self):
+ return "<DocumentFragment>"
+
+# ===== NodeList
+
+class NodeList:
+
+ def __init__(self, impl):
+ self._impl = impl
+
+ self.__dict__['__len__'] = self._impl.getLength
+ self.__dict__['_get_length'] = self._impl.getLength
+ self.__dict__['item'] = self._impl.item
+
+ # Python list methods
+
+ def __getitem__(self, ix):
+ if ix < 0:
+ ix = len(self) + ix
+
+ node = self._impl.item(ix)
+ if node == None:
+ raise IndexError, ix
+ else:
+ return _wrap_node(node)
+
+ def __setitem__(self, ix, item):
+ raise TypeError, "NodeList instances don't support item assignment"
+
+ def __delitem__(self, ix, item):
+ raise TypeError, "NodeList instances don't support item deletion"
+
+ def __setslice__(self, i, j, list):
+ raise TypeError, "NodeList instances don't support slice assignment"
+
+ def __delslice__(self, i, j):
+ raise TypeError, "NodeList instances don't support slice deletion"
+
+ def append(self, item):
+ raise TypeError, "NodeList instances don't support .append()"
+
+ def insert(self, i, item):
+ raise TypeError, "NodeList instances don't support .insert()"
+
+ def pop(self, i=-1):
+ raise TypeError, "NodeList instances don't support .pop()"
+
+ def remove(self, item):
+ raise TypeError, "NodeList instances don't support .remove()"
+
+ def reverse(self):
+ raise TypeError, "NodeList instances don't support .reverse()"
+
+ def sort(self, *args):
+ raise TypeError, "NodeList instances don't support .sort()"
+
+ def __add__(self, *args):
+ raise TypeError, "NodeList instances don't support +"
+
+ def __radd__(self, *args):
+ raise TypeError, "NodeList instances don't support +"
+
+ def __mul__(self, *args):
+ raise TypeError, "NodeList instances don't support *"
+
+ def __rmul__(self, *args):
+ raise TypeError, "NodeList instances don't support *"
+
+ def count(self, *args):
+ raise TypeError, "NodeList instances can't support count without equality"
+
+ def count(self, *args):
+ raise TypeError, "NodeList instances can't support index without equality"
+
+ def __getslice__(self, i, j):
+ if i < len(self):
+ i = len(self) + i
+ if j < len(self):
+ j = len(self) + j
+
+ slice = []
+ for ix in range(i, min(j, len(self))):
+ slice.append(self[ix])
+ return slice
+
+ def __repr__(self):
+ return "<NodeList [ %s ]>" % string.join(map(repr, self), ", ")
+
+# ===== NamedNodeMap
+
+class NamedNodeMap:
+
+ def __init__(self, impl):
+ self._impl = impl
+
+ self.__dict__['_get_length'] = self._impl.getLength
+ self.__dict__['__len__'] = self._impl.getLength
+
+ # methods
+
+ def getNamedItem(self, name):
+ return _wrap_node(self._impl.getNamedItem(name))
+
+ def setNamedItem(self, node):
+ return _wrap_node(self._impl.setNamedItem(node._impl))
+
+ def removeNamedItem(self, name):
+ return _wrap_node(self._impl.removeNamedItem(name))
+
+ def item(self, index):
+ return _wrap_node(self._impl.item(index))
+
+ # Python dictionary methods
+
+ def __getitem__(self, key):
+ node = self._impl.getNamedItem(key)
+
+ if node is None:
+ raise KeyError, key
+ else:
+ return _wrap_node(node)
+
+ def get(self, key, alternative = None):
+ node = self._impl.getNamedItem(key)
+ if node is None:
+ return alternative
+ else:
+ return _wrap_node(node)
+
+ def has_key(self, key):
+ return self._impl.getNamedItem(key) != None
+
+ def items(self):
+ list = []
+ for ix in range(self._impl.getLength()):
+ node = self._impl.item(ix)
+ list.append((node.getNodeName(), _wrap_node(node)))
+ return list
+
+ def keys(self):
+ list = []
+ for ix in range(self._impl.getLength()):
+ list.append(self._impl.item(ix)._get_nodeName())
+ return list
+
+ def values(self):
+ list = []
+ for ix in range(self._impl.getLength()):
+ list.append(_wrap_node(self._impl.item(ix)))
+ return list
+
+ def __setitem__(self, key, item):
+ assert key == item._impl._get_nodeName()
+ self._impl.setNamedItem(item._impl)
+
+ def update(self, nnm):
+ for v in nnm.values():
+ self._impl.setNamedItem(v._impl)
+
+ def __repr__(self):
+ pairs = []
+ for pair in self.items():
+ pairs.append("'%s' : %s" % pair)
+ return "<NamedNodeMap { %s }>" % string.join(pairs, ", ")
+
+# ===== Various stuff
+
+NODE_CLASS_MAP = {
+ ELEMENT_NODE : Element,
+ ATTRIBUTE_NODE : Attr,
+ TEXT_NODE : Text,
+ CDATA_SECTION_NODE : CDATASection,
+ ENTITY_REFERENCE_NODE : EntityReference,
+ ENTITY_NODE : Entity,
+ PROCESSING_INSTRUCTION_NODE : ProcessingInstruction,
+ COMMENT_NODE : Comment,
+ DOCUMENT_NODE : Document,
+ DOCUMENT_TYPE_NODE : DocumentType,
+ DOCUMENT_FRAGMENT_NODE : DocumentFragment,
+ NOTATION_NODE : Notation
+ }
+
+# ===== Self-test
+
+if __name__ == "__main__":
+ impl = BrownellDomImplementation() #XercesDomImplementation() #SunDomImplementation()
+ doc2 = impl.createDocument()
+ print doc2
+ print doc2._get_implementation()
+ root = doc2.createElement("doc")
+ print root
+ doc2.appendChild(root)
+ txt = doc2.createTextNode("This is a simple sample \n")
+ print txt
+ root.appendChild(txt)
+
+ print root._get_childNodes()[0]
+ print root._get_childNodes()
+
+ root.setAttribute("huba", "haba")
+ print root
+ print root._get_attributes()
diff --git a/lib/jython/Lib/xml/dom/minidom.py b/lib/jython/Lib/xml/dom/minidom.py new file mode 100644 index 000000000..37649c4c2 --- /dev/null +++ b/lib/jython/Lib/xml/dom/minidom.py @@ -0,0 +1,916 @@ +"""\
+minidom.py -- a lightweight DOM implementation.
+
+parse("foo.xml")
+
+parseString("<foo><bar/></foo>")
+
+Todo:
+=====
+ * convenience methods for getting elements and text.
+ * more testing
+ * bring some of the writer and linearizer code into conformance with this
+ interface
+ * SAX 2 namespaces
+"""
+
+import string
+_string = string
+del string
+
+from xml.dom import HierarchyRequestErr
+
+# localize the types, and allow support for Unicode values if available:
+import types
+_TupleType = types.TupleType
+try:
+ _StringTypes = (types.StringType, types.UnicodeType)
+except AttributeError:
+ _StringTypes = (types.StringType,)
+del types
+
+import xml.dom
+_Node = xml.dom.Node
+
+class Node(_Node):
+ allnodes = {}
+ _debug = 0
+ _makeParentNodes = 1
+ debug = None
+ childNodeTypes = ()
+ namespaceURI = None # this is non-null only for elements and attributes
+
+ def __init__(self):
+ self.childNodes = []
+ self.parentNode = self.ownerDocument = None
+ if Node._debug:
+ index = repr(id(self)) + repr(self.__class__)
+ Node.allnodes[index] = repr(self.__dict__)
+ if Node.debug is None:
+ Node.debug = _get_StringIO()
+ #open("debug4.out", "w")
+ Node.debug.write("create %s\n" % index)
+
+ def __getattr__(self, key):
+ if key[0:2] == "__":
+ raise AttributeError, key
+ # getattr should never call getattr!
+ if self.__dict__.has_key("inGetAttr"):
+ del self.inGetAttr
+ raise AttributeError, key
+
+ prefix, attrname = key[:5], key[5:]
+ if prefix == "_get_":
+ self.inGetAttr = 1
+ if hasattr(self, attrname):
+ del self.inGetAttr
+ return (lambda self=self, attrname=attrname:
+ getattr(self, attrname))
+ else:
+ del self.inGetAttr
+ raise AttributeError, key
+ else:
+ self.inGetAttr = 1
+ try:
+ func = getattr(self, "_get_" + key)
+ except AttributeError:
+ raise AttributeError, key
+ del self.inGetAttr
+ return func()
+
+ def __nonzero__(self):
+ return 1
+
+ def toxml(self):
+ writer = _get_StringIO()
+ self.writexml(writer)
+ return writer.getvalue()
+
+ def toprettyxml(self, indent="\t", newl="\n"):
+ # indent = the indentation string to prepend, per level
+ # newl = the newline string to append
+ writer = _get_StringIO()
+ self.writexml(writer, "", indent, newl)
+ return writer.getvalue()
+
+ def hasChildNodes(self):
+ if self.childNodes:
+ return 1
+ else:
+ return 0
+
+ def _get_firstChild(self):
+ if self.childNodes:
+ return self.childNodes[0]
+
+ def _get_lastChild(self):
+ if self.childNodes:
+ return self.childNodes[-1]
+
+ def insertBefore(self, newChild, refChild):
+ if newChild.nodeType == self.DOCUMENT_FRAGMENT_NODE:
+ for c in newChild.childNodes:
+ self.insertBefore(c, refChild)
+ ### The DOM does not clearly specify what to return in this case
+ return newChild
+ if newChild.nodeType not in self.childNodeTypes:
+ raise HierarchyRequestErr, \
+ "%s cannot be child of %s" % (repr(newChild), repr(self))
+ if newChild.parentNode is not None:
+ newChild.parentNode.removeChild(newChild)
+ if refChild is None:
+ self.appendChild(newChild)
+ else:
+ index = self.childNodes.index(refChild)
+ self.childNodes.insert(index, newChild)
+ newChild.nextSibling = refChild
+ refChild.previousSibling = newChild
+ if index:
+ node = self.childNodes[index-1]
+ node.nextSibling = newChild
+ newChild.previousSibling = node
+ else:
+ newChild.previousSibling = None
+ if self._makeParentNodes:
+ newChild.parentNode = self
+ return newChild
+
+ def appendChild(self, node):
+ if node.nodeType == self.DOCUMENT_FRAGMENT_NODE:
+ for c in node.childNodes:
+ self.appendChild(c)
+ ### The DOM does not clearly specify what to return in this case
+ return node
+ if node.nodeType not in self.childNodeTypes:
+ raise HierarchyRequestErr, \
+ "%s cannot be child of %s" % (repr(node), repr(self))
+ if node.parentNode is not None:
+ node.parentNode.removeChild(node)
+ if self.childNodes:
+ last = self.lastChild
+ node.previousSibling = last
+ last.nextSibling = node
+ else:
+ node.previousSibling = None
+ node.nextSibling = None
+ self.childNodes.append(node)
+ if self._makeParentNodes:
+ node.parentNode = self
+ return node
+
+ def replaceChild(self, newChild, oldChild):
+ if newChild.nodeType == self.DOCUMENT_FRAGMENT_NODE:
+ refChild = oldChild.nextSibling
+ self.removeChild(oldChild)
+ return self.insertBefore(newChild, refChild)
+ if newChild.nodeType not in self.childNodeTypes:
+ raise HierarchyRequestErr, \
+ "%s cannot be child of %s" % (repr(newChild), repr(self))
+ if newChild.parentNode is not None:
+ newChild.parentNode.removeChild(newChild)
+ if newChild is oldChild:
+ return
+ index = self.childNodes.index(oldChild)
+ self.childNodes[index] = newChild
+ if self._makeParentNodes:
+ newChild.parentNode = self
+ oldChild.parentNode = None
+ newChild.nextSibling = oldChild.nextSibling
+ newChild.previousSibling = oldChild.previousSibling
+ oldChild.nextSibling = None
+ oldChild.previousSibling = None
+ if newChild.previousSibling:
+ newChild.previousSibling.nextSibling = newChild
+ if newChild.nextSibling:
+ newChild.nextSibling.previousSibling = newChild
+ return oldChild
+
+ def removeChild(self, oldChild):
+ self.childNodes.remove(oldChild)
+ if oldChild.nextSibling is not None:
+ oldChild.nextSibling.previousSibling = oldChild.previousSibling
+ if oldChild.previousSibling is not None:
+ oldChild.previousSibling.nextSibling = oldChild.nextSibling
+ oldChild.nextSibling = oldChild.previousSibling = None
+
+ if self._makeParentNodes:
+ oldChild.parentNode = None
+ return oldChild
+
+ def normalize(self):
+ L = []
+ for child in self.childNodes:
+ if child.nodeType == Node.TEXT_NODE:
+ data = child.data
+ if data and L and L[-1].nodeType == child.nodeType:
+ # collapse text node
+ node = L[-1]
+ node.data = node.nodeValue = node.data + child.data
+ node.nextSibling = child.nextSibling
+ child.unlink()
+ elif data:
+ if L:
+ L[-1].nextSibling = child
+ child.previousSibling = L[-1]
+ else:
+ child.previousSibling = None
+ L.append(child)
+ else:
+ # empty text node; discard
+ child.unlink()
+ else:
+ if L:
+ L[-1].nextSibling = child
+ child.previousSibling = L[-1]
+ else:
+ child.previousSibling = None
+ L.append(child)
+ if child.nodeType == Node.ELEMENT_NODE:
+ child.normalize()
+ self.childNodes[:] = L
+
+ def cloneNode(self, deep):
+ import new
+ clone = new.instance(self.__class__, self.__dict__.copy())
+ if self._makeParentNodes:
+ clone.parentNode = None
+ clone.childNodes = []
+ if deep:
+ for child in self.childNodes:
+ clone.appendChild(child.cloneNode(1))
+ return clone
+
+ # DOM Level 3 (Working Draft 2001-Jan-26)
+
+ def isSameNode(self, other):
+ return self is other
+
+ # minidom-specific API:
+
+ def unlink(self):
+ self.parentNode = self.ownerDocument = None
+ for child in self.childNodes:
+ child.unlink()
+ self.childNodes = None
+ self.previousSibling = None
+ self.nextSibling = None
+ if Node._debug:
+ index = repr(id(self)) + repr(self.__class__)
+ self.debug.write("Deleting: %s\n" % index)
+ del Node.allnodes[index]
+
+def _write_data(writer, data):
+ "Writes datachars to writer."
+ replace = _string.replace
+ data = replace(data, "&", "&")
+ data = replace(data, "<", "<")
+ data = replace(data, "\"", """)
+ data = replace(data, ">", ">")
+ writer.write(data)
+
+def _getElementsByTagNameHelper(parent, name, rc):
+ for node in parent.childNodes:
+ if node.nodeType == Node.ELEMENT_NODE and \
+ (name == "*" or node.tagName == name):
+ rc.append(node)
+ _getElementsByTagNameHelper(node, name, rc)
+ return rc
+
+def _getElementsByTagNameNSHelper(parent, nsURI, localName, rc):
+ for node in parent.childNodes:
+ if node.nodeType == Node.ELEMENT_NODE:
+ if ((localName == "*" or node.localName == localName) and
+ (nsURI == "*" or node.namespaceURI == nsURI)):
+ rc.append(node)
+ _getElementsByTagNameNSHelper(node, nsURI, localName, rc)
+ return rc
+
+class DocumentFragment(Node):
+ nodeType = Node.DOCUMENT_FRAGMENT_NODE
+ nodeName = "#document-fragment"
+ nodeValue = None
+ attributes = None
+ parentNode = None
+ childNodeTypes = (Node.ELEMENT_NODE,
+ Node.TEXT_NODE,
+ Node.CDATA_SECTION_NODE,
+ Node.ENTITY_REFERENCE_NODE,
+ Node.PROCESSING_INSTRUCTION_NODE,
+ Node.COMMENT_NODE,
+ Node.NOTATION_NODE)
+
+
+class Attr(Node):
+ nodeType = Node.ATTRIBUTE_NODE
+ attributes = None
+ ownerElement = None
+ childNodeTypes = (Node.TEXT_NODE, Node.ENTITY_REFERENCE_NODE)
+
+ def __init__(self, qName, namespaceURI="", localName=None, prefix=None):
+ # skip setattr for performance
+ d = self.__dict__
+ d["localName"] = localName or qName
+ d["nodeName"] = d["name"] = qName
+ d["namespaceURI"] = namespaceURI
+ d["prefix"] = prefix
+ Node.__init__(self)
+ # nodeValue and value are set elsewhere
+
+ def __setattr__(self, name, value):
+ d = self.__dict__
+ if name in ("value", "nodeValue"):
+ d["value"] = d["nodeValue"] = value
+ elif name in ("name", "nodeName"):
+ d["name"] = d["nodeName"] = value
+ else:
+ d[name] = value
+
+ def cloneNode(self, deep):
+ clone = Node.cloneNode(self, deep)
+ if clone.__dict__.has_key("ownerElement"):
+ del clone.ownerElement
+ return clone
+
+
+class NamedNodeMap:
+ """The attribute list is a transient interface to the underlying
+ dictionaries. Mutations here will change the underlying element's
+ dictionary.
+
+ Ordering is imposed artificially and does not reflect the order of
+ attributes as found in an input document.
+ """
+
+ def __init__(self, attrs, attrsNS):
+ self._attrs = attrs
+ self._attrsNS = attrsNS
+
+ def __getattr__(self, name):
+ if name == "length":
+ return len(self._attrs)
+ raise AttributeError, name
+
+ def item(self, index):
+ try:
+ return self[self._attrs.keys()[index]]
+ except IndexError:
+ return None
+
+ def items(self):
+ L = []
+ for node in self._attrs.values():
+ L.append((node.nodeName, node.value))
+ return L
+
+ def itemsNS(self):
+ L = []
+ for node in self._attrs.values():
+ L.append(((node.URI, node.localName), node.value))
+ return L
+
+ def keys(self):
+ return self._attrs.keys()
+
+ def keysNS(self):
+ return self._attrsNS.keys()
+
+ def values(self):
+ return self._attrs.values()
+
+ def get(self, name, value = None):
+ return self._attrs.get(name, value)
+
+ def __len__(self):
+ return self.length
+
+ def __cmp__(self, other):
+ if self._attrs is getattr(other, "_attrs", None):
+ return 0
+ else:
+ return cmp(id(self), id(other))
+
+ #FIXME: is it appropriate to return .value?
+ def __getitem__(self, attname_or_tuple):
+ if type(attname_or_tuple) is _TupleType:
+ return self._attrsNS[attname_or_tuple]
+ else:
+ return self._attrs[attname_or_tuple]
+
+ # same as set
+ def __setitem__(self, attname, value):
+ if type(value) in _StringTypes:
+ node = Attr(attname)
+ node.value = value
+ else:
+ if not isinstance(value, Attr):
+ raise TypeError, "value must be a string or Attr object"
+ node = value
+ self.setNamedItem(node)
+
+ def setNamedItem(self, node):
+ if not isinstance(node, Attr):
+ raise HierarchyRequestErr, \
+ "%s cannot be child of %s" % (repr(node), repr(self))
+ old = self._attrs.get(node.name)
+ if old:
+ old.unlink()
+ self._attrs[node.name] = node
+ self._attrsNS[(node.namespaceURI, node.localName)] = node
+ return old
+
+ def setNamedItemNS(self, node):
+ return self.setNamedItem(node)
+
+ def __delitem__(self, attname_or_tuple):
+ node = self[attname_or_tuple]
+ node.unlink()
+ del self._attrs[node.name]
+ del self._attrsNS[(node.namespaceURI, node.localName)]
+ self.length = len(self._attrs)
+
+AttributeList = NamedNodeMap
+
+
+class Element(Node):
+ nodeType = Node.ELEMENT_NODE
+ nextSibling = None
+ previousSibling = None
+ childNodeTypes = (Node.ELEMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE,
+ Node.COMMENT_NODE, Node.TEXT_NODE,
+ Node.CDATA_SECTION_NODE, Node.ENTITY_REFERENCE_NODE)
+
+ def __init__(self, tagName, namespaceURI=None, prefix="",
+ localName=None):
+ Node.__init__(self)
+ self.tagName = self.nodeName = tagName
+ self.localName = localName or tagName
+ self.prefix = prefix
+ self.namespaceURI = namespaceURI
+ self.nodeValue = None
+
+ self._attrs = {} # attributes are double-indexed:
+ self._attrsNS = {} # tagName -> Attribute
+ # URI,localName -> Attribute
+ # in the future: consider lazy generation
+ # of attribute objects this is too tricky
+ # for now because of headaches with
+ # namespaces.
+
+ def cloneNode(self, deep):
+ clone = Node.cloneNode(self, deep)
+ clone._attrs = {}
+ clone._attrsNS = {}
+ for attr in self._attrs.values():
+ node = attr.cloneNode(1)
+ clone._attrs[node.name] = node
+ clone._attrsNS[(node.namespaceURI, node.localName)] = node
+ node.ownerElement = clone
+ return clone
+
+ def unlink(self):
+ for attr in self._attrs.values():
+ attr.unlink()
+ self._attrs = None
+ self._attrsNS = None
+ Node.unlink(self)
+
+ def getAttribute(self, attname):
+ try:
+ return self._attrs[attname].value
+ except KeyError:
+ return ""
+
+ def getAttributeNS(self, namespaceURI, localName):
+ try:
+ return self._attrsNS[(namespaceURI, localName)].value
+ except KeyError:
+ return ""
+
+ def setAttribute(self, attname, value):
+ attr = Attr(attname)
+ # for performance
+ attr.__dict__["value"] = attr.__dict__["nodeValue"] = value
+ self.setAttributeNode(attr)
+
+ def setAttributeNS(self, namespaceURI, qualifiedName, value):
+ prefix, localname = _nssplit(qualifiedName)
+ # for performance
+ attr = Attr(qualifiedName, namespaceURI, localname, prefix)
+ attr.__dict__["value"] = attr.__dict__["nodeValue"] = value
+ self.setAttributeNode(attr)
+
+ def getAttributeNode(self, attrname):
+ return self._attrs.get(attrname)
+
+ def getAttributeNodeNS(self, namespaceURI, localName):
+ return self._attrsNS.get((namespaceURI, localName))
+
+ def setAttributeNode(self, attr):
+ if attr.ownerElement not in (None, self):
+ raise xml.dom.InuseAttributeErr("attribute node already owned")
+ old = self._attrs.get(attr.name, None)
+ if old:
+ old.unlink()
+ self._attrs[attr.name] = attr
+ self._attrsNS[(attr.namespaceURI, attr.localName)] = attr
+
+ # This creates a circular reference, but Element.unlink()
+ # breaks the cycle since the references to the attribute
+ # dictionaries are tossed.
+ attr.ownerElement = self
+
+ if old is not attr:
+ # It might have already been part of this node, in which case
+ # it doesn't represent a change, and should not be returned.
+ return old
+
+ setAttributeNodeNS = setAttributeNode
+
+ def removeAttribute(self, name):
+ attr = self._attrs[name]
+ self.removeAttributeNode(attr)
+
+ def removeAttributeNS(self, namespaceURI, localName):
+ attr = self._attrsNS[(namespaceURI, localName)]
+ self.removeAttributeNode(attr)
+
+ def removeAttributeNode(self, node):
+ node.unlink()
+ del self._attrs[node.name]
+ del self._attrsNS[(node.namespaceURI, node.localName)]
+
+ removeAttributeNodeNS = removeAttributeNode
+
+ def hasAttribute(self, name):
+ return self._attrs.has_key(name)
+
+ def hasAttributeNS(self, namespaceURI, localName):
+ return self._attrsNS.has_key((namespaceURI, localName))
+
+ def getElementsByTagName(self, name):
+ return _getElementsByTagNameHelper(self, name, [])
+
+ def getElementsByTagNameNS(self, namespaceURI, localName):
+ return _getElementsByTagNameNSHelper(self, namespaceURI, localName, [])
+
+ def __repr__(self):
+ return "<DOM Element: %s at %s>" % (self.tagName, id(self))
+
+ def writexml(self, writer, indent="", addindent="", newl=""):
+ # indent = current indentation
+ # addindent = indentation to add to higher levels
+ # newl = newline string
+ writer.write(indent+"<" + self.tagName)
+
+ attrs = self._get_attributes()
+ a_names = attrs.keys()
+ a_names.sort()
+
+ for a_name in a_names:
+ writer.write(" %s=\"" % a_name)
+ _write_data(writer, attrs[a_name].value)
+ writer.write("\"")
+ if self.childNodes:
+ writer.write(">%s"%(newl))
+ for node in self.childNodes:
+ node.writexml(writer,indent+addindent,addindent,newl)
+ writer.write("%s</%s>%s" % (indent,self.tagName,newl))
+ else:
+ writer.write("/>%s"%(newl))
+
+ def _get_attributes(self):
+ return AttributeList(self._attrs, self._attrsNS)
+
+ def hasAttributes(self):
+ if self._attrs or self._attrsNS:
+ return 1
+ else:
+ return 0
+
+class Comment(Node):
+ nodeType = Node.COMMENT_NODE
+ nodeName = "#comment"
+ attributes = None
+ childNodeTypes = ()
+
+ def __init__(self, data):
+ Node.__init__(self)
+ self.data = self.nodeValue = data
+
+ def writexml(self, writer, indent="", addindent="", newl=""):
+ writer.write("%s<!--%s-->%s" % (indent,self.data,newl))
+
+class ProcessingInstruction(Node):
+ nodeType = Node.PROCESSING_INSTRUCTION_NODE
+ attributes = None
+ childNodeTypes = ()
+
+ def __init__(self, target, data):
+ Node.__init__(self)
+ self.target = self.nodeName = target
+ self.data = self.nodeValue = data
+
+ def writexml(self, writer, indent="", addindent="", newl=""):
+ writer.write("%s<?%s %s?>%s" % (indent,self.target, self.data, newl))
+
+class CharacterData(Node):
+ def __init__(self, data):
+ if type(data) not in _StringTypes:
+ raise TypeError, "node contents must be a string"
+ Node.__init__(self)
+ self.data = self.nodeValue = data
+ self.length = len(data)
+
+ def __repr__(self):
+ if len(self.data) > 10:
+ dotdotdot = "..."
+ else:
+ dotdotdot = ""
+ return "<DOM %s node \"%s%s\">" % (
+ self.__class__.__name__, self.data[0:10], dotdotdot)
+
+ def substringData(self, offset, count):
+ if offset < 0:
+ raise xml.dom.IndexSizeErr("offset cannot be negative")
+ if offset >= len(self.data):
+ raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
+ if count < 0:
+ raise xml.dom.IndexSizeErr("count cannot be negative")
+ return self.data[offset:offset+count]
+
+ def appendData(self, arg):
+ self.data = self.data + arg
+ self.nodeValue = self.data
+ self.length = len(self.data)
+
+ def insertData(self, offset, arg):
+ if offset < 0:
+ raise xml.dom.IndexSizeErr("offset cannot be negative")
+ if offset >= len(self.data):
+ raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
+ if arg:
+ self.data = "%s%s%s" % (
+ self.data[:offset], arg, self.data[offset:])
+ self.nodeValue = self.data
+ self.length = len(self.data)
+
+ def deleteData(self, offset, count):
+ if offset < 0:
+ raise xml.dom.IndexSizeErr("offset cannot be negative")
+ if offset >= len(self.data):
+ raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
+ if count < 0:
+ raise xml.dom.IndexSizeErr("count cannot be negative")
+ if count:
+ self.data = self.data[:offset] + self.data[offset+count:]
+ self.nodeValue = self.data
+ self.length = len(self.data)
+
+ def replaceData(self, offset, count, arg):
+ if offset < 0:
+ raise xml.dom.IndexSizeErr("offset cannot be negative")
+ if offset >= len(self.data):
+ raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
+ if count < 0:
+ raise xml.dom.IndexSizeErr("count cannot be negative")
+ if count:
+ self.data = "%s%s%s" % (
+ self.data[:offset], arg, self.data[offset+count:])
+ self.nodeValue = self.data
+ self.length = len(self.data)
+
+class Text(CharacterData):
+ nodeType = Node.TEXT_NODE
+ nodeName = "#text"
+ attributes = None
+ childNodeTypes = ()
+
+ def splitText(self, offset):
+ if offset < 0 or offset > len(self.data):
+ raise xml.dom.IndexSizeErr("illegal offset value")
+ newText = Text(self.data[offset:])
+ next = self.nextSibling
+ if self.parentNode and self in self.parentNode.childNodes:
+ if next is None:
+ self.parentNode.appendChild(newText)
+ else:
+ self.parentNode.insertBefore(newText, next)
+ self.data = self.data[:offset]
+ self.nodeValue = self.data
+ self.length = len(self.data)
+ return newText
+
+ def writexml(self, writer, indent="", addindent="", newl=""):
+ _write_data(writer, "%s%s%s"%(indent, self.data, newl))
+
+
+class CDATASection(Text):
+ nodeType = Node.CDATA_SECTION_NODE
+ nodeName = "#cdata-section"
+
+ def writexml(self, writer, indent="", addindent="", newl=""):
+ _write_data(writer, "<![CDATA[%s]]>" % self.data)
+
+
+def _nssplit(qualifiedName):
+ fields = _string.split(qualifiedName, ':', 1)
+ if len(fields) == 2:
+ return fields
+ elif len(fields) == 1:
+ return ('', fields[0])
+
+
+class DocumentType(Node):
+ nodeType = Node.DOCUMENT_TYPE_NODE
+ nodeValue = None
+ attributes = None
+ name = None
+ publicId = None
+ systemId = None
+ internalSubset = None
+ entities = None
+ notations = None
+
+ def __init__(self, qualifiedName):
+ Node.__init__(self)
+ if qualifiedName:
+ prefix, localname = _nssplit(qualifiedName)
+ self.name = localname
+
+
+class DOMImplementation:
+ def hasFeature(self, feature, version):
+ if version not in ("1.0", "2.0"):
+ return 0
+ feature = _string.lower(feature)
+ return feature == "core"
+
+ def createDocument(self, namespaceURI, qualifiedName, doctype):
+ if doctype and doctype.parentNode is not None:
+ raise xml.dom.WrongDocumentErr(
+ "doctype object owned by another DOM tree")
+ doc = self._createDocument()
+ if doctype is None:
+ doctype = self.createDocumentType(qualifiedName, None, None)
+ if not qualifiedName:
+ # The spec is unclear what to raise here; SyntaxErr
+ # would be the other obvious candidate. Since Xerces raises
+ # InvalidCharacterErr, and since SyntaxErr is not listed
+ # for createDocument, that seems to be the better choice.
+ # XXX: need to check for illegal characters here and in
+ # createElement.
+ raise xml.dom.InvalidCharacterErr("Element with no name")
+ prefix, localname = _nssplit(qualifiedName)
+ if prefix == "xml" \
+ and namespaceURI != "http://www.w3.org/XML/1998/namespace":
+ raise xml.dom.NamespaceErr("illegal use of 'xml' prefix")
+ if prefix and not namespaceURI:
+ raise xml.dom.NamespaceErr(
+ "illegal use of prefix without namespaces")
+ element = doc.createElementNS(namespaceURI, qualifiedName)
+ doc.appendChild(element)
+ doctype.parentNode = doctype.ownerDocument = doc
+ doc.doctype = doctype
+ doc.implementation = self
+ return doc
+
+ def createDocumentType(self, qualifiedName, publicId, systemId):
+ doctype = DocumentType(qualifiedName)
+ doctype.publicId = publicId
+ doctype.systemId = systemId
+ return doctype
+
+ # internal
+ def _createDocument(self):
+ return Document()
+
+class Document(Node):
+ nodeType = Node.DOCUMENT_NODE
+ nodeName = "#document"
+ nodeValue = None
+ attributes = None
+ doctype = None
+ parentNode = None
+ previousSibling = nextSibling = None
+
+ implementation = DOMImplementation()
+ childNodeTypes = (Node.ELEMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE,
+ Node.COMMENT_NODE, Node.DOCUMENT_TYPE_NODE)
+
+ def appendChild(self, node):
+ if node.nodeType not in self.childNodeTypes:
+ raise HierarchyRequestErr, \
+ "%s cannot be child of %s" % (repr(node), repr(self))
+ if node.parentNode is not None:
+ node.parentNode.removeChild(node)
+
+ if node.nodeType == Node.ELEMENT_NODE \
+ and self._get_documentElement():
+ raise xml.dom.HierarchyRequestErr(
+ "two document elements disallowed")
+ return Node.appendChild(self, node)
+
+ def removeChild(self, oldChild):
+ self.childNodes.remove(oldChild)
+ oldChild.nextSibling = oldChild.previousSibling = None
+ oldChild.parentNode = None
+ if self.documentElement is oldChild:
+ self.documentElement = None
+
+ return oldChild
+
+ def _get_documentElement(self):
+ for node in self.childNodes:
+ if node.nodeType == Node.ELEMENT_NODE:
+ return node
+
+ def unlink(self):
+ if self.doctype is not None:
+ self.doctype.unlink()
+ self.doctype = None
+ Node.unlink(self)
+
+ def createDocumentFragment(self):
+ d = DocumentFragment()
+ d.ownerDoc = self
+ return d
+
+ def createElement(self, tagName):
+ e = Element(tagName)
+ e.ownerDocument = self
+ return e
+
+ def createTextNode(self, data):
+ t = Text(data)
+ t.ownerDocument = self
+ return t
+
+ def createCDATASection(self, data):
+ c = CDATASection(data)
+ c.ownerDocument = self
+ return c
+
+ def createComment(self, data):
+ c = Comment(data)
+ c.ownerDocument = self
+ return c
+
+ def createProcessingInstruction(self, target, data):
+ p = ProcessingInstruction(target, data)
+ p.ownerDocument = self
+ return p
+
+ def createAttribute(self, qName):
+ a = Attr(qName)
+ a.ownerDocument = self
+ a.value = ""
+ return a
+
+ def createElementNS(self, namespaceURI, qualifiedName):
+ prefix, localName = _nssplit(qualifiedName)
+ e = Element(qualifiedName, namespaceURI, prefix, localName)
+ e.ownerDocument = self
+ return e
+
+ def createAttributeNS(self, namespaceURI, qualifiedName):
+ prefix, localName = _nssplit(qualifiedName)
+ a = Attr(qualifiedName, namespaceURI, localName, prefix)
+ a.ownerDocument = self
+ a.value = ""
+ return a
+
+ def getElementsByTagName(self, name):
+ return _getElementsByTagNameHelper(self, name, [])
+
+ def getElementsByTagNameNS(self, namespaceURI, localName):
+ return _getElementsByTagNameNSHelper(self, namespaceURI, localName, [])
+
+ def writexml(self, writer, indent="", addindent="", newl=""):
+ writer.write('<?xml version="1.0" ?>\n')
+ for node in self.childNodes:
+ node.writexml(writer, indent, addindent, newl)
+
+def _get_StringIO():
+ # we can't use cStringIO since it doesn't support Unicode strings
+ from StringIO import StringIO
+ return StringIO()
+
+def _doparse(func, args, kwargs):
+ events = apply(func, args, kwargs)
+ toktype, rootNode = events.getEvent()
+ events.expandNode(rootNode)
+ events.clear()
+ return rootNode
+
+def parse(*args, **kwargs):
+ """Parse a file into a DOM by filename or file object."""
+ from xml.dom import pulldom
+ return _doparse(pulldom.parse, args, kwargs)
+
+def parseString(*args, **kwargs):
+ """Parse a file into a DOM from a string."""
+ from xml.dom import pulldom
+ return _doparse(pulldom.parseString, args, kwargs)
+
+def getDOMImplementation():
+ return Document.implementation
diff --git a/lib/jython/Lib/xml/dom/minitraversal.py b/lib/jython/Lib/xml/dom/minitraversal.py new file mode 100644 index 000000000..888800463 --- /dev/null +++ b/lib/jython/Lib/xml/dom/minitraversal.py @@ -0,0 +1,34 @@ +"""A DOM implementation that offers traversal and ranges on top of
+minidom, using the 4DOM traversal implementation."""
+
+import minidom, string
+
+class DOMImplementation(minidom.DOMImplementation):
+ def hasFeature(self, feature, version):
+ if version not in ("1.0", "2.0"):
+ return 0
+ feature = string.lower(feature)
+ if feature in ['traversal','range']:
+ return 1
+ return minidom.DOMImplementation.hasFeature(self, feature, version)
+
+ def _createDocument(self):
+ return Document()
+
+class Document(minidom.Document):
+ implementation = DOMImplementation()
+ def createNodeIterator(self, root, whatToShow, filter, entityReferenceExpansion):
+ from xml.dom import NodeIterator
+ nodi = NodeIterator.NodeIterator(root, whatToShow, filter, entityReferenceExpansion)
+ return nodi
+
+ def createTreeWalker(self, root, whatToShow, filter, entityReferenceExpansion):
+ from TreeWalker import TreeWalker
+ return TreeWalker(root, whatToShow, filter, entityReferenceExpansion)
+
+ def createRange(self):
+ import Range
+ return Range.Range(self)
+
+def getDOMImplementation():
+ return Document.implementation
diff --git a/lib/jython/Lib/xml/dom/pulldom.py b/lib/jython/Lib/xml/dom/pulldom.py new file mode 100644 index 000000000..37a3dbc3c --- /dev/null +++ b/lib/jython/Lib/xml/dom/pulldom.py @@ -0,0 +1,319 @@ +import xml.sax
+import xml.sax.handler
+import types
+
+try:
+ _StringTypes = [types.StringType, types.UnicodeType]
+except AttributeError:
+ _StringTypes = [types.StringType]
+
+START_ELEMENT = "START_ELEMENT"
+END_ELEMENT = "END_ELEMENT"
+COMMENT = "COMMENT"
+START_DOCUMENT = "START_DOCUMENT"
+END_DOCUMENT = "END_DOCUMENT"
+PROCESSING_INSTRUCTION = "PROCESSING_INSTRUCTION"
+IGNORABLE_WHITESPACE = "IGNORABLE_WHITESPACE"
+CHARACTERS = "CHARACTERS"
+
+class PullDOM(xml.sax.ContentHandler):
+ _locator = None
+ document = None
+
+ def __init__(self, documentFactory=None):
+ self.documentFactory = documentFactory
+ self.firstEvent = [None, None]
+ self.lastEvent = self.firstEvent
+ self.elementStack = []
+ self.push = self.elementStack.append
+ try:
+ self.pop = self.elementStack.pop
+ except AttributeError:
+ # use class' pop instead
+ pass
+ self._ns_contexts = [{}] # contains uri -> prefix dicts
+ self._current_context = self._ns_contexts[-1]
+ self.pending_events = []
+
+ def pop(self):
+ result = self.elementStack[-1]
+ del self.elementStack[-1]
+ return result
+
+ def setDocumentLocator(self, locator):
+ self._locator = locator
+
+ def startPrefixMapping(self, prefix, uri):
+ if not hasattr(self, '_xmlns_attrs'):
+ self._xmlns_attrs = []
+ self._xmlns_attrs.append((prefix or 'xmlns', uri))
+ self._ns_contexts.append(self._current_context.copy())
+ self._current_context[uri] = prefix or ''
+
+ def endPrefixMapping(self, prefix):
+ self._current_context = self._ns_contexts.pop()
+
+ def startElementNS(self, name, tagName , attrs):
+ # Retrieve xml namespace declaration attributes.
+ xmlns_uri = 'http://www.w3.org/2000/xmlns/'
+ xmlns_attrs = getattr(self, '_xmlns_attrs', None)
+ if xmlns_attrs is not None:
+ for aname, value in xmlns_attrs:
+ attrs._attrs[(xmlns_uri, aname)] = value
+ self._xmlns_attrs = []
+ uri, localname = name
+ if uri:
+ # When using namespaces, the reader may or may not
+ # provide us with the original name. If not, create
+ # *a* valid tagName from the current context.
+ if tagName is None:
+ prefix = self._current_context[uri]
+ if prefix:
+ tagName = prefix + ":" + localname
+ else:
+ tagName = localname
+ if self.document:
+ node = self.document.createElementNS(uri, tagName)
+ else:
+ node = self.buildDocument(uri, tagName)
+ else:
+ # When the tagname is not prefixed, it just appears as
+ # localname
+ if self.document:
+ node = self.document.createElement(localname)
+ else:
+ node = self.buildDocument(None, localname)
+
+ for aname,value in attrs.items():
+ a_uri, a_localname = aname
+ if a_uri == xmlns_uri:
+ if a_localname == 'xmlns':
+ qname = a_localname
+ else:
+ qname = 'xmlns:' + a_localname
+ attr = self.document.createAttributeNS(a_uri, qname)
+ node.setAttributeNodeNS(attr)
+ elif a_uri:
+ prefix = self._current_context[a_uri]
+ if prefix:
+ qname = prefix + ":" + a_localname
+ else:
+ qname = a_localname
+ attr = self.document.createAttributeNS(a_uri, qname)
+ node.setAttributeNodeNS(attr)
+ else:
+ attr = self.document.createAttribute(a_localname)
+ node.setAttributeNode(attr)
+ attr.value = value
+
+ self.lastEvent[1] = [(START_ELEMENT, node), None]
+ self.lastEvent = self.lastEvent[1]
+ self.push(node)
+
+ def endElementNS(self, name, tagName):
+ self.lastEvent[1] = [(END_ELEMENT, self.pop()), None]
+ self.lastEvent = self.lastEvent[1]
+
+ def startElement(self, name, attrs):
+ if self.document:
+ node = self.document.createElement(name)
+ else:
+ node = self.buildDocument(None, name)
+
+ for aname,value in attrs.items():
+ attr = self.document.createAttribute(aname)
+ attr.value = value
+ node.setAttributeNode(attr)
+
+ self.lastEvent[1] = [(START_ELEMENT, node), None]
+ self.lastEvent = self.lastEvent[1]
+ self.push(node)
+
+ def endElement(self, name):
+ self.lastEvent[1] = [(END_ELEMENT, self.pop()), None]
+ self.lastEvent = self.lastEvent[1]
+
+ def comment(self, s):
+ if self.document:
+ node = self.document.createComment(s)
+ self.lastEvent[1] = [(COMMENT, node), None]
+ self.lastEvent = self.lastEvent[1]
+ else:
+ event = [(COMMENT, s), None]
+ self.pending_events.append(event)
+
+ def processingInstruction(self, target, data):
+ if self.document:
+ node = self.document.createProcessingInstruction(target, data)
+ self.lastEvent[1] = [(PROCESSING_INSTRUCTION, node), None]
+ self.lastEvent = self.lastEvent[1]
+ else:
+ event = [(PROCESSING_INSTRUCTION, target, data), None]
+ self.pending_events.append(event)
+
+ def ignorableWhitespace(self, chars):
+ node = self.document.createTextNode(chars)
+ self.lastEvent[1] = [(IGNORABLE_WHITESPACE, node), None]
+ self.lastEvent = self.lastEvent[1]
+
+ def characters(self, chars):
+ node = self.document.createTextNode(chars)
+ self.lastEvent[1] = [(CHARACTERS, node), None]
+ self.lastEvent = self.lastEvent[1]
+
+ def startDocument(self):
+ if self.documentFactory is None:
+ import xml.dom.minidom
+ self.documentFactory = xml.dom.minidom.Document.implementation
+
+ def buildDocument(self, uri, tagname):
+ # Can't do that in startDocument, since we need the tagname
+ # XXX: obtain DocumentType
+ node = self.documentFactory.createDocument(uri, tagname, None)
+ self.document = node
+ self.lastEvent[1] = [(START_DOCUMENT, node), None]
+ self.lastEvent = self.lastEvent[1]
+ self.push(node)
+ # Put everything we have seen so far into the document
+ for e in self.pending_events:
+ if e[0][0] == PROCESSING_INSTRUCTION:
+ _,target,data = e[0]
+ n = self.document.createProcessingInstruction(target, data)
+ e[0] = (PROCESSING_INSTRUCTION, n)
+ elif e[0][0] == COMMENT:
+ n = self.document.createComment(e[0][1])
+ e[0] = (COMMENT, n)
+ else:
+ raise AssertionError("Unknown pending event ",e[0][0])
+ self.lastEvent[1] = e
+ self.lastEvent = e
+ self.pending_events = None
+ return node.firstChild
+
+ def endDocument(self):
+ self.lastEvent[1] = [(END_DOCUMENT, self.document), None]
+ self.pop()
+
+ def clear(self):
+ "clear(): Explicitly release parsing structures"
+ self.document = None
+
+class ErrorHandler:
+ def warning(self, exception):
+ print exception
+ def error(self, exception):
+ raise exception
+ def fatalError(self, exception):
+ raise exception
+
+class DOMEventStream:
+ def __init__(self, stream, parser, bufsize):
+ self.stream = stream
+ self.parser = parser
+ self.bufsize = bufsize
+ self.reset()
+
+ def reset(self):
+ self.pulldom = PullDOM()
+ # This content handler relies on namespace support
+ self.parser.setFeature(xml.sax.handler.feature_namespaces, 1)
+ self.parser.setContentHandler(self.pulldom)
+
+ def __getitem__(self, pos):
+ rc = self.getEvent()
+ if rc:
+ return rc
+ raise IndexError
+
+ def expandNode(self, node):
+ event = self.getEvent()
+ parents = [node]
+ while event:
+ token, cur_node = event
+ if cur_node is node:
+ return
+ if token != END_ELEMENT:
+ parents[-1].appendChild(cur_node)
+ if token == START_ELEMENT:
+ parents.append(cur_node)
+ elif token == END_ELEMENT:
+ del parents[-1]
+ event = self.getEvent()
+
+ def getEvent(self):
+ if not self.pulldom.firstEvent[1]:
+ self.pulldom.lastEvent = self.pulldom.firstEvent
+ while not self.pulldom.firstEvent[1]:
+ buf = self.stream.read(self.bufsize)
+ if not buf:
+ self.parser.close()
+ return None
+ self.parser.feed(buf)
+ rc = self.pulldom.firstEvent[1][0]
+ self.pulldom.firstEvent[1] = self.pulldom.firstEvent[1][1]
+ return rc
+
+ def clear(self):
+ "clear(): Explicitly release parsing objects"
+ self.pulldom.clear()
+ del self.pulldom
+ self.parser = None
+ self.stream = None
+
+class SAX2DOM(PullDOM):
+
+ def startElementNS(self, name, tagName , attrs):
+ PullDOM.startElementNS(self, name, tagName, attrs)
+ curNode = self.elementStack[-1]
+ parentNode = self.elementStack[-2]
+ parentNode.appendChild(curNode)
+
+ def startElement(self, name, attrs):
+ PullDOM.startElement(self, name, attrs)
+ curNode = self.elementStack[-1]
+ parentNode = self.elementStack[-2]
+ parentNode.appendChild(curNode)
+
+ def processingInstruction(self, target, data):
+ PullDOM.processingInstruction(self, target, data)
+ node = self.lastEvent[0][1]
+ parentNode = self.elementStack[-1]
+ parentNode.appendChild(node)
+
+ def ignorableWhitespace(self, chars):
+ PullDOM.ignorableWhitespace(self, chars)
+ node = self.lastEvent[0][1]
+ parentNode = self.elementStack[-1]
+ parentNode.appendChild(node)
+
+ def characters(self, chars):
+ PullDOM.characters(self, chars)
+ node = self.lastEvent[0][1]
+ parentNode = self.elementStack[-1]
+ parentNode.appendChild(node)
+
+
+default_bufsize = (2 ** 14) - 20
+
+def parse(stream_or_string, parser=None, bufsize=None):
+ if bufsize is None:
+ bufsize = default_bufsize
+ if type(stream_or_string) in _StringTypes:
+ stream = open(stream_or_string)
+ else:
+ stream = stream_or_string
+ if not parser:
+ parser = xml.sax.make_parser()
+ return DOMEventStream(stream, parser, bufsize)
+
+def parseString(string, parser=None):
+ try:
+ from cStringIO import StringIO
+ except ImportError:
+ from StringIO import StringIO
+
+ bufsize = len(string)
+ buf = StringIO(string)
+ if not parser:
+ parser = xml.sax.make_parser()
+ return DOMEventStream(buf, parser, bufsize)
diff --git a/lib/jython/Lib/xml/ns.py b/lib/jython/Lib/xml/ns.py new file mode 100644 index 000000000..6066c8137 --- /dev/null +++ b/lib/jython/Lib/xml/ns.py @@ -0,0 +1,179 @@ +"""NS module -- XML Namespace constants
+
+This module contains the definitions of namespaces (and sometimes other
+URI's) used by a variety of XML standards. Each class has a short
+all-uppercase name, which should follow any (emerging) convention for
+how that standard is commonly used. For example, ds is almost always
+used as the namespace prefixes for items in XML Signature, so DS is the
+class name. Attributes within that class, all uppercase, define symbolic
+names (hopefully evocative) for "constants" used in that standard.
+"""
+
+
+class XMLNS:
+ """XMLNS, Namespaces in XML
+
+ XMLNS (14-Jan-1999) is a W3C Recommendation. It is specified in
+ http://www.w3.org/TR/REC-xml-names
+ BASE -- the basic namespace defined by the specification
+ XML -- the namespace for XML 1.0
+ HTML -- the namespace for HTML4.0
+ """
+
+ BASE = "http://www.w3.org/2000/xmlns/"
+ XML = "http://www.w3.org/XML/1998/namespace"
+ HTML = "http://www.w3.org/TR/REC-html40"
+
+
+class SOAP:
+ """SOAP, the Simple Object Access Protocol
+
+ SOAP (v1.1, 8-May-2000) is a W3C note. It is specified in
+ http://www.w3.org/TR/SOAP
+ ENV -- namespace for the SOAP envelope
+ ENC -- namespace for the SOAP encoding in section 5
+ ACTOR_NEXT -- the URI for the "next" actor
+ (Note that no BASE is defined.)
+ """
+
+ ENV = "http://schemas.xmlsoap.org/soap/envelope/"
+ ENC = "http://schemas.xmlsoap.org/soap/encoding/"
+ ACTOR_NEXT = "http://schemas.xmlsoap.org/soap/actor/next"
+
+
+class DSIG:
+ """DSIG, XML-Signature Syntax and Processing
+
+ DSIG (19-Apr-2001) is a W3C Candidate Recommendation. It is specified
+ in http://www.w3.org/TR/xmldsig-core/
+ BASE -- the basic namespace defined by the specification
+ DIGEST_SHA1 -- The SHA-1 digest method
+ DIGEST_MD2 -- The MD2 digest method
+ DIGEST_MD5 -- The MD5 digest method
+ SIG_DSA_SHA1 -- The DSA/DHA-1 signature method
+ SIG_RSA_SHA1 -- The RSA/DHA-1 signature method
+ HMAC_SHA1 -- The SHA-1 HMAC method
+ ENC_BASE64 -- The Base64 encoding method
+ ENVELOPED -- an enveloped XML signature
+ C14N -- XML canonicalization
+ C14N_COMM -- XML canonicalization, retaining comments
+ """
+
+ BASE = "http://www.w3.org/2000/09/xmldsig#"
+ DIGEST_SHA1 = BASE + "sha1"
+ DIGEST_MD2 = BASE + "md2"
+ DIGEST_MD5 = BASE + "md5"
+ SIG_DSA_SHA1= BASE + "dsa-sha1"
+ SIG_RSA_SHA1= BASE + "rsa-sha1"
+ HMAC_SHA1 = BASE + "hmac-sha1"
+ ENC_BASE64 = BASE + "base64"
+ ENVELOPED = BASE + "enveloped-signature"
+ C14N = "http://www.w3.org/TR/2000/CR-xml-c14n-20010315"
+ C14N_COMM = C14N + "#WithComments"
+
+
+class ENCRYPTION:
+ """ENCRYPTION, XML-Encryption Syntax and Processing
+
+ ENCRYPTION (26-Jun-2001) is a W3C Working Draft. It is specified in
+ http://www.w3.org/TR/xmlenc-core/
+ BASE -- the basic namespace defined by the specification
+ BLOCK_3DES -- The triple-DES symmetric encryption method
+ BLOCK_AES128 -- The 128-bit AES symmetric encryption method
+ BLOCK_AES256 -- The 256-bit AES symmetric encryption method
+ BLOCK_AES192 -- The 192-bit AES symmetric encryption method
+ STREAM_ARCFOUR -- The ARCFOUR symmetric encryption method
+ KT_RSA_1_5 -- The RSA v1.5 key transport method
+ KT_RSA_OAEP -- The RSA OAEP key transport method
+ KA_DH -- The Diffie-Hellman key agreement method
+ WRAP_3DES -- The triple-DES symmetric key wrap method
+ WRAP_AES128 -- The 128-bit AES symmetric key wrap method
+ WRAP_AES256 -- The 256-bit AES symmetric key wrap method
+ WRAP_AES192 -- The 192-bit AES symmetric key wrap method
+ DIGEST_SHA256 -- The SHA-256 digest method
+ DIGEST_SHA512 -- The SHA-512 digest method
+ DIGEST_RIPEMD160 -- The RIPEMD-160 digest method
+ """
+
+ BASE = "http://www.w3.org/2001/04/xmlenc#"
+ BLOCK_3DES = BASE + "des-cbc"
+ BLOCK_AES128 = BASE + "aes128-cbc"
+ BLOCK_AES256 = BASE + "aes256-cbc"
+ BLOCK_AES192 = BASE + "aes192-cbc"
+ STREAM_ARCFOUR = BASE + "arcfour"
+ KT_RSA_1_5 = BASE + "rsa-1_5"
+ KT_RSA_OAEP = BASE + "rsa-oaep-mgf1p"
+ KA_DH = BASE + "dh"
+ WRAP_3DES = BASE + "kw-3des"
+ WRAP_AES128 = BASE + "kw-aes128"
+ WRAP_AES256 = BASE + "kw-aes256"
+ WRAP_AES192 = BASE + "kw-aes192"
+ DIGEST_SHA256 = BASE + "sha256"
+ DIGEST_SHA512 = BASE + "sha512"
+ DIGEST_RIPEMD160 = BASE + "ripemd160"
+
+
+class SCHEMA:
+ """SCHEMA, XML Schema
+
+ XML Schema (30-Mar-2001) is a W3C candidate recommendation. It is
+ specified in http://www.w3.org/TR/xmlschema-1 (Structures) and
+ http://www.w3.org/TR/xmlschema-2 (Datatypes). Schema has been under
+ development for a comparitively long time, and other standards have
+ at times used earlier drafts. This class defines the most-used, and
+ sets BASE to the latest.
+ BASE -- the basic namespace (2001)
+ XSD1, XSI1 -- schema and schema-instance for 1999
+ XSD2, XSI2 -- schema and schema-instance for October 2000
+ XSD3, XSI3 -- schema and schema-instance for 2001
+ XSD_LIST -- a sequence of the XSDn values
+ XSI_LIST -- a sequence of the XSIn values
+ """
+
+ XSD1 = "http://www.w3.org/1999/XMLSchema"
+ XSD2 = "http://www.w3.org/2000/10/XMLSchema"
+ XSD3 = "http://www.w3.org/2001/XMLSchema"
+ XSD_LIST = [ XSD1, XSD2, XSD3 ]
+ XSI1 = "http://www.w3.org/1999/XMLSchema-instance"
+ XSI2 = "http://www.w3.org/2000/10/XMLSchema-instance"
+ XSI3 = "http://www.w3.org/2001/XMLSchema-instance"
+ XSI_LIST = [ XSI1, XSI2, XSI3 ]
+ BASE = XSD3
+
+
+class XSLT:
+ """XSLT, XSL Transformations
+
+ XSLT (16-Nov-1999) is a W3C Recommendation. It is specified in
+ http://www.w3.org/TR/xslt/
+ BASE -- the basic namespace defined by this specification
+ """
+
+ BASE = "http://www.w3.org/1999/XSL/Transform"
+
+
+class XPATH:
+ """XPATH, XML Path Language
+
+ XPATH (16-Nov-1999) is a W3C Recommendation. It is specified in
+ http://www.w3.org/TR/xpath. This class is currently empty.
+ """
+
+ pass
+
+
+class WSDL:
+ """WSDL, Web Services Description Language
+
+ WSDL (V1.1, 15-Mar-2001) is a W3C Note. It is specified in
+ http://www.w3.org/TR/wsdl
+ BASE -- the basic namespace defined by this specification
+ BIND_SOAP -- SOAP binding for WSDL
+ BIND_HTTP -- HTTP GET and POST binding for WSDL
+ BIND_MIME -- MIME binding for WSDL
+ """
+
+ BASE = "http://schemas.xmlsoap.org/wsdl/"
+ BIND_SOAP = BASE + "soap/"
+ BIND_HTTP = BASE + "http/"
+ BIND_MIME = BASE + "mime/"
diff --git a/lib/jython/Lib/xml/parsers/__init__.py b/lib/jython/Lib/xml/parsers/__init__.py new file mode 100644 index 000000000..f6690a039 --- /dev/null +++ b/lib/jython/Lib/xml/parsers/__init__.py @@ -0,0 +1 @@ +__all__ = ['xmllib', 'sgmllib', 'xmlproc']
diff --git a/lib/jython/Lib/xml/parsers/xmlproc/__init__.py b/lib/jython/Lib/xml/parsers/xmlproc/__init__.py new file mode 100644 index 000000000..ab5e94050 --- /dev/null +++ b/lib/jython/Lib/xml/parsers/xmlproc/__init__.py @@ -0,0 +1 @@ +"The XMLProc parser."
diff --git a/lib/jython/Lib/xml/parsers/xmlproc/_outputters.py b/lib/jython/Lib/xml/parsers/xmlproc/_outputters.py new file mode 100644 index 000000000..95e96831f --- /dev/null +++ b/lib/jython/Lib/xml/parsers/xmlproc/_outputters.py @@ -0,0 +1,59 @@ +
+# This module contains common functionality used by xvcmd.py and xpcmd.py
+
+import sys,string
+
+from xml.parsers.xmlproc import xmlapp, utils
+
+# Backwards compatibility declarations
+
+ESISDocHandler = utils.ESISDocHandler
+Canonizer = utils.Canonizer
+DocGenerator = utils.DocGenerator
+
+# Error handler
+
+class MyErrorHandler(xmlapp.ErrorHandler):
+
+ def __init__(self, locator, parser, warnings, entstack, rawxml):
+ xmlapp.ErrorHandler.__init__(self,locator)
+ self.show_warnings=warnings
+ self.show_entstack=entstack
+ self.show_rawxml=rawxml
+ self.parser=parser
+ self.reset()
+
+ def __show_location(self,prefix,msg):
+ print "%s:%s: %s" % (prefix,self.get_location(),msg)
+ if self.show_entstack:
+ print " Document entity"
+ for item in self.parser.get_current_ent_stack():
+ print " %s: %s" % item
+ if self.show_rawxml:
+ raw=self.parser.get_raw_construct()
+ if len(raw)>50:
+ print " Raw construct too big, suppressed."
+ else:
+ print " '%s'" % raw
+
+ def get_location(self):
+ return "%s:%d:%d" % (self.locator.get_current_sysid(),\
+ self.locator.get_line(),
+ self.locator.get_column())
+
+ def warning(self,msg):
+ if self.show_warnings:
+ self.__show_location("W",msg)
+ self.warnings=self.warnings+1
+
+ def error(self,msg):
+ self.fatal(msg)
+
+ def fatal(self,msg):
+ self.__show_location("E",msg)
+ self.errors=self.errors+1
+
+ def reset(self):
+ self.errors=0
+ self.warnings=0
+
diff --git a/lib/jython/Lib/xml/parsers/xmlproc/catalog.py b/lib/jython/Lib/xml/parsers/xmlproc/catalog.py new file mode 100644 index 000000000..7cb0f2d26 --- /dev/null +++ b/lib/jython/Lib/xml/parsers/xmlproc/catalog.py @@ -0,0 +1,312 @@ +"""
+An SGML Open catalog file parser.
+$Id: catalog.py,v 1.9 2000/09/26 14:43:10 loewis Exp $
+"""
+
+import string,sys
+
+import xmlutils,xmlapp
+
+# --- Parser factory class
+
+class CatParserFactory:
+ """This class is used by the CatalogManager to create new parsers as they
+ are needed."""
+
+ def __init__(self,error_lang=None):
+ self.error_lang=error_lang
+
+ def make_parser(self,sysid):
+ return CatalogParser(self.error_lang)
+
+# --- Empty catalog application class
+
+class CatalogApp:
+
+ def handle_public(self,pubid,sysid):
+ pass
+
+ def handle_delegate(self,prefix,sysid):
+ pass
+
+ def handle_document(self,sysid):
+ pass
+
+ def handle_system(self,sysid1,sysid2):
+ pass
+
+ def handle_base(self,sysid):
+ pass
+
+ def handle_catalog(self,sysid):
+ pass
+
+ def handle_override(self,yesno):
+ pass
+
+# --- Abstract catalog parser with common functionality
+
+class AbstrCatalogParser:
+ "Abstract catalog parser with functionality needed in all such parsers."
+
+ def __init__(self,error_lang=None):
+ self.app=CatalogApp()
+ self.err=xmlapp.ErrorHandler(None)
+ self.error_lang=error_lang
+
+ def set_application(self,app):
+ self.app=app
+
+ def set_error_handler(self,err):
+ self.err=err
+
+# --- The catalog file parser (SGML Open Catalogs)
+
+class CatalogParser(AbstrCatalogParser,xmlutils.EntityParser):
+ "A parser for SGML Open catalog files."
+
+ def __init__(self,error_lang=None):
+ AbstrCatalogParser.__init__(self,error_lang)
+ xmlutils.EntityParser.__init__(self)
+
+ # p=pubid (or prefix)
+ # s=sysid (to be resolved)
+ # o=other
+ self.entry_hash={ "PUBLIC": ("p","s"), "DELEGATE": ("p","s"),
+ "CATALOG": ("s"), "DOCUMENT": ("s"),
+ "BASE": ("o"), "SYSTEM": ("o","s"),
+ "OVERRIDE": ("o") }
+
+ def parseStart(self):
+ if self.error_lang:
+ self.set_error_language(self.error_lang)
+
+ def do_parse(self):
+ try:
+ while self.pos+1<self.datasize:
+ prepos=self.pos
+
+ self.skip_stuff()
+ if self.pos+1>=self.datasize:
+ break
+
+ entryname=self.find_reg(xmlutils.reg_ws)
+ if not self.entry_hash.has_key(entryname):
+ self.report_error(5100,(entryname,))
+ else:
+ self.parse_entry(entryname,self.entry_hash[entryname])
+
+ except xmlutils.OutOfDataException,e:
+ if self.final:
+ raise sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]
+ #raise e
+ else:
+ self.pos=prepos # Didn't complete the construct
+
+ def parse_arg(self):
+ if self.now_at('"'):
+ delim='"'
+ elif self.now_at("'"):
+ delim="'"
+ else:
+ return self.find_reg(xmlutils.reg_ws,0)
+
+ return self.scan_to(delim)
+
+ def skip_stuff(self):
+ "Skips whitespace and comments between items."
+ while 1:
+ self.skip_ws()
+ if self.now_at("--"):
+ self.scan_to("--")
+ else:
+ break
+
+ def parse_entry(self,name,args):
+ arglist=[]
+ for arg in args:
+ self.skip_stuff()
+ arglist.append(self.parse_arg())
+
+ if name=="PUBLIC":
+ self.app.handle_public(arglist[0],arglist[1])
+ elif name=="CATALOG":
+ self.app.handle_catalog(arglist[0])
+ elif name=="DELEGATE":
+ self.app.handle_delegate(arglist[0],arglist[1])
+ elif name=="BASE":
+ self.app.handle_base(arglist[0])
+ elif name=="DOCUMENT":
+ self.app.handle_document(arglist[0])
+ elif name=="SYSTEM":
+ self.app.handle_system(arglist[0],arglist[1])
+ elif name=="OVERRIDE":
+ self.app.handle_override(arglist[0])
+
+# --- A catalog file manager
+
+class CatalogManager(CatalogApp):
+
+ def __init__(self,error_handler=None):
+ self.__public={}
+ self.__system={}
+ self.__delegations=[]
+ self.__document=None
+ self.__base=None
+
+ # Keeps track of sysid base even if we recurse into other catalogs
+ self.__catalog_stack=[]
+
+ if error_handler==None:
+ self.err=xmlapp.ErrorHandler(None)
+ else:
+ self.err=error_handler
+ self.parser_fact=CatParserFactory()
+ self.parser=None
+
+ # --- application interface
+
+ def set_error_handler(self,err):
+ self.err=err
+
+ def set_parser_factory(self,parser_fact):
+ self.parser_fact=parser_fact
+
+ def parse_catalog(self,sysid):
+ self.__catalog_stack.append((self.__base,))
+ self.__base=sysid
+
+ self.parser=self.parser_fact.make_parser(sysid)
+ self.parser.set_error_handler(self.err)
+ self.parser.set_application(self)
+ self.parser.parse_resource(sysid)
+
+ self.__base=self.__catalog_stack[-1][0]
+ del self.__catalog_stack[-1]
+
+ def report(self,out=sys.stdout):
+ out.write("Document sysid: %s\n" % self.__document)
+
+ out.write("FPI mappings:\n")
+ for it in self.__public.items():
+ out.write(" %s -> %s\n" % it)
+
+ out.write("Sysid mappings:\n")
+ for it in self.__system.items():
+ out.write(" %s -> %s\n" % it)
+
+ out.write("Delegates:\n")
+ for (prefix,cat_man) in self.__delegations:
+ out.write("---PREFIX MAPPER: %s\n" % prefix)
+ cat_man.report(out)
+ out.write("---EOPM\n")
+
+ # --- parse events
+
+ def handle_base(self,newbase):
+ self.__base=newbase
+
+ def handle_catalog(self,sysid):
+ self.parse_catalog(self.__resolve_sysid(sysid))
+
+ def handle_public(self,pubid,sysid):
+ self.__public[pubid]=self.__resolve_sysid(sysid)
+
+ def handle_system(self,sysid1,sysid2):
+ self.__system[self.__resolve_sysid(sysid1)]=\
+ self.__resolve_sysid(sysid2)
+
+ def handle_delegate(self,prefix,sysid):
+ catalog_manager=CatalogManager()
+ catalog_manager.set_parser_factory(self.parser_fact)
+ catalog_manager.parse_catalog(self.__resolve_sysid(sysid))
+ self.__delegations.append((prefix,catalog_manager))
+
+ def handle_document(self,sysid):
+ self.__document=self.__resolve_sysid(sysid)
+
+ # --- client services
+
+ def get_public_ids(self):
+ """Returns a list of all declared public indentifiers in this catalog
+ and delegates."""
+ list=self.__public.keys()
+ for delegate in self.__delegations:
+ list=list+delegate.get_public_ids()
+
+ return list
+
+ def get_document_sysid(self):
+ return self.__document
+
+ def remap_sysid(self,sysid):
+ try:
+ return self.__system[sysid]
+ except KeyError:
+ return sysid
+
+ def resolve_sysid(self,pubid,sysid):
+ if pubid!=None:
+ resolved=0
+ for (prefix,catalog) in self.__delegations:
+ if prefix==pubid[:len(prefix)]:
+ sysid=catalog.resolve_sysid(pubid,sysid)
+ resolved=1
+ break
+
+ if not resolved:
+ try:
+ sysid=self.__public[pubid]
+ except KeyError,e:
+ self.err.error("Unknown public identifier '%s'" % pubid)
+
+ return sysid
+ else:
+ self.remap_sysid(sysid)
+
+ # --- internal methods
+
+ def __resolve_sysid(self,sysid):
+ return xmlutils.join_sysids(self.__base,sysid)
+
+# --- An xmlproc catalog client
+
+class xmlproc_catalog:
+
+ def __init__(self,sysid,pf,error_handler=None):
+ self.catalog=CatalogManager(error_handler)
+ self.catalog.set_parser_factory(pf)
+ self.catalog.parse_catalog(sysid)
+
+ def get_document_sysid(self):
+ return self.catalog.get_document_sysid()
+
+ def resolve_pe_pubid(self,pubid,sysid):
+ if pubid==None:
+ return self.catalog.remap_sysid(sysid)
+ else:
+ return self.catalog.resolve_sysid(pubid,sysid)
+
+ def resolve_doctype_pubid(self,pubid,sysid):
+ if pubid==None:
+ return self.catalog.remap_sysid(sysid)
+ else:
+ return self.catalog.resolve_sysid(pubid,sysid)
+
+ def resolve_entity_pubid(self,pubid,sysid):
+ if pubid==None:
+ return self.catalog.remap_sysid(sysid)
+ else:
+ return self.catalog.resolve_sysid(pubid,sysid)
+
+# --- A SAX catalog client
+
+class SAX_catalog:
+
+ def __init__(self,sysid,pf):
+ self.catalog=CatalogManager()
+ self.catalog.set_parser_factory(pf)
+ self.catalog.parse_catalog(sysid)
+
+ def resolveEntity(self,pubid,sysid):
+ return self.catalog.resolve_sysid(pubid,sysid)
diff --git a/lib/jython/Lib/xml/parsers/xmlproc/charconv.py b/lib/jython/Lib/xml/parsers/xmlproc/charconv.py new file mode 100644 index 000000000..18a868215 --- /dev/null +++ b/lib/jython/Lib/xml/parsers/xmlproc/charconv.py @@ -0,0 +1,203 @@ +
+# Some experiments in adding character encoding conversions to xmlproc.
+# This module is not yet used by the released xmlproc, since I'm awaiting
+# a reorganization.
+#
+# $Id: charconv.py,v 1.5 2000/09/26 14:43:10 loewis Exp $
+
+import string
+
+# --- Conversion tables
+
+# CP 850 to ISO 8859-1
+
+# First element is no. 128, second 129 ...
+# The non-ISO characters, such as <empty set>, are mapped to non-ISO chars
+# 127-145 and 147-159 in the order they appear in CP 850. Since there are
+# more non-ISO chars than there is room for in these intervals, some of
+# the last chars are also mapped to 159.
+
+cp850_iso=[199,252,233,226,228,224,229,231,234,235,232,239,238,236,196,197,
+ 201,230,198,244,246,242,251,249,255,246,220,248,163,127,215,128,
+ 225,237,243,250,241,209,170,186,191,174,172,189,188,161,171,187,
+ 129,130,131,132,133,193,194,192,169,134,135,136,137,162,165,138,
+ 139,140,141,142,143,144,227,195,145,147,148,149,150,151,152,164,
+ 240,208,202,203,200,153,205,206,207,154,155,156,157,166,204,158,
+ 211,223,212,210,245,213,181,222,254,218,219,217,253,221,175,180,
+ 173,177,159,190,182,167,247,184,176,168,159,185,179,178,159,160]
+
+cp850_iso_tbl=""
+for ix in range(128):
+ cp850_iso_tbl=cp850_iso_tbl+chr(ix)
+for chno in cp850_iso:
+ cp850_iso_tbl=cp850_iso_tbl+chr(chno)
+
+# ISO 8859-1 to CP 850
+
+iso_cp850=[0]*256
+for ix in range(256):
+ iso_cp850[ord(cp850_iso_tbl[ix])]=ix
+
+iso_cp850_tbl=""
+for chno in iso_cp850:
+ iso_cp850_tbl=iso_cp850_tbl+chr(chno)
+
+# Windows CP 1252 to ISO 8859-1
+# Maps characters 128-159, 63 means non-mappable, 127 means unused in 1252
+# Does a fuzzy transform (ndash and mdash both mapped to -, and so on)
+
+cp1252_iso=[127,127,44,63,63,95,63,63,94,63,63,60,198,127,127,127,127,39,39,
+ 34,34,183,45,45,126,63,63,62,230,127,127,127]
+
+cp1252_iso_tbl=""
+for char in map(chr,range(128)+cp1252_iso+range(160,256)):
+ cp1252_iso_tbl=cp1252_iso_tbl+char
+
+# --- Conversion functions
+
+def utf8_to_iso8859(data):
+ out=""
+
+ ix=0
+ for ix in range(len(data)):
+ chn=ord(data[ix])
+ if chn & 224==192: # 110xxxxx
+ out=out+chr( ((chn & 3) << 6) + (ord(data[ix+1]) & 63))
+ elif chn & 128==0: # 0xxxxxxx
+ out=out+data[ix]
+
+ return out
+
+def iso8859_to_utf8(data):
+ out=""
+
+ for ch in data:
+ if ord(ch)<128:
+ out=out+ch
+ else:
+ chno=ord(ch)
+ out=out+chr(192+((chno & 192)>>6))+chr(128+(chno & 63))
+
+ return out
+
+def cp850_to_iso8859(data):
+ return string.translate(data,cp850_iso_tbl)
+
+def iso8859_to_cp850(data):
+ return string.translate(data,iso_cp850_tbl)
+
+def id_conv(data):
+ return data
+
+def cp850_to_utf8(data):
+ return iso8859_to_utf8(cp850_to_iso8859(data))
+
+def utf8_to_cp850(data):
+ return iso8859_to_cp850(utf8_to_iso8859(data))
+
+def cp1252_to_iso8859(data):
+ return string.translate(data,cp1252_iso_tbl)
+
+# --- Conversion function database
+
+class ConverterDatabase:
+ """This class knows about all registered converting functions, and can be
+ queried for information about converters."""
+
+ def __init__(self):
+ self.__map={}
+ self.__alias_map={}
+
+ def add_alias(self,canonical,alias):
+ "Adds an alias for a character set."
+ self.__alias_map[string.lower(alias)]=string.lower(canonical)
+
+ def can_convert(self,from_encoding,to_encoding):
+ """Returns true if converters to from from_encoding to to_encoding are
+ known. Encoding names follow the syntax specified by the XML rec."""
+ from_encoding=self._canonize_name(from_encoding)
+ to_encoding=self._canonize_name(to_encoding)
+
+ if from_encoding==to_encoding:
+ return 1
+
+ try:
+ return self.__map[from_encoding].has_key(to_encoding)
+ except KeyError:
+ return 0
+
+ def get_converter(self,from_encoding,to_encoding):
+ """Returns a converter function that converts from the character
+ encoding from_encoding to to_encoding. A KeyError will be thrown
+ if no converter is known."""
+ from_encoding=self._canonize_name(from_encoding)
+ to_encoding=self._canonize_name(to_encoding)
+
+ if from_encoding==to_encoding:
+ return id_conv
+ else:
+ return self.__map[from_encoding][to_encoding]
+
+ def add_converter(self,from_encoding,to_encoding,converter):
+ from_encoding=self._canonize_name(from_encoding)
+ to_encoding=self._canonize_name(to_encoding)
+
+ if not self.__map.has_key(from_encoding):
+ self.__map[from_encoding]={}
+
+ self.__map[from_encoding][to_encoding]=converter
+
+ def _canonize_name(self,name):
+ "Returns the canonical form of a charset name."
+ name=string.lower(name)
+ if self.__alias_map.has_key(name):
+ return self.__alias_map[name]
+ else:
+ return name
+
+# --- Globals
+
+convdb=ConverterDatabase()
+convdb.add_alias("US-ASCII","ANSI_X3.4-1968")
+convdb.add_alias("US-ASCII","iso-ir-6")
+convdb.add_alias("US-ASCII","ANSI_X3.4-1986")
+convdb.add_alias("US-ASCII","ISO_646.irv:1991")
+convdb.add_alias("US-ASCII","ASCII")
+convdb.add_alias("US-ASCII","ISO646-US")
+convdb.add_alias("US-ASCII","us")
+convdb.add_alias("US-ASCII","IBM367")
+convdb.add_alias("US-ASCII","cp367")
+convdb.add_alias("US-ASCII","csASCII")
+
+convdb.add_alias("ISO-8859-1","ISO_8859-1:1987")
+convdb.add_alias("ISO-8859-1","iso-ir-100")
+convdb.add_alias("ISO-8859-1","ISO_8859-1")
+convdb.add_alias("ISO-8859-1","latin1")
+convdb.add_alias("ISO-8859-1","l1")
+convdb.add_alias("ISO-8859-1","IBM819")
+convdb.add_alias("ISO-8859-1","CP819")
+convdb.add_alias("ISO-8859-1","csISOLatin1")
+
+convdb.add_alias("IBM850","cp850")
+convdb.add_alias("IBM850","850")
+convdb.add_alias("IBM850","csPC850Multilingual")
+
+# converters (foo -> foo case not needed, handled automatically)
+
+convdb.add_converter("IBM850","ISO-8859-1",cp850_to_iso8859)
+convdb.add_converter("US-ASCII","ISO-8859-1",id_conv)
+convdb.add_converter("windows-1252","ISO-8859-1",cp1252_to_iso8859)
+
+convdb.add_converter("ISO-8859-1","IBM850",iso8859_to_cp850)
+convdb.add_converter("US-ASCII","IBM850",id_conv)
+
+convdb.add_converter("ISO-8859-1","WINDOWS-1252",id_conv)
+
+convdb.add_converter("US-ASCII","UTF-8",id_conv)
+
+# UTF-8 stuff disabled due to total lack of speed
+
+# convdb.add_converter("UTF-8","ISO-8859-1",utf8_to_iso8859)
+# convdb.add_converter("ISO-8859-1","UTF-8",iso8859_to_utf8)
+# convdb.add_converter("UTF-8","IBM850",utf8_to_cp850)
+# convdb.add_converter("IBM850","UTF-8",cp850_to_utf8)
diff --git a/lib/jython/Lib/xml/parsers/xmlproc/dtdparser.py b/lib/jython/Lib/xml/parsers/xmlproc/dtdparser.py new file mode 100644 index 000000000..9485ddd2f --- /dev/null +++ b/lib/jython/Lib/xml/parsers/xmlproc/dtdparser.py @@ -0,0 +1,733 @@ +"""
+This module contains a DTD parser that reports DTD parse events to a listener.
+Used by xmlproc to parse DTDs, but can be used for other purposes as well.
+
+$Id: dtdparser.py,v 1.7 2000/12/19 03:36:28 mikeolson Exp $
+"""
+
+from types import StringType
+import string
+
+string_find = string.find # optimization
+
+from xmlutils import *
+from xmldtd import *
+
+# ==============================
+# A DTD parser
+# ==============================
+
+class DTDParser(XMLCommonParser):
+ "A parser for XML DTDs, both internal and external."
+
+ # --- LOW-LEVEL SCANNING METHODS
+ # Redefined here with extra checking for parameter entity processing
+
+ def find_reg(self,regexp,required=1):
+ oldpos=self.pos
+ mo=regexp.search(self.data,self.pos)
+ if mo==None:
+ if self.final and not required:
+ self.pos=len(self.data) # Just moved to the end
+ return self.data[oldpos:]
+
+ if self.in_peref:
+ self.pop_entity()
+ self.in_peref=0
+ self._skip_ws()
+ return self.find_reg(regexp,required)
+
+ raise OutOfDataException()
+
+ self.pos=mo.start(0)
+ return self.data[oldpos:self.pos]
+
+ def scan_to(self,target):
+ new_pos=string_find(self.data,target,self.pos)
+ if new_pos==-1:
+ if self.in_peref:
+ self.pop_entity()
+ self.in_peref=0
+ self._skip_ws()
+ return self.scan_to(target)
+ raise OutOfDataException()
+ res=self.data[self.pos:new_pos]
+ self.pos=new_pos+len(target)
+ return res
+
+ def get_index(self,target):
+ new_pos=string_find(self.data,target,self.pos)
+ if new_pos==-1:
+ if self.in_peref:
+ self.pop_entity()
+ self.in_peref=0
+ self._skip_ws()
+ return self.get_index(target)
+ raise OutOfDataException()
+ return new_pos
+
+ def test_str(self,str):
+ if self.datasize-self.pos<len(str) and not self.final:
+ if self.in_peref:
+ self.pop_entity()
+ self.in_peref=0
+ self._skip_ws()
+ return self.test_str(str)
+ raise OutOfDataException()
+ return self.data[self.pos:self.pos+len(str)]==str
+
+ def now_at(self,test_str):
+ if self.datasize-self.pos<len(test_str) and not self.final:
+ if self.in_peref:
+ self.pop_entity()
+ self.in_peref=0
+ self._skip_ws()
+ return self.now_at(test_str)
+ raise OutOfDataException()
+
+ if self.data[self.pos:self.pos+len(test_str)]==test_str:
+ self.pos=self.pos+len(test_str)
+ return 1
+ else:
+ return 0
+
+ def _skip_ws(self,necessary=0):
+ start=self.pos
+
+ try:
+ while self.data[self.pos] in whitespace:
+ self.pos=self.pos+1
+
+ if necessary and self.pos==start and self.data[self.pos]!="%":
+ self.report_error(3002)
+ except IndexError:
+ if self.in_peref:
+ self.pop_entity()
+ self.in_peref=0
+ self._skip_ws()
+ return
+
+ if necessary and start==self.pos:
+ if self.final:
+ self.report_error(3002)
+ else:
+ raise OutOfDataException()
+
+ def skip_ws(self,necessary=0):
+ self._skip_ws(necessary)
+ if not self.internal:
+ try:
+ if not self.now_at("%"):
+ return
+ except OutOfDataException:
+ return
+
+ name=self._get_name()
+
+ if not self.now_at(";"):
+ self.report_error(3005,";")
+
+ try:
+ ent=self.dtd.resolve_pe(name)
+ except KeyError,e:
+ self.report_error(3038,name)
+ return
+
+ if ent.is_internal():
+ self.in_peref=1
+ self.push_entity(self.get_current_sysid(),ent.value)
+ self.final=1 # Reset by pop_ent, needed for buffer handling
+ else:
+ self.report_error(4003)
+
+ # At this point we need to try again, since the entity we just
+ # tried may have contained only whitespace (or nothing at all).
+ # Using self._skip_ws() makes us fail when an empty PE is followed
+ # by a non-empty one. (DocBook has examples of this.)
+ self.skip_ws()
+
+ def test_reg(self,regexp):
+ if self.pos>self.datasize-5 and not self.final:
+ if self.in_peref:
+ self.pop_entity()
+ self.in_peref=0
+ self._skip_ws()
+ return self.test_reg(regexp)
+ raise OutOfDataException()
+
+ return regexp.match(self.data,self.pos)!=None
+
+ def get_match(self,regexp):
+ if self.pos>self.datasize-5 and not self.final:
+ if self.in_peref:
+ self.pop_entity()
+ self.in_peref=0
+ self._skip_ws()
+ return self.get_match(regexp)
+ raise OutOfDataException()
+
+ ent=regexp.match(self.data,self.pos)
+ if ent==None:
+ self.report_error(reg2code[regexp.pattern])
+ return ""
+
+ end=ent.end(0) # Speeds us up slightly
+ if end==self.datasize:
+ if self.in_peref:
+ self.pop_entity()
+ self.in_peref=0
+ #self._skip_ws()
+ return ent.group(0)
+ raise OutOfDataException()
+
+ self.pos=end
+ return ent.group(0)
+
+ # --- DTD Parser proper
+
+ def __init__(self):
+ EntityParser.__init__(self)
+ self.internal=0
+ self.seen_xmldecl=0
+ self.dtd=DTDConsumerPE() # Keeps track of PE info
+ self.dtd_consumer=self.dtd # Where all events go
+ self.in_peref=0
+ self.ignores_entered=0
+ self.includes_entered=0
+ self.own_ent_stack=[] # Keeps includes_entered
+
+ def reset(self):
+ EntityParser.reset(self)
+ if hasattr(self,"dtd"):
+ self.dtd.reset()
+
+ self.internal=0
+ self.seen_xmldecl=0
+ self.in_peref=0
+ self.ignores_entered=0
+ self.includes_entered=0
+ self.own_ent_stack=[] # Keeps includes_entered
+ self.dtd_start_called = 0 # Set to 1 if parsing external subset from
+ # xmlproc.py (which has called dtd_start...)
+
+ def parseStart(self):
+ if not self.dtd_start_called:
+ self.dtd_consumer.dtd_start()
+
+ def parseEnd(self):
+ self.dtd_consumer.dtd_end()
+
+ def set_dtd_consumer(self,dtd):
+ "Tells the parser where to send DTD information."
+ self.dtd_consumer=dtd
+
+ def set_dtd_object(self,dtd):
+ """Tells the parser where to mirror PE information (in addition to
+ what goes to the DTD consumer and where to get PE information."""
+ self.dtd=dtd
+
+ def set_internal(self,yesno):
+ "Tells the parser whether the DTD is internal or external."
+ self.internal=yesno
+
+ def deref(self):
+ "Removes circular references."
+ self.ent = self.dtd_consumer = self.dtd = self.app = self.err = None
+
+ def do_parse(self):
+ "Does the actual parsing."
+
+ try:
+ prepos=self.pos
+
+ if self.ignores_entered>0:
+ self.parse_ignored_data()
+
+ self._skip_ws()
+ while self.pos<self.datasize:
+ if self.now_at("<!ELEMENT"):
+ self.parse_elem_type()
+ elif self.now_at("<!ENTITY"):
+ self.parse_entity()
+ elif self.now_at("<!ATTLIST"):
+ self.parse_attlist()
+ elif self.now_at("<!NOTATION"):
+ self.parse_notation()
+ elif self.test_reg(reg_pe_ref):
+ self.parse_pe_ref()
+ elif self.now_at("<?"):
+ self.parse_pi(self.dtd_consumer)
+ elif self.now_at("<!--"):
+ self.parse_comment(self.dtd_consumer)
+ elif self.now_at("<!["):
+ self.parse_conditional()
+ elif self.now_at("]]>") and self.includes_entered>0:
+ self.includes_entered=self.includes_entered-1
+ else:
+ self.report_error(3013)
+ self.scan_to(">")
+
+ prepos=self.pos
+ self._skip_ws()
+
+ if self.final and self.includes_entered>0:
+ self.report_error(3043)
+
+ except OutOfDataException,e:
+ if self.final:
+ raise e
+ else:
+ self.pos=prepos
+ except IndexError,e:
+ if self.final:
+ raise OutOfDataException()
+ else:
+ self.pos=prepos
+
+ def parse_entity(self):
+ "Parses an entity declaration."
+
+ EntityParser.skip_ws(self,1) # No PE refs allowed here
+ if self.now_at("%"):
+ pedecl=1
+ EntityParser.skip_ws(self,1) # No PE refs allowed here
+ else:
+ pedecl=0
+
+ ent_name=self._get_name()
+ self.skip_ws(1)
+
+ (pub_id,sys_id)=self.parse_external_id(0)
+
+ if sys_id==None:
+ internal=1
+ ent_val=self.parse_ent_repltext()
+ else:
+ internal=0
+
+ if self.now_at("NDATA"):
+ self.report_error(3002)
+ else:
+ self.skip_ws()
+
+ if not internal and self.now_at("NDATA"):
+ # Parsing the optional NDataDecl
+ if pedecl:
+ self.report_error(3035)
+ self.skip_ws()
+
+ ndata=self._get_name()
+ self.skip_ws()
+ else:
+ ndata=""
+
+ if not self.now_at(">"):
+ self.report_error(3005,">")
+
+ if pedecl:
+ # These are echoed to self.dtd so we remember this stuff
+ if internal:
+ self.dtd_consumer.new_parameter_entity(ent_name,ent_val)
+ if self.dtd!=self.dtd_consumer:
+ self.dtd.new_parameter_entity(ent_name,ent_val)
+ else:
+ self.dtd_consumer.new_external_pe(ent_name,pub_id,sys_id)
+ if self.dtd!=self.dtd_consumer:
+ self.dtd.new_external_pe(ent_name,pub_id,sys_id)
+ else:
+ if internal:
+ self.dtd_consumer.new_general_entity(ent_name,ent_val)
+ else:
+ self.dtd_consumer.new_external_entity(ent_name,pub_id,sys_id,ndata)
+
+ def parse_ent_repltext(self):
+ """Parses an entity replacement text and resolves all character
+ entity and parameter entity references in it."""
+
+ val=""
+ if self.now_at('"'):
+ delim='"'
+ elif self.now_at("'"):
+ delim="'"
+ else:
+ self.report_error(3004,("'","\""))
+ self.scan_to(">")
+ return
+
+ return self.parse_ent_litval(self.scan_to(delim))
+
+ def parse_ent_litval(self,litval):
+ pos=0
+ val=""
+
+ while 1:
+ res=reg_litval_stop.search(litval,pos)
+
+ if res==None:
+ break
+
+ val=val+litval[pos:res.start(0)]
+ pos=res.start(0)
+
+ if litval[pos:pos+2]=="&#":
+ endpos=string_find(litval,";",pos)
+ if endpos==-1:
+ self.report_error(3005,";")
+ break
+
+ if litval[pos+2]=="x":
+ digs=unhex(litval[pos+3:endpos])
+ else:
+ digs=int(litval[pos+2:endpos])
+
+ if not (digs==9 or digs==10 or digs==13 or \
+ (digs>=32 and digs<=255)):
+ if digs>255:
+ self.report_error(1005,digs)
+ else:
+ self.report_error(3018,digs)
+ else:
+ val=val+chr(digs)
+
+ pos=endpos+1
+ elif litval[pos]=="%":
+ endpos=string_find(litval,";",pos)
+ if endpos==-1:
+ self.report_error(3005,";")
+ break
+
+ name=litval[pos+1:endpos]
+ try:
+ ent=self.dtd.resolve_pe(name)
+ if ent.is_internal():
+ val=val+self.parse_ent_litval(ent.value)
+ else:
+ self.report_error(3037) # FIXME: Easily solved now...?
+ except KeyError,e:
+ self.report_error(3038,name)
+
+ pos=endpos+1
+ else:
+ self.report_error(4001)
+ break
+
+ return val+litval[pos:]
+
+ def parse_notation(self):
+ "Parses a notation declaration."
+ self.skip_ws(1)
+ name=self._get_name()
+ self.skip_ws(1)
+
+ (pubid,sysid)=self.parse_external_id(1,0)
+ self.skip_ws()
+ if not self.now_at(">"):
+ self.report_error(3005,">")
+
+ self.dtd_consumer.new_notation(name,pubid,sysid)
+
+ def parse_pe_ref(self):
+ "Parses a reference to a parameter entity."
+ name=self.get_match(reg_pe_ref)[1:-1]
+
+ try:
+ ent=self.dtd.resolve_pe(name)
+ except KeyError,e:
+ self.report_error(3038,name)
+ return
+
+ if ent.is_internal():
+ self.push_entity(self.get_current_sysid(),ent.value)
+ self.do_parse()
+ self.pop_entity()
+ else:
+ sysid=self.pubres.resolve_pe_pubid(ent.get_pubid(),
+ ent.get_sysid())
+ int=self.internal
+ self.set_internal(0)
+ try:
+ self.open_entity(sysid) # Does parsing and popping
+ finally:
+ self.set_internal(int)
+
+ def parse_attlist(self):
+ "Parses an attribute list declaration."
+
+ self.skip_ws(1)
+ elem=self._get_name()
+ self.skip_ws(1)
+
+ while not self.test_str(">"):
+ attr=self._get_name()
+ self.skip_ws(1)
+
+ if self.test_reg(reg_attr_type):
+ a_type=self.get_match(reg_attr_type)
+ elif self.now_at("NOTATION"):
+ self.skip_ws(1)
+ a_type=("NOTATION",self.__parse_list(reg_name,"|"))
+ elif self.now_at("("):
+ self.pos=self.pos-1 # Does not expect '(' to be skipped
+ a_type=self.__parse_list(reg_nmtoken,"|")
+
+ tokens={}
+ for token in a_type:
+ if tokens.has_key(token):
+ self.report_error(3044,(token,))
+ else:
+ tokens[token]=1
+ else:
+ self.report_error(3039)
+ self.scan_to(">")
+ return
+
+ self.skip_ws(1)
+
+ if self.test_str("\"") or self.test_str("'"):
+ a_decl="#DEFAULT"
+ a_def=self.parse_ent_repltext()
+ elif self.now_at("#IMPLIED"):
+ a_decl="#IMPLIED"
+ a_def=None
+ elif self.now_at("#REQUIRED"):
+ a_decl="#REQUIRED"
+ a_def=None
+ elif self.now_at("#FIXED"):
+ self.skip_ws(1)
+ a_decl="#FIXED"
+ a_def=self.parse_ent_repltext()
+ else:
+ self.report_error(3909)
+ a_decl=None
+ a_def=None
+
+ self.skip_ws()
+ self.dtd_consumer.new_attribute(elem,attr,a_type,a_decl,a_def)
+
+ self.pos=self.pos+1 # Skipping the '>'
+
+ def parse_elem_type(self):
+ "Parses an element type declaration."
+
+ self.skip_ws(1)
+ #elem_name=self.get_match(reg_name)
+ elem_name=self._get_name()
+ self.skip_ws(1)
+
+ # content-spec
+ if self.now_at("EMPTY"):
+ elem_cont="EMPTY"
+ elif self.now_at("ANY"):
+ elem_cont="ANY"
+ elif self.now_at("("):
+ elem_cont=self._parse_content_model()
+ else:
+ self.report_error(3004,("EMPTY, ANY","("))
+ elem_cont="ANY" # Just so things don't fall apart downstream
+
+ self.skip_ws()
+ if not self.now_at(">"):
+ self.report_error(3005,">")
+
+ self.dtd_consumer.new_element_type(elem_name,elem_cont)
+
+ def _parse_content_model(self,level=0):
+ """Parses the content model of an element type declaration. Level
+ tells the function if we are on the top level (=0) or not (=1).
+ The '(' has just been passed over, we read past the ')'. Returns
+ a tuple (separator, contents, modifier), where content consists
+ of (cp, modifier) tuples and cp can be a new content model tuple."""
+
+ self.skip_ws()
+
+ # Creates a content list with separator first
+ cont_list=[]
+ sep=""
+
+ if self.now_at("#PCDATA") and level==0:
+ return self.parse_mixed_content_model()
+
+ while 1:
+ self.skip_ws()
+ if self.now_at("("):
+ cp=self._parse_content_model(1)
+ else:
+ cp=self._get_name()
+
+ if self.test_str("?") or self.test_str("*") or self.test_str("+"):
+ mod=self.data[self.pos]
+ self.pos=self.pos+1
+ else:
+ mod=""
+
+ if type(cp)==StringType:
+ cont_list.append((cp,mod))
+ else:
+ cont_list.append(cp)
+
+ self.skip_ws()
+ if self.now_at(")"):
+ break
+
+ if sep=="":
+ if self.test_str("|") or self.test_str(","):
+ sep=self.data[self.pos]
+ else:
+ self.report_error(3004,("'|'",","))
+ self.pos=self.pos+1
+ else:
+ if not self.now_at(sep):
+ self.report_error(3040)
+ self.scan_to(")")
+
+ if self.test_str("+") or self.test_str("?") or self.test_str("*"):
+ mod=self.data[self.pos]
+ self.pos=self.pos+1
+ else:
+ mod=""
+
+ return (sep,cont_list,mod)
+
+ def parse_mixed_content_model(self):
+ "Parses mixed content models. Ie: ones containing #PCDATA."
+
+ cont_list=[("#PCDATA","")]
+ sep=""
+ mod=""
+
+ while 1:
+ try:
+ self.skip_ws()
+ except OutOfDataException,e:
+ raise e
+
+ if self.now_at("|"):
+ sep="|"
+ elif self.now_at(")"):
+ break
+ else:
+ self.report_error(3005,"|")
+ self.scan_to(">")
+
+ self.skip_ws()
+ cont_list.append((self.get_match(reg_name),""))
+
+ if self.now_at("*"):
+ mod="*"
+ elif sep=="|":
+ self.report_error(3005,"*")
+
+ return (sep,cont_list,mod)
+
+ def parse_conditional(self):
+ "Parses a conditional section."
+ if self.internal:
+ self.report_error(3041)
+ ignore=1
+ self.scan_to("]]>")
+ else:
+ self.skip_ws()
+
+ if self.now_at("IGNORE"):
+ self.ignores_entered=1
+ self.skip_ws()
+ if not self.now_at("["):
+ self.report_error(3005,"[")
+ self.parse_ignored_data()
+ return
+
+ if not self.now_at("INCLUDE"):
+ self.report_error(3004,("'IGNORE'","INCLUDE"))
+ self.scan_to("[")
+ self.includes_entered=self.includes_entered+1
+
+ self.skip_ws()
+ if not self.now_at("["):
+ self.report_error(3005,"[")
+
+ # Doing an extra skip_ws and waiting until we get here
+ # before increasing the include count, to avoid increasing
+ # the count inside a PE, where it would be forgotten after pop.
+ self.skip_ws()
+ self.includes_entered=self.includes_entered+1
+
+ def parse_ignored_data(self):
+ try:
+ counter=self.ignores_entered
+ while counter:
+ self.find_reg(reg_cond_sect)
+ if self.now_at("]]>"):
+ counter=counter-1
+ else:
+ counter=counter+1
+ self.pos=self.pos+3
+
+ except OutOfDataException,e:
+ if self.final:
+ self.report_error(3043)
+
+ self.ignores_entered=counter
+ self.data=""
+ self.pos=0
+ self.datasize=0
+ raise e
+
+ self.ignores_entered=0
+
+ def __parse_list(self, elem_regexp, separator):
+ "Parses a '(' S? elem_regexp S? separator ... ')' list. (Internal.)"
+
+ list=[]
+ self.skip_ws()
+ if not self.now_at("("):
+ self.report_error(3005,"(")
+
+ while 1:
+ self.skip_ws()
+ list.append(self.get_match(elem_regexp))
+ self.skip_ws()
+ if self.now_at(")"):
+ break
+ elif not self.now_at(separator):
+ self.report_error(3004,("')'",separator))
+ break
+
+ return list
+
+ def is_external(self):
+ return not self.internal
+
+ # --- Internal methods
+
+ def _push_ent_stack(self,name="None"):
+ EntityParser._push_ent_stack(self,name)
+ self.own_ent_stack.append(self.includes_entered)
+ self.includes_entered=0
+
+ def _pop_ent_stack(self):
+ EntityParser._pop_ent_stack(self)
+ self.includes_entered=self.own_ent_stack[-1]
+ del self.own_ent_stack[-1]
+
+# --- Minimal DTD consumer
+
+class DTDConsumerPE(DTDConsumer):
+
+ def __init__(self):
+ DTDConsumer.__init__(self,None)
+ self.param_ents={}
+ self.used_notations = {}
+
+ def new_parameter_entity(self,name,val):
+ if not self.param_ents.has_key(name): #Keep first decl
+ self.param_ents[name]=InternalEntity(name,val)
+
+ def new_external_pe(self,name,pubid,sysid):
+ if not self.param_ents.has_key(name): # Keep first decl
+ self.param_ents[name]=ExternalEntity(name,pubid,sysid,"")
+
+ def resolve_pe(self,name):
+ return self.param_ents[name]
+
+ def reset(self):
+ self.param_ents={}
diff --git a/lib/jython/Lib/xml/parsers/xmlproc/errors.py b/lib/jython/Lib/xml/parsers/xmlproc/errors.py new file mode 100644 index 000000000..95c15cecf --- /dev/null +++ b/lib/jython/Lib/xml/parsers/xmlproc/errors.py @@ -0,0 +1,276 @@ +
+# This file contains the lists of error messages used by xmlproc
+
+import string
+
+# The interface to the outside world
+
+error_lists={} # The hash of errors
+
+def add_error_list(language,list):
+ error_lists[string.lower(language)]=list
+
+def get_error_list(language):
+ return error_lists[string.lower(language)]
+
+def get_language_list():
+ return error_lists.keys()
+
+# Errors in English
+
+english={
+
+ # --- Warnings: 1000-1999
+ 1000: "Undeclared namespace prefix '%s'",
+ 1002: "Unsupported encoding '%s'",
+ 1003: "Obsolete namespace syntax",
+ 1005: "Unsupported character number '%d' in character reference",
+ 1006: "Element '%s' has attribute list, but no element declaration",
+ 1007: "Attribute '%s' defined more than once",
+ 1008: "Ambiguous content model",
+
+ # --- Namespace warnings
+ 1900: "Namespace prefix names cannot contain ':'s.",
+ 1901: "Namespace URI cannot be empty",
+ 1902: "Namespace prefix not declared",
+ 1903: "Attribute names not unique after namespace processing",
+
+ # --- Validity errors: 2000-2999
+ 2000: "Actual value of attribute '%s' does not match fixed value",
+ 2001: "Element '%s' not allowed here",
+ 2002: "Document root element '%s' does not match declared root element",
+ 2003: "Element '%s' not declared",
+ 2004: "Element '%s' ended, but not finished",
+ 2005: "Character data not allowed in the content of this element",
+ 2006: "Attribute '%s' not declared",
+ 2007: "ID '%s' appears more than once in document",
+ 2008: "Only unparsed entities allowed as the values of ENTITY attributes",
+ 2009: "Notation '%s' not declared",
+ 2010: "Required attribute '%s' not present",
+ 2011: "IDREF referred to non-existent ID '%s'",
+ 2012: "Element '%s' declared more than once",
+ 2013: "Only one ID attribute allowed on each element type",
+ 2014: "ID attributes cannot be #FIXED or defaulted",
+ 2015: "xml:space must be declared an enumeration type",
+ 2016: "xml:space must have exactly the values 'default' and 'preserve'",
+ 2017: "'%s' is not an allowed value for the '%s' attribute",
+ 2018: "Value of '%s' attribute must be a valid name",
+ 2019: "Value of '%s' attribute not a valid name token",
+ 2020: "Value of '%s' attribute not a valid name token sequence",
+ 2021: "Token '%s' in the value of the '%s' attribute is not a valid name",
+ 2022: "Notation attribute '%s' uses undeclared notation '%s'",
+ 2023: "Unparsed entity '%s' uses undeclared notation '%s'",
+
+ # --- Well-formedness errors: 3000-3999
+ # From xmlutils
+ 3000: "Couldn't open resource '%s'",
+ 3001: "Construct started, but never completed",
+ 3002: "Whitespace expected here",
+ 3003: "Didn't match '%s'", ## FIXME: This must be redone
+ 3004: "One of %s or '%s' expected",
+ 3005: "'%s' expected",
+
+ # From xmlproc.XMLCommonParser
+ 3006: "SYSTEM or PUBLIC expected",
+ 3007: "Text declaration must appear first in entity",
+ 3008: "XML declaration must appear first in document",
+ 3009: "Multiple text declarations in a single entity",
+ 3010: "Multiple XML declarations in a single document",
+ 3011: "XML version missing on XML declaration",
+ 3012: "Standalone declaration on text declaration not allowed",
+ 3045: "Processing instruction target names beginning with 'xml' are reserved",
+ 3046: "Unsupported XML version",
+
+ # From xmlproc.XMLProcessor
+ 3013: "Illegal construct",
+ 3014: "Premature document end, element '%s' not closed",
+ 3015: "Premature document end, no root element",
+ 3016: "Attribute '%s' occurs twice",
+ 3017: "Elements not allowed outside root element",
+ 3018: "Illegal character number '%d' in character reference",
+ 3019: "Entity recursion detected",
+ 3020: "External entity references not allowed in attribute values",
+ 3021: "Undeclared entity '%s'",
+ 3022: "'<' not allowed in attribute values",
+ 3023: "End tag for '%s' seen, but '%s' expected",
+ 3024: "Element '%s' not open",
+ 3025: "']]>' must not occur in character data",
+ 3027: "Not a valid character number",
+ 3028: "Character references not allowed outside root element",
+ 3029: "Character data not allowed outside root element",
+ 3030: "Entity references not allowed outside root element",
+ 3031: "References to unparsed entities not allowed in element content",
+ 3032: "Multiple document type declarations",
+ 3033: "Document type declaration not allowed inside root element",
+ 3034: "Premature end of internal DTD subset",
+ 3042: "Element crossed entity boundary",
+
+ # From xmlproc.DTDParser
+ 3035: "Parameter entities cannot be unparsed",
+ 3036: "Parameter entity references not allowed in internal subset declarations",
+ 3037: "External entity references not allowed in entity replacement text",
+ 3038: "Unknown parameter entity '%s'",
+ 3039: "Expected type or alternative list",
+ 3040: "Choice and sequence lists cannot be mixed",
+ 3041: "Conditional sections not allowed in internal subset",
+ 3043: "Conditional section not closed",
+ 3044: "Token '%s' defined more than once",
+ # next: 3047
+
+ # From regular expressions that were not matched
+ 3900: "Not a valid name",
+ 3901: "Not a valid version number (%s)",
+ 3902: "Not a valid encoding name",
+ 3903: "Not a valid comment",
+ 3905: "Not a valid hexadecimal number",
+ 3906: "Not a valid number",
+ 3907: "Not a valid parameter reference",
+ 3908: "Not a valid attribute type",
+ 3909: "Not a valid attribute default definition",
+ 3910: "Not a valid enumerated attribute value",
+ 3911: "Not a valid standalone declaration",
+
+ # --- Internal errors: 4000-4999
+ 4000: "Internal error: Entity stack broken",
+ 4001: "Internal error: Entity reference expected.",
+ 4002: "Internal error: Unknown error number.",
+ 4003: "Internal error: External PE references not allowed in declarations",
+
+ # --- XCatalog errors: 5000-5099
+ 5000: "Uknown XCatalog element: %s.",
+ 5001: "Required XCatalog attribute %s on %s missing.",
+
+ # --- SOCatalog errors: 5100-5199
+ 5100: "Invalid or unsupported construct: %s.",
+ }
+
+# Errors in Norwegian
+
+norsk={
+
+ # --- Warnings: 1000-1999
+ 1000: "Navneroms-prefikset '%s' er ikke deklarert",
+ 1002: "Tegn-kodingen '%s' er ikke støttet",
+ 1003: "Denne navnerom-syntaksen er foreldet",
+ 1005: "Tegn nummer '%d' i tegn-referansen er ikke støttet",
+ 1006: "Element '%s' har attributt-liste, men er ikke deklarert",
+ 1007: "Attributt '%s' deklarert flere ganger",
+ 1008: "Tvetydig innholds-modell",
+
+ # --- Namespace warnings: 1900-1999
+ 1900: "Navnerommets prefiks-navn kan ikke inneholde kolon",
+ 1901: "Navnerommets URI kan ikke være tomt",
+ 1902: "Navnerommets prefiks er ikke deklarert",
+ 1903: "Attributt-navn ikke unike etter navneroms-prosessering",
+
+ # --- Validity errors: 2000-2999
+ 2000: "Faktisk verdi til attributtet '%s' er ikke lik #FIXED-verdien",
+ 2001: "Elementet '%s' er ikke tillatt her",
+ 2002: "Dokumentets rot-element '%s' er ikke det samme som det deklarerte",
+ 2003: "Element-typen '%s' er ikke deklarert",
+ 2004: "Elementet '%s' avsluttet, men innholdet ikke ferdig",
+ 2005: "Tekst-data er ikke tillatt i dette elementets innhold",
+ 2006: "Attributtet '%s' er ikke deklarert",
+ 2007: "ID-en '%s' brukt mer enn en gang",
+ 2008: "Bare uparserte entiteter er tillatt som verdier til ENTITY-attributter",
+ 2009: "Notasjonen '%s' er ikke deklarert",
+ 2010: "Påkrevd attributt '%s' mangler",
+ 2011: "IDREF viste til ikke-eksisterende ID '%s'",
+ 2012: "Elementet '%s' deklarert mer enn en gang",
+ 2013: "Bare ett ID-attributt er tillatt pr element-type",
+ 2014: "ID-attributter kan ikke være #FIXED eller ha standard-verdier",
+ 2015: "xml:space må deklareres som en oppramstype",
+ 2016: "xml:space må ha verdiene 'default' og 'preserve'",
+ 2017: "'%s' er ikke en gyldig verdi for '%s'-attributtet",
+ 2018: "Verdien til '%s'-attributtet må være et gyldig navn",
+ 2019: "Verdien til '%s'-attributtet er ikke et gyldig NMTOKEN",
+ 2020: "Verdien til '%s'-attributtet er ikke et gyldig NMTOKENS",
+ 2021: "Symbolet '%s' i verdien til '%s'-attributtet er ikke et gyldig navn",
+ 2022: "Notasjons-attributtet '%s' bruker en notasjon '%s' som ikke er deklarert",
+ 2023: "Uparsert entitet '%s' bruker en notasjon '%s' som ikke er deklarert",
+
+ # --- Well-formedness errors: 3000-3999
+ # From xmlutils
+ 3000: "Kunne ikke åpne '%s'",
+ 3001: "For tidlig slutt på entiteten",
+ 3002: "Blanke forventet her",
+ 3003: "Matchet ikke '%s'", ## FIXME: This must be redone
+ 3004: "En av %s eller '%s' forventet",
+ 3005: "'%s' forventet",
+
+ # From xmlproc.XMLCommonParser
+ 3006: "SYSTEM eller PUBLIC forventet",
+ 3007: "Tekst-deklarasjonen må stå først i entiteten",
+ 3008: "XML-deklarasjonen må stå først i dokumentet",
+ 3009: "Flere tekst-deklarasjoner i samme entitet",
+ 3010: "Flere tekst-deklarasjoner i samme dokument",
+ 3011: "XML-versjonen mangler på XML-deklarasjonen",
+ 3012: "'Standalone'-deklarasjon på tekst-deklarasjon ikke tillatt",
+
+ # From xmlproc.XMLProcessor
+ 3013: "Syntaksfeil",
+ 3014: "Dokumentet slutter for tidlig, elementet '%s' er ikke lukket",
+ 3015: "Dokumentet slutter for tidlig, rot-elementet mangler",
+ 3016: "Attributtet '%s' gjentatt",
+ 3017: "Kun ett rot-element er tillatt",
+ 3018: "Ulovlig tegn nummer '%d' i tegn-referanse",
+ 3019: "Entitets-rekursjon oppdaget",
+ 3020: "Eksterne entitets-referanser ikke tillatt i attributt-verdier",
+ 3021: "Entiteten '%s' er ikke deklarert",
+ 3022: "'<' er ikke tillatt i attributt-verdier",
+ 3023: "Slutt-tagg for '%s', men '%s' forventet",
+ 3024: "Elementet '%s' lukket, men ikke åpent",
+ 3025: "']]>' ikke tillatt i tekst-data",
+ 3027: "Ikke et gyldig tegn-nummer",
+ 3028: "Tegn-referanser ikke tillatt utenfor rot-elementet",
+ 3029: "Tekst-data ikke tillatt utenfor rot-elementet",
+ 3030: "Entitets-referanser ikke tillatt utenfor rot-elementet",
+ 3031: "Referanser til uparserte entiteter er ikke tillatt i element-innhold",
+ 3032: "Mer enn en dokument-type-deklarasjon",
+ 3033: "Dokument-type-deklarasjon kun tillatt før rot-elementet",
+ 3034: "Det interne DTD-subsettet slutter for tidlig",
+ 3042: "Element krysset entitets-grense",
+ 3045: "Processing instruction navn som begynner med 'xml' er reservert",
+ 3046: "Denne XML-versjonen er ikke støttet",
+
+ # From xmlproc.DTDParser
+ 3035: "Parameter-entiteter kan ikke være uparserte",
+ 3036: "Parameter-entitets-referanser ikke tillatt inne i deklarasjoner i det interne DTD-subsettet",
+ 3037: "Eksterne entitets-referanser ikke tillatt i entitetsdeklarasjoner",
+ 3038: "Parameter-entiteten '%s' ikke deklarert",
+ 3039: "Forventet attributt-type eller liste av alternativer",
+ 3040: "Valg- og sekvens-lister kan ikke blandes",
+ 3041: "'Conditional sections' er ikke tillatt i det interne DTD-subsettet",
+ 3043: "'Conditional section' ikke lukket",
+ 3044: "Symbolet '%s' er definert mer enn en gang",
+
+ # From regular expressions that were not matched
+ 3900: "Ikke et gyldig navn",
+ 3901: "Ikke et gyldig versjonsnummer (%s)",
+ 3902: "Ikke et gyldig tegnkodings-navn",
+ 3903: "Ikke en gyldig kommentar",
+ 3905: "Ikke et gyldig heksadesimalt tall",
+ 3906: "Ikke et gyldig tall",
+ 3907: "Ikke en gyldig parameter-entitets-referanse",
+ 3908: "Ikke en gyldig attributt-type",
+ 3909: "Ikke en gyldig attributt-standard-verdi",
+ 3910: "Ikke en gyldig verdi for opprams-attributter",
+ 3911: "Ikke en gyldig verdi for 'standalone'",
+
+ # --- Internal errors: 4000-4999
+ 4000: "Intern feil: Entitets-stakken korrupt.",
+ 4001: "Intern feil: Entitets-referanse forventet.",
+ 4002: "Intern feil: Ukjent feilmelding.",
+ 4003: "Intern feil: Eksterne parameter-entiteter ikke tillatt i deklarasjoner",
+ # --- XCatalog errors: 5000-5099
+ 5000: "Ukjent XCatalog-element: %s.",
+ 5001: "Påkrevd XCatalog-attributt %s på %s mangler.",
+
+ # --- SOCatalog errors: 5100-5199
+ 5100: "Ugyldig eller ikke støttet konstruksjon: %s.",
+ }
+
+# Updating the error hash
+
+add_error_list("en",english)
+add_error_list("no",norsk)
diff --git a/lib/jython/Lib/xml/parsers/xmlproc/namespace.py b/lib/jython/Lib/xml/parsers/xmlproc/namespace.py new file mode 100644 index 000000000..adb27ab6d --- /dev/null +++ b/lib/jython/Lib/xml/parsers/xmlproc/namespace.py @@ -0,0 +1,169 @@ +"""
+A parser filter for namespace support. Placed externally to the parser
+for efficiency reasons.
+
+$Id: namespace.py,v 1.4 2000/09/26 14:43:10 loewis Exp $
+"""
+
+import string
+import xmlapp
+
+# --- ParserFilter
+
+class ParserFilter(xmlapp.Application):
+ "A generic parser filter class."
+
+ def __init__(self):
+ xmlapp.Application.__init__(self)
+ self.app=xmlapp.Application()
+
+ def set_application(self,app):
+ "Sets the application to report events to."
+ self.app=app
+
+ # --- Methods inherited from xmlapp.Application
+
+ def set_locator(self,locator):
+ xmlapp.Application.set_locator(self,locator)
+ self.app.set_locator(locator)
+
+ def doc_start(self):
+ self.app.doc_start()
+
+ def doc_end(self):
+ self.app.doc_end()
+
+ def handle_comment(self,data):
+ self.app.handle_comment(data)
+
+ def handle_start_tag(self,name,attrs):
+ self.app.handle_start_tag(name,attrs)
+
+ def handle_end_tag(self,name):
+ self.app.handle_end_tag(name)
+
+ def handle_data(self,data,start,end):
+ self.app.handle_data(data,start,end)
+
+ def handle_ignorable_data(self,data,start,end):
+ self.app.handle_ignorable_data(data,start,end)
+
+ def handle_pi(self,target,data):
+ self.app.handle_pi(target,data)
+
+ def handle_doctype(self,root,pubID,sysID):
+ self.app.handle_doctype(root,pubID,sysID)
+
+ def set_entity_info(self,xmlver,enc,sddecl):
+ self.app.set_entity_info(xmlver,enc,sddecl)
+
+# --- NamespaceFilter
+
+class NamespaceFilter(ParserFilter):
+ """An xmlproc application that processes qualified names and reports them
+ as 'URI local-part' names. It reports errors through the error reporting
+ mechanisms of the parser."""
+
+ def __init__(self,parser):
+ ParserFilter.__init__(self)
+ self.ns_map={} # Current prefix -> URI map
+ self.ns_stack=[] # Pushed for each element, used to maint ns_map
+ self.rep_ns_attrs=0 # Report xmlns-attributes?
+ self.parser=parser
+
+ def set_report_ns_attributes(self,action):
+ "Tells the filter whether to report or delete xmlns-attributes."
+ self.rep_ns_attrs=action
+
+ # --- Overridden event methods
+
+ def handle_start_tag(self,name,attrs):
+ old_ns={} # Reset ns_map to these values when we leave this element
+ del_ns=[] # Delete these prefixes from ns_map when we leave element
+
+ # attrs=attrs.copy() Will have to do this if more filters are made
+
+ # Find declarations, update self.ns_map and self.ns_stack
+ for (a,v) in attrs.items():
+ if a[:6]=="xmlns:":
+ prefix=a[6:]
+ if string.find(prefix,":")!=-1:
+ self.parser.report_error(1900)
+
+ if v=="":
+ self.parser.report_error(1901)
+ elif a=="xmlns":
+ prefix=""
+ else:
+ continue
+
+ if self.ns_map.has_key(prefix):
+ old_ns[prefix]=self.ns_map[prefix]
+ else:
+ del_ns.append(prefix)
+
+ if prefix=="" and v=="":
+ del self.ns_map[prefix]
+ else:
+ self.ns_map[prefix]=v
+
+ if not self.rep_ns_attrs:
+ del attrs[a]
+
+ self.ns_stack.append((old_ns,del_ns))
+
+ # Process elem and attr names
+ name=self.__process_name(name)
+
+ parts=string.split(name)
+ if len(parts)>1:
+ ns=parts[0]
+ else:
+ ns=None
+
+ for (a,v) in attrs.items():
+ del attrs[a]
+ aname=self.__process_name(a,ns)
+ if attrs.has_key(aname):
+ self.parser.report_error(1903)
+ attrs[aname]=v
+
+ # Report event
+ self.app.handle_start_tag(name,attrs)
+
+ def handle_end_tag(self,name):
+ name=self.__process_name(name)
+
+ # Clean up self.ns_map and self.ns_stack
+ (old_ns,del_ns)=self.ns_stack[-1]
+ del self.ns_stack[-1]
+
+ self.ns_map.update(old_ns)
+ for prefix in del_ns:
+ del self.ns_map[prefix]
+
+ self.app.handle_end_tag(name)
+
+ # --- Internal methods
+
+ def __process_name(self,name,default_to=None):
+ n=string.split(name,":")
+ if len(n)>2:
+ self.parser.report_error(1900)
+ return name
+ elif len(n)==2:
+ if n[0]=="xmlns":
+ return name
+
+ try:
+ return "%s %s" % (self.ns_map[n[0]],n[1])
+ except KeyError:
+ self.parser.report_error(1902)
+ return name
+ elif default_to!=None:
+ return "%s %s" % (default_to,name)
+ elif self.ns_map.has_key("") and name!="xmlns":
+ return "%s %s" % (self.ns_map[""],name)
+ else:
+ return name
+
diff --git a/lib/jython/Lib/xml/parsers/xmlproc/utils.py b/lib/jython/Lib/xml/parsers/xmlproc/utils.py new file mode 100644 index 000000000..30a59c82d --- /dev/null +++ b/lib/jython/Lib/xml/parsers/xmlproc/utils.py @@ -0,0 +1,197 @@ +"""
+Some utilities for use with xmlproc.
+
+$Id: utils.py,v 1.2 2000/09/26 14:43:10 loewis Exp $
+"""
+
+import xmlapp,sys,string,types
+
+replace = string.replace
+
+# --- ErrorPrinter
+
+class ErrorPrinter(xmlapp.ErrorHandler):
+ """An error handler that prints out warning messages."""
+
+ def __init__(self,locator,level=0,out=sys.stderr):
+ self.locator=locator
+ self.level=level
+ self.out=out
+
+ def warning(self,msg):
+ if self.level<1:
+ self.out.write("WARNING: %s at %s\n" % (msg,self.__get_location()))
+
+ def error(self,msg):
+ if self.level<2:
+ self.out.write("ERROR: %s at %s\n" % (msg,self.__get_location()))
+
+ def fatal(self,msg):
+ self.out.write("ERROR: %s at %s\n" % (msg,self.__get_location()))
+
+ def __get_location(self):
+ return "%s:%d:%d" % (self.locator.get_current_sysid(),
+ self.locator.get_line(),
+ self.locator.get_column())
+# --- ErrorCounter
+
+class ErrorCounter(xmlapp.ErrorHandler):
+ """An error handler that counts errors."""
+
+ def __init__(self,locator):
+ self.reset()
+
+ def reset(self):
+ self.warnings=0
+ self.errors =0
+ self.fatals =0
+
+ def warning(self,msg):
+ self.warnings=self.warnings+1
+
+ def error(self,msg):
+ self.errors=self.errors+1
+
+ def fatal(self,msg):
+ self.fatals=self.fatals+1
+
+# --- ESIS document handler
+
+class ESISDocHandler(xmlapp.Application):
+
+ def __init__(self,writer=sys.stdout):
+ self.writer=writer
+
+ def handle_pi(self,target,data):
+ self.writer.write("?"+target+" "+data+"\n")
+
+ def handle_start_tag(self,name,amap):
+ self.writer.write("("+name+"\n")
+ for a_name in amap.keys():
+ self.writer.write("A"+a_name+" "+amap[a_name]+"\n")
+
+ def handle_end_tag(self,name):
+ self.writer.write(")"+name+"\n")
+
+ def handle_data(self,data,start_ix,end_ix):
+ self.writer.write("-"+data[start_ix:end_ix]+"\n")
+
+# --- XML canonizer
+
+class Canonizer(xmlapp.Application):
+
+ def __init__(self,writer=sys.stdout):
+ self.elem_level=0
+ self.writer=writer
+
+ def handle_pi(self,target, remainder):
+ if target!="xml":
+ self.writer.write("<?"+target+" "+remainder+"?>")
+
+ def handle_start_tag(self,name,amap):
+ self.writer.write("<"+name)
+
+ a_names=amap.keys()
+ a_names.sort()
+
+ for a_name in a_names:
+ self.writer.write(" "+a_name+"=\"")
+ self.write_data(amap[a_name])
+ self.writer.write("\"")
+ self.writer.write(">")
+ self.elem_level=self.elem_level+1
+
+ def handle_end_tag(self,name):
+ self.writer.write("</"+name+">")
+ self.elem_level=self.elem_level-1
+
+ def handle_ignorable_data(self,data,start_ix,end_ix):
+ self.write_data(data[start_ix:end_ix])
+
+ def handle_data(self,data,start_ix,end_ix):
+ if self.elem_level>0:
+ self.write_data(data[start_ix:end_ix])
+
+ def write_data(self,data):
+ data=replace(data,"&","&")
+ data=replace(data,"<","<")
+ data=replace(data,"\"",""")
+ data=replace(data,">",">")
+ data=replace(data,chr(9),"	")
+ data=replace(data,chr(10)," ")
+ data=replace(data,chr(13)," ")
+ self.writer.write(data)
+
+# --- DocGenerator
+
+def escape_content(str):
+ return replace(replace(str, "&", "&"), "<", "<")
+
+def escape_attval(str):
+ return replace(replace(replace(str, "&", "&"), "<", "<"), '"',
+ """)
+
+class DocGenerator(xmlapp.Application):
+
+ def __init__(self, out = sys.stdout):
+ self.out = out
+
+ def handle_pi(self, target, remainder):
+ self.out.write("<?%s %s?>" % (target, remainder))
+
+ def handle_start_tag(self,name,amap):
+ self.out.write("<"+name)
+ for (name, value) in amap.items():
+ self.out.write(' %s="%s"' % (name, escape_attval(value)))
+ self.out.write(">")
+
+ def handle_end_tag(self,name):
+ self.out.write("</%s>" % name)
+
+ def handle_ignorable_data(self,data,start_ix,end_ix):
+ self.out.write(escape_content(data[start_ix:end_ix]))
+
+ def handle_data(self,data,start_ix,end_ix):
+ self.out.write(escape_content(data[start_ix:end_ix]))
+
+# --- DictResolver
+
+class DictResolver(xmlapp.PubIdResolver):
+
+ def __init__(self, mapping = None):
+ if mapping == None:
+ mapping = {}
+
+ self.mapping = mapping
+
+ def resolve_pe_pubid(self, pubid, sysid):
+ return self.mapping.get(pubid, sysid)
+
+ def resolve_doctype_pubid(self, pubid, sysid):
+ return self.mapping.get(pubid, sysid)
+
+ def resolve_entity_pubid(self, pubid, sysid):
+ return self.mapping.get(pubid, sysid)
+
+# --- Various DTD and validation tools
+
+def load_dtd(sysid):
+ import dtdparser,xmldtd
+
+ dp=dtdparser.DTDParser()
+ dtd=xmldtd.CompleteDTD(dp)
+ dp.set_dtd_consumer(dtd)
+ dp.parse_resource(sysid)
+
+ return dtd
+
+def validate_doc(dtd,sysid):
+ import xmlval
+
+ parser=xmlval.XMLValidator(dtd)
+ parser.dtd=dtd # FIXME: what to do if there is a !DOCTYPE?
+ parser.set_error_handler(ErrorPrinter(parser))
+ parser.parse_resource(sysid)
+
+ dtd.rollback_changes()
+
diff --git a/lib/jython/Lib/xml/parsers/xmlproc/xcatalog.py b/lib/jython/Lib/xml/parsers/xmlproc/xcatalog.py new file mode 100644 index 000000000..68f6e3f6c --- /dev/null +++ b/lib/jython/Lib/xml/parsers/xmlproc/xcatalog.py @@ -0,0 +1,66 @@ +"""
+Support for XCatalog catalog files.
+$Id: xcatalog.py,v 1.7 2000/09/26 14:43:10 loewis Exp $
+"""
+
+import catalog,xmlapp,xmlproc
+
+# --- An XCatalog parser factory
+
+class XCatParserFactory:
+
+ def __init__(self,error_lang=None):
+ self.error_lang=error_lang
+
+ def make_parser(self,sysid):
+ return XCatalogParser(self.error_lang)
+
+class FancyParserFactory:
+
+ def __init__(self,error_lang=None):
+ self.error_lang=error_lang
+
+ def make_parser(self,sysid):
+ if sysid[-4:]==".soc":
+ return catalog.CatalogParser(self.error_lang)
+ elif sysid[-4:]==".xml":
+ return XCatalogParser(self.error_lang)
+ else:
+ return catalog.CatalogParser(self.error_lang)
+
+# --- An XCatalog 0.1 parser
+
+class XCatalogParser(catalog.AbstrCatalogParser,xmlapp.Application):
+
+ def __init__(self,error_lang=None):
+ catalog.AbstrCatalogParser.__init__(self)
+ xmlapp.Application.__init__(self)
+ self.error_lang=error_lang
+
+ def parse_resource(self,sysid):
+ parser=xmlproc.XMLProcessor()
+ self.parser=parser
+ parser.set_application(self)
+ if self.error_lang!=None:
+ parser.set_error_language(self.error_lang)
+ parser.set_error_handler(self.err)
+ parser.parse_resource(sysid)
+ del self.parser
+
+ def handle_start_tag(self,name,attrs):
+ try:
+ if name=="Base":
+ self.app.handle_base(attrs["HRef"])
+ elif name=="Map":
+ self.app.handle_public(attrs["PublicID"],attrs["HRef"])
+ elif name=="Delegate":
+ self.app.handle_delegate(attrs["PublicID"],attrs["HRef"])
+ elif name=="Extend":
+ self.app.handle_catalog(attrs["HRef"])
+ elif name!="XCatalog":
+ self.parser.report_error(5000,(name,))
+ except KeyError,e:
+ if e.args[0]=="HRef" or e.args[0]=="PublicID" or e.args[0]=="HRef":
+ self.parser.report_error(5001,(e.args[0],name))
+ else:
+ raise e # This came from the application, pass it on
diff --git a/lib/jython/Lib/xml/parsers/xmlproc/xmlapp.py b/lib/jython/Lib/xml/parsers/xmlproc/xmlapp.py new file mode 100644 index 000000000..a14935cc6 --- /dev/null +++ b/lib/jython/Lib/xml/parsers/xmlproc/xmlapp.py @@ -0,0 +1,227 @@ +"""
+This file contains the default classes that are used to receive events
+from the XML parser. All these classes are meant to be subclassed (or
+imitated) by clients that want to handle these functions themselves.
+Application is the class that receives document data from the parser,
+and is probably the one most people want.
+
+$Id: xmlapp.py,v 1.9 2000/09/26 14:43:10 loewis Exp $
+"""
+
+import sys,urllib
+
+from xmlutils import *
+
+# ==============================
+# The default application class
+# ==============================
+
+class Application:
+ """This is the class that represents the application that receives
+ parsed data from the parser. It is meant to be subclassed by users."""
+
+ def __init__(self):
+ self.locator=None
+
+ def set_locator(self,locator):
+ """Gives the application an object to ask for the current location.
+ Called automagically by the parser."""
+ self.locator=locator
+
+ def doc_start(self):
+ "Notifies the application of the start of the document."
+ pass
+
+ def doc_end(self):
+ "Notifies the application of the end of the document."
+ pass
+
+ def handle_comment(self,data):
+ "Notifies the application of comments."
+ pass
+
+ def handle_start_tag(self,name,attrs):
+ "Notifies the application of start tags (and empty element tags)."
+ pass
+
+ def handle_end_tag(self,name):
+ "Notifies the application of end tags (and empty element tags)."
+ pass
+
+ def handle_data(self,data,start,end):
+ "Notifies the application of character data."
+ pass
+
+ def handle_ignorable_data(self,data,start,end):
+ "Notifies the application of character data that can be ignored."
+ pass
+
+ def handle_pi(self,target,data):
+ "Notifies the application of processing instructions."
+ pass
+
+ def handle_doctype(self,root,pubID,sysID):
+ "Notifies the application of the document type declaration."
+ pass
+
+ def set_entity_info(self,xmlver,enc,sddecl):
+ """Notifies the application of information about the current entity
+ supplied by an XML or text declaration. All three parameters will be
+ None, if they weren't present."""
+ pass
+
+# ==============================
+# The public identifier resolver
+# ==============================
+
+class PubIdResolver:
+ """An application class that resolves public identifiers to system
+ identifiers."""
+
+ def resolve_pe_pubid(self,pubid,sysid):
+ """Maps the public identifier of a parameter entity to a system
+ identifier. The default implementation just returns the system
+ identifier."""
+ return sysid
+
+ def resolve_doctype_pubid(self,pubid,sysid):
+ """Maps the public identifier of the DOCTYPE declaration to a system
+ identifier. The default implementation just returns the system
+ identifier."""
+ return sysid
+
+ def resolve_entity_pubid(self,pubid,sysid):
+ """Maps the public identifier of an external entity to a system
+ identifier. The default implementation just returns the system
+ identifier."""
+ return sysid
+
+# ==============================
+# The default error handler
+# ==============================
+
+class ErrorHandler:
+ """An error handler for the parser. This class can be subclassed by clients
+ that want to use their own error handlers."""
+
+ def __init__(self,locator):
+ self.locator=locator
+
+ def set_locator(self,loc):
+ self.locator=loc
+
+ def get_locator(self):
+ return self.locator
+
+ def warning(self,msg):
+ "Handles a non-fatal error message."
+ pass
+
+ def error(self,msg):
+ self.fatal(msg)
+
+ # "The reports of the error's fatality are much exaggerated"
+ # --Paul Prescod
+
+ def fatal(self,msg):
+ "Handles a fatal error message."
+ if self.locator==None:
+ print "ERROR: "+msg
+ else:
+ print "ERROR: "+msg+" at %s:%d:%d" % (self.locator.get_current_sysid(),\
+ self.locator.get_line(),\
+ self.locator.get_column())
+ print "TEXT: '%s'" % (self.locator.data[self.locator.pos:\
+ self.locator.pos+10])
+ sys.exit(1)
+
+# ==============================
+# The default entity handler
+# ==============================
+
+class EntityHandler:
+ "An entity handler for the parser."
+
+ def __init__(self,parser):
+ self.parser=parser
+
+ def resolve_ent_ref(self,entname):
+ """Resolves a general entity reference and returns its contents. The
+ default method only resolves the predefined entities. Returns a
+ 2-tuple (n,m) where n is true if the entity is internal. For internal
+ entities m is the value, for external ones it is the system id."""
+
+ try:
+ return (1,predef_ents[entname])
+ except KeyError,e:
+ self.parser.report_error(3021,entname)
+ return (1,"")
+
+# ==============================
+# A DTD event handler
+# ==============================
+
+class DTDConsumer:
+ """Represents an XML DTD. This class can be subclassed by applications
+ which want to handle the DTD information themselves."""
+
+ def __init__(self,parser):
+ self.parser=parser
+
+ def dtd_start(self):
+ "Called when DTD parsing starts."
+ pass
+
+ def dtd_end(self):
+ "Called when the DTD is completely parsed."
+ pass
+
+ def new_general_entity(self,name,val):
+ "Receives internal general entity declarations."
+ pass
+
+ def new_external_entity(self,ent_name,pub_id,sys_id,ndata):
+ """Receives external general entity declarations. 'ndata' is the
+ empty string if the entity is parsed."""
+ pass
+
+ def new_parameter_entity(self,name,val):
+ "Receives internal parameter entity declarations."
+ pass
+
+ def new_external_pe(self,name,pubid,sysid):
+ "Receives external parameter entity declarations."
+ pass
+
+ def new_notation(self,name,pubid,sysid):
+ "Receives notation declarations."
+ pass
+
+ def new_element_type(self,elem_name,elem_cont):
+ "Receives the declaration of an element type."
+ pass
+
+ def new_attribute(self,elem,attr,a_type,a_decl,a_def):
+ "Receives the declaration of a new attribute."
+ pass
+
+ def handle_comment(self,contents):
+ "Receives the contents of a comment."
+ pass
+
+ def handle_pi(self,target,data):
+ "Receives the target and data of processing instructions."
+ pass
+
+# ==============================
+# An inputsource factory
+# ==============================
+
+class InputSourceFactory:
+ "A class that creates file-like objects from system identifiers."
+
+ def create_input_source(self,sysid):
+ if sysid[1:3]==":\\":
+ return open(sysid)
+ else:
+ return urllib.urlopen(sysid)
diff --git a/lib/jython/Lib/xml/parsers/xmlproc/xmldtd.py b/lib/jython/Lib/xml/parsers/xmlproc/xmldtd.py new file mode 100644 index 000000000..091574618 --- /dev/null +++ b/lib/jython/Lib/xml/parsers/xmlproc/xmldtd.py @@ -0,0 +1,870 @@ +"""
+These are the DTD-aware classes of xmlproc. They provide both the
+DTD event consumers for the DTD parser as well as the objects that
+store DTD information for retrieval by clients (including the
+validating parser).
+
+$Id: xmldtd.py,v 1.11 2000/09/26 14:43:10 loewis Exp $
+"""
+
+import types
+
+from xmlutils import *
+from xmlapp import *
+
+# ==============================
+# WFC-DTD
+# ==============================
+
+class WFCDTD(DTDConsumer):
+ "DTD-representing class for the WFC parser."
+
+ def __init__(self,parser):
+ DTDConsumer.__init__(self,parser)
+ self.dtd_listener=DTDConsumer(parser)
+ self.reset()
+
+ def reset(self):
+ "Clears all DTD information."
+ self.gen_ents={}
+ self.param_ents={}
+ self.elems={}
+ self.attrinfo={}
+ self.used_notations={} # Notations used by NOTATION attrs
+
+ # Adding predefined entities
+ for name in predef_ents.keys():
+ self.new_general_entity(name,predef_ents[name])
+
+ def set_dtd_listener(self,listener):
+ "Registers an object that listens for DTD parse events."
+ self.dtd_listener=listener
+
+ def resolve_pe(self,name):
+ """Returns the entitiy object associated with this parameter entity
+ name. Throws KeyError if the entity is not declared."""
+ return self.param_ents[name]
+
+ def resolve_ge(self,name):
+ """Returns the entitiy object associated with this general entity
+ name. Throws KeyError if the entity is not declared."""
+ return self.gen_ents[name]
+
+ def get_general_entities(self):
+ """Returns the names of all declared general entities."""
+ return self.gen_ents.keys()
+
+ def get_parameter_entities(self):
+ "Returns the names of all declared parameter entities."
+ return self.param_ents.keys()
+
+ def get_elem(self,name):
+ """Returns the declaration of this element. Throws KeyError if the
+ element does not exist."""
+ return self.elems[name]
+
+ def get_elements(self):
+ "Returns a list of all declared element names."
+ return self.elems.keys()
+
+ def get_notation(self,name):
+ """Returns the declaration of the notation. Throws KeyError if the
+ notation does not exist."""
+ raise KeyError(name)
+
+ def get_notations(self):
+ """Returns the names of all declared notations."""
+ return []
+
+ def get_root_elem(self,name):
+ """Returns the name of the declared root element, or None if none
+ were declared."""
+ return None
+
+ # --- Shortcut information for validation
+
+ def dtd_end(self):
+ "Stores shortcut information."
+ self.attrinfo={}
+ for elem in self.elems.values():
+ self.attrinfo[elem.get_name()]=(elem.get_default_attributes(),
+ elem.get_fixed_attributes())
+
+ self.dtd_listener.dtd_end()
+
+ def get_element_info(self,name):
+ return self.attrinfo[name]
+
+ # --- Parse events
+
+ def new_attribute(self,elem,attr,a_type,a_decl,a_def):
+ "Receives the declaration of a new attribute."
+ self.dtd_listener.new_attribute(elem,attr,a_type,a_decl,a_def)
+
+ if not self.elems.has_key(elem):
+ self.elems[elem]=ElementTypeAny(elem) # Adding dummy
+
+ self.elems[elem].add_attr(attr,a_type,a_decl,a_def,self.parser)
+
+ # --- Echoing DTD parse events
+
+ def dtd_start(self):
+ self.dtd_listener.dtd_start()
+
+ # dtd_end is implemented in WFCDTD, no need to repeat here
+
+ def handle_comment(self, contents):
+ self.dtd_listener.handle_comment(contents)
+
+ def handle_pi(self, target, data):
+ self.dtd_listener.handle_pi(target, data)
+
+ def new_general_entity(self,name,val):
+ if self.gen_ents.has_key(name):
+ ## FIXME: May warn
+ return # Keep first decl
+
+ ent=InternalEntity(name,val)
+ self.gen_ents[name]=ent
+ self.dtd_listener.new_general_entity(name,val)
+
+ def new_parameter_entity(self,name,val):
+ if self.param_ents.has_key(name):
+ ## FIXME: May warn
+ return # Keep first decl
+
+ ent=InternalEntity(name,val)
+ self.param_ents[name]=ent
+ self.dtd_listener.new_parameter_entity(name,val)
+
+ def new_external_entity(self,ent_name,pubid,sysid,ndata):
+ if self.gen_ents.has_key(ent_name):
+ ## FIXME: May warn
+ return # Keep first decl
+
+ if ndata!="" and hasattr(self,"notations"):
+ if not self.notations.has_key(ndata):
+ self.used_notations[ndata]=(ent_name,2023)
+
+ ent=ExternalEntity(ent_name,pubid,sysid,ndata)
+ self.gen_ents[ent_name]=ent
+ self.dtd_listener.new_external_entity(ent_name,pubid,sysid,ndata)
+
+ def new_external_pe(self,name,pubid,sysid):
+ if self.param_ents.has_key(name):
+ ## FIXME: May warn
+ return # Keep first decl
+
+ ent=ExternalEntity(name,pubid,sysid,"")
+ self.param_ents[name]=ent
+ self.dtd_listener.new_external_pe(name,pubid,sysid)
+
+ def new_comment(self,contents):
+ self.dtd_listener.new_comment(contents)
+
+ def new_pi(self,target,rem):
+ self.dtd_listener.new_pi(target,rem)
+
+ def new_notation(self,name,pubid,sysid):
+ self.dtd_listener.new_notation(name,pubid,sysid)
+
+ def new_element_type(self,elem_name,elem_cont):
+ self.dtd_listener.new_element_type(elem_name,elem_cont)
+
+# ==============================
+# DTD consumer for the validating parser
+# ==============================
+
+class CompleteDTD(WFCDTD):
+ "Complete DTD handler for the validating parser."
+
+ def __init__(self,parser):
+ WFCDTD.__init__(self,parser)
+
+ def reset(self):
+ "Clears all DTD information."
+ WFCDTD.reset(self)
+ self.notations={}
+ self.attlists={} # Attribute lists of elements not yet declared
+ self.root_elem=None
+ self.cmhash={}
+
+ def get_root_elem(self):
+ "Returns the name of the declared root element."
+ return self.root_elem
+
+ def get_notation(self,name):
+ """Returns the declaration of the notation. Throws KeyError if the
+ notation does not exist."""
+ return self.notations[name]
+
+ def get_notations(self):
+ """Returns the names of all declared notations."""
+ return self.notations.keys()
+
+ # --- DTD parse events
+
+ def dtd_end(self):
+ WFCDTD.dtd_end(self)
+ self.cmhash={}
+
+ for elem in self.attlists.keys():
+ self.parser.report_error(1006,elem)
+ self.attlists={} # Not needed any more, can free this memory
+
+ for notation in self.used_notations.keys():
+ try:
+ self.get_notation(notation)
+ except KeyError,e:
+ self.parser.report_error(2022,(self.used_notations[notation],
+ notation))
+ self.used_notations={} # Not needed, save memory
+
+ def new_notation(self,name,pubid,sysid):
+ self.notations[name]=(pubid,sysid)
+ self.dtd_listener.new_notation(name,pubid,sysid)
+
+ def new_element_type(self,elem_name,elem_cont):
+ if self.elems.has_key(elem_name):
+ self.parser.report_error(2012,elem_name)
+ return # Keeping first declaration
+
+ if elem_cont=="EMPTY":
+ elem_cont=("",[],"")
+ self.elems[elem_name]=ElementType(elem_name,make_empty_model(),
+ elem_cont)
+ elif elem_cont=="ANY":
+ elem_cont=None
+ self.elems[elem_name]=ElementTypeAny(elem_name)
+ else:
+ model=make_model(self.cmhash,elem_cont,self.parser)
+ self.elems[elem_name]=ElementType(elem_name,model,elem_cont)
+
+ if self.attlists.has_key(elem_name):
+ for (attr,a_type,a_decl,a_def) in self.attlists[elem_name]:
+ self.elems[elem_name].add_attr(attr,a_type,a_decl,a_def,\
+ self.parser)
+ del self.attlists[elem_name]
+
+ self.dtd_listener.new_element_type(elem_name,elem_cont)
+
+ def new_attribute(self,elem,attr,a_type,a_decl,a_def):
+ "Receives the declaration of a new attribute."
+ self.dtd_listener.new_attribute(elem,attr,a_type,a_decl,a_def)
+ try:
+ self.elems[elem].add_attr(attr,a_type,a_decl,a_def,self.parser)
+ except KeyError,e:
+ try:
+ self.attlists[elem].append((attr,a_type,a_decl,a_def))
+ except KeyError,e:
+ self.attlists[elem]=[(attr,a_type,a_decl,a_def)]
+
+# ==============================
+# Represents an XML element type
+# ==============================
+
+class ElementType:
+ "Represents an element type."
+
+ def __init__(self,name,compiled,original):
+ self.name=name
+ self.attrhash={}
+ self.attrlist=[]
+ self.content_model=compiled
+ self.content_model_structure=original
+
+ def get_name(self):
+ "Returns the name of the element type."
+ return self.name
+
+ def get_attr_list(self):
+ """Returns a list of the declared attribute names in the order the
+ attributes were declared."""
+ return self.attrlist
+
+ def get_attr(self,name):
+ "Returns the attribute or throws a KeyError if it's not declared."
+ return self.attrhash[name]
+
+ def add_attr(self,attr,a_type,a_decl,a_def,parser):
+ "Adds a new attribute to the element."
+ if self.attrhash.has_key(attr):
+ parser.report_error(1007,attr)
+ return # Keep first declaration
+
+ self.attrlist.append(attr)
+
+ if a_type=="ID":
+ for attr_name in self.attrhash.keys():
+ if self.attrhash[attr_name].type=="ID":
+ parser.report_error(2013)
+
+ if a_decl!="#REQUIRED" and a_decl!="#IMPLIED":
+ parser.report_error(2014)
+ elif type(a_type)==types.TupleType and a_type[0]=="NOTATION":
+ for notation in a_type[1]:
+ parser.dtd.used_notations[notation]=attr
+
+ self.attrhash[attr]=Attribute(attr,a_type,a_decl,a_def,parser)
+
+ if a_def!=None:
+ self.attrhash[attr].validate(self.attrhash[attr].default,parser)
+
+ def get_start_state(self):
+ "Return the start state of this content model."
+ return self.content_model["start"]
+
+ def final_state(self,state):
+ "True if 'state' is a final state."
+ return self.content_model["final"] & state
+
+ def next_state(self,state,elem_name):
+ """Returns the next state of the content model from the given one
+ when elem_name is encountered. Character data is represented as
+ '#PCDATA'. If 0 is returned the element is not allowed here or if
+ the state is unknown."""
+ try:
+ return self.content_model[state][elem_name]
+ except KeyError:
+ return 0
+
+ def get_valid_elements(self,state):
+ """Returns a list of the valid elements in the given state, or the
+ empty list if none are valid (or if the state is unknown). If the
+ content model is ANY, the empty list is returned."""
+ if self.content_model==None: # that is, any
+ return [] # any better ideas?
+
+ try:
+ return self.content_model[state].keys()
+ except KeyError:
+ return []
+
+ def get_content_model(self):
+ """Returns the element content model in (sep,cont,mod) format, where
+ cont is a list of (name,mod) and (sep,cont,mod) tuples. ANY content
+ models are represented as None, and EMPTYs as ("",[],"")."""
+ return self.content_model_structure
+
+ # --- Methods used to create shortcut validation information
+
+ def get_default_attributes(self):
+ defs={}
+ for attr in self.attrhash.values():
+ if attr.get_default()!=None:
+ defs[attr.get_name()]=attr.get_default()
+
+ return defs
+
+ def get_fixed_attributes(self):
+ fixed={}
+ for attr in self.attrhash.values():
+ if attr.get_decl()=="#FIXED":
+ fixed[attr.get_name()]=attr.get_default()
+
+ return fixed
+
+# --- Element types with ANY content
+
+class ElementTypeAny(ElementType):
+
+ def __init__(self,name):
+ ElementType.__init__(self,name,None,None)
+
+ def get_start_state(self):
+ return 1
+
+ def final_state(self,state):
+ return 1
+
+ def next_state(self,state,elem_name):
+ return 1
+
+# ==============================
+# Attribute
+# ==============================
+
+class Attribute:
+ "Represents a declared attribute."
+
+ def __init__(self,name,attrtype,decl,default,parser):
+ self.name=name
+ self.type=attrtype
+ self.decl=decl
+
+ # Normalize the default value before setting it
+ if default!=None and self.type!="CDATA":
+ self.default=string.join(string.split(default))
+ else:
+ self.default=default
+
+ # Handling code for special attribute xml:space
+
+ if name=="xml:space":
+ if type(self.type)==types.StringType:
+ parser.report_error(2015)
+ return
+
+ if len(self.type)!=2:
+ error=1
+ else:
+ if (self.type[0]=="default" and self.type[1]=="preserve") or \
+ (self.type[1]=="default" and self.type[0]=="preserve"):
+ error=0
+ else:
+ error=1
+
+ if error: parser.report_error(2016)
+
+ def validate(self,value,parser):
+ "Validates given value for correctness."
+
+ if type(self.type)!=types.StringType:
+ for val in self.type:
+ if val==value: return
+ parser.report_error(2017,(value,self.name))
+ elif self.type=="CDATA":
+ return
+ elif self.type=="ID" or self.type=="IDREF" or self.type=="ENTITIY":
+ if not matches(reg_name,value):
+ parser.report_error(2018,self.name)
+ elif self.type=="NMTOKEN":
+ if not matches(reg_nmtoken,value):
+ parser.report_error(2019,self.name)
+ elif self.type=="NMTOKENS":
+ if not matches(reg_nmtokens,value):
+ parser.report_error(2020,self.name)
+ elif self.type=="IDREFS" or self.type=="ENTITIES":
+ for token in string.split(value):
+ if not matches(reg_name,token):
+ parser.report_error(2021,(token,self.name))
+
+ def get_name(self):
+ "Returns the attribute name."
+ return self.name
+
+ def get_type(self):
+ "Returns the type of the attribute. (ID, CDATA etc)"
+ return self.type
+
+ def get_decl(self):
+ "Returns the declaration (#IMPLIED, #REQUIRED, #FIXED or #DEFAULT)."
+ return self.decl
+
+ def get_default(self):
+ """Returns the default value of the attribute, or None if none has
+ been declared."""
+ return self.default
+
+# ==============================
+# Entities
+# ==============================
+
+class InternalEntity:
+
+ def __init__(self,name,value):
+ self.name=name
+ self.value=value
+
+ def is_internal(self):
+ return 1
+
+ def get_value(self):
+ "Returns the replacement text of the entity."
+ return self.value
+
+class ExternalEntity:
+
+ def __init__(self,name,pubid,sysid,notation):
+ self.name=name
+ self.pubid=pubid
+ self.sysid=sysid
+ self.notation=notation
+
+ def is_parsed(self):
+ "True if this is a parsed entity."
+ return self.notation==""
+
+ def is_internal(self):
+ return 0
+
+ def get_pubid(self):
+ "Returns the public identifier of the entity."
+ return self.pubid
+
+ def get_sysid(self):
+ "Returns the system identifier of the entity."
+ return self.sysid
+
+ def get_notation(self):
+ "Returns the notation of the entity, or None if there is none."
+ return self.notation
+
+# ==============================
+# Internal classes
+# ==============================
+
+# Non-deterministic state model builder
+
+class FNDABuilder:
+ "Builds a finite non-deterministic automaton."
+
+ def __init__(self):
+ self.__current=0
+ self.__transitions=[[]]
+ self.__mem=[]
+
+ def remember_state(self):
+ "Makes the builder remember the current state."
+ self.__mem.append(self.__current)
+
+ def set_current_to_remembered(self):
+ """Makes the current state the last remembered one. The last remembered
+ one is not forgotten."""
+ self.__current=self.__mem[-1]
+
+ def forget_state(self):
+ "Makes the builder forget the current remembered state."
+ del self.__mem[-1]
+
+ def new_state(self):
+ "Creates a new last state and makes it the current one."
+ self.__transitions.append([])
+ self.__current=len(self.__transitions)-1
+
+ def get_automaton(self):
+ "Returns the automaton produced by the builder."
+ return self.__transitions
+
+ def get_current_state(self):
+ "Returns the current state."
+ return self.__current
+
+ def new_transition(self,label,frm,to):
+ "Creates a new transition from frm to to, over label."
+ self.__transitions[frm].append((to,label))
+
+ def new_transition_to_new(self,label):
+ """Creates a new transition from the current state to a new state,
+ which becomes the new current state."""
+ self.remember_state()
+ self.new_state()
+ self.__transitions[self.__mem[-1]].append((self.__current,label))
+ self.forget_state()
+
+ def new_transition_cur2rem(self,label):
+ """Adds a new transition from the current state to the last remembered
+ state."""
+ self.__transitions[self.__current].append((self.__mem[-1],label))
+
+ def new_transition_rem2cur(self,label):
+ """Creates a new transition from the current state to the last
+ remembered one."""
+ self.__transitions[self.__mem[-1]].append((self.__current,label))
+
+ def new_transition_2cur(self,frm,label):
+ "Creates a new transition from frm to current state, with label."
+ self.__transitions[frm].append((self.__current,label))
+
+# Content model class
+
+class ContentModel:
+ "Represents a singleton content model. (Internal.)"
+
+ def __init__(self,contents,modifier):
+ self.contents=contents
+ self.modifier=modifier
+
+ def add_states(self,builder):
+ "Builds the part of the automaton corresponding to this model part."
+ if self.modifier=="?":
+ builder.remember_state()
+ self.add_contents(builder)
+ builder.new_transition_rem2cur("")
+ builder.forget_state()
+ elif self.modifier=="+":
+ self.add_contents(builder)
+ builder.remember_state()
+ self.add_contents(builder,1)
+ builder.set_current_to_remembered()
+ builder.forget_state()
+ elif self.modifier=="*":
+ builder.remember_state()
+ builder.new_transition_to_new("")
+ self.add_contents(builder,1)
+ builder.new_transition_rem2cur("")
+ builder.forget_state()
+ else:
+ self.add_contents(builder)
+
+ def add_contents(self,builder,loop=0):
+ """Adds the states and transitions belonging to the self.contents
+ parts. If loop is true the states will loop back to the first state."""
+ if type(self.contents[0])==types.InstanceType:
+ if loop:
+ builder.remember_state()
+ self.contents[0].add_states(builder)
+ builder.new_transition_cur2rem("")
+ builder.set_current_to_remembered()
+ builder.forget_state()
+ else:
+ self.contents[0].add_states(builder)
+ else:
+ if loop:
+ builder.new_transition(self.contents[0],
+ builder.get_current_state(),
+ builder.get_current_state())
+ else:
+ builder.new_transition_to_new(self.contents[0])
+
+# Sequential content model
+
+class SeqContentModel(ContentModel):
+ "Represents a sequential content model. (Internal.)"
+
+ def add_contents(self,builder,loop=0):
+ if loop:
+ builder.remember_state()
+
+ for cp in self.contents:
+ cp.add_states(builder)
+
+ if loop:
+ builder.new_transition_cur2rem("")
+ builder.forget_state()
+
+# Choice content model
+
+class ChoiceContentModel(ContentModel):
+ "Represents a choice content model. (Internal.)"
+
+ def add_contents(self,builder,loop=0):
+ builder.remember_state()
+ end_states=[] # The states at the end of each alternative
+
+ for cp in self.contents:
+ builder.new_state()
+ builder.new_transition_rem2cur("")
+ cp.add_states(builder)
+ end_states.append(builder.get_current_state())
+
+ builder.new_state()
+ for state in end_states:
+ builder.new_transition_2cur(state,"")
+
+ if loop:
+ builder.new_transition_cur2rem("")
+
+ builder.forget_state()
+
+# ==============================
+# Conversion of FDAs
+# ==============================
+
+def hash(included):
+ "Creates a hash number from the included array."
+ no=0
+ exp=1L
+ for state in included:
+ if state:
+ no=no+exp
+ exp=exp*2L
+
+ return no
+
+def fnda2fda(transitions,final_state,parser):
+ """Converts a finite-state non-deterministic automaton into a deterministic
+ one."""
+
+ # transitions: old FNDA as [[(to,over),(to,over),...],
+ # [(to,over),(to,over),...]] structure
+ # new FDA as [{over:to,over:to,...},
+ # {over:to,over:to,...}] structure
+ # err: error-handler
+
+ #print_trans(transitions)
+ transitions.append([])
+ new_states={}
+
+ # Compute the e-closure of the start state
+ closure_hash={}
+ start_state=[0]*len(transitions)
+ compute_closure(0,start_state,transitions)
+ state_key=hash(start_state)
+ closure_hash[0]=state_key
+
+ # Add transitions and the other states
+ add_transitions(0,transitions,new_states,start_state,state_key,parser,
+ closure_hash)
+
+ states=new_states.keys()
+ states.sort()
+
+ #print_states(new_states,2)
+
+ for state in states:
+ if state % 2==1:
+ new_states["start"]=state
+ break
+
+ new_states["final"]=pow(2L,final_state)
+ return new_states
+
+def add_transitions(ix,transitions,new_states,cur_state_list,state_key,parser,
+ closure_hash):
+ "Set up transitions and create new states."
+
+ new_states[state_key]={} # OK, a new one, create it
+ new_trans={} # Hash from label to a list of the possible destination states
+
+ # Find all transitions from this set of states and group them by their
+ # labels in the new_trans hash
+
+ no=0
+ for old_state in cur_state_list:
+ if old_state:
+ for (to,what) in transitions[no]:
+ if what!="":
+ if new_trans.has_key(what):
+ new_trans[what].append(to)
+ else:
+ new_trans[what]=[to]
+
+ no=no+1
+
+ # Go through the list of transitions, creating new transitions and
+ # destination states in the model
+
+ for (over,destlist) in new_trans.items():
+ # creating new state
+
+ # Reports ambiguity, but rather crudely. Will improve this later.
+# if len(destlist)>1:
+# parser.report_error(1008)
+
+ if len(destlist)==1 and closure_hash.has_key(destlist[0]):
+ # The closure of this state has been computed before, don't repeat
+ new_state=closure_hash[destlist[0]]
+ else:
+ new_inc=[0]*len(transitions)
+ for to in destlist:
+ compute_closure(to,new_inc,transitions)
+
+ new_state=hash(new_inc)
+ if len(destlist)==1:
+ closure_hash[destlist[0]]=new_state
+
+ # add transition and destination state
+ new_states[state_key][over]=new_state
+ if not new_states.has_key(new_state):
+ add_transitions(to,transitions,new_states,new_inc,\
+ new_state,parser,closure_hash)
+
+def compute_closure(ix,included,transitions):
+ "Computes the e-closure of this state."
+ included[ix]=1
+ for (to,what) in transitions[ix]:
+ if what=="" and not included[to]:
+ compute_closure(to,included,transitions)
+
+def print_trans(model):
+ ix=0
+ for transitions in model:
+ print "STATE: %d" % ix
+ for step in transitions:
+ print " TO %d OVER %s" % step
+ ix=ix+1
+ raw_input()
+
+def print_states(states,stop=0):
+ assert not (states.has_key("start") or states.has_key("final"))
+
+ for trans_key in states.keys():
+ trans=states[trans_key]
+ print "State: "+`trans_key`
+ for (to,what) in trans:
+ try:
+ print " To: "+`to`+" over: "+what
+ except TypeError,e:
+ print "ERROR: "+`what`
+
+ if stop>1:
+ raw_input()
+
+ if stop:
+ raw_input()
+
+def make_empty_model():
+ "Constructs a state model for empty content models."
+ return { 1:{}, "final":1, "start":1 }
+
+def make_model(cmhash,content_model,err):
+ "Creates an FDA from the content model."
+ cm=`content_model`
+ if cmhash.has_key(cm):
+ return cmhash[cm]
+ else:
+ content_model=make_objects(content_model)
+ builder=FNDABuilder()
+ content_model.add_states(builder)
+ content_model=fnda2fda(builder.get_automaton(),
+ builder.get_current_state(),
+ err)
+ cmhash[cm]=content_model
+ return content_model
+
+def make_objects(content_model):
+ "Turns a tuple-ized content model into one based on objects."
+ (sep,contents,mod)=content_model
+ if contents[0][0]=="#PCDATA":
+ mod="*" # it's implied that #PCDATA can occur more than once
+
+ newconts=[]
+ for tup in contents:
+ if len(tup)==2:
+ newconts.append(ContentModel([tup[0]],tup[1]))
+ else:
+ newconts.append(make_objects(tup))
+
+ if sep==",":
+ return SeqContentModel(newconts,mod)
+ elif sep=="|":
+ return ChoiceContentModel(newconts,mod)
+ elif sep=="":
+ return ContentModel(newconts,mod)
+
+# --- Various utilities
+
+def compile_content_model(cm):
+ "Parses a content model string, returning a compiled content model."
+ import dtdparser,utils
+
+ p=dtdparser.DTDParser()
+ p.set_error_handler(utils.ErrorPrinter(p))
+ p.data=cm[1:]
+ p.datasize=len(p.data)
+ p.final=1
+ return make_model({},p._parse_content_model(),p)
+
+def parse_content_model(cm):
+ "Parses a content model string, returning a compiled content model."
+ import dtdparser,utils
+
+ p=dtdparser.DTDParser()
+ p.set_error_handler(utils.ErrorPrinter(p))
+ p.data=cm[1:]
+ p.datasize=len(p.data)
+ p.final=1
+ return p._parse_content_model()
+
+def load_dtd(sysid):
+ import dtdparser,utils
+
+ dp=dtdparser.DTDParser()
+ dp.set_error_handler(utils.ErrorPrinter(dp))
+ dtd=CompleteDTD(dp)
+ dp.set_dtd_consumer(dtd)
+ dp.parse_resource(sysid)
+
+ return dtd
+
diff --git a/lib/jython/Lib/xml/parsers/xmlproc/xmlproc.py b/lib/jython/Lib/xml/parsers/xmlproc/xmlproc.py new file mode 100644 index 000000000..a49ff841e --- /dev/null +++ b/lib/jython/Lib/xml/parsers/xmlproc/xmlproc.py @@ -0,0 +1,592 @@ +"""
+The main module of the parser. All other modules will be imported into this
+one, so this module is the only one one needs to import. For validating
+parsing, import xmlval instead.
+"""
+
+# $Id: xmlproc.py,v 1.13 2001/01/14 10:42:24 loewis Exp $
+
+import re,string,sys,urllib,urlparse
+
+string_translate=string.translate # optimization. made 10% difference!
+string_find =string.find
+
+from dtdparser import *
+from xmlutils import *
+from xmlapp import *
+from xmldtd import *
+
+version="0.70"
+revision="$Revision: 1.13 $"
+
+# ==============================
+# A full well-formedness parser
+# ==============================
+
+class XMLProcessor(XMLCommonParser):
+ "A parser that performs a complete well-formedness check."
+
+ def __init__(self):
+ EntityParser.__init__(self)
+
+ # Various handlers
+ self.app=Application()
+ self.dtd=WFCDTD(self)
+ self.ent=self.dtd
+ self.dtd_listener=None
+ self.stop_on_wf=1
+
+ def set_application(self,app):
+ "Sets the object to send data events to."
+ self.app=app
+ app.set_locator(self)
+
+ def set_dtd_listener(self,listener):
+ "Registers an object that listens for DTD parse events."
+ self.dtd_listener=listener
+
+ def set_data_after_wf_error(self,stop_on_wf=0):
+ """Sets the parser policy on well-formedness errors. If this is set to
+ 0 data events are still delivered, even after well-formedness errors.
+ Otherwise no more data events reach the application after such erors.
+ """
+ self.stop_on_wf=stop_on_wf
+
+ def set_read_external_subset(self,read_it):
+ """Tells the parser whether to read the external subset of documents
+ or not."""
+ self.read_external_subset=read_it
+
+ def report_error(self,number,args=None):
+ if self.stop_on_wf and number>2999:
+ self.app=Application() # No more data events reported
+ EntityParser.report_error(self,number,args)
+
+ def reset(self):
+ EntityParser.reset(self)
+ if hasattr(self,"dtd"):
+ self.dtd.reset()
+
+ # State vars
+ self.stack=[]
+ self.seen_root=0
+ self.seen_doctype=0
+ self.seen_xmldecl=0
+ self.stop_on_wf=1
+ self.read_external_subset=0
+
+ def deref(self):
+ "Deletes circular references."
+ self.dtd = self.ent = self.err = self.app = self.pubres = None
+
+ def do_parse(self):
+ "Does the actual parsing."
+ try:
+ while self.pos<self.datasize:
+ self.prepos=self.pos
+
+ if self.data[self.pos]=="<":
+ try:
+ t=self.data[self.pos+1] # Optimization
+ except IndexError,e:
+ raise OutOfDataException()
+ if t=="/":
+ self.parse_end_tag()
+ elif t!="!" and t!="?":
+ self.parse_start_tag()
+ elif self.now_at("<!--"):
+ self.parse_comment(self.app)
+ elif self.now_at("<?"): # FIXME: use t and modify self.pos?
+ self.parse_pi(self.app,1)
+ elif self.now_at("<![CDATA["):
+ self.parse_cdata()
+ elif self.now_at("<!DOCTYPE"):
+ self.parse_doctype()
+ else:
+ self.report_error(3013)
+ self.scan_to(">") # Avoid endless loops
+ elif self.data[self.pos]=="&":
+ if self.now_at("&#"):
+ self.parse_charref()
+ else:
+ self.pos=self.pos+1 # Skipping the '&'
+ self.parse_ent_ref()
+ else:
+ self.parse_data()
+ except OutOfDataException,e:
+ if self.final:
+ raise e
+ else:
+ self.pos=self.prepos # Didn't complete the construct
+
+ def parseStart(self):
+ "Must be called before parsing starts. (Notifies application.)"
+ self.app.doc_start()
+
+ def parseEnd(self):
+ """Must be called when parsing is finished. (Does some checks and "
+ "notifies the application.)"""
+ if self.stack!=[] and self.ent_stack==[]:
+ self.report_error(3014,self.stack[-1])
+ elif not self.seen_root:
+ self.report_error(3015)
+
+ self.app.doc_end()
+
+ def parse_start_tag(self):
+ "Parses the start tag."
+ self.pos=self.pos+1 # Skips the '<'
+ name=self._get_name()
+ self.skip_ws()
+
+ try:
+ (attrs,fixeds)=self.dtd.attrinfo[name]
+ attrs=attrs.copy()
+ except KeyError:
+ attrs={}
+ fixeds={}
+
+ if self.data[self.pos]!=">" and self.data[self.pos]!="/":
+ seen={}
+ while not self.test_str(">") and not self.test_str("/>"):
+ a_name=self._get_name()
+ self.skip_ws()
+ if not self.now_at("="):
+ self.report_error(3005,"=")
+ self.scan_to(">") ## Panic! Get out of the tag!
+ a_val=""
+ break
+ self.skip_ws()
+
+ a_val=self.parse_att_val()
+ if a_val==-1:
+ # WF error, we've skipped the rest of the tag
+ self.pos=self.pos-1 # Lets us find the '>'
+ if self.data[self.pos-1]=="/":
+ self.pos=self.pos-1 # Gets the '/>' cases right
+ break
+
+ if seen.has_key(a_name):
+ self.report_error(3016,a_name)
+ else:
+ seen[a_name]=1
+
+ attrs[a_name]=a_val
+ if fixeds.has_key(a_name) and fixeds[a_name]!=a_val:
+ self.report_error(2000,a_name)
+ self.skip_ws()
+
+ # --- Take care of the tag
+
+ if self.stack==[] and self.seen_root:
+ self.report_error(3017)
+
+ self.seen_root=1
+
+ if self.now_at(">"):
+ self.app.handle_start_tag(name,attrs)
+ self.stack.append(name)
+ elif self.now_at("/>"):
+ self.app.handle_start_tag(name,attrs)
+ self.app.handle_end_tag(name)
+ else:
+ self.report_error(3004,("'>'","/>"))
+
+ def parse_att_val(self):
+ "Parses an attribute value and resolves all entity references in it."
+
+ val=""
+ if self.now_at('"'):
+ delim='"'
+ reg_attval_stop=reg_attval_stop_quote
+ elif self.now_at("'"):
+ delim="'"
+ reg_attval_stop=reg_attval_stop_sing
+ else:
+ self.report_error(3004,("'","\""))
+ self.scan_to(">")
+ return -1 # FIXME: Ugly. Should throw an exception instead
+
+ while 1:
+ piece=self.find_reg(reg_attval_stop)
+ val=val+string_translate(piece,ws_trans)
+
+ if self.now_at(delim):
+ break
+
+ if self.now_at("&#"):
+ val=val+self._read_char_ref()
+ elif self.now_at("&"):
+ name=self._get_name()
+
+ if name in self.open_ents:
+ self.report_error(3019)
+ return
+ else:
+ self.open_ents.append(name)
+
+ try:
+ ent=self.ent.resolve_ge(name)
+ if ent.is_internal():
+ # Doing all this here sucks a bit, but...
+ self.push_entity(self.get_current_sysid(),\
+ ent.value,name)
+
+ self.final=1 # Only one block
+
+ val=val+self.parse_literal_entval()
+ if not self.pos==self.datasize:
+ self.report_error(3001) # Thing started, not compl
+
+ self.pop_entity()
+ else:
+ self.report_error(3020)
+ except KeyError,e:
+ self.report_error(3021,name) ## FIXME: Check standalone dcl
+
+ del self.open_ents[-1]
+
+ elif self.now_at("<"):
+ self.report_error(3022)
+ continue
+ else:
+ self.report_error(4001)
+ self.pos=self.pos+1 # Avoid endless loop
+ continue
+
+ if not self.now_at(";"):
+ self.report_error(3005,";")
+
+ return val
+
+ def parse_literal_entval(self):
+ "Parses a literal entity value for insertion in an attribute value."
+
+ val=""
+ reg_stop=re.compile("&")
+
+ while 1:
+ try:
+ piece=self.find_reg(reg_stop)
+ except OutOfDataException,e:
+ # Only character data left
+ val=val+string_translate(self.data[self.pos:],ws_trans)
+ self.pos=self.datasize
+ break
+
+ val=val+string_translate(piece,ws_trans)
+
+ if self.now_at("&#"):
+ val=val+self._read_char_ref()
+ elif self.now_at("&"):
+ name=self._get_name()
+
+ if name in self.open_ents:
+ self.report_error(3019)
+ return ""
+ else:
+ self.open_ents.append(name)
+
+ try:
+ ent=self.ent.resolve_ge(name)
+ if ent.is_internal():
+ # Doing all this here sucks a bit, but...
+ self.push_entity(self.get_current_sysid(),\
+ ent.value,name)
+
+ self.final=1 # Only one block
+
+ val=val+self.parse_literal_entval()
+ if not self.pos==self.datasize:
+ self.report_error(3001)
+
+ self.pop_entity()
+ else:
+ self.report_error(3020)
+ except KeyError,e:
+ self.report_error(3021,name)
+
+ del self.open_ents[-1]
+
+ else:
+ self.report_error(4001)
+
+ if not self.now_at(";"):
+ self.report_error(3005,";")
+ self.scan_to(">")
+
+ return val
+
+ def parse_end_tag(self):
+ "Parses the end tag from after the '</' and beyond '>'."
+ self.pos=self.pos+2 # Skips the '</'
+ name=self._get_name()
+
+ if self.data[self.pos]!=">":
+ self.skip_ws() # Probably rare to find whitespace here
+ if not self.now_at(">"): self.report_error(3005,">")
+ else:
+ self.pos=self.pos+1
+
+ try:
+ elem=self.stack[-1]
+ del self.stack[-1]
+ if name!=elem:
+ self.report_error(3023,(name,elem))
+
+ # Let's do some guessing in case we continue
+ if len(self.stack)>0 and self.stack[-1]==name:
+ del self.stack[-1]
+ else:
+ self.stack.append(elem) # Put it back
+
+ except IndexError,e:
+ self.report_error(3024,name)
+
+ self.app.handle_end_tag(name)
+
+ def parse_data(self):
+ "Parses character data."
+ start=self.pos
+ end=string_find(self.data,"<",self.pos)
+ if end==-1:
+ end=string_find(self.data,"&",self.pos)
+
+ if end==-1:
+ if not self.final:
+ raise OutOfDataException()
+
+ end=self.datasize
+ else:
+ ampend=string_find(self.data,"&",self.pos,end)
+ if ampend!=-1:
+ end=ampend
+
+ self.pos=end
+
+ if string_find(self.data,"]]>",start,end)!=-1:
+ self.pos=string_find(self.data,"]]>",start,end)
+ self.report_error(3025)
+ self.pos=self.pos+3 # Skipping over it
+
+ if self.stack==[]:
+ res=reg_ws.match(self.data,start)
+ if res==None or res.end(0)!=end:
+ self.report_error(3029)
+ else:
+ self.app.handle_data(self.data,start,end)
+
+ def parse_charref(self):
+ "Parses a character reference."
+ if self.now_at("x"):
+ digs=unhex(self.get_match(reg_hex_digits))
+ else:
+ try:
+ digs=int(self.get_match(reg_digits))
+ except ValueError,e:
+ self.report_error(3027)
+ digs=None
+
+ if not self.now_at(";"): self.report_error(3005,";")
+ if digs==None: return
+
+ if not (digs==9 or digs==10 or digs==13 or \
+ (digs>=32 and digs<=255)):
+ if digs>255:
+ self.report_error(1005,digs)
+ else:
+ self.report_error(3018,digs)
+ else:
+ if self.stack==[]:
+ self.report_error(3028)
+ self.app.handle_data(chr(digs),0,1)
+
+ def parse_cdata(self):
+ "Parses a CDATA marked section from after the '<![CDATA['."
+ new_pos=self.get_index("]]>")
+ if self.stack==[]:
+ self.report_error(3029)
+ self.app.handle_data(self.data,self.pos,new_pos)
+ self.pos=new_pos+3
+
+ def parse_ent_ref(self):
+ "Parses a general entity reference from after the '&'."
+ name=self._get_name()
+ if not self.now_at(";"): self.report_error(3005,";")
+
+ try:
+ ent=self.ent.resolve_ge(name)
+ except KeyError,e:
+ self.report_error(3021,name)
+ return
+
+ if ent.name in self.open_ents:
+ self.report_error(3019)
+ return
+
+ self.open_ents.append(ent.name)
+
+ if self.stack==[]:
+ self.report_error(3030)
+
+ # Storing size of current element stack
+ stack_size=len(self.stack)
+
+ if ent.is_internal():
+ self.push_entity(self.get_current_sysid(),ent.value,name)
+ try:
+ self.do_parse()
+ except OutOfDataException: # Ran out of data before done
+ self.report_error(3001)
+
+ self.flush()
+ self.pop_entity()
+ else:
+ if ent.notation!="":
+ self.report_error(3031)
+
+ tmp=self.seen_xmldecl
+ self.seen_xmldecl=0 # Avoid complaints
+ self.seen_root=0 # Haven't seen root in the new entity yet
+ self.open_entity(self.pubres.resolve_entity_pubid(ent.get_pubid(),
+ ent.get_sysid()),
+ name)
+ self.seen_root=1 # Entity references only allowed inside elements
+ self.seen_xmldecl=tmp
+
+ # Did any elements cross the entity boundary?
+ if stack_size!=len(self.stack):
+ self.report_error(3042)
+
+ del self.open_ents[-1]
+
+ def parse_doctype(self):
+ "Parses the document type declaration."
+
+ if self.seen_doctype:
+ self.report_error(3032)
+ if self.seen_root:
+ self.report_error(3033)
+
+ self.skip_ws(1)
+ rootname=self._get_name()
+ self.skip_ws(1)
+
+ (pub_id,sys_id)=self.parse_external_id()
+ self.skip_ws()
+
+ self.app.handle_doctype(rootname, pub_id, sys_id)
+ self.dtd.dtd_start()
+
+ if self.now_at("["):
+ self.parse_internal_dtd()
+ elif not self.now_at(">"):
+ self.report_error(3005,">")
+
+ # External subset must be parsed _after_ the internal one
+ if pub_id!=None or sys_id!=None: # Was there an external id at all?
+ if self.read_external_subset:
+ try:
+ sys_id = self.pubres.resolve_doctype_pubid(pub_id, sys_id)
+ p=self._setup_dtd_parser(0)
+ p.dtd_start_called = 1
+ p.parse_resource(join_sysids(self.get_current_sysid(),
+ sys_id))
+ finally:
+ p.deref()
+ self.err.set_locator(self)
+
+ if (pub_id == None and sys_id == None) or \
+ not self.read_external_subset:
+ # If we parse the external subset dtd_end is called for us by
+ # the dtd parser. If we don't we must call it ourselves.
+ self.dtd.dtd_end()
+
+ self.seen_doctype=1 # Has to be at the end to avoid block trouble
+
+ def parse_internal_dtd(self):
+ "Parse the internal DTD beyond the '['."
+
+ self.set_start_point() # Record start of int_subset, preserve data
+ self.update_pos()
+ line=self.line
+ lb=self.last_break
+ last_part_size=0
+
+ while 1:
+ self.find_reg(reg_int_dtd)
+
+ if self.now_at("\""): self.scan_to("\"")
+ elif self.now_at("'"): self.scan_to("'")
+ elif self.now_at("<?"): self.scan_to("?>")
+ elif self.now_at("<!--"): self.scan_to("-->")
+ elif self.now_at("<!["): self.scan_to("]]>")
+ elif self.now_at("]"):
+ p=self.pos
+ self.skip_ws()
+ if self.now_at(">"):
+ last_part_size=(self.pos-p)+1
+ break
+
+ # [:lps] cuts off the "]\s+>" at the end
+ self.handle_internal_dtd(line,lb,self.get_region()[:-last_part_size])
+
+ def handle_internal_dtd(self,doctype_line,doctype_lb,int_dtd):
+ "Handles the internal DTD."
+ try:
+ p=self._setup_dtd_parser(1)
+ try:
+ p.line=doctype_line
+ p.last_break=doctype_lb
+
+ p.set_sysid(self.get_current_sysid())
+ p.final=1
+ p.feed(int_dtd)
+ except OutOfDataException,e:
+ self.report_error(3034)
+ finally:
+ p.deref()
+ self.err.set_locator(self)
+
+ def _setup_dtd_parser(self, internal_subset):
+ p=DTDParser()
+ p.set_error_handler(self.err)
+ p.set_dtd_consumer(self.dtd)
+ p.set_error_language(self.err_lang)
+ p.set_inputsource_factory(self.isf)
+ p.set_pubid_resolver(self.pubres)
+ p.set_dtd_object(self.dtd)
+ if self.dtd_listener!=None:
+ self.dtd.set_dtd_listener(self.dtd_listener)
+ p.set_internal(internal_subset)
+ self.err.set_locator(p)
+ return p
+
+ # ===== The introspection methods =====
+
+ def get_elem_stack(self):
+ "Returns the internal element stack. Note: this is a live list!"
+ return self.stack
+
+ def get_data_buffer(self):
+ "Returns the current data buffer."
+ return self.data
+
+ def get_construct_start(self):
+ """Returns the start position of the current construct (tag, comment,
+ etc)."""
+ return self.prepos
+
+ def get_construct_end(self):
+ """Returns the end position of the current construct (tag, comment,
+ etc)."""
+ return self.pos
+
+ def get_raw_construct(self):
+ "Returns the raw form of the current construct."
+ return self.data[self.prepos:self.pos]
+
+ def get_current_ent_stack(self):
+ """Returns a snapshot of the entity stack. A list of the system
+ identifier of the entity and its name, if any."""
+ return map(lambda ent: (ent[0],ent[9]),self.ent_stack)
diff --git a/lib/jython/Lib/xml/parsers/xmlproc/xmlutils.py b/lib/jython/Lib/xml/parsers/xmlproc/xmlutils.py new file mode 100644 index 000000000..375733342 --- /dev/null +++ b/lib/jython/Lib/xml/parsers/xmlproc/xmlutils.py @@ -0,0 +1,763 @@ +"""
+Some common declarations for the xmlproc system gathered in one file.
+"""
+
+# $Id: xmlutils.py,v 1.13 2001/03/15 00:14:48 larsga Exp $
+
+import string,re,urlparse,os,sys
+
+import xmlapp,charconv,errors
+
+# Standard exceptions
+
+class OutOfDataException(Exception):
+ """An exception that signals that more data is expected, but the current
+ buffer has been exhausted."""
+ pass
+
+# ==============================
+# The general entity parser
+# ==============================
+
+class EntityParser:
+ """A generalized parser for XML entities, whether DTD, documents or even
+ catalog files."""
+
+ def __init__(self):
+ # --- Creating support objects
+ self.err=xmlapp.ErrorHandler(self)
+ self.ent=xmlapp.EntityHandler(self.err)
+ self.isf=xmlapp.InputSourceFactory()
+ self.pubres=xmlapp.PubIdResolver()
+ self.data_charset="iso-8859-1"
+ self.charset_converter=charconv.id_conv # the identity transform
+ self.err_lang="en"
+ self.errors=errors.get_error_list(self.err_lang)
+
+ self.reset()
+
+ def set_error_language(self,language):
+ """Sets the language in which errors are reported. (ISO 3166 codes.)
+ Throws a KeyError if the language is not supported."""
+ self.errors=errors.get_error_list(string.lower(language))
+ self.err_lang=string.lower(language) # only set if supported
+
+ def set_error_handler(self,err):
+ "Sets the object to send error events to."
+ self.err=err
+
+ def set_pubid_resolver(self,pubres):
+ self.pubres=pubres
+
+ def set_entity_handler(self,ent):
+ "Sets the object that resolves entity references."
+ self.ent=ent
+
+ def set_inputsource_factory(self,isf):
+ "Sets the object factory used to create input sources from sysids."
+ self.isf=isf
+
+ def set_data_charset(self,charset):
+ """Tells the parser which character encoding to use when reporting data
+ to applications. [Currently not in use!]"""
+ self.data_charset=charset
+
+ def parse_resource(self,sysID,bufsize=16384):
+ """Begin parsing an XML entity with the specified system
+ identifier. Only used for the document entity, not to handle
+ subentities, which open_entity takes care of."""
+
+ self.current_sysID=sysID
+ try:
+ infile=self.isf.create_input_source(sysID)
+ except IOError,e:
+ self.report_error(3000,sysID)
+ return
+
+ self.read_from(infile,bufsize)
+ infile.close()
+ self.flush()
+ self.parseEnd()
+
+ def open_entity(self,sysID,name="None"):
+ """Starts parsing a new entity, pushing the old onto the stack. This
+ method must not be used to start parsing, use parse_resource for
+ that."""
+
+ sysID=join_sysids(self.get_current_sysid(),sysID)
+
+ try:
+ inf=self.isf.create_input_source(sysID)
+ except IOError,e:
+ self.report_error(3000,sysID)
+ return
+
+ self._push_ent_stack(name)
+ self.current_sysID=sysID
+ self.pos=0
+ self.line=1
+ self.last_break=0
+ self.data=""
+
+ self.read_from(inf)
+
+ self.flush()
+ self.pop_entity()
+
+ def push_entity(self,sysID,contents,name="None"):
+ """Parse some text and consider it a new entity, making it possible
+ to return to the original entity later."""
+ self._push_ent_stack(name)
+ self.data=contents
+ self.current_sysID=sysID
+ self.pos=0
+ self.line=1
+ self.last_break=0
+ self.datasize=len(contents)
+ self.last_upd_pos=0
+ self.final=1
+
+ def pop_entity(self):
+ "Skips out of the current entity and back to the previous one."
+ if self.ent_stack==[]: self.report_error(4000)
+
+ self._pop_ent_stack()
+ self.final=0
+
+ def read_from(self,fileobj,bufsize=16384):
+ """Reads data from a file-like object until EOF. Does not close it.
+ **WARNING**: This method does not call the parseStart/parseEnd methods,
+ since it does not know if it may be called several times. Use
+ parse_resource if you just want to read a file."""
+ while 1:
+ buf=fileobj.read(bufsize)
+ if buf=="": break
+
+ try:
+ self.feed(buf)
+ except OutOfDataException,e:
+ break
+
+ def reset(self):
+ """Resets the parser, losing all unprocessed data."""
+ self.ent_stack=[]
+ self.open_ents=[] # Used to test for entity recursion
+ self.current_sysID="Unknown"
+ self.first_feed=1
+
+ # Block information
+ self.data=""
+ self.final=0
+ self.datasize=0
+ self.start_point=-1
+
+ # Location tracking
+ self.line=1
+ self.last_break=0
+ self.block_offset=0 # Offset from start of stream to start of cur block
+ self.pos=0
+ self.last_upd_pos=0
+
+ def feed(self,new_data):
+ """Accepts more data from the data source. This method must
+ set self.datasize and correctly update self.pos and self.data.
+ It also does character encoding translation."""
+ if self.first_feed:
+ self.first_feed=0
+ self.parseStart()
+
+ self.update_pos() # Update line/col count
+
+ new_data=self.charset_converter(new_data) # Character enc conversion
+
+ if self.start_point==-1:
+ self.block_offset=self.block_offset+self.datasize
+ self.data=self.data[self.pos:]
+ self.last_break=self.last_break-self.pos # Keep track of column
+ self.pos=0
+ self.last_upd_pos=0
+
+ # Adding new data and doing line end normalization
+ self.data=string.replace(self.data+new_data,
+ "\015\012","\012")
+ self.datasize=len(self.data)
+
+ self.do_parse()
+
+ def close(self):
+ "Closes the parser, processing all remaining data. Calls parseEnd."
+ self.flush()
+ self.parseEnd()
+
+ def parseStart(self):
+ "Called before the parse starts to notify subclasses."
+ pass
+
+ def parseEnd(self):
+ "Called when there are no more data to notify subclasses."
+ pass
+
+ def flush(self):
+ "Parses any remnants of data in the last block."
+ if not self.pos+1==self.datasize:
+ self.final=1
+ pos=self.pos
+ try:
+ self.do_parse()
+ except OutOfDataException,e:
+ if pos!=self.pos:
+ self.report_error(3001)
+
+ # --- GENERAL UTILITY
+
+ # --- LOW-LEVEL SCANNING METHODS
+
+ def set_start_point(self):
+ """Stores the current position and tells the parser not to forget any
+ of the data beyond this point until get_region is called."""
+ self.start_point=self.pos
+
+ def store_state(self):
+ """Makes the parser remember where we are now, so we can go back
+ later with restore_state."""
+ self.set_start_point()
+ self.old_state=(self.last_upd_pos,self.line,self.last_break)
+
+ def restore_state(self):
+ """Goes back to a state previously remembered with store_state."""
+ self.pos=self.start_point
+ self.start_point=-1
+ (self.last_upd_pos,self.line,self.last_break)=self.old_state
+
+ def get_region(self):
+ """Returns the area from start_point to current position and remove
+ start_point."""
+ data=self.data[self.start_point:self.pos]
+ self.start_point=-1
+ return data
+
+ def find_reg(self,regexp,required=1):
+ """Moves self.pos to the first character that matches the regexp and
+ returns everything from pos and up to (but not including) that
+ character."""
+ oldpos=self.pos
+ mo=regexp.search(self.data,self.pos)
+ if mo==None:
+ if self.final and not required:
+ self.pos=len(self.data) # Just moved to the end
+ return self.data[oldpos:]
+
+ raise OutOfDataException()
+
+ self.pos=mo.start(0)
+ return self.data[oldpos:self.pos]
+
+ def scan_to(self,target):
+ "Moves self.pos to beyond target and returns skipped text."
+ new_pos=string.find(self.data,target,self.pos)
+ if new_pos==-1:
+ raise OutOfDataException()
+ res=self.data[self.pos:new_pos]
+ self.pos=new_pos+len(target)
+ return res
+
+ def get_index(self,target):
+ "Finds the position where target starts and returns it."
+ new_pos=string.find(self.data,target,self.pos)
+ if new_pos==-1:
+ raise OutOfDataException()
+ return new_pos
+
+ def test_str(self,test_str):
+ "See if text at current position matches test_str, without moving."
+ if self.datasize-self.pos<len(test_str) and not self.final:
+ raise OutOfDataException()
+ return self.data[self.pos:self.pos+len(test_str)]==test_str
+
+ def now_at(self,test_str):
+ "Checks if we are at this string now, and if so skips over it."
+ pos=self.pos
+ if self.datasize-pos<len(test_str) and not self.final:
+ raise OutOfDataException()
+
+ if self.data[pos:pos+len(test_str)]==test_str:
+ self.pos=self.pos+len(test_str)
+ return 1
+ else:
+ return 0
+
+ def skip_ws(self,necessary=0):
+ "Skips over any whitespace at this point."
+ start=self.pos
+
+ try:
+ while self.data[self.pos] in whitespace:
+ self.pos=self.pos+1
+ except IndexError:
+ if necessary and start==self.pos:
+ if self.final:
+ self.report_error(3002)
+ else:
+ raise OutOfDataException()
+
+ def test_reg(self,regexp):
+ "Checks if we match the regexp."
+ if self.pos>self.datasize-5 and not self.final:
+ raise OutOfDataException()
+
+ return regexp.match(self.data,self.pos)!=None
+
+ def get_match(self,regexp):
+ "Returns the result of matching the regexp and advances self.pos."
+ if self.pos>self.datasize-5 and not self.final:
+ raise OutOfDataException()
+
+ ent=regexp.match(self.data,self.pos)
+ if ent==None:
+ self.report_error(reg2code[regexp.pattern])
+ return ""
+
+ end=ent.end(0) # Speeds us up slightly
+ if end==self.datasize:
+ raise OutOfDataException()
+
+ self.pos=end
+ return ent.group(0)
+
+ def update_pos(self):
+ "Updates (line,col)-pos by checking processed blocks."
+ breaks=string.count(self.data,"\n",self.last_upd_pos,self.pos)
+ self.last_upd_pos=self.pos
+
+ if breaks>0:
+ self.line=self.line+breaks
+ self.last_break=string.rfind(self.data,"\n",0,self.pos)
+
+ def get_wrapped_match(self,wraps):
+ "Returns a contained match. Useful for regexps inside quotes."
+ found=0
+ for (wrap,regexp) in wraps:
+ if self.test_str(wrap):
+ found=1
+ self.pos=self.pos+len(wrap)
+ break
+
+ if not found:
+ msg=""
+ for (wrap,regexp) in wraps[:-1]:
+ msg="%s'%s', " % (msg,wrap)
+ self.report_error(3004,(msg[:-2],wraps[-1][0]))
+
+ data=self.get_match(regexp)
+ if not self.now_at(wrap):
+ self.report_error(3005,wrap)
+
+ return data
+
+ #--- ERROR HANDLING
+
+ def report_error(self,number,args=None):
+ try:
+ msg=self.errors[number]
+ if args!=None:
+ msg=msg % args
+ except KeyError:
+ msg=self.errors[4002] # Unknown err msg :-)
+
+ if number<2000:
+ self.err.warning(msg)
+ elif number<3000:
+ self.err.error(msg)
+ else:
+ self.err.fatal(msg)
+
+ #--- USEFUL METHODS
+
+ def get_current_sysid(self):
+ "Returns the sysid of the file we are reading now."
+ return self.current_sysID
+
+ def set_sysid(self,sysID):
+ "Sets the current system identifier. Does not store the old one."
+ self.current_sysID=sysID
+
+ def get_offset(self):
+ "Returns the current offset from the start of the stream."
+ return self.block_offset+self.pos
+
+ def get_line(self):
+ "Returns the current line number."
+ self.update_pos()
+ return self.line
+
+ def get_column(self):
+ "Returns the current column position."
+ self.update_pos()
+ return self.pos-self.last_break
+
+ def is_root_entity(self):
+ "Returns true if the current entity is the root entity."
+ return self.ent_stack==[]
+
+ def is_external(self):
+ """Returns true if the current entity is an external entity. The root
+ (or document) entity is not considered external."""
+ return self.ent_stack!=[] and \
+ self.ent_stack[0][0]!=self.get_current_sysid()
+
+ # --- Internal methods
+
+ def _push_ent_stack(self,name="None"):
+ self.ent_stack.append((self.get_current_sysid(),self.data,self.pos,\
+ self.line,self.last_break,self.datasize,\
+ self.last_upd_pos,self.block_offset,self.final,
+ name))
+
+ def _pop_ent_stack(self):
+ (self.current_sysID,self.data,self.pos,self.line,self.last_break,\
+ self.datasize,self.last_upd_pos,self.block_offset,self.final,dummy)=\
+ self.ent_stack[-1]
+ del self.ent_stack[-1]
+
+# ==============================
+# Common code for some parsers
+# ==============================
+
+class XMLCommonParser(EntityParser):
+
+ def parse_external_id(self,required=0,sysidreq=1):
+ """Parses an external ID declaration and returns a tuple consisting
+ of (pubid,sysid). If the required attribute is false neither SYSTEM
+ nor PUBLIC identifiers are required. If sysidreq is false a SYSTEM
+ identifier is not required after a PUBLIC one."""
+
+ pub_id=None
+ sys_id=None
+
+ if self.now_at("SYSTEM"):
+ self.skip_ws(1)
+ sys_id=self.get_wrapped_match([("\"",reg_sysid_quote),\
+ ("'",reg_sysid_apo)])
+ elif self.now_at("PUBLIC"):
+ self.skip_ws(1)
+ pub_id=self.get_wrapped_match([("\"",reg_pubid_quote),\
+ ("'",reg_pubid_apo)])
+ pub_id=string.join(string.split(pub_id))
+
+ if sysidreq:
+ self.skip_ws(1)
+ sys_id=self.get_wrapped_match([("\"",reg_sysid_quote),\
+ ("'",reg_sysid_apo)])
+ else:
+ if self.test_str("'") or self.test_str('"'):
+ self.report_error(3002)
+ self.skip_ws()
+ if self.test_str("'") or self.test_str('"'):
+ sys_id=self.get_wrapped_match([("\"",reg_sysid_quote),\
+ ("'",reg_sysid_apo)])
+ else:
+ if required: self.report_error(3006)
+
+ return (pub_id,sys_id)
+
+ def __get_quoted_string(self):
+ "Returns the contents of a quoted string at current position."
+ try:
+ quo=self.data[self.pos]
+ except IndexError:
+ raise OutOfDataException()
+
+ if not (self.now_at('"') or self.now_at("'")):
+ self.report_error(3004,("'\"'","'"))
+ self.scan_to(">")
+ return ""
+
+ return self.scan_to(quo)
+
+ def parse_xml_decl(self,handler=None):
+ "Parses the contents of the XML declaration from after the '<?xml'."
+
+ textdecl=self.is_external() # If this is an external entity, then this
+ # is a text declaration, not an XML decl
+
+ self.update_pos()
+ if self.get_column()!=5 or self.get_line()!=1 or \
+ (self.ent_stack!=[] and not textdecl):
+ if textdecl:
+ self.report_error(3007)
+ else:
+ self.report_error(3008)
+
+ if self.seen_xmldecl: # Set in parse_pi, to avoid block problems
+ if textdecl:
+ self.report_error(3009)
+ else:
+ self.report_error(3010)
+
+ enc=None
+ sddecl=None
+ ver=None
+ self.skip_ws()
+
+ if self.now_at("version"):
+ self.skip_ws()
+ if not self.now_at("="): self.report_error(3005,"=")
+ self.skip_ws()
+ ver=self.__get_quoted_string()
+
+ m=reg_ver.match(ver)
+ if m==None or m.end()!=len(ver):
+ self.report_error(3901,ver)
+ elif ver!="1.0":
+ self.report_error(3046)
+
+ if self.test_str("encoding") or self.test_str("standalone"):
+ self.report_error(3002)
+ self.skip_ws()
+ elif not textdecl:
+ self.report_error(3011)
+
+ if self.now_at("encoding"):
+ self.skip_ws()
+ if not self.now_at("="): self.report_error(3005,"=")
+ self.skip_ws()
+ enc=self.__get_quoted_string()
+ if reg_enc_name.match(enc)==None:
+ self.report_error(3902)
+
+ # Setting up correct conversion
+ if charconv.convdb.can_convert(enc,self.data_charset):
+ self.charset_converter=\
+ charconv.convdb.get_converter(enc,self.data_charset)
+ else:
+ self.report_error(1002,enc)
+
+ self.skip_ws()
+
+ if self.now_at("standalone"):
+ if textdecl:
+ self.report_error(3012)
+ sddecl="yes"
+ else:
+ self.skip_ws()
+ if not self.now_at("="): self.report_error(3005,"=")
+ self.skip_ws()
+ sddecl=self.__get_quoted_string()
+ if reg_std_alone.match(sddecl)==None:
+ self.report_error(3911)
+
+ self.standalone= sddecl=="yes"
+
+ self.skip_ws()
+
+ self.skip_ws()
+
+ if handler!=None:
+ handler.set_entity_info(ver,enc,sddecl)
+
+ def parse_pi(self,handler,report_xml_decl=0):
+ """Parses a processing instruction from after the '<?' to beyond
+ the '?>'."""
+ trgt=self._get_name()
+
+ if trgt=="xml":
+ if report_xml_decl:
+ self.parse_xml_decl(handler)
+ else:
+ self.parse_xml_decl()
+
+ if not self.now_at("?>"):
+ self.report_error(3005,"?>")
+ self.seen_xmldecl=1
+ else:
+ if self.now_at("?>"):
+ rem=""
+ else:
+ self.skip_ws(1)
+ rem=self.scan_to("?>") # OutOfDataException if not found
+
+ if reg_res_pi.match(trgt)!=None:
+ if trgt=="xml:namespace":
+ self.report_error(1003)
+ elif trgt!="xml-stylesheet":
+ self.report_error(3045)
+
+ handler.handle_pi(trgt,rem)
+
+ def parse_comment(self,handler):
+ "Parses the comment from after '<!--' to beyond '-->'."
+ new_pos = self.get_index("--")
+ handler.handle_comment(self.data[self.pos : new_pos])
+ self.pos = new_pos
+ if not self.now_at("-->"):
+ self.report_error(3005,"-->")
+
+ def _read_char_ref(self):
+ "Parses a character reference and returns the character."
+ if self.now_at("x"):
+ digs=unhex(self.get_match(reg_hex_digits))
+ else:
+ digs=int(self.get_match(reg_digits))
+
+ if not (digs==9 or digs==10 or digs==13 or \
+ (digs>=32 and digs<=255)):
+ if digs>255:
+ self.report_error(1005,digs)
+ else:
+ self.report_error(3018,digs)
+ return ""
+ else:
+ return chr(digs)
+
+ def _get_name(self):
+ """Parses the name at the current position and returns it. An error
+ is reported if no name is present."""
+ if self.pos>self.datasize-5 and not self.final:
+ raise OutOfDataException()
+
+ data=self.data
+ pos=self.pos
+ if data[pos] in namestart:
+ start=pos
+ pos=pos+1
+
+ try:
+ while data[pos] in namechars:
+ pos=pos+1
+
+ self.pos=pos
+ return intern(data[start:pos])
+ except IndexError:
+ self.pos=pos
+ if self.final:
+ return intern(data[start:])
+ else:
+ raise OutOfDataException()
+ else:
+ self.report_error(3900)
+ return ""
+
+# --- A collection of useful functions
+
+# Utility functions
+
+def unhex(hex_value):
+ "Converts a string hex-value to an integer."
+
+ sum=0
+ for char in hex_value:
+ sum=sum*16
+ char=ord(char)
+
+ if char<58 and char>=48:
+ sum=sum+(char-48)
+ elif char>=97 and char<=102:
+ sum=sum+(char-87)
+ elif char>=65 and char<=70:
+ sum=sum+(char-55)
+ # else ERROR, but it can't occur here
+
+ return sum
+
+def matches(regexp,str):
+ mo=regexp.match(str)
+ return mo!=None and len(mo.group(0))==len(str)
+
+def join_sysids_general(base,url):
+ if urlparse.urlparse(base)[0]=="":
+ if urlparse.urlparse(url)[0]=="":
+ return os.path.join(os.path.split(base)[0],url)
+ else:
+ return url
+ else:
+ return urlparse.urljoin(base,url)
+
+def join_sysids_win32(base,url):
+ if len(urlparse.urlparse(base)[0])<2: # Handles drive identifiers correctly
+ if len(urlparse.urlparse(url)[0])<2:
+ return os.path.join(os.path.split(base)[0],url)
+ else:
+ return url
+ else:
+ return urlparse.urljoin(base,url)
+
+# here join_sysids(base,url): is set to the correct function
+
+if sys.platform=="win32":
+ join_sysids=join_sysids_win32
+else:
+ join_sysids=join_sysids_general
+
+# --- Some useful regexps
+
+namestart="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_:"+\
+ "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ"
+namechars=namestart+"0123456789.·-"
+whitespace="\n\t \r"
+
+reg_ws=re.compile("[\n\t \r]+")
+reg_ver=re.compile("[-a-zA-Z0-9_.:]+")
+reg_enc_name=re.compile("[A-Za-z][-A-Za-z0-9._]*")
+reg_std_alone=re.compile("yes|no")
+reg_name=re.compile("["+namestart+"]["+namechars+"]*")
+reg_names=re.compile("["+namestart+"]["+namechars+"]*"
+ "([\n\t \r]+["+namestart+"]["+namechars+"]*)*")
+reg_nmtoken=re.compile("["+namechars+"]+")
+reg_nmtokens=re.compile("["+namechars+"]+([\n\t \r]+["+namechars+"]+)*")
+reg_sysid_quote=re.compile("[^\"]*")
+reg_sysid_apo=re.compile("[^']*")
+reg_pubid_quote=re.compile("[- \n\t\ra-zA-Z0-9'()+,./:=?;!*#@$_%]*")
+reg_pubid_apo=re.compile("[- \n\t\ra-zA-Z0-9()+,./:=?;!*#@$_%]*")
+reg_start_tag=re.compile("<[A-Za-z_:]")
+reg_quoted_attr=re.compile("[^<\"]*")
+reg_apo_attr=re.compile("[^<']*")
+reg_c_data=re.compile("[<&]")
+reg_pe_ref=re.compile("%["+namestart+"]["+namechars+"]*;")
+
+reg_ent_val_quote=re.compile("[^\"]+")
+reg_ent_val_apo=re.compile("[^\']+")
+
+reg_attr_type=re.compile(r"CDATA|IDREFS|IDREF|ID|ENTITY|ENTITIES|NMTOKENS|"
+ "NMTOKEN") # NOTATION support separate
+reg_attr_def=re.compile(r"#REQUIRED|#IMPLIED")
+
+reg_digits=re.compile("[0-9]+")
+reg_hex_digits=re.compile("[0-9a-fA-F]+")
+
+reg_res_pi=re.compile("xml",re.I)
+
+reg_int_dtd=re.compile("\"|'|<\\?|<!--|\\]|<!\\[")
+
+reg_attval_stop_quote=re.compile("<|&|\"")
+reg_attval_stop_sing=re.compile("<|&|'")
+
+reg_decl_with_pe=re.compile("<(![^-\[]|\?)")
+reg_subst_pe_search=re.compile(">|%")
+
+reg_cond_sect=re.compile("<!\\[|\\]\\]>")
+reg_litval_stop=re.compile("%|&#")
+
+# RFC 1766 language codes
+
+reg_lang_code=re.compile("([a-zA-Z][a-zA-Z]|[iIxX]-([a-zA-Z])+)(-[a-zA-Z])*")
+
+# Mapping regexps to error codes
+# NB: 3900 is reported directly from _get_name
+
+reg2code={
+ reg_name.pattern : 3900, reg_ver.pattern : 3901,
+ reg_enc_name.pattern : 3902, reg_std_alone.pattern : 3903,
+ reg_hex_digits.pattern : 3905,
+ reg_digits.pattern : 3906, reg_pe_ref.pattern : 3907,
+ reg_attr_type.pattern : 3908, reg_attr_def.pattern : 3909,
+ reg_nmtoken.pattern : 3910}
+
+# Some useful variables
+
+predef_ents={"lt":"<","gt":">","amp":"&","apos":"'",
+ "quot":'"'}
+
+# Translation tables
+
+ws_trans=string.maketrans("\r\t\n"," ") # Whitespace normalization
+id_trans=string.maketrans("","") # Identity transform
diff --git a/lib/jython/Lib/xml/parsers/xmlproc/xmlval.py b/lib/jython/Lib/xml/parsers/xmlproc/xmlval.py new file mode 100644 index 000000000..250684c16 --- /dev/null +++ b/lib/jython/Lib/xml/parsers/xmlproc/xmlval.py @@ -0,0 +1,310 @@ +
+"""This is the parts of xmlproc that are specific to validation. They
+are an application class that receive data from the parser and a
+subclass of the parser object that sets this up.
+
+$Id: xmlval.py,v 1.11 2001/03/03 07:32:35 loewis Exp $
+"""
+
+import urlparse,os,anydbm,string,cPickle,time
+
+from xmlproc import *
+from xmldtd import *
+from xmlapp import *
+
+# ==============================
+# The validator class
+# ==============================
+
+class XMLValidator:
+ """XML parser that validates a document and does some of what is required
+ of a validating parser, like adding fixed and default attribute values
+ etc."""
+
+ def __init__(self):
+ self.parser=XMLProcessor()
+ self.app=Application()
+ self.dtd=CompleteDTD(self.parser)
+ self.val=ValidatingApp(self.dtd,self.parser)
+ self.reset()
+
+ def parse_resource(self,sysid):
+ self.parser.parse_resource(sysid)
+
+ def reset(self):
+ self.dtd.reset()
+ self.val.reset()
+
+ self.parser.reset()
+ self.parser.set_application(self.val)
+ self.parser.dtd=self.dtd
+ self.parser.ent=self.dtd
+ self.parser.set_read_external_subset(1)
+
+ def feed(self,data):
+ self.parser.feed(data)
+
+ def close(self):
+ self.parser.close()
+
+ def deref(self):
+ self.parser.deref()
+
+ def set_application(self,app):
+ self.app=app
+ self.val.set_real_app(self.app)
+ app.set_locator(self.parser)
+
+ def set_error_language(self,language):
+ self.parser.set_error_language(language)
+
+ def set_error_handler(self,err):
+ self.parser.set_error_handler(err)
+
+ def set_dtd_listener(self,dtd_listener):
+ self.parser.set_dtd_listener(dtd_listener)
+
+ def set_inputsource_factory(self,isf):
+ self.parser.set_inputsource_factory(isf)
+
+ def set_pubid_resolver(self,pubres):
+ self.val.set_pubid_resolver(pubres)
+ self.parser.set_pubid_resolver(pubres)
+
+ def set_data_after_wf_error(self,stop_on_wf=0):
+ self.parser.set_data_after_wf_error(stop_on_wf)
+
+ def set_sysid(self, sysid):
+ self.parser.set_sysid(sysid)
+
+ def set_read_external_subset(self,read_it):
+ pass # This parser always reads it
+
+ def get_dtd(self):
+ return self.dtd
+
+ def get_current_sysid(self):
+ return self.parser.get_current_sysid()
+
+ def get_offset(self):
+ return self.parser.get_offset()
+
+ def get_line(self):
+ return self.parser.get_line()
+
+ def get_column(self):
+ return self.parser.get_column()
+
+ def parseStart(self):
+ self.parser.parseStart()
+
+ def parseEnd(self):
+ self.parser.parseEnd()
+
+ def read_from(self,file,bufsize=16384):
+ self.parser.read_from(file,bufsize)
+
+ def flush(self):
+ self.parser.flush()
+
+ def report_error(self,errno,args=None):
+ self.parser.report_error(errno,args)
+
+ # ===== The introspection methods =====
+
+ def get_elem_stack(self):
+ "Returns the internal element stack. Note: this is a live list!"
+ return self.parser.stack
+
+ def get_data_buffer(self):
+ "Returns the current data buffer."
+ return self.parser.data
+
+ def get_construct_start(self):
+ """Returns the start position of the current construct (tag, comment,
+ etc)."""
+ return self.parser.prepos
+
+ def get_construct_end(self):
+ """Returns the end position of the current construct (tag, comment,
+ etc)."""
+ return self.parser.pos
+
+ def get_raw_construct(self):
+ "Returns the raw form of the current construct."
+ return self.parser.data[self.parser.prepos:parser.self.pos]
+
+ def get_current_ent_stack(self):
+ """Returns a snapshot of the entity stack. A list of the system
+ identifier of the entity and its name, if any."""
+ return map(lambda ent: (ent[0],ent[9]),self.parser.ent_stack)
+
+# ==============================
+# Application object that checks the document
+# ==============================
+
+class ValidatingApp(Application):
+ "The object that uses the DTD to actually validate XML documents."
+
+ def __init__(self,dtd,parser):
+ self.dtd=dtd
+ self.parser=parser
+ self.realapp=Application()
+ self.pubres=PubIdResolver()
+ self.reset()
+
+ def reset(self):
+ self.cur_elem=None
+ self.cur_state=0
+ self.stack=[]
+ self.ids={}
+ self.idrefs=[]
+
+ def set_real_app(self,app):
+ self.realapp=app
+
+ def set_pubid_resolver(self,pubres):
+ self.pubres=pubres
+
+ def set_locator(self,locator):
+ Application.set_locator(self,locator)
+ self.realapp.set_locator(locator)
+
+ def handle_start_tag(self,name,attrs):
+ decl_root=self.dtd.get_root_elem()
+
+ if self.cur_elem!=None:
+ if self.cur_state!=-1:
+ next=self.cur_elem.next_state(self.cur_state,name)
+ if next==0:
+ self.parser.report_error(2001,name)
+ else:
+ self.cur_state=next
+
+ self.stack.append((self.cur_elem,self.cur_state))
+ elif decl_root!=None and name!=decl_root:
+ self.parser.report_error(2002,name)
+
+ try:
+ self.cur_elem=self.dtd.get_elem(name)
+ self.cur_state=self.cur_elem.get_start_state()
+ self.validate_attributes(self.dtd.get_elem(name),attrs)
+ except KeyError,e:
+ self.parser.report_error(2003,name)
+ self.cur_state=-1
+
+ self.realapp.handle_start_tag(name,attrs)
+
+ def handle_end_tag(self,name):
+ "Notifies the application of end tags (and empty element tags)."
+ if self.cur_elem!=None and \
+ not self.cur_elem.final_state(self.cur_state):
+ self.parser.report_error(2004,name)
+
+ if self.stack!=[]:
+ (self.cur_elem,self.cur_state)=self.stack[-1]
+ del self.stack[-1]
+
+ self.realapp.handle_end_tag(name)
+
+ def handle_data(self,data,start,end):
+ "Notifies the application of character data."
+ if self.cur_elem!=None and self.cur_state!=-1:
+ next=self.cur_elem.next_state(self.cur_state,"#PCDATA")
+
+ if next==0:
+ self.realapp.handle_ignorable_data(data,start,end)
+ for ch in data[start:end]:
+ if not ch in " \t\r\n":
+ self.parser.report_error(2005)
+ break
+
+ return
+ else:
+ self.cur_state=next
+
+ self.realapp.handle_data(data,start,end)
+
+ def validate_attributes(self,element,attrs):
+ """Validates the attributes against the element declaration and adds
+ fixed and default attributes."""
+
+ # Check the values of the present attributes
+ for attr in attrs.keys():
+ try:
+ decl=element.get_attr(attr)
+ except KeyError,e:
+ self.parser.report_error(2006,attr)
+ return
+
+ if decl.type!="CDATA":
+ attrs[attr]=string.join(string.split(attrs[attr]))
+
+ decl.validate(attrs[attr],self.parser)
+
+ if decl.type=="ID":
+ if self.ids.has_key(attrs[attr]):
+ self.parser.report_error(2007,attrs[attr])
+ self.ids[attrs[attr]]=""
+ elif decl.type=="IDREF":
+ self.idrefs.append((self.locator.get_line(),
+ self.locator.get_column(),
+ attrs[attr]))
+ elif decl.type=="IDREFS":
+ for idref in string.split(attrs[attr]):
+ self.idrefs.append((self.locator.get_line(),
+ self.locator.get_column(),
+ idref))
+ elif decl.type=="ENTITY":
+ self.__validate_attr_entref(attrs[attr])
+ elif decl.type=="ENTITIES":
+ for ent_ref in string.split(attrs[attr]):
+ self.__validate_attr_entref(ent_ref)
+
+ # Check for missing required attributes
+ for attr in element.get_attr_list():
+ decl=element.get_attr(attr)
+ if decl.decl=="#REQUIRED" and not attrs.has_key(attr):
+ self.parser.report_error(2010,attr)
+
+ def __validate_attr_entref(self,name):
+ try:
+ ent=self.dtd.resolve_ge(name)
+ if ent.notation=="":
+ self.parser.report_error(2008)
+ else:
+ try:
+ self.dtd.get_notation(ent.notation)
+ except KeyError,e:
+ self.parser.report_error(2009,ent.notation)
+ except KeyError,e:
+ self.parser.report_error(3021,name)
+
+ def doc_end(self):
+ for (line,col,id) in self.idrefs:
+ if not self.ids.has_key(id):
+ self.parser.report_error(2011,id)
+
+ self.realapp.doc_end()
+
+ def handle_doctype(self,rootname,pub_id,sys_id):
+ self.realapp.handle_doctype(rootname,pub_id,sys_id)
+ self.dtd.root_elem=rootname
+
+ # --- These methods added only to make this hanger-on application
+ # invisible to external users.
+
+ def doc_start(self):
+ self.realapp.doc_start()
+
+ def handle_comment(self,data):
+ self.realapp.handle_comment(data)
+
+ def handle_ignorable_data(self,data,start,end):
+ self.realapp.handle_ignorable_data(data,start,end)
+
+ def handle_pi(self,target,data):
+ self.realapp.handle_pi(target,data)
+
+ def set_entity_info(self,xmlver,enc,sddecl):
+ self.realapp.set_entity_info(xmlver,enc,sddecl)
diff --git a/lib/jython/Lib/xml/sax/__init__.py b/lib/jython/Lib/xml/sax/__init__.py new file mode 100644 index 000000000..e76618cb7 --- /dev/null +++ b/lib/jython/Lib/xml/sax/__init__.py @@ -0,0 +1,47 @@ +"""Simple API for XML (SAX) implementation for Python.
+
+This module provides an implementation of the SAX 2 interface;
+information about the Java version of the interface can be found at
+http://www.megginson.com/SAX/. The Python version of the interface is
+documented at <...>.
+
+This package contains the following interface classes and functions:
+
+ContentHandler, ErrorHandler - base classes for SAX2 handlers
+SAXException, SAXNotRecognizedException,
+SAXParseException, SAXNotSupportedException - SAX exceptions
+
+make_parser - creation of a new parser object
+parse, parseString - parse a document, using a provided handler
+
+"""
+
+from xmlreader import InputSource
+from handler import ContentHandler, ErrorHandler
+from _exceptions import SAXException, SAXNotRecognizedException,\
+ SAXParseException, SAXNotSupportedException,\
+ SAXReaderNotAvailable
+
+from sax2exts import make_parser
+
+def parse(filename_or_stream, handler, errorHandler=ErrorHandler()):
+ parser = make_parser()
+ parser.setContentHandler(handler)
+ parser.setErrorHandler(errorHandler)
+ parser.parse(filename_or_stream)
+
+def parseString(string, handler, errorHandler=ErrorHandler()):
+ try:
+ from cStringIO import StringIO
+ except ImportError:
+ from StringIO import StringIO
+
+ if errorHandler is None:
+ errorHandler = ErrorHandler()
+ parser = make_parser()
+ parser.setContentHandler(handler)
+ parser.setErrorHandler(errorHandler)
+
+ inpsrc = InputSource()
+ inpsrc.setByteStream(StringIO(string))
+ parser.parse(inpsrc)
diff --git a/lib/jython/Lib/xml/sax/_exceptions.py b/lib/jython/Lib/xml/sax/_exceptions.py new file mode 100644 index 000000000..b4f534bb7 --- /dev/null +++ b/lib/jython/Lib/xml/sax/_exceptions.py @@ -0,0 +1,126 @@ +"""Different kinds of SAX Exceptions"""
+import sys
+if sys.platform[:4] == "java":
+ from java.lang import Exception
+del sys
+
+# ===== SAXEXCEPTION =====
+
+class SAXException(Exception):
+ """Encapsulate an XML error or warning. This class can contain
+ basic error or warning information from either the XML parser or
+ the application: you can subclass it to provide additional
+ functionality, or to add localization. Note that although you will
+ receive a SAXException as the argument to the handlers in the
+ ErrorHandler interface, you are not actually required to throw
+ the exception; instead, you can simply read the information in
+ it."""
+
+ def __init__(self, msg, exception=None):
+ """Creates an exception. The message is required, but the exception
+ is optional."""
+ self._msg = msg
+ self._exception = exception
+ Exception.__init__(self, msg)
+
+ def getMessage(self):
+ "Return a message for this exception."
+ return self._msg
+
+ def getException(self):
+ "Return the embedded exception, or None if there was none."
+ return self._exception
+
+ def __str__(self):
+ "Create a string representation of the exception."
+ return self._msg
+
+ def __getitem__(self, ix):
+ """Avoids weird error messages if someone does exception[ix] by
+ mistake, since Exception has __getitem__ defined."""
+ raise AttributeError("__getitem__")
+
+
+# ===== SAXPARSEEXCEPTION =====
+
+class SAXParseException(SAXException):
+ """Encapsulate an XML parse error or warning.
+
+ This exception will include information for locating the error in
+ the original XML document. Note that although the application will
+ receive a SAXParseException as the argument to the handlers in the
+ ErrorHandler interface, the application is not actually required
+ to throw the exception; instead, it can simply read the
+ information in it and take a different action.
+
+ Since this exception is a subclass of SAXException, it inherits
+ the ability to wrap another exception."""
+
+ def __init__(self, msg, exception, locator):
+ "Creates the exception. The exception parameter is allowed to be None."
+ SAXException.__init__(self, msg, exception)
+ self._locator = locator
+
+ # We need to cache this stuff at construction time.
+ # If this exception is thrown, the objects through which we must
+ # traverse to get this information may be deleted by the time
+ # it gets caught.
+ self._systemId = self._locator.getSystemId()
+ self._colnum = self._locator.getColumnNumber()
+ self._linenum = self._locator.getLineNumber()
+
+ def getColumnNumber(self):
+ """The column number of the end of the text where the exception
+ occurred."""
+ return self._colnum
+
+ def getLineNumber(self):
+ "The line number of the end of the text where the exception occurred."
+ return self._linenum
+
+ def getPublicId(self):
+ "Get the public identifier of the entity where the exception occurred."
+ return self._locator.getPublicId()
+
+ def getSystemId(self):
+ "Get the system identifier of the entity where the exception occurred."
+ return self._systemId
+
+ def __str__(self):
+ "Create a string representation of the exception."
+ sysid = self.getSystemId()
+ if sysid is None:
+ sysid = "<unknown>"
+ return "%s:%d:%d: %s" % (sysid, self.getLineNumber(),
+ self.getColumnNumber(), self._msg)
+
+
+# ===== SAXNOTRECOGNIZEDEXCEPTION =====
+
+class SAXNotRecognizedException(SAXException):
+ """Exception class for an unrecognized identifier.
+
+ An XMLReader will raise this exception when it is confronted with an
+ unrecognized feature or property. SAX applications and extensions may
+ use this class for similar purposes."""
+
+
+# ===== SAXNOTSUPPORTEDEXCEPTION =====
+
+class SAXNotSupportedException(SAXException):
+ """Exception class for an unsupported operation.
+
+ An XMLReader will raise this exception when a service it cannot
+ perform is requested (specifically setting a state or value). SAX
+ applications and extensions may use this class for similar
+ purposes."""
+
+# ===== SAXNOTSUPPORTEDEXCEPTION =====
+
+class SAXReaderNotAvailable(SAXNotSupportedException):
+ """Exception class for a missing driver.
+
+ An XMLReader module (driver) should raise this exception when it
+ is first imported, e.g. when a support module cannot be imported.
+ It also may be raised during parsing, e.g. if executing an external
+ program is not permitted."""
diff --git a/lib/jython/Lib/xml/sax/drivers2/__init__.py b/lib/jython/Lib/xml/sax/drivers2/__init__.py new file mode 100644 index 000000000..cd29f76cf --- /dev/null +++ b/lib/jython/Lib/xml/sax/drivers2/__init__.py @@ -0,0 +1 @@ +"Directory for SAX version 2 drivers."
diff --git a/lib/jython/Lib/xml/sax/drivers2/drv_xmlproc.py b/lib/jython/Lib/xml/sax/drivers2/drv_xmlproc.py new file mode 100644 index 000000000..192ee056a --- /dev/null +++ b/lib/jython/Lib/xml/sax/drivers2/drv_xmlproc.py @@ -0,0 +1,392 @@ +"""
+A SAX 2.0 driver for xmlproc.
+
+$Id: drv_xmlproc.py,v 1.8 2001/03/04 22:10:49 loewis Exp $
+"""
+
+import types, string
+
+from xml.parsers.xmlproc import xmlproc, xmlval, xmlapp
+from xml.sax import saxlib
+from xml.sax.xmlreader import AttributesImpl, AttributesNSImpl
+from xml.sax.saxutils import ContentGenerator, prepare_input_source
+
+# Todo
+# - EntityResolver
+# - as much as possible of LexicalHandler
+# - entity expansion features
+# - core properties
+# - extra properties/features
+# - element stack
+# - entity stack
+# - current error code
+# - byte offset
+# - DTD object
+# - catalog path
+# - use catalogs
+# - regression test
+# - methods from Python SAX extensions?
+# - remove FIXMEs
+
+class XmlprocDriver(saxlib.XMLReader):
+
+ # ===== SAX 2.0 INTERFACES
+
+ # --- XMLReader methods
+
+ def __init__(self):
+ saxlib.XMLReader.__init__(self)
+ self.__parsing = 0
+ self.__validate = 0
+ self.__namespaces = 1
+
+ self.__locator = 0
+
+ self._lex_handler = saxlib.LexicalHandler()
+ self._decl_handler = saxlib.DeclHandler()
+
+ def parse(self, source):
+ try:
+ self.__parsing = 1
+
+ # interpret source
+
+ source = prepare_input_source(source)
+
+ # create parser
+
+ if self.__validate:
+ parser = xmlval.XMLValidator()
+ else:
+ parser = xmlproc.XMLProcessor()
+
+ # set handlers
+
+ if self._cont_handler != None or self._lex_handler != None:
+ if self._cont_handler == None:
+ self._cont_handler = saxlib.ContentHandler()
+ if self._lex_handler == None:
+ self._lex_handler = saxlib.LexicalHandler()
+
+ if self.__namespaces:
+ filter = NamespaceFilter(parser, self._cont_handler,
+ self._lex_handler, self)
+ parser.set_application(filter)
+ else:
+ parser.set_application(self)
+
+ if self._err_handler != None:
+ parser.set_error_handler(self)
+
+ if self._decl_handler != None or self._dtd_handler != None:
+ parser.set_dtd_listener(self)
+
+ # FIXME: set other handlers
+
+ bufsize=16384
+ self._parser = parser # make it available for callbacks
+ #parser.parse_resource(source.getSystemId()) # FIXME: rest!
+ parser.set_sysid(source.getSystemId())
+ parser.read_from(source.getByteStream(), bufsize)
+ source.getByteStream().close()
+ parser.flush()
+ parser.parseEnd()
+
+ finally:
+ self._parser = None
+ self.__parsing = 0
+
+ def setLocale(self, locale):
+ pass
+
+ def getFeature(self, name):
+ if name == saxlib.feature_string_interning or \
+ name == saxlib.feature_external_ges or \
+ name == saxlib.feature_external_pes:
+ return 1
+ elif name == saxlib.feature_validation:
+ return self.__validate
+ elif name == saxlib.feature_namespaces:
+ return self.__namespaces
+ else:
+ raise saxlib.SAXNotRecognizedException("Feature '%s' not recognized" %
+ name)
+
+ def setFeature(self, name, state):
+ if self.__parsing:
+ raise saxlib.SAXNotSupportedException("Cannot set feature '%s' during parsing" % name)
+
+ if name == saxlib.feature_string_interning:
+ pass
+ elif name == saxlib.feature_validation:
+ self.__validate = state
+ elif name == saxlib.feature_namespaces:
+ self.__namespaces = state
+ elif name == saxlib.feature_external_ges or \
+ name == saxlib.feature_external_pes:
+ if not state:
+ raise saxlib.SAXNotSupportedException("This feature cannot be turned off with xmlproc.")
+ else:
+ raise saxlib.SAXNotRecognizedException("Feature '%s' not recognized" %
+ name)
+
+ def getProperty(self, name):
+ if name == saxlib.property_lexical_handler:
+ return self._lex_handler
+ elif name == saxlib.property_declaration_handler:
+ return self._decl_handler
+
+ raise saxlib.SAXNotRecognizedException("Property '%s' not recognized" % name)
+
+ def setProperty(self, name, value):
+ if name == saxlib.property_lexical_handler:
+ self._lex_handler = value
+ elif name == saxlib.property_declaration_handler:
+ self._decl_handler = value
+ else:
+ raise saxlib.SAXNotRecognizedException("Property '%s' not recognized" % name)
+
+ # --- Locator methods
+
+ def getColumnNumber(self):
+ return self._parser.get_column()
+
+ def getLineNumber(self):
+ return self._parser.get_line()
+
+ def getPublicId(self):
+ return None # FIXME: Try to find this. Perhaps from InputSource?
+
+ def getSystemId(self):
+ return self._parser.get_current_sysid() # FIXME?
+
+ # ===== XMLPROC INTERFACES
+
+ # --- Application methods
+
+ def set_locator(self, locator):
+ self._locator = locator
+
+ def doc_start(self):
+ self._cont_handler.startDocument()
+
+ def doc_end(self):
+ self._cont_handler.endDocument()
+
+ def handle_comment(self, data):
+ self._lex_handler.comment(data)
+
+ def handle_start_tag(self, name, attrs):
+ self._cont_handler.startElement(name, AttributesImpl(attrs))
+
+ def handle_end_tag(self,name):
+ self._cont_handler.endElement(name)
+
+ def handle_data(self, data, start, end):
+ self._cont_handler.characters(data[start:end])
+
+ def handle_ignorable_data(self, data, start, end):
+ self._cont_handler.ignorableWhitespace(data[start:end])
+
+ def handle_pi(self, target, data):
+ self._cont_handler.processingInstruction(target, data)
+
+ def handle_doctype(self, root, pubId, sysId):
+ self._lex_handler.startDTD(root, pubId, sysId)
+
+ def set_entity_info(self, xmlver, enc, sddecl):
+ pass
+
+ # --- ErrorHandler methods
+
+ # set_locator implemented as Application method above
+
+ def get_locator(self):
+ return self._locator
+
+ def warning(self, msg):
+ self._err_handler.warning(saxlib.SAXParseException(msg, None, self))
+
+ def error(self, msg):
+ self._err_handler.error(saxlib.SAXParseException(msg, None, self))
+
+ def fatal(self, msg):
+ self._err_handler.fatalError(saxlib.SAXParseException(msg, None, self))
+
+ # --- DTDConsumer methods
+
+ def dtd_start(self):
+ pass # this is done by handle_doctype
+
+ def dtd_end(self):
+
+ self._lex_handler.endDTD()
+
+ def handle_comment(self, contents):
+ self._lex_handler.comment(contents)
+
+ def handle_pi(self, target, rem):
+ self._cont_handler.processingInstruction(target, rem)
+
+ def new_general_entity(self, name, val):
+ self._decl_handler.internalEntityDecl(name, val)
+
+ def new_external_entity(self, ent_name, pub_id, sys_id, ndata):
+ if not ndata:
+ self._decl_handler.externalEntityDecl(ent_name, pub_id, sys_id)
+ else:
+ self._dtd_handler.unparsedEntityDecl(ent_name, pub_id, sys_id,
+ ndata)
+
+ def new_parameter_entity(self, name, val):
+ self._decl_handler.internalEntityDecl("%" + name, val)
+
+ def new_external_pe(self, name, pubid, sysid):
+ self._decl_handler.externalEntityDecl("%" + name, pubid, sysid)
+
+ def new_notation(self, name, pubid, sysid):
+ self._dtd_handler.notationDecl(name, pubid, sysid)
+
+ def new_element_type(self, elem_name, elem_cont):
+ if elem_cont == None:
+ elem_cont = "ANY"
+ elif elem_cont == ("", [], ""):
+ elem_cont = "EMPTY"
+ self._decl_handler.elementDecl(elem_name, elem_cont)
+
+ def new_attribute(self, elem, attr, type, a_decl, a_def):
+ self._decl_handler.attributeDecl(elem, attr, type, a_decl, a_def)
+
+# --- NamespaceFilter
+
+class NamespaceFilter:
+ """An xmlproc application that processes qualified names and reports them
+ as (URI, local-part). It reports errors through the error reporting
+ mechanisms of the parser."""
+
+ def __init__(self, parser, content, lexical, driver):
+ self._cont_handler = content
+ self._lex_handler = lexical
+ self.driver = driver
+ self.ns_map = {} # Current prefix -> URI map
+ self.ns_map["xml"] = "http://www.w3.org/XML/1998/namespace"
+ self.ns_stack = [] # Pushed for each element, used to maint ns_map
+ self.rep_ns_attrs = 0 # Report xmlns-attributes?
+ self.parser = parser
+
+ def set_locator(self, locator):
+ self.driver.set_locator(locator)
+
+ def doc_start(self):
+ self._cont_handler.startDocument()
+
+ def doc_end(self):
+ self._cont_handler.endDocument()
+
+ def handle_comment(self, data):
+ self._lex_handler.comment(data)
+
+ def handle_start_tag(self,name,attrs):
+ old_ns={} # Reset ns_map to these values when we leave this element
+ del_ns=[] # Delete these prefixes from ns_map when we leave element
+
+ # attrs=attrs.copy() Will have to do this if more filters are made
+
+ # Find declarations, update self.ns_map and self.ns_stack
+ for (a,v) in attrs.items():
+ if a[:6]=="xmlns:":
+ prefix=a[6:]
+ if string.find(prefix,":")!=-1:
+ self.parser.report_error(1900)
+
+ #if v=="":
+ # self.parser.report_error(1901)
+ elif a=="xmlns":
+ prefix=""
+ else:
+ continue
+
+ if self.ns_map.has_key(prefix):
+ old_ns[prefix]=self.ns_map[prefix]
+ if v:
+ self.ns_map[prefix]=v
+ else:
+ del self.ns_map[prefix]
+
+ if not self.rep_ns_attrs:
+ del attrs[a]
+
+ self.ns_stack.append((old_ns,del_ns))
+
+ # Process elem and attr names
+ cooked_name = self.__process_name(name)
+ ns = cooked_name[0]
+
+ rawnames = {}
+ for (a,v) in attrs.items():
+ del attrs[a]
+ aname = self.__process_name(a, is_attr=1)
+ if attrs.has_key(aname):
+ self.parser.report_error(1903)
+ attrs[aname] = v
+ rawnames[aname] = a
+
+ # Report event
+ self._cont_handler.startElementNS(cooked_name, name,
+ AttributesNSImpl(attrs, rawnames))
+
+ def handle_end_tag(self, rawname):
+ name = self.__process_name(rawname)
+
+ # Clean up self.ns_map and self.ns_stack
+ (old_ns,del_ns)=self.ns_stack[-1]
+ del self.ns_stack[-1]
+
+ self.ns_map.update(old_ns)
+ for prefix in del_ns:
+ del self.ns_map[prefix]
+
+ self._cont_handler.endElementNS(name, rawname)
+
+ def handle_data(self, data, start, end):
+ self._cont_handler.characters(data[start:end])
+
+ def handle_ignorable_data(self, data, start, end):
+ self._cont_handler.ignorableWhitespace(data[start:end])
+
+ def handle_pi(self, target, data):
+ self._cont_handler.processingInstruction(target, data)
+
+ def handle_doctype(self, root, pubId, sysId):
+ self._lex_handler.startDTD(root, pubId, sysId)
+
+ def set_entity_info(self, xmlver, enc, sddecl):
+ pass
+
+ # --- Internal methods
+
+ def __process_name(self, name, default_to=None, is_attr=0):
+ n=string.split(name,":")
+ if len(n)>2:
+ self.parser.report_error(1900)
+ return (None, name)
+ elif len(n)==2:
+ if n[0]=="xmlns":
+ return (None, name)
+
+ try:
+ return (self.ns_map[n[0]], n[1])
+ except KeyError:
+ self.parser.report_error(1902)
+ return (None, name)
+ elif is_attr:
+ return (None, name)
+ elif default_to != None:
+ return (default_to, name)
+ elif self.ns_map.has_key("") and name != "xmlns":
+ return (self.ns_map[""],name)
+ else:
+ return (None, name)
+
+def create_parser():
+ return XmlprocDriver()
diff --git a/lib/jython/Lib/xml/sax/expatreader.py b/lib/jython/Lib/xml/sax/expatreader.py new file mode 100644 index 000000000..44de0d77e --- /dev/null +++ b/lib/jython/Lib/xml/sax/expatreader.py @@ -0,0 +1,240 @@ +"""
+SAX driver for the Pyexpat C module. This driver works with
+pyexpat.__version__ == '2.22'.
+"""
+
+version = "0.20"
+
+from xml.sax._exceptions import *
+try:
+ from xml.parsers import expat
+except ImportError:
+ raise SAXReaderNotAvailable("expat not supported",None)
+from xml.sax import xmlreader, saxutils, handler
+
+AttributesImpl = xmlreader.AttributesImpl
+AttributesNSImpl = xmlreader.AttributesNSImpl
+
+import string
+
+# --- ExpatParser
+
+class ExpatParser(xmlreader.IncrementalParser, xmlreader.Locator):
+ "SAX driver for the Pyexpat C module."
+
+ def __init__(self, namespaceHandling=0, bufsize=2**16-20):
+ xmlreader.IncrementalParser.__init__(self, bufsize)
+ self._source = xmlreader.InputSource()
+ self._parser = None
+ self._namespaces = namespaceHandling
+ self._lex_handler_prop = None
+ self._parsing = 0
+ self._entity_stack = []
+
+ # XMLReader methods
+
+ def parse(self, source):
+ "Parse an XML document from a URL or an InputSource."
+ source = saxutils.prepare_input_source(source)
+
+ self._source = source
+ self.reset()
+ self._cont_handler.setDocumentLocator(self)
+ xmlreader.IncrementalParser.parse(self, source)
+
+ def prepareParser(self, source):
+ if source.getSystemId() != None:
+ self._parser.SetBase(source.getSystemId())
+
+ def getFeature(self, name):
+ if name == handler.feature_namespaces:
+ return self._namespaces
+ raise SAXNotRecognizedException("Feature '%s' not recognized" % name)
+
+ def setFeature(self, name, state):
+ if self._parsing:
+ raise SAXNotSupportedException("Cannot set features while parsing")
+ if name == handler.feature_namespaces:
+ self._namespaces = state
+ else:
+ raise SAXNotRecognizedException("Feature '%s' not recognized" %
+ name)
+
+ def getProperty(self, name):
+ if name == handler.property_lexical_handler:
+ return self._lex_handler_prop
+ raise SAXNotRecognizedException("Property '%s' not recognized" % name)
+
+ def setProperty(self, name, value):
+ if name == handler.property_lexical_handler:
+ self._lex_handler_prop = value
+ else:
+ raise SAXNotRecognizedException("Property '%s' not recognized" % name)
+
+ # IncrementalParser methods
+
+ def feed(self, data, isFinal = 0):
+ if not self._parsing:
+ self.reset()
+ self._parsing = 1
+ self._cont_handler.startDocument()
+
+ try:
+ # The isFinal parameter is internal to the expat reader.
+ # If it is set to true, expat will check validity of the entire
+ # document. When feeding chunks, they are not normally final -
+ # except when invoked from close.
+ self._parser.Parse(data, isFinal)
+ except expat.error:
+ error_code = self._parser.ErrorCode
+ exc = SAXParseException(expat.ErrorString(error_code), None, self)
+ # FIXME: when to invoke error()?
+ self._err_handler.fatalError(exc)
+
+ def close(self):
+ if self._entity_stack:
+ # If we are completing an external entity, do nothing here
+ return
+ self.feed("", isFinal = 1)
+ self._cont_handler.endDocument()
+ self._parsing = 0
+ # break cycle created by expat handlers pointing to our methods
+ self._parser = None
+
+ def reset(self):
+ if self._namespaces:
+ self._parser = expat.ParserCreate(None, " ")
+ self._parser.StartElementHandler = self.start_element_ns
+ self._parser.EndElementHandler = self.end_element_ns
+ else:
+ self._parser = expat.ParserCreate()
+ self._parser.StartElementHandler = self.start_element
+ self._parser.EndElementHandler = self.end_element
+
+ self._parser.ProcessingInstructionHandler = \
+ self._cont_handler.processingInstruction
+ self._parser.CharacterDataHandler = self._cont_handler.characters
+ self._parser.UnparsedEntityDeclHandler = self.unparsed_entity_decl
+ self._parser.NotationDeclHandler = self.notation_decl
+ self._parser.StartNamespaceDeclHandler = self.start_namespace_decl
+ self._parser.EndNamespaceDeclHandler = self.end_namespace_decl
+
+ self._decl_handler_prop = None
+ if self._lex_handler_prop:
+ self._parser.CommentHandler = self._lex_handler_prop.comment
+ self._parser.StartCdataSectionHandler = self._lex_handler_prop.startCDATA
+ self._parser.EndCdataSectionHandler = self._lex_handler_prop.endCDATA
+# self._parser.DefaultHandler =
+# self._parser.DefaultHandlerExpand =
+# self._parser.NotStandaloneHandler =
+ self._parser.ExternalEntityRefHandler = self.external_entity_ref
+
+ self._parsing = 0
+ self._entity_stack = []
+
+ # Locator methods
+
+ def getColumnNumber(self):
+ if self._parser is None:
+ return None
+ return self._parser.ErrorColumnNumber
+
+ def getLineNumber(self):
+ if self._parser is None:
+ return 1
+ return self._parser.ErrorLineNumber
+
+ def getPublicId(self):
+ return self._source.getPublicId()
+
+ def getSystemId(self):
+ return self._source.getSystemId()
+
+ # event handlers
+ def start_element(self, name, attrs):
+ self._cont_handler.startElement(name, AttributesImpl(attrs))
+
+ def end_element(self, name):
+ self._cont_handler.endElement(name)
+
+ def start_element_ns(self, name, attrs):
+ pair = string.split(name)
+ if len(pair) == 1:
+ pair = (None, name)
+ else:
+ pair = tuple(pair)
+
+ newattrs = {}
+ for (aname, value) in attrs.items():
+ apair = string.split(aname)
+ if len(apair) == 1:
+ apair = (None, aname)
+ else:
+ apair = tuple(apair)
+
+ newattrs[apair] = value
+
+ self._cont_handler.startElementNS(pair, None,
+ AttributesNSImpl(newattrs, {}))
+
+ def end_element_ns(self, name):
+ pair = string.split(name)
+ if len(pair) == 1:
+ pair = (None, name)
+ else:
+ pair = tuple(pair)
+
+ self._cont_handler.endElementNS(pair, None)
+
+ # this is not used (call directly to ContentHandler)
+ def processing_instruction(self, target, data):
+ self._cont_handler.processingInstruction(target, data)
+
+ # this is not used (call directly to ContentHandler)
+ def character_data(self, data):
+ self._cont_handler.characters(data)
+
+ def start_namespace_decl(self, prefix, uri):
+ self._cont_handler.startPrefixMapping(prefix, uri)
+
+ def end_namespace_decl(self, prefix):
+ self._cont_handler.endPrefixMapping(prefix)
+
+ def unparsed_entity_decl(self, name, base, sysid, pubid, notation_name):
+ self._dtd_handler.unparsedEntityDecl(name, pubid, sysid, notation_name)
+
+ def notation_decl(self, name, base, sysid, pubid):
+ self._dtd_handler.notationDecl(name, pubid, sysid)
+
+ def external_entity_ref(self, context, base, sysid, pubid):
+ source = self._ent_handler.resolveEntity(pubid, sysid)
+ source = saxutils.prepare_input_source(source,
+ self._source.getSystemId() or
+ "")
+
+ self._entity_stack.append((self._parser, self._source))
+ self._parser = self._parser.ExternalEntityParserCreate(context)
+ self._source = source
+
+ try:
+ xmlreader.IncrementalParser.parse(self, source)
+ except:
+ return 0 # FIXME: save error info here?
+
+ (self._parser, self._source) = self._entity_stack[-1]
+ del self._entity_stack[-1]
+ return 1
+
+# ---
+
+def create_parser(*args, **kwargs):
+ return apply(ExpatParser, args, kwargs)
+
+# ---
+
+if __name__ == "__main__":
+ import xml.sax
+ p = create_parser()
+ p.setContentHandler(xml.sax.XMLGenerator())
+ p.setErrorHandler(xml.sax.ErrorHandler())
+ p.parse("../../../hamlet.xml")
diff --git a/lib/jython/Lib/xml/sax/handler.py b/lib/jython/Lib/xml/sax/handler.py new file mode 100644 index 000000000..4329e1b1d --- /dev/null +++ b/lib/jython/Lib/xml/sax/handler.py @@ -0,0 +1,321 @@ +"""
+This module contains the core classes of version 2.0 of SAX for Python.
+This file provides only default classes with absolutely minimum
+functionality, from which drivers and applications can be subclassed.
+
+Many of these classes are empty and are included only as documentation
+of the interfaces.
+
+$Id: handler.py,v 1.2 2000/12/28 19:57:06 loewis Exp $
+"""
+
+version = '2.0beta'
+
+#============================================================================
+#
+# HANDLER INTERFACES
+#
+#============================================================================
+
+# ===== ERRORHANDLER =====
+
+class ErrorHandler:
+ """Basic interface for SAX error handlers.
+
+ If you create an object that implements this interface, then
+ register the object with your XMLReader, the parser will call the
+ methods in your object to report all warnings and errors. There
+ are three levels of errors available: warnings, (possibly)
+ recoverable errors, and unrecoverable errors. All methods take a
+ SAXParseException as the only parameter."""
+
+ def error(self, exception):
+ "Handle a recoverable error."
+ raise exception
+
+ def fatalError(self, exception):
+ "Handle a non-recoverable error."
+ raise exception
+
+ def warning(self, exception):
+ "Handle a warning."
+ print exception
+
+
+# ===== CONTENTHANDLER =====
+
+class ContentHandler:
+ """Interface for receiving logical document content events.
+
+ This is the main callback interface in SAX, and the one most
+ important to applications. The order of events in this interface
+ mirrors the order of the information in the document."""
+
+ def __init__(self):
+ self._locator = None
+
+ def setDocumentLocator(self, locator):
+ """Called by the parser to give the application a locator for
+ locating the origin of document events.
+
+ SAX parsers are strongly encouraged (though not absolutely
+ required) to supply a locator: if it does so, it must supply
+ the locator to the application by invoking this method before
+ invoking any of the other methods in the DocumentHandler
+ interface.
+
+ The locator allows the application to determine the end
+ position of any document-related event, even if the parser is
+ not reporting an error. Typically, the application will use
+ this information for reporting its own errors (such as
+ character content that does not match an application's
+ business rules). The information returned by the locator is
+ probably not sufficient for use with a search engine.
+
+ Note that the locator will return correct information only
+ during the invocation of the events in this interface. The
+ application should not attempt to use it at any other time."""
+ self._locator = locator
+
+ def startDocument(self):
+ """Receive notification of the beginning of a document.
+
+ The SAX parser will invoke this method only once, before any
+ other methods in this interface or in DTDHandler (except for
+ setDocumentLocator)."""
+
+ def endDocument(self):
+ """Receive notification of the end of a document.
+
+ The SAX parser will invoke this method only once, and it will
+ be the last method invoked during the parse. The parser shall
+ not invoke this method until it has either abandoned parsing
+ (because of an unrecoverable error) or reached the end of
+ input."""
+
+ def startPrefixMapping(self, prefix, uri):
+ """Begin the scope of a prefix-URI Namespace mapping.
+
+ The information from this event is not necessary for normal
+ Namespace processing: the SAX XML reader will automatically
+ replace prefixes for element and attribute names when the
+ http://xml.org/sax/features/namespaces feature is true (the
+ default).
+
+ There are cases, however, when applications need to use
+ prefixes in character data or in attribute values, where they
+ cannot safely be expanded automatically; the
+ start/endPrefixMapping event supplies the information to the
+ application to expand prefixes in those contexts itself, if
+ necessary.
+
+ Note that start/endPrefixMapping events are not guaranteed to
+ be properly nested relative to each-other: all
+ startPrefixMapping events will occur before the corresponding
+ startElement event, and all endPrefixMapping events will occur
+ after the corresponding endElement event, but their order is
+ not guaranteed."""
+
+ def endPrefixMapping(self, prefix):
+ """End the scope of a prefix-URI mapping.
+
+ See startPrefixMapping for details. This event will always
+ occur after the corresponding endElement event, but the order
+ of endPrefixMapping events is not otherwise guaranteed."""
+
+ def startElement(self, name, attrs):
+ """Signals the start of an element in non-namespace mode.
+
+ The name parameter contains the raw XML 1.0 name of the
+ element type as a string and the attrs parameter holds an
+ instance of the Attributes class containing the attributes of
+ the element."""
+
+ def endElement(self, name):
+ """Signals the end of an element in non-namespace mode.
+
+ The name parameter contains the name of the element type, just
+ as with the startElement event."""
+
+ def startElementNS(self, name, qname, attrs):
+ """Signals the start of an element in namespace mode.
+
+ The name parameter contains the name of the element type as a
+ (uri, localname) tuple, the qname parameter the raw XML 1.0
+ name used in the source document, and the attrs parameter
+ holds an instance of the Attributes class containing the
+ attributes of the element."""
+
+ def endElementNS(self, name, qname):
+ """Signals the end of an element in namespace mode.
+
+ The name parameter contains the name of the element type, just
+ as with the startElementNS event."""
+
+ def characters(self, content):
+ """Receive notification of character data.
+
+ The Parser will call this method to report each chunk of
+ character data. SAX parsers may return all contiguous
+ character data in a single chunk, or they may split it into
+ several chunks; however, all of the characters in any single
+ event must come from the same external entity so that the
+ Locator provides useful information."""
+
+ def ignorableWhitespace(self, whitespace):
+ """Receive notification of ignorable whitespace in element content.
+
+ Validating Parsers must use this method to report each chunk
+ of ignorable whitespace (see the W3C XML 1.0 recommendation,
+ section 2.10): non-validating parsers may also use this method
+ if they are capable of parsing and using content models.
+
+ SAX parsers may return all contiguous whitespace in a single
+ chunk, or they may split it into several chunks; however, all
+ of the characters in any single event must come from the same
+ external entity, so that the Locator provides useful
+ information.
+
+ The application must not attempt to read from the array
+ outside of the specified range."""
+
+ def processingInstruction(self, target, data):
+ """Receive notification of a processing instruction.
+
+ The Parser will invoke this method once for each processing
+ instruction found: note that processing instructions may occur
+ before or after the main document element.
+
+ A SAX parser should never report an XML declaration (XML 1.0,
+ section 2.8) or a text declaration (XML 1.0, section 4.3.1)
+ using this method."""
+
+ def skippedEntity(self, name):
+ """Receive notification of a skipped entity.
+
+ The Parser will invoke this method once for each entity
+ skipped. Non-validating processors may skip entities if they
+ have not seen the declarations (because, for example, the
+ entity was declared in an external DTD subset). All processors
+ may skip external entities, depending on the values of the
+ http://xml.org/sax/features/external-general-entities and the
+ http://xml.org/sax/features/external-parameter-entities
+ properties."""
+
+
+# ===== DTDHandler =====
+
+class DTDHandler:
+ """Handle DTD events.
+
+ This interface specifies only those DTD events required for basic
+ parsing (unparsed entities and attributes)."""
+
+ def notationDecl(self, name, publicId, systemId):
+ "Handle a notation declaration event."
+
+ def unparsedEntityDecl(self, name, publicId, systemId, ndata):
+ "Handle an unparsed entity declaration event."
+
+
+# ===== ENTITYRESOLVER =====
+
+class EntityResolver:
+ """Basic interface for resolving entities. If you create an object
+ implementing this interface, then register the object with your
+ Parser, the parser will call the method in your object to
+ resolve all external entities. Note that DefaultHandler implements
+ this interface with the default behaviour."""
+
+ def resolveEntity(self, publicId, systemId):
+ """Resolve the system identifier of an entity and return either
+ the system identifier to read from as a string, or an InputSource
+ to read from."""
+ return systemId
+
+
+#============================================================================
+#
+# CORE FEATURES
+#
+#============================================================================
+
+feature_namespaces = "http://xml.org/sax/features/namespaces"
+# true: Perform Namespace processing (default).
+# false: Optionally do not perform Namespace processing
+# (implies namespace-prefixes).
+# access: (parsing) read-only; (not parsing) read/write
+
+feature_namespace_prefixes = "http://xml.org/sax/features/namespace-prefixes"
+# true: Report the original prefixed names and attributes used for Namespace
+# declarations.
+# false: Do not report attributes used for Namespace declarations, and
+# optionally do not report original prefixed names (default).
+# access: (parsing) read-only; (not parsing) read/write
+
+feature_string_interning = "http://xml.org/sax/features/string-interning"
+# true: All element names, prefixes, attribute names, Namespace URIs, and
+# local names are interned using the built-in intern function.
+# false: Names are not necessarily interned, although they may be (default).
+# access: (parsing) read-only; (not parsing) read/write
+
+feature_validation = "http://xml.org/sax/features/validation"
+# true: Report all validation errors (implies external-general-entities and
+# external-parameter-entities).
+# false: Do not report validation errors.
+# access: (parsing) read-only; (not parsing) read/write
+
+feature_external_ges = "http://xml.org/sax/features/external-general-entities"
+# true: Include all external general (text) entities.
+# false: Do not include external general entities.
+# access: (parsing) read-only; (not parsing) read/write
+
+feature_external_pes = "http://xml.org/sax/features/external-parameter-entities"
+# true: Include all external parameter entities, including the external
+# DTD subset.
+# false: Do not include any external parameter entities, even the external
+# DTD subset.
+# access: (parsing) read-only; (not parsing) read/write
+
+all_features = [feature_namespaces,
+ feature_namespace_prefixes,
+ feature_string_interning,
+ feature_validation,
+ feature_external_ges,
+ feature_external_pes]
+
+
+#============================================================================
+#
+# CORE PROPERTIES
+#
+#============================================================================
+
+property_lexical_handler = "http://xml.org/sax/properties/lexical-handler"
+# data type: xml.sax.sax2lib.LexicalHandler
+# description: An optional extension handler for lexical events like comments.
+# access: read/write
+
+property_declaration_handler = "http://xml.org/sax/properties/declaration-handler"
+# data type: xml.sax.sax2lib.DeclHandler
+# description: An optional extension handler for DTD-related events other
+# than notations and unparsed entities.
+# access: read/write
+
+property_dom_node = "http://xml.org/sax/properties/dom-node"
+# data type: org.w3c.dom.Node
+# description: When parsing, the current DOM node being visited if this is
+# a DOM iterator; when not parsing, the root DOM node for
+# iteration.
+# access: (parsing) read-only; (not parsing) read/write
+
+property_xml_string = "http://xml.org/sax/properties/xml-string"
+# data type: String
+# description: The literal string of characters that was the source for
+# the current event.
+# access: read-only
+
+all_properties = [property_lexical_handler,
+ property_dom_node,
+ property_declaration_handler,
+ property_xml_string]
diff --git a/lib/jython/Lib/xml/sax/sax2exts.py b/lib/jython/Lib/xml/sax/sax2exts.py new file mode 100644 index 000000000..13e33a3df --- /dev/null +++ b/lib/jython/Lib/xml/sax/sax2exts.py @@ -0,0 +1,34 @@ +"""
+Various extensions to the core SAX 2.0 API.
+
+$Id: sax2exts.py,v 1.4 2001/03/03 07:30:06 loewis Exp $
+"""
+
+import saxexts,saxlib
+
+# In SAX2, validation is turned-on through a property. Make sure
+# that all parsers returned from this factory are validating
+class ValidatingReaderFactory(saxexts.ParserFactory):
+ def make_parser(self, parser_list = []):
+ p = saxexts.ParserFactory.make_parser(self,parser_list)
+ p.setFeature(saxlib.feature_validation, 1)
+ return p
+
+
+# --- XMLReader factory
+
+XMLReaderFactory = saxexts.ParserFactory
+
+# --- Creating parser factories
+
+XMLParserFactory = XMLReaderFactory(["xml.sax.drivers2.drv_pyexpat",
+ "xml.sax.drivers2.drv_xmlproc"])
+
+XMLValParserFactory = ValidatingReaderFactory(["xml.sax.drivers2.drv_xmlproc"])
+
+HTMLParserFactory = XMLReaderFactory([])
+
+SGMLParserFactory = XMLReaderFactory([])
+
+def make_parser(parser_list = []):
+ return XMLParserFactory.make_parser(parser_list)
diff --git a/lib/jython/Lib/xml/sax/saxexts.py b/lib/jython/Lib/xml/sax/saxexts.py new file mode 100644 index 000000000..a38eb34aa --- /dev/null +++ b/lib/jython/Lib/xml/sax/saxexts.py @@ -0,0 +1,168 @@ +"""
+A module of experimental extensions to the standard SAX interface.
+
+$Id: saxexts.py,v 1.13 2001/01/27 09:03:52 loewis Exp $
+"""
+
+import _exceptions, handler, sys, string, os, types
+
+# --- Parser factory
+
+class ParserFactory:
+ """A general class to be used by applications for creating parsers on
+ foreign systems where it is unknown which parsers exist."""
+
+ def __init__(self,list=[]):
+ # Python 2 compatibility: let consider environment variables
+ # and properties override list argument
+ if os.environ.has_key("PY_SAX_PARSER"):
+ list = string.split(os.environ["PY_SAX_PARSER"], ",")
+ _key = "python.xml.sax.parser"
+ if sys.platform[:4] == "java" \
+ and sys.registry.containsKey(_key):
+ list = string.split(sys.registry.getProperty(_key), ",")
+ self.parsers=list
+
+ def get_parser_list(self):
+ "Returns the list of possible drivers."
+ return self.parsers
+
+ def set_parser_list(self,list):
+ "Sets the driver list."
+ self.parsers=list
+
+ if sys.platform[ : 4] == "java":
+ def _create_parser(self,parser_name):
+ from org.python.core import imp
+ drv_module = imp.importName(parser_name, 0, globals())
+ return drv_module.create_parser()
+
+ else:
+ def _create_parser(self,parser_name):
+ drv_module = __import__(parser_name,{},{},['create_parser'])
+ return drv_module.create_parser()
+
+ def make_parser(self, parser_list = []):
+ """Returns a SAX driver for the first available parser of the parsers
+ in the list. Note that the list is one of drivers, so it first tries
+ the driver and if that exists imports it to see if the parser also
+ exists. If no parsers are available a SAXException is thrown.
+
+ Accepts a list of driver package names as an optional argument."""
+
+ import sys
+ # SAX1 expected a single package name as optional argument
+ # Python 2 changed this to be a list of parser names
+ # We now support both, as well as None (which was the default)
+ if parser_list is None:
+ parser_list = []
+ elif type(parser_list) == types.StringType:
+ parser_list = [parser_list]
+
+ for parser_name in parser_list+self.parsers:
+ try:
+ return self._create_parser(parser_name)
+ except ImportError,e:
+ if sys.modules.has_key(parser_name):
+ # The parser module was found, but importing it
+ # failed unexpectedly, pass this exception through
+ raise
+ except _exceptions.SAXReaderNotAvailable:
+ # The parser module detected that it won't work properly,
+ # so mark it as unusable, and try the next one
+ def _create_parser():
+ raise _exceptions.SAXReaderNotAvailable
+ sys.modules[parser_name].create_parser = _create_parser
+
+ raise _exceptions.SAXReaderNotAvailable("No parsers found", None)
+
+# --- Experimental extension to Parser interface
+import saxlib
+class ExtendedParser(saxlib.Parser):
+ "Experimental unofficial SAX level 2 extended parser interface."
+
+ def get_parser_name(self):
+ "Returns a single-word parser name."
+ raise _exceptions.SAXException("Method not supported.",None)
+
+ def get_parser_version(self):
+ """Returns the version of the imported parser, which may not be the
+ one the driver was implemented for."""
+ raise _exceptions.SAXException("Method not supported.",None)
+
+ def get_driver_version(self):
+ "Returns the version number of the driver."
+ raise _exceptions.SAXException("Method not supported.",None)
+
+ def is_validating(self):
+ "True if the parser is validating, false otherwise."
+ raise _exceptions.SAXException("Method not supported.",None)
+
+ def is_dtd_reading(self):
+ """True if the parser is non-validating, but conforms to the spec by
+ reading the DTD."""
+ raise _exceptions.SAXException("Method not supported.",None)
+
+ def reset(self):
+ "Makes the parser start parsing afresh."
+ raise _exceptions.SAXException("Method not supported.",None)
+
+ def feed(self,data):
+ "Feeds data to the parser."
+ raise _exceptions.SAXException("Method not supported.",None)
+
+ def close(self):
+ "Called after the last call to feed, when there are no more data."
+ raise _exceptions.SAXException("Method not supported.",None)
+
+# --- Experimental document handler which does not slice strings
+
+class NosliceDocumentHandler(saxlib.DocumentHandler):
+ """A document handler that does not force the client application to
+ slice character data strings."""
+
+ def __init__(self):
+ handler.DocumentHandler.__init__()
+ self.characters=self.safe_handler
+
+ def safe_handler(self,data,start,length):
+ """A characters event handler that always works, but doesn't always
+ slice strings."""
+ if start==0 and length==len(data):
+ self.handle_data(data)
+ else:
+ self.handle_data(data[start:start+length])
+
+ def slice_handler(self,data,start,length):
+ "A character event handler that always slices strings."
+ self.handle_data(data[start:start+length])
+
+ def noslice_handler(self,data,start,length):
+ "A character event handler that never slices strings."
+ self.handle_data(data)
+
+ def handle_data(self,data):
+ "This is the character data event method to override."
+ pass
+
+# --- Creating parser factories
+
+XMLParserFactory=ParserFactory(["xml.sax.drivers.drv_pyexpat",
+ "xml.sax.drivers.drv_xmltok",
+ "xml.sax.drivers.drv_xmlproc",
+ "xml.sax.drivers.drv_xmltoolkit",
+ "xml.sax.drivers.drv_xmllib",
+ "xml.sax.drivers.drv_xmldc",
+ "xml.sax.drivers.drv_sgmlop"])
+
+XMLValParserFactory=ParserFactory(["xml.sax.drivers.drv_xmlproc_val"])
+
+HTMLParserFactory=ParserFactory(["xml.sax.drivers.drv_htmllib",
+ "xml.sax.drivers.drv_sgmlop",
+ "xml.sax.drivers.drv_sgmllib"])
+
+SGMLParserFactory=ParserFactory(["xml.sax.drivers.drv_sgmlop",
+ "xml.sax.drivers.drv_sgmllib"])
+
+def make_parser(parser_list = []):
+ return XMLParserFactory.make_parser(parser_list)
diff --git a/lib/jython/Lib/xml/sax/saxlib.py b/lib/jython/Lib/xml/sax/saxlib.py new file mode 100644 index 000000000..62c1dd573 --- /dev/null +++ b/lib/jython/Lib/xml/sax/saxlib.py @@ -0,0 +1,430 @@ +"""
+This module contains the core classes of version 2.0 of SAX for Python.
+This file provides only default classes with absolutely minimum
+functionality, from which drivers and applications can be subclassed.
+
+Many of these classes are empty and are included only as documentation
+of the interfaces.
+
+$Id: saxlib.py,v 1.11 2001/01/27 09:03:52 loewis Exp $
+"""
+
+version = '2.0beta'
+
+# A number of interfaces used to live in saxlib, but are now in
+# various other modules for Python 2 compatibility. If nobody uses
+# them here any longer, the references can be removed
+
+from handler import ErrorHandler, ContentHandler, DTDHandler, EntityResolver
+from xmlreader import XMLReader, InputSource, Locator, IncrementalParser
+from _exceptions import *
+
+from handler import \
+ feature_namespaces,\
+ feature_namespace_prefixes,\
+ feature_string_interning,\
+ feature_validation,\
+ feature_external_ges,\
+ feature_external_pes,\
+ all_features,\
+ property_lexical_handler,\
+ property_declaration_handler,\
+ property_dom_node,\
+ property_xml_string,\
+ all_properties
+
+#============================================================================
+#
+# MAIN INTERFACES
+#
+#============================================================================
+
+# ===== XMLFILTER =====
+
+class XMLFilter(XMLReader):
+ """Interface for a SAX2 parser filter.
+
+ A parser filter is an XMLReader that gets its events from another
+ XMLReader (which may in turn also be a filter) rather than from a
+ primary source like a document or other non-SAX data source.
+ Filters can modify a stream of events before passing it on to its
+ handlers."""
+
+ def __init__(self, parent = None):
+ """Creates a filter instance, allowing applications to set the
+ parent on instantiation."""
+ XMLReader.__init__(self)
+ self._parent = parent
+
+ def setParent(self, parent):
+ """Sets the parent XMLReader of this filter. The argument may
+ not be None."""
+ self._parent = parent
+
+ def getParent(self):
+ "Returns the parent of this filter."
+ return self._parent
+
+# ===== ATTRIBUTES =====
+
+class Attributes:
+ """Interface for a list of XML attributes.
+
+ Contains a list of XML attributes, accessible by name."""
+
+ def getLength(self):
+ "Returns the number of attributes in the list."
+ raise NotImplementedError("This method must be implemented!")
+
+ def getType(self, name):
+ "Returns the type of the attribute with the given name."
+ raise NotImplementedError("This method must be implemented!")
+
+ def getValue(self, name):
+ "Returns the value of the attribute with the given name."
+ raise NotImplementedError("This method must be implemented!")
+
+ def getValueByQName(self, name):
+ """Returns the value of the attribute with the given raw (or
+ qualified) name."""
+ raise NotImplementedError("This method must be implemented!")
+
+ def getNameByQName(self, name):
+ """Returns the namespace name of the attribute with the given
+ raw (or qualified) name."""
+ raise NotImplementedError("This method must be implemented!")
+
+ def getNames(self):
+ """Returns a list of the names of all attributes
+ in the list."""
+ raise NotImplementedError("This method must be implemented!")
+
+ def getQNames(self):
+ """Returns a list of the raw qualified names of all attributes
+ in the list."""
+ raise NotImplementedError("This method must be implemented!")
+
+ def __len__(self):
+ "Alias for getLength."
+ raise NotImplementedError("This method must be implemented!")
+
+ def __getitem__(self, name):
+ "Alias for getValue."
+ raise NotImplementedError("This method must be implemented!")
+
+ def keys(self):
+ "Returns a list of the attribute names in the list."
+ raise NotImplementedError("This method must be implemented!")
+
+ def has_key(self, name):
+ "True if the attribute is in the list, false otherwise."
+ raise NotImplementedError("This method must be implemented!")
+
+ def get(self, name, alternative=None):
+ """Return the value associated with attribute name; if it is not
+ available, then return the alternative."""
+ raise NotImplementedError("This method must be implemented!")
+
+ def copy(self):
+ "Return a copy of the Attributes object."
+ raise NotImplementedError("This method must be implemented!")
+
+ def items(self):
+ "Return a list of (attribute_name, value) pairs."
+ raise NotImplementedError("This method must be implemented!")
+
+ def values(self):
+ "Return a list of all attribute values."
+ raise NotImplementedError("This method must be implemented!")
+
+
+#============================================================================
+#
+# HANDLER INTERFACES
+#
+#============================================================================
+
+
+# ===== DECLHANDLER =====
+
+class DeclHandler:
+ """Optional SAX2 handler for DTD declaration events.
+
+ Note that some DTD declarations are already reported through the
+ DTDHandler interface. All events reported to this handler will
+ occur between the startDTD and endDTD events of the
+ LexicalHandler.
+
+ To se the DeclHandler for an XMLReader, use the setProperty method
+ with the identifier http://xml.org/sax/handlers/DeclHandler."""
+
+ def attributeDecl(self, elem_name, attr_name, type, value_def, value):
+ """Report an attribute type declaration.
+
+ Only the first declaration will be reported. The type will be
+ one of the strings "CDATA", "ID", "IDREF", "IDREFS",
+ "NMTOKEN", "NMTOKENS", "ENTITY", "ENTITIES", or "NOTATION", or
+ a list of names (in the case of enumerated definitions).
+
+ elem_name is the element type name, attr_name the attribute
+ type name, type a string representing the attribute type,
+ value_def a string representing the default declaration
+ ('#IMPLIED', '#REQUIRED', '#FIXED' or None). value is a string
+ representing the attribute's default value, or None if there
+ is none."""
+
+ def elementDecl(self, elem_name, content_model):
+ """Report an element type declaration.
+
+ Only the first declaration will be reported.
+
+ content_model is the string 'EMPTY', the string 'ANY' or the content
+ model structure represented as tuple (separator, tokens, modifier)
+ where separator is the separator in the token list (that is, '|' or
+ ','), tokens is the list of tokens (element type names or tuples
+ representing parentheses) and modifier is the quantity modifier
+ ('*', '?' or '+')."""
+
+ def internalEntityDecl(self, name, value):
+ """Report an internal entity declaration.
+
+ Only the first declaration of an entity will be reported.
+
+ name is the name of the entity. If it is a parameter entity,
+ the name will begin with '%'. value is the replacement text of
+ the entity."""
+
+ def externalEntityDecl(self, name, public_id, system_id):
+ """Report a parsed entity declaration. (Unparsed entities are
+ reported to the DTDHandler.)
+
+ Only the first declaration for each entity will be reported.
+
+ name is the name of the entity. If it is a parameter entity,
+ the name will begin with '%'. public_id and system_id are the
+ public and system identifiers of the entity. public_id will be
+ None if none were declared."""
+
+
+
+# ===== LEXICALHANDLER =====
+
+class LexicalHandler:
+ """Optional SAX2 handler for lexical events.
+
+ This handler is used to obtain lexical information about an XML
+ document, that is, information about how the document was encoded
+ (as opposed to what it contains, which is reported to the
+ ContentHandler), such as comments and CDATA marked section
+ boundaries.
+
+ To set the LexicalHandler of an XMLReader, use the setProperty
+ method with the property identifier
+ 'http://xml.org/sax/handlers/LexicalHandler'. There is no
+ guarantee that the XMLReader will support or recognize this
+ property."""
+
+ def comment(self, content):
+ """Reports a comment anywhere in the document (including the
+ DTD and outside the document element).
+
+ content is a string that holds the contents of the comment."""
+
+ def startDTD(self, name, public_id, system_id):
+ """Report the start of the DTD declarations, if the document
+ has an associated DTD.
+
+ A startEntity event will be reported before declaration events
+ from the external DTD subset are reported, and this can be
+ used to infer from which subset DTD declarations derive.
+
+ name is the name of the document element type, public_id the
+ public identifier of the DTD (or None if none were supplied)
+ and system_id the system identfier of the external subset (or
+ None if none were supplied)."""
+
+ def endDTD(self):
+ "Signals the end of DTD declarations."
+
+ def startEntity(self, name):
+ """Report the beginning of an entity.
+
+ The start and end of the document entity is not reported. The
+ start and end of the external DTD subset is reported with the
+ pseudo-name '[dtd]'.
+
+ Skipped entities will be reported through the skippedEntity
+ event of the ContentHandler rather than through this event.
+
+ name is the name of the entity. If it is a parameter entity,
+ the name will begin with '%'."""
+
+ def endEntity(self, name):
+ """Reports the end of an entity. name is the name of the
+ entity, and follows the same conventions as for
+ startEntity."""
+
+ def startCDATA(self):
+ """Reports the beginning of a CDATA marked section.
+
+ The contents of the CDATA marked section will be reported
+ through the characters event."""
+
+ def endCDATA(self):
+ "Reports the end of a CDATA marked section."
+
+
+#============================================================================
+#
+# SAX 1.0 COMPATIBILITY CLASSES
+# Note that these are all deprecated.
+#
+#============================================================================
+
+# ===== ATTRIBUTELIST =====
+
+class AttributeList:
+ """Interface for an attribute list. This interface provides
+ information about a list of attributes for an element (only
+ specified or defaulted attributes will be reported). Note that the
+ information returned by this object will be valid only during the
+ scope of the DocumentHandler.startElement callback, and the
+ attributes will not necessarily be provided in the order declared
+ or specified."""
+
+ def getLength(self):
+ "Return the number of attributes in list."
+
+ def getName(self, i):
+ "Return the name of an attribute in the list."
+
+ def getType(self, i):
+ """Return the type of an attribute in the list. (Parameter can be
+ either integer index or attribute name.)"""
+
+ def getValue(self, i):
+ """Return the value of an attribute in the list. (Parameter can be
+ either integer index or attribute name.)"""
+
+ def __len__(self):
+ "Alias for getLength."
+
+ def __getitem__(self, key):
+ "Alias for getName (if key is an integer) and getValue (if string)."
+
+ def keys(self):
+ "Returns a list of the attribute names."
+
+ def has_key(self, key):
+ "True if the attribute is in the list, false otherwise."
+
+ def get(self, key, alternative=None):
+ """Return the value associated with attribute name; if it is not
+ available, then return the alternative."""
+
+ def copy(self):
+ "Return a copy of the AttributeList."
+
+ def items(self):
+ "Return a list of (attribute_name,value) pairs."
+
+ def values(self):
+ "Return a list of all attribute values."
+
+
+# ===== DOCUMENTHANDLER =====
+
+class DocumentHandler:
+ """Handle general document events. This is the main client
+ interface for SAX: it contains callbacks for the most important
+ document events, such as the start and end of elements. You need
+ to create an object that implements this interface, and then
+ register it with the Parser. If you do not want to implement
+ the entire interface, you can derive a class from HandlerBase,
+ which implements the default functionality. You can find the
+ location of any document event using the Locator interface
+ supplied by setDocumentLocator()."""
+
+ def characters(self, ch, start, length):
+ "Handle a character data event."
+
+ def endDocument(self):
+ "Handle an event for the end of a document."
+
+ def endElement(self, name):
+ "Handle an event for the end of an element."
+
+ def ignorableWhitespace(self, ch, start, length):
+ "Handle an event for ignorable whitespace in element content."
+
+ def processingInstruction(self, target, data):
+ "Handle a processing instruction event."
+
+ def setDocumentLocator(self, locator):
+ "Receive an object for locating the origin of SAX document events."
+
+ def startDocument(self):
+ "Handle an event for the beginning of a document."
+
+ def startElement(self, name, atts):
+ "Handle an event for the beginning of an element."
+
+
+# ===== HANDLERBASE =====
+
+class HandlerBase(EntityResolver, DTDHandler, DocumentHandler,\
+ ErrorHandler):
+ """Default base class for handlers. This class implements the
+ default behaviour for four SAX interfaces: EntityResolver,
+ DTDHandler, DocumentHandler, and ErrorHandler: rather
+ than implementing those full interfaces, you may simply extend
+ this class and override the methods that you need. Note that the
+ use of this class is optional (you are free to implement the
+ interfaces directly if you wish)."""
+
+
+# ===== PARSER =====
+
+class Parser:
+ """Basic interface for SAX (Simple API for XML) parsers. All SAX
+ parsers must implement this basic interface: it allows users to
+ register handlers for different types of events and to initiate a
+ parse from a URI, a character stream, or a byte stream. SAX
+ parsers should also implement a zero-argument constructor."""
+
+ def __init__(self):
+ self.doc_handler = DocumentHandler()
+ self.dtd_handler = DTDHandler()
+ self.ent_handler = EntityResolver()
+ self.err_handler = ErrorHandler()
+
+ def parse(self, systemId):
+ "Parse an XML document from a system identifier."
+
+ def parseFile(self, fileobj):
+ "Parse an XML document from a file-like object."
+
+ def setDocumentHandler(self, handler):
+ "Register an object to receive basic document-related events."
+ self.doc_handler=handler
+
+ def setDTDHandler(self, handler):
+ "Register an object to receive basic DTD-related events."
+ self.dtd_handler=handler
+
+ def setEntityResolver(self, resolver):
+ "Register an object to resolve external entities."
+ self.ent_handler=resolver
+
+ def setErrorHandler(self, handler):
+ "Register an object to receive error-message events."
+ self.err_handler=handler
+
+ def setLocale(self, locale):
+ """Allow an application to set the locale for errors and warnings.
+
+ SAX parsers are not required to provide localisation for errors
+ and warnings; if they cannot support the requested locale,
+ however, they must throw a SAX exception. Applications may
+ request a locale change in the middle of a parse."""
+ raise SAXNotSupportedException("Locale support not implemented")
diff --git a/lib/jython/Lib/xml/sax/saxutils.py b/lib/jython/Lib/xml/sax/saxutils.py new file mode 100644 index 000000000..3b7ef937b --- /dev/null +++ b/lib/jython/Lib/xml/sax/saxutils.py @@ -0,0 +1,661 @@ +"""
+A library of useful helper classes to the saxlib classes, for the
+convenience of application and driver writers.
+
+$Id: saxutils.py,v 1.19 2001/03/20 07:19:46 loewis Exp $
+"""
+
+import types, sys, urllib, urlparse, os, string
+import handler, _exceptions, xmlreader
+
+try:
+ _StringTypes = [types.StringType, types.UnicodeType]
+except AttributeError: # 1.5 compatibility:UnicodeType not defined
+ _StringTypes = [types.StringType]
+
+def escape(data, entities={}):
+ """Escape &, <, and > in a string of data.
+
+ You can escape other strings of data by passing a dictionary as
+ the optional entities parameter. The keys and values must all be
+ strings; each key will be replaced with its corresponding value.
+ """
+ data = string.replace(data, "&", "&")
+ data = string.replace(data, "<", "<")
+ data = string.replace(data, ">", ">")
+ for chars, entity in entities.items():
+ data = string.replace(data, chars, entity)
+ return data
+
+# --- DefaultHandler
+
+class DefaultHandler(handler.EntityResolver, handler.DTDHandler,
+ handler.ContentHandler, handler.ErrorHandler):
+ """Default base class for SAX2 event handlers. Implements empty
+ methods for all callback methods, which can be overridden by
+ application implementors. Replaces the deprecated SAX1 HandlerBase
+ class."""
+
+# --- Location
+
+class Location:
+ """Represents a location in an XML entity. Initialized by being passed
+ a locator, from which it reads off the current location, which is then
+ stored internally."""
+
+ def __init__(self, locator):
+ self.__col = locator.getColumnNumber()
+ self.__line = locator.getLineNumber()
+ self.__pubid = locator.getPublicId()
+ self.__sysid = locator.getSystemId()
+
+ def getColumnNumber(self):
+ return self.__col
+
+ def getLineNumber(self):
+ return self.__line
+
+ def getPublicId(self):
+ return self.__pubid
+
+ def getSystemId(self):
+ return self.__sysid
+
+# --- ErrorPrinter
+
+class ErrorPrinter:
+ "A simple class that just prints error messages to standard out."
+
+ def __init__(self, level=0, outfile=sys.stderr):
+ self._level = level
+ self._outfile = outfile
+
+ def warning(self, exception):
+ if self._level <= 0:
+ self._outfile.write("WARNING in %s: %s\n" %
+ (self.__getpos(exception),
+ exception.getMessage()))
+
+ def error(self, exception):
+ if self._level <= 1:
+ self._outfile.write("ERROR in %s: %s\n" %
+ (self.__getpos(exception),
+ exception.getMessage()))
+
+ def fatalError(self, exception):
+ if self._level <= 2:
+ self._outfile.write("FATAL ERROR in %s: %s\n" %
+ (self.__getpos(exception),
+ exception.getMessage()))
+
+ def __getpos(self, exception):
+ if isinstance(exception, _exceptions.SAXParseException):
+ return "%s:%s:%s" % (exception.getSystemId(),
+ exception.getLineNumber(),
+ exception.getColumnNumber())
+ else:
+ return "<unknown>"
+
+# --- ErrorRaiser
+
+class ErrorRaiser:
+ "A simple class that just raises the exceptions it is passed."
+
+ def __init__(self, level = 0):
+ self._level = level
+
+ def error(self, exception):
+ if self._level <= 1:
+ raise exception
+
+ def fatalError(self, exception):
+ if self._level <= 2:
+ raise exception
+
+ def warning(self, exception):
+ if self._level <= 0:
+ raise exception
+
+# --- AttributesImpl now lives in xmlreader
+from xmlreader import AttributesImpl
+
+# --- XMLGenerator is the SAX2 ContentHandler for writing back XML
+try:
+ import codecs
+ def _outputwrapper(stream,encoding):
+ writerclass = codecs.lookup(encoding)[3]
+ return writerclass(stream)
+except ImportError: # 1.5 compatibility: fall back to do-nothing
+ def _outputwrapper(stream,encoding):
+ return stream
+
+class XMLGenerator(handler.ContentHandler):
+
+ def __init__(self, out=None, encoding="iso-8859-1"):
+ if out is None:
+ import sys
+ out = sys.stdout
+ handler.ContentHandler.__init__(self)
+ self._out = _outputwrapper(out,encoding)
+ self._ns_contexts = [{}] # contains uri -> prefix dicts
+ self._current_context = self._ns_contexts[-1]
+ self._undeclared_ns_maps = []
+ self._encoding = encoding
+
+ # ContentHandler methods
+
+ def startDocument(self):
+ self._out.write('<?xml version="1.0" encoding="%s"?>\n' %
+ self._encoding)
+
+ def startPrefixMapping(self, prefix, uri):
+ self._ns_contexts.append(self._current_context.copy())
+ self._current_context[uri] = prefix
+ self._undeclared_ns_maps.append((prefix, uri))
+
+ def endPrefixMapping(self, prefix):
+ self._current_context = self._ns_contexts[-1]
+ del self._ns_contexts[-1]
+
+ def startElement(self, name, attrs):
+ self._out.write('<' + name)
+ for (name, value) in attrs.items():
+ self._out.write(' %s="%s"' % (name, escape(value)))
+ self._out.write('>')
+
+ def endElement(self, name):
+ self._out.write('</%s>' % name)
+
+ def startElementNS(self, name, qname, attrs):
+ if name[0] is None:
+ name = name[1]
+ elif self._current_context[name[0]] is None:
+ # default namespace
+ name = name[1]
+ else:
+ name = self._current_context[name[0]] + ":" + name[1]
+ self._out.write('<' + name)
+
+ for k,v in self._undeclared_ns_maps:
+ if k is None:
+ self._out.write(' xmlns="%s"' % v)
+ else:
+ self._out.write(' xmlns:%s="%s"' % (k,v))
+ self._undeclared_ns_maps = []
+
+ for (name, value) in attrs.items():
+ name = self._current_context[name[0]] + ":" + name[1]
+ self._out.write(' %s="%s"' % (name, escape(value)))
+ self._out.write('>')
+
+ def endElementNS(self, name, qname):
+ # XXX: if qname is not None, we better use it.
+ # Python 2.0b2 requires us to use the recorded prefix for
+ # name[0], though
+ if name[0] is None:
+ qname = name[1]
+ elif self._current_context[name[0]] is None:
+ qname = name[1]
+ else:
+ qname = self._current_context[name[0]] + ":" + name[1]
+ self._out.write('</%s>' % qname)
+
+ def characters(self, content):
+ self._out.write(escape(content))
+
+ def ignorableWhitespace(self, content):
+ self._out.write(content)
+
+ def processingInstruction(self, target, data):
+ self._out.write('<?%s %s?>' % (target, data))
+
+# --- ContentGenerator is the SAX1 DocumentHandler for writing back XML
+class ContentGenerator(XMLGenerator):
+
+ def characters(self, str, start, end):
+ # In SAX1, characters receives start and end; in SAX2, it receives
+ # a string. For plain strings, we may want to use a buffer object.
+ return XMLGenerator.characters(self, str[start:start+end])
+
+# --- XMLFilterImpl
+class XMLFilterBase(xmlreader.XMLReader):
+ """This class is designed to sit between an XMLReader and the
+ client application's event handlers. By default, it does nothing
+ but pass requests up to the reader and events on to the handlers
+ unmodified, but subclasses can override specific methods to modify
+ the event stream or the configuration requests as they pass
+ through."""
+
+ # ErrorHandler methods
+
+ def error(self, exception):
+ self._err_handler.error(exception)
+
+ def fatalError(self, exception):
+ self._err_handler.fatalError(exception)
+
+ def warning(self, exception):
+ self._err_handler.warning(exception)
+
+ # ContentHandler methods
+
+ def setDocumentLocator(self, locator):
+ self._cont_handler.setDocumentLocator(locator)
+
+ def startDocument(self):
+ self._cont_handler.startDocument()
+
+ def endDocument(self):
+ self._cont_handler.endDocument()
+
+ def startPrefixMapping(self, prefix, uri):
+ self._cont_handler.startPrefixMapping(prefix, uri)
+
+ def endPrefixMapping(self, prefix):
+ self._cont_handler.endPrefixMapping(prefix)
+
+ def startElement(self, name, attrs):
+ self._cont_handler.startElement(name, attrs)
+
+ def endElement(self, name):
+ self._cont_handler.endElement(name)
+
+ def startElementNS(self, name, qname, attrs):
+ self._cont_handler.startElementNS(name, qname, attrs)
+
+ def endElementNS(self, name, qname):
+ self._cont_handler.endElementNS(name, qname)
+
+ def characters(self, content):
+ self._cont_handler.characters(content)
+
+ def ignorableWhitespace(self, chars):
+ self._cont_handler.ignorableWhitespace(chars)
+
+ def processingInstruction(self, target, data):
+ self._cont_handler.processingInstruction(target, data)
+
+ def skippedEntity(self, name):
+ self._cont_handler.skippedEntity(name)
+
+ # DTDHandler methods
+
+ def notationDecl(self, name, publicId, systemId):
+ self._dtd_handler.notationDecl(name, publicId, systemId)
+
+ def unparsedEntityDecl(self, name, publicId, systemId, ndata):
+ self._dtd_handler.unparsedEntityDecl(name, publicId, systemId, ndata)
+
+ # EntityResolver methods
+
+ def resolveEntity(self, publicId, systemId):
+ self._ent_handler.resolveEntity(publicId, systemId)
+
+ # XMLReader methods
+
+ def parse(self, source):
+ self._parent.setContentHandler(self)
+ self._parent.setErrorHandler(self)
+ self._parent.setEntityResolver(self)
+ self._parent.setDTDHandler(self)
+ self._parent.parse(source)
+
+ def setLocale(self, locale):
+ self._parent.setLocale(locale)
+
+ def getFeature(self, name):
+ return self._parent.getFeature(name)
+
+ def setFeature(self, name, state):
+ self._parent.setFeature(name, state)
+
+ def getProperty(self, name):
+ return self._parent.getProperty(name)
+
+ def setProperty(self, name, value):
+ self._parent.setProperty(name, value)
+
+# FIXME: remove this backward compatibility hack when not needed anymore
+XMLFilterImpl = XMLFilterBase
+
+# --- BaseIncrementalParser
+
+class BaseIncrementalParser(xmlreader.IncrementalParser):
+ """This class implements the parse method of the XMLReader
+ interface using the feed, close and reset methods of the
+ IncrementalParser interface as a convenience to SAX 2.0 driver
+ writers."""
+
+ def parse(self, source):
+ source = prepare_input_source(source)
+ self.prepareParser(source)
+
+ self._cont_handler.startDocument()
+
+ # FIXME: what about char-stream?
+ inf = source.getByteStream()
+ buffer = inf.read(16384)
+ while buffer != "":
+ self.feed(buffer)
+ buffer = inf.read(16384)
+
+ self.close()
+ self.reset()
+
+ self._cont_handler.endDocument()
+
+ def prepareParser(self, source):
+ """This method is called by the parse implementation to allow
+ the SAX 2.0 driver to prepare itself for parsing."""
+ raise NotImplementedError("prepareParser must be overridden!")
+
+# --- Utility functions
+
+def prepare_input_source(source, base = ""):
+ """This function takes an InputSource and an optional base URL and
+ returns a fully resolved InputSource object ready for reading."""
+
+ if type(source) in _StringTypes:
+ source = xmlreader.InputSource(source)
+ elif hasattr(source, "read"):
+ f = source
+ source = xmlreader.InputSource()
+ source.setByteStream(f)
+ if hasattr(f, "name"):
+ source.setSystemId(f.name)
+
+ if source.getByteStream() is None:
+ sysid = source.getSystemId()
+ if os.path.isfile(sysid):
+ basehead = os.path.split(os.path.normpath(base))[0]
+ source.setSystemId(os.path.join(basehead, sysid))
+ f = open(sysid, "rb")
+ else:
+ source.setSystemId(urlparse.urljoin(base, sysid))
+ f = urllib.urlopen(source.getSystemId())
+
+ source.setByteStream(f)
+
+ return source
+
+# ===========================================================================
+#
+# DEPRECATED SAX 1.0 CLASSES
+#
+# ===========================================================================
+
+# --- AttributeMap
+
+class AttributeMap:
+ """An implementation of AttributeList that takes an (attr,val) hash
+ and uses it to implement the AttributeList interface."""
+
+ def __init__(self, map):
+ self.map=map
+
+ def getLength(self):
+ return len(self.map.keys())
+
+ def getName(self, i):
+ try:
+ return self.map.keys()[i]
+ except IndexError,e:
+ return None
+
+ def getType(self, i):
+ return "CDATA"
+
+ def getValue(self, i):
+ try:
+ if type(i)==types.IntType:
+ return self.map[self.getName(i)]
+ else:
+ return self.map[i]
+ except KeyError,e:
+ return None
+
+ def __len__(self):
+ return len(self.map)
+
+ def __getitem__(self, key):
+ if type(key)==types.IntType:
+ return self.map.keys()[key]
+ else:
+ return self.map[key]
+
+ def items(self):
+ return self.map.items()
+
+ def keys(self):
+ return self.map.keys()
+
+ def has_key(self,key):
+ return self.map.has_key(key)
+
+ def get(self, key, alternative=None):
+ return self.map.get(key, alternative)
+
+ def copy(self):
+ return AttributeMap(self.map.copy())
+
+ def values(self):
+ return self.map.values()
+
+# --- Event broadcasting object
+
+class EventBroadcaster:
+ """Takes a list of objects and forwards any method calls received
+ to all objects in the list. The attribute list holds the list and
+ can freely be modified by clients."""
+
+ class Event:
+ "Helper objects that represent event methods."
+
+ def __init__(self,list,name):
+ self.list=list
+ self.name=name
+
+ def __call__(self,*rest):
+ for obj in self.list:
+ apply(getattr(obj,self.name), rest)
+
+ def __init__(self,list):
+ self.list=list
+
+ def __getattr__(self,name):
+ return self.Event(self.list,name)
+
+ def __repr__(self):
+ return "<EventBroadcaster instance at %d>" % id(self)
+
+# --- ESIS document handler
+import saxlib
+class ESISDocHandler(saxlib.HandlerBase):
+ "A SAX document handler that produces naive ESIS output."
+
+ def __init__(self,writer=sys.stdout):
+ self.writer=writer
+
+ def processingInstruction (self,target, remainder):
+ """Receive an event signalling that a processing instruction
+ has been found."""
+ self.writer.write("?"+target+" "+remainder+"\n")
+
+ def startElement(self,name,amap):
+ "Receive an event signalling the start of an element."
+ self.writer.write("("+name+"\n")
+ for a_name in amap.keys():
+ self.writer.write("A"+a_name+" "+amap[a_name]+"\n")
+
+ def endElement(self,name):
+ "Receive an event signalling the end of an element."
+ self.writer.write(")"+name+"\n")
+
+ def characters(self,data,start_ix,length):
+ "Receive an event signalling that character data has been found."
+ self.writer.write("-"+data[start_ix:start_ix+length]+"\n")
+
+# --- XML canonizer
+
+class Canonizer(saxlib.HandlerBase):
+ "A SAX document handler that produces canonized XML output."
+
+ def __init__(self,writer=sys.stdout):
+ self.elem_level=0
+ self.writer=writer
+
+ def processingInstruction (self,target, remainder):
+ if not target=="xml":
+ self.writer.write("<?"+target+" "+remainder+"?>")
+
+ def startElement(self,name,amap):
+ self.writer.write("<"+name)
+
+ a_names=amap.keys()
+ a_names.sort()
+
+ for a_name in a_names:
+ self.writer.write(" "+a_name+"=\"")
+ self.write_data(amap[a_name])
+ self.writer.write("\"")
+ self.writer.write(">")
+ self.elem_level=self.elem_level+1
+
+ def endElement(self,name):
+ self.writer.write("</"+name+">")
+ self.elem_level=self.elem_level-1
+
+ def ignorableWhitespace(self,data,start_ix,length):
+ self.characters(data,start_ix,length)
+
+ def characters(self,data,start_ix,length):
+ if self.elem_level>0:
+ self.write_data(data[start_ix:start_ix+length])
+
+ def write_data(self,data):
+ "Writes datachars to writer."
+ data=string.replace(data,"&","&")
+ data=string.replace(data,"<","<")
+ data=string.replace(data,"\"",""")
+ data=string.replace(data,">",">")
+ data=string.replace(data,chr(9),"	")
+ data=string.replace(data,chr(10)," ")
+ data=string.replace(data,chr(13)," ")
+ self.writer.write(data)
+
+# --- mllib
+
+class mllib:
+ """A re-implementation of the htmllib, sgmllib and xmllib interfaces as a
+ SAX DocumentHandler."""
+
+# Unsupported:
+# - setnomoretags
+# - setliteral
+# - translate_references
+# - handle_xml
+# - handle_doctype
+# - handle_charref
+# - handle_entityref
+# - handle_comment
+# - handle_cdata
+# - tag_attributes
+
+ def __init__(self):
+ self.reset()
+
+ def reset(self):
+ import saxexts # only used here
+ self.parser=saxexts.XMLParserFactory.make_parser()
+ self.handler=mllib.Handler(self.parser,self)
+ self.handler.reset()
+
+ def feed(self,data):
+ self.parser.feed(data)
+
+ def close(self):
+ self.parser.close()
+
+ def get_stack(self):
+ return self.handler.get_stack()
+
+ # --- Handler methods (to be overridden)
+
+ def handle_starttag(self,name,method,atts):
+ method(atts)
+
+ def handle_endtag(self,name,method):
+ method()
+
+ def handle_data(self,data):
+ pass
+
+ def handle_proc(self,target,data):
+ pass
+
+ def unknown_starttag(self,name,atts):
+ pass
+
+ def unknown_endtag(self,name):
+ pass
+
+ def syntax_error(self,message):
+ pass
+
+ # --- The internal handler class
+
+ class Handler(saxlib.DocumentHandler,saxlib.ErrorHandler):
+ """An internal class to handle SAX events and translate them to mllib
+ events."""
+
+ def __init__(self,driver,handler):
+ self.driver=driver
+ self.driver.setDocumentHandler(self)
+ self.driver.setErrorHandler(self)
+ self.handler=handler
+ self.reset()
+
+ def get_stack(self):
+ return self.stack
+
+ def reset(self):
+ self.stack=[]
+
+ # --- DocumentHandler methods
+
+ def characters(self, ch, start, length):
+ self.handler.handle_data(ch[start:start+length])
+
+ def endElement(self, name):
+ if hasattr(self.handler,"end_"+name):
+ self.handler.handle_endtag(name,
+ getattr(self.handler,"end_"+name))
+ else:
+ self.handler.unknown_endtag(name)
+
+ del self.stack[-1]
+
+ def ignorableWhitespace(self, ch, start, length):
+ self.handler.handle_data(ch[start:start+length])
+
+ def processingInstruction(self, target, data):
+ self.handler.handle_proc(target,data)
+
+ def startElement(self, name, atts):
+ self.stack.append(name)
+
+ if hasattr(self.handler,"start_"+name):
+ self.handler.handle_starttag(name,
+ getattr(self.handler,
+ "start_"+name),
+ atts)
+ else:
+ self.handler.unknown_starttag(name,atts)
+
+ # --- ErrorHandler methods
+
+ def error(self, exception):
+ self.handler.syntax_error(str(exception))
+
+ def fatalError(self, exception):
+ raise RuntimeError(str(exception))
diff --git a/lib/jython/Lib/xml/sax/writer.py b/lib/jython/Lib/xml/sax/writer.py new file mode 100644 index 000000000..dc37396c3 --- /dev/null +++ b/lib/jython/Lib/xml/sax/writer.py @@ -0,0 +1,534 @@ +"""SAX document handlers that support output generation of XML, SGML,
+and XHTML.
+
+This module provides three different groups of objects: the actual SAX
+document handlers that drive the output, DTD information containers,
+and syntax descriptors (of limited public use in most cases).
+
+
+Output Drivers
+--------------
+
+The output drivers conform to the SAX C<DocumentHandler> protocol.
+They can be used anywhere a C<DocumentHandler> is used. Two drivers
+are provided: a `basic' driver which creates a fairly minimal output
+without much intelligence, and a `pretty-printing' driver that
+performs pretty-printing with nice indentation and the like. Both can
+optionally make use of DTD information and syntax objects.
+
+
+DTD Information Containers
+--------------------------
+
+
+
+Each DTD information object provides an attribute C<syntax> which
+describes the expected output syntax; an alternate can be provided to
+the output drivers if desired.
+
+
+Syntax Descriptors
+------------------
+
+Syntax descriptor objects provide several attributes which describe
+the various lexical components of XML & SGML markup. The attributes
+have names that reflect the shorthand notation from the SGML world,
+but the values are strings which give the appropriate characters for
+the markup language being described. The one addition is the
+C<empty_stagc> attribute which should be used to end the start tag of
+elements which have no content. This is needed to properly support
+XML and XHTML.
+
+"""
+__version__ = '$Revision: 1.4 $'
+
+import string
+
+import xml.parsers.xmlproc.dtdparser
+import xml.parsers.xmlproc.xmlapp
+from xml.sax.saxutils import escape
+
+
+DEFAULT_LINELENGTH = 74
+
+
+
+class Syntax:
+ com = "--" # comment start or end
+ cro = "&#" # character reference open
+ refc = ";" # reference close
+ dso = "[" # declaration subset open
+ dsc = "]" # declaration subset close
+ ero = "&" # entity reference open
+ lit = '"' # literal start or end
+ lita = "'" # literal start or end (alternative)
+ mdo = "<!" # markup declaration open
+ mdc = ">" # markup declaration close
+ msc = "]]" # marked section close
+ pio = "<?" # processing instruciton open
+ stago = "<" # start tag open
+ etago = "</" # end tag open
+ tagc = ">" # tag close
+ vi = "=" # value indicator
+
+ def __init__(self):
+ if self.__class__ is Syntax:
+ raise RuntimeError, "Syntax must be subclassed to be used!"
+
+
+class SGMLSyntax(Syntax):
+ empty_stagc = ">"
+ pic = ">" # processing instruction close
+ net = "/" # null end tag
+
+
+class XMLSyntax(Syntax):
+ empty_stagc = "/>"
+ pic = "?>" # processing instruction close
+ net = None # null end tag not supported
+
+
+class XHTMLSyntax(XMLSyntax):
+ empty_stagc = " />"
+
+
+
+class DoctypeInfo:
+ syntax = XMLSyntax()
+
+ fpi = None
+ sysid = None
+
+ def __init__(self):
+ self.__empties = {}
+ self.__elements_only = {}
+ self.__attribs = {}
+
+ def is_empty(self, gi):
+ return self.__empties.has_key(gi)
+
+ def get_empties_list(self):
+ return self.__empties.keys()
+
+ def has_element_content(self, gi):
+ return self.__elements_only.has_key(gi)
+
+ def get_element_containers_list(self):
+ return self.__elements_only.keys()
+
+ def get_attributes_list(self, gi):
+ return self.__attribs.get(gi, {}).keys()
+
+ def get_attribute_info(self, gi, attr):
+ return self.__attribs[gi][attr]
+
+ def add_empty(self, gi):
+ self.__empties[gi] = 1
+
+ def add_element_container(self, gi):
+ self.__elements_only[gi] = gi
+
+ def add_attribute_defn(self, gi, attr, type, decl, default):
+ try:
+ d = self.__attribs[gi]
+ except KeyError:
+ d = self.__attribs[gi] = {}
+ if not d.has_key(attr):
+ d[attr] = (type, decl, default)
+ else:
+ print "<%s> attribute %s already defined" % (gi, attr)
+
+ def load_pubtext(self, pubtext):
+ raise NotImplementedError, "sublasses must implement load_pubtext()"
+
+
+class _XMLDTDLoader(xml.parsers.xmlproc.xmlapp.DTDConsumer):
+ def __init__(self, info, parser):
+ self.info = info
+ xml.parsers.xmlproc.xmlapp.DTDConsumer.__init__(self, parser)
+ self.new_attribute = info.add_attribute_defn
+
+ def new_element_type(self, gi, model):
+ if model[0] == "|" and model[1][0] == ("#PCDATA", ""):
+ # no action required
+ pass
+ elif model == ("", [], ""):
+ self.info.add_empty(gi)
+ else:
+ self.info.add_element_container(gi)
+
+
+class XMLDoctypeInfo(DoctypeInfo):
+ def load_pubtext(self, sysid):
+ parser = xml.parsers.xmlproc.dtdparser.DTDParser()
+ loader = _XMLDTDLoader(self, parser)
+ parser.set_dtd_consumer(loader)
+ parser.parse_resource(sysid)
+
+
+class XHTMLDoctypeInfo(XMLDoctypeInfo):
+ # Bogus W3C cruft requires the extra space when terminating empty elements.
+ syntax = XHTMLSyntax()
+
+
+class SGMLDoctypeInfo(DoctypeInfo):
+ syntax = SGMLSyntax()
+
+ import re
+ __element_prefix_search = re.compile("<!ELEMENT", re.IGNORECASE).search
+ __element_prefix_len = len("<!ELEMENT")
+ del re
+
+ def load_pubtext(self, sysid):
+ #
+ # Really should build a proper SGML DTD parser!
+ #
+ pubtext = open(sysid).read()
+ m = self.__element_prefix_search(pubtext)
+ while m:
+ pubtext = pubtext[m.end():]
+ if pubtext and pubtext[0] in string.whitespace:
+ pubtext = string.lstrip(pubtext)
+ else:
+ continue
+ gi, pubtext = string.split(pubtext, None, 1)
+ pubtext = string.lstrip(pubtext)
+ # maybe need to remove/collect tag occurance specifiers
+ # ...
+ raise NotImplementedError, "implementation incomplete"
+ #
+ m = self.__element_prefix_search(pubtext)
+
+
+
+class XmlWriter:
+ """Basic XML output handler."""
+
+ def __init__(self, fp, standalone=None, dtdinfo=None,
+ syntax=None, linelength=None):
+ self._offset = 0
+ self._packing = 0
+ self._flowing = 1
+ self._write = fp.write
+ self._dtdflowing = None
+ self._prefix = ''
+ self.__stack = []
+ self.__lang = None
+ self.__pending_content = 0
+ self.__pending_doctype = 1
+ self.__standalone = standalone
+ self.__dtdinfo = dtdinfo
+ if syntax is None:
+ if dtdinfo:
+ syntax = dtdinfo.syntax
+ else:
+ syntax = XMLSyntax()
+ self.__syntax = syntax
+ self.indentation = 0
+ self.indentEndTags = 0
+ if linelength is None:
+ self.lineLength = DEFAULT_LINELENGTH
+ else:
+ self.lineLength = linelength
+
+ def setDocumentLocator(self, locator):
+ self.locator = locator
+
+ def startDocument(self):
+ if self.__syntax.pic == "?>":
+ lit = self.__syntax.lit
+ s = '%sxml version=%s1.0%s encoding%s%siso-8859-1%s' % (
+ self.__syntax.pio, lit, lit, self.__syntax.vi, lit, lit)
+ if self.__standalone:
+ s = '%s standalone%s%s%s%s' % (
+ s, self.__syntax.vi, lit, self.__standalone, lit)
+ self._write("%s%s\n" % (s, self.__syntax.pic))
+
+ def endDocument(self):
+ if self.__stack:
+ raise RuntimeError, "open element stack cannot be empty on close"
+
+ def startElement(self, tag, attrs={}):
+ if self.__pending_doctype:
+ self.handle_doctype(tag)
+ self._check_pending_content()
+ self.__pushtag(tag)
+ self.__check_flowing(tag, attrs)
+ if attrs.has_key("xml:lang"):
+ self.__lang = attrs["xml:lang"]
+ del attrs["xml:lang"]
+ if self._packing:
+ prefix = ""
+ elif self._flowing:
+ prefix = self._prefix[:-self.indentation]
+ else:
+ prefix = ""
+ stag = "%s%s%s" % (prefix, self.__syntax.stago, tag)
+ prefix = "%s %s" % (prefix, (len(tag) * " "))
+ lit = self.__syntax.lit
+ vi = self.__syntax.vi
+ a = ''
+ if self._flowing != self.__stack[-1][0]:
+ if self._dtdflowing is not None \
+ and self._flowing == self._dtdflowing:
+ pass
+ else:
+ a = ' xml:space%s%s%s%s' \
+ % (vi, lit, ["default", "preserve"][self._flowing], lit)
+ if self.__lang != self.__stack[-1][1]:
+ a = '%s xml:lang%s%s%s%s' % (a, vi, lit, self.lang, lit)
+ line = stag + a
+ self._offset = self._offset + len(line)
+ a = ''
+ for k, v in attrs.items():
+ if v is None:
+ continue
+ a = ' %s%s%s%s%s' % (k, vi, lit, escape(str(v)), lit)
+ if (self._offset + len(a)) > self.lineLength:
+ self._write(line + "\n")
+ line = prefix + a
+ self._offset = len(line)
+ else:
+ line = line + a
+ self._offset = self._offset + len(a)
+ self._write(line)
+ self.__pending_content = 1
+ if ( self.__dtdinfo and not
+ (self.__dtdinfo.has_element_content(tag)
+ or self.__dtdinfo.is_empty(tag))):
+ self._packing = 1
+
+ def endElement(self, tag):
+ if self.__pending_content:
+ if self._flowing:
+ self._write(self.__syntax.empty_stagc)
+ if self._packing:
+ self._offset = self._offset \
+ + len(self.__syntax.empty_stagc)
+ else:
+ self._write("\n")
+ self._offset = 0
+ else:
+ self._write(self.__syntax.empty_stagc)
+ self._offset = self._offset + len(self.__syntax.empty_stagc)
+ self.__pending_content = 0
+ self.__poptag(tag)
+ return
+ depth = len(self.__stack)
+ if depth == 1 or self._packing or not self._flowing:
+ prefix = ''
+ else:
+ prefix = self._prefix[:-self.indentation] \
+ + (" " * self.indentEndTags)
+ self.__poptag(tag)
+ self._write("%s%s%s%s" % (
+ prefix, self.__syntax.etago, tag, self.__syntax.tagc))
+ if self._packing:
+ self._offset = self._offset + len(tag) + 3
+ else:
+ self._write("\n")
+ self._offset = 0
+
+ def characters(self, data, start, length):
+ data = data[start: start+length]
+ if data:
+ data = escape(data)
+ if "\n" in data:
+ p = string.find(data, "\n")
+ self._offset = len(data) - (p + 1)
+ else:
+ self._offset = self._offset + len(data)
+ self._write(data)
+
+ def comment(self, data, start, length):
+ data = data[start: start+length]
+ self._check_pending_content()
+ s = "%s%s%s%s%s" % (self.__syntax.mdo, self.__syntax.com,
+ data, self.__syntax.com, self.__syntax.mdc)
+ p = string.rfind(s, "\n")
+ if self._packing:
+ if p >= 0:
+ self._offset = len(s) - (p + 1)
+ else:
+ self._offset = self._offset + len(s)
+ else:
+ self._write("%s%s\n" % (self._prefix, s))
+ self._offset = 0
+
+ def ignorableWhitespace(self, data, start, length):
+ pass
+
+ def processingInstruction(self, target, data):
+ s = "%s%s %s%s" % (self.__syntax.pio, target, data, self.__syntax.pic)
+ prefix = self._prefix[:-self.indentation] \
+ + (" " * self.indentEndTags)
+ if "\n" in s:
+ pos = string.rfind(s, "\n")
+ if self._flowing and not self._packing:
+ self._write(prefix + s + "\n")
+ self._offset = 0
+ else:
+ self._write(s)
+ self._offset = len(s) - (p + 1)
+ elif self._flowing and not self._packing:
+ self._write(prefix + s + "\n")
+ self._offset = 0
+ else:
+ self._write(s)
+ self._offset = len(s) - (p + 1)
+
+
+ # This doesn't actually have a SAX equivalent, so we'll use it as
+ # an internal helper.
+
+ def handle_doctype(self, root):
+ self.__pending_doctype = 0
+ if self.__dtdinfo:
+ fpi = self.__dtdinfo.fpi
+ sysid = self.__dtdinfo.sysid
+ else:
+ fpi = sysid = None
+ lit = self.__syntax.lit
+ isxml = self.__syntax.pic == "?>"
+ if isxml and sysid:
+ s = '%sDOCTYPE %s\n' % (self.__syntax.mdo, root)
+ if fpi:
+ s = s + ' PUBLIC %s%s%s\n' % (lit, fpi, lit)
+ s = s + ' %s%s%s>\n' % (lit, sysid, lit)
+ else:
+ s = s + ' SYSTEM %s%s%s>\n' % (lit, sysid, lit)
+ self._write(s)
+ self._offset = 0
+ elif not isxml:
+ s = "%sDOCTYPE %s" % (self.__syntax.mdo, root)
+ if fpi:
+ s = '%s\n PUBLIC %s%s%s' % (s, lit, fpi, lit)
+ if sysid:
+ s = '%s\n SYSTEM %s%s%s' % (s, lit, sysid, lit)
+ self._write("%s%s\n" % (s, self.__syntax.mdc))
+ self._offset = 0
+
+ def handle_cdata(self, data):
+ self._check_pending_content()
+ # There should be a better way to generate '[CDATA['
+ start = self.__syntax.mdo + "[CDATA["
+ end = self.__syntax.msc + self.__syntax.mdc
+ s = "%s%s%s" % (start, escape(data), end)
+ if self._packing:
+ if "\n" in s:
+ rpos = string.rfind(s, "\n")
+ self._offset = len(s) - (rpos + 1) + len(end)
+ else:
+ self._offset = self.__offset + len(s) + len(start + end)
+ self._write(s)
+ else:
+ self._offset = 0
+ self._write(s + "\n")
+
+
+ # Internal helper methods.
+
+ def __poptag(self, tag):
+ state = self.__stack.pop()
+ self._flowing, self.__lang, expected_tag, \
+ self._packing, self._dtdflowing = state
+ if tag != expected_tag:
+ raise RuntimeError, \
+ "expected </%s>, got </%s>" % (expected_tag, tag)
+ self._prefix = self._prefix[:-self.indentation]
+
+ def __pushtag(self, tag):
+ self.__stack.append((self._flowing, self.__lang, tag,
+ self._packing, self._dtdflowing))
+ self._prefix = self._prefix + " " * self.indentation
+
+ def __check_flowing(self, tag, attrs):
+ """Check the contents of attrs and the DTD information to determine
+ whether the following content should be flowed.
+
+ tag -- general identifier of the element being opened
+ attrs -- attributes dictionary as reported by the parser or
+ application
+
+ This sets up both the _flowing and _dtdflowing (object) attributes.
+ """
+ docspec = dtdspec = None
+ if self.__dtdinfo:
+ try:
+ info = self.__dtdinfo.get_attribute_info(tag, "xml:space")
+ except KeyError:
+ info = None
+ if info is not None:
+ self._flowing = info[2] != "preserve"
+ self._dtdflowing = self._flowing
+ if attrs.has_key("xml:space"):
+ self._flowing = attrs["xml:space"] != "preserve"
+ del attrs["xml:space"]
+
+ def _check_pending_content(self):
+ if self.__pending_content:
+ s = self.__syntax.tagc
+ if self._flowing and not self._packing:
+ s = s + "\n"
+ self._offset = 0
+ else:
+ self._offset = self._offset + len(s)
+ self._write(s)
+ self.__pending_content = 0
+
+
+class PrettyPrinter(XmlWriter):
+ """Pretty-printing XML output handler."""
+
+ def __init__(self, fp, standalone=None, dtdinfo=None,
+ syntax=None, linelength=None,
+ indentation=2, endtagindentation=None):
+ XmlWriter.__init__(self, fp, standalone=standalone, dtdinfo=dtdinfo,
+ syntax=syntax, linelength=linelength)
+ self.indentation = indentation
+ if endtagindentation is not None:
+ self.indentEndTags = endtagindentation
+ else:
+ self.indentEndTags = indentation
+
+ def characters(self, data, start, length):
+ data = data[start: start + length]
+ if not data:
+ return
+ self._check_pending_content()
+ data = escape(data)
+ if not self._flowing:
+ self._write(data)
+ return
+ words = string.split(data)
+ begspace = data[0] in string.whitespace
+ endspace = words and (data[-1] in string.whitespace)
+ prefix = self._prefix
+ if len(prefix) > 40:
+ prefix = " "
+ offset = self._offset
+ L = []
+ append = L.append
+ if begspace:
+ append(" ")
+ offset = offset + 1
+ ws = ""
+ ws_len = 0
+ while words:
+ w = words[0]
+ del words[0]
+ if (offset + ws_len + len(w)) > self.lineLength:
+ append("\n")
+ append(prefix)
+ append(w)
+ offset = len(prefix) + len(w)
+ else:
+ append(ws)
+ ws, ws_len = " ", 1
+ append(w)
+ offset = offset + 1 + len(w)
+ if endspace:
+ append(" ")
+ offset = offset + 1
+ self._offset = offset
+ self._write(string.join(L, ""))
diff --git a/lib/jython/Lib/xml/sax/xmlreader.py b/lib/jython/Lib/xml/sax/xmlreader.py new file mode 100644 index 000000000..1b5ec9215 --- /dev/null +++ b/lib/jython/Lib/xml/sax/xmlreader.py @@ -0,0 +1,376 @@ +"""An XML Reader is the SAX 2 name for an XML parser. XML Parsers
+should be based on this code. """
+
+import handler
+from _exceptions import *
+
+# ===== XMLREADER =====
+
+class XMLReader:
+ """Interface for reading an XML document using callbacks.
+
+ XMLReader is the interface that an XML parser's SAX2 driver must
+ implement. This interface allows an application to set and query
+ features and properties in the parser, to register event handlers
+ for document processing, and to initiate a document parse.
+
+ All SAX interfaces are assumed to be synchronous: the parse
+ methods must not return until parsing is complete, and readers
+ must wait for an event-handler callback to return before reporting
+ the next event."""
+
+ def __init__(self):
+ self._cont_handler = handler.ContentHandler()
+ self._dtd_handler = handler.DTDHandler()
+ self._ent_handler = handler.EntityResolver()
+ self._err_handler = handler.ErrorHandler()
+
+ def parse(self, source):
+ "Parse an XML document from a system identifier or an InputSource."
+ raise NotImplementedError("This method must be implemented!")
+
+ def getContentHandler(self):
+ "Returns the current ContentHandler."
+ return self._cont_handler
+
+ def setContentHandler(self, handler):
+ "Registers a new object to receive document content events."
+ self._cont_handler = handler
+
+ def getDTDHandler(self):
+ "Returns the current DTD handler."
+ return self._dtd_handler
+
+ def setDTDHandler(self, handler):
+ "Register an object to receive basic DTD-related events."
+ self._dtd_handler = handler
+
+ def getEntityResolver(self):
+ "Returns the current EntityResolver."
+ return self._ent_handler
+
+ def setEntityResolver(self, resolver):
+ "Register an object to resolve external entities."
+ self._ent_handler = resolver
+
+ def getErrorHandler(self):
+ "Returns the current ErrorHandler."
+ return self._err_handler
+
+ def setErrorHandler(self, handler):
+ "Register an object to receive error-message events."
+ self._err_handler = handler
+
+ def setLocale(self, locale):
+ """Allow an application to set the locale for errors and warnings.
+
+ SAX parsers are not required to provide localization for errors
+ and warnings; if they cannot support the requested locale,
+ however, they must throw a SAX exception. Applications may
+ request a locale change in the middle of a parse."""
+ raise SAXNotSupportedException("Locale support not implemented")
+
+ def getFeature(self, name):
+ "Looks up and returns the state of a SAX2 feature."
+ raise SAXNotRecognizedException("Feature '%s' not recognized" % name)
+
+ def setFeature(self, name, state):
+ "Sets the state of a SAX2 feature."
+ raise SAXNotRecognizedException("Feature '%s' not recognized" % name)
+
+ def getProperty(self, name):
+ "Looks up and returns the value of a SAX2 property."
+ raise SAXNotRecognizedException("Property '%s' not recognized" % name)
+
+ def setProperty(self, name, value):
+ "Sets the value of a SAX2 property."
+ raise SAXNotRecognizedException("Property '%s' not recognized" % name)
+
+class IncrementalParser(XMLReader):
+ """This interface adds three extra methods to the XMLReader
+ interface that allow XML parsers to support incremental
+ parsing. Support for this interface is optional, since not all
+ underlying XML parsers support this functionality.
+
+ When the parser is instantiated it is ready to begin accepting
+ data from the feed method immediately. After parsing has been
+ finished with a call to close the reset method must be called to
+ make the parser ready to accept new data, either from feed or
+ using the parse method.
+
+ Note that these methods must _not_ be called during parsing, that
+ is, after parse has been called and before it returns.
+
+ By default, the class also implements the parse method of the XMLReader
+ interface using the feed, close and reset methods of the
+ IncrementalParser interface as a convenience to SAX 2.0 driver
+ writers."""
+
+ def __init__(self, bufsize=2**16):
+ self._bufsize = bufsize
+ XMLReader.__init__(self)
+
+ def parse(self, source):
+ import saxutils
+ source = saxutils.prepare_input_source(source)
+
+ self.prepareParser(source)
+ file = source.getByteStream()
+ buffer = file.read(self._bufsize)
+ while buffer != "":
+ self.feed(buffer)
+ buffer = file.read(self._bufsize)
+ self.close()
+
+ def feed(self, data):
+ """This method gives the raw XML data in the data parameter to
+ the parser and makes it parse the data, emitting the
+ corresponding events. It is allowed for XML constructs to be
+ split across several calls to feed.
+
+ feed may raise SAXException."""
+ raise NotImplementedError("This method must be implemented!")
+
+ def prepareParser(self, source):
+ """This method is called by the parse implementation to allow
+ the SAX 2.0 driver to prepare itself for parsing."""
+ raise NotImplementedError("prepareParser must be overridden!")
+
+ def close(self):
+ """This method is called when the entire XML document has been
+ passed to the parser through the feed method, to notify the
+ parser that there are no more data. This allows the parser to
+ do the final checks on the document and empty the internal
+ data buffer.
+
+ The parser will not be ready to parse another document until
+ the reset method has been called.
+
+ close may raise SAXException."""
+ raise NotImplementedError("This method must be implemented!")
+
+ def reset(self):
+ """This method is called after close has been called to reset
+ the parser so that it is ready to parse new documents. The
+ results of calling parse or feed after close without calling
+ reset are undefined."""
+ raise NotImplementedError("This method must be implemented!")
+
+# ===== LOCATOR =====
+
+class Locator:
+ """Interface for associating a SAX event with a document
+ location. A locator object will return valid results only during
+ calls to DocumentHandler methods; at any other time, the
+ results are unpredictable."""
+
+ def getColumnNumber(self):
+ "Return the column number where the current event ends."
+ return -1
+
+ def getLineNumber(self):
+ "Return the line number where the current event ends."
+ return -1
+
+ def getPublicId(self):
+ "Return the public identifier for the current event."
+ return None
+
+ def getSystemId(self):
+ "Return the system identifier for the current event."
+ return None
+
+# ===== INPUTSOURCE =====
+
+class InputSource:
+ """Encapsulation of the information needed by the XMLReader to
+ read entities.
+
+ This class may include information about the public identifier,
+ system identifier, byte stream (possibly with character encoding
+ information) and/or the character stream of an entity.
+
+ Applications will create objects of this class for use in the
+ XMLReader.parse method and for returning from
+ EntityResolver.resolveEntity.
+
+ An InputSource belongs to the application, the XMLReader is not
+ allowed to modify InputSource objects passed to it from the
+ application, although it may make copies and modify those."""
+
+ def __init__(self, system_id = None):
+ self.__system_id = system_id
+ self.__public_id = None
+ self.__encoding = None
+ self.__bytefile = None
+ self.__charfile = None
+
+ def setPublicId(self, public_id):
+ "Sets the public identifier of this InputSource."
+ self.__public_id = public_id
+
+ def getPublicId(self):
+ "Returns the public identifier of this InputSource."
+ return self.__public_id
+
+ def setSystemId(self, system_id):
+ "Sets the system identifier of this InputSource."
+ self.__system_id = system_id
+
+ def getSystemId(self):
+ "Returns the system identifier of this InputSource."
+ return self.__system_id
+
+ def setEncoding(self, encoding):
+ """Sets the character encoding of this InputSource.
+
+ The encoding must be a string acceptable for an XML encoding
+ declaration (see section 4.3.3 of the XML recommendation).
+
+ The encoding attribute of the InputSource is ignored if the
+ InputSource also contains a character stream."""
+ self.__encoding = encoding
+
+ def getEncoding(self):
+ "Get the character encoding of this InputSource."
+ return self.__encoding
+
+ def setByteStream(self, bytefile):
+ """Set the byte stream (a Python file-like object which does
+ not perform byte-to-character conversion) for this input
+ source.
+
+ The SAX parser will ignore this if there is also a character
+ stream specified, but it will use a byte stream in preference
+ to opening a URI connection itself.
+
+ If the application knows the character encoding of the byte
+ stream, it should set it with the setEncoding method."""
+ self.__bytefile = bytefile
+
+ def getByteStream(self):
+ """Get the byte stream for this input source.
+
+ The getEncoding method will return the character encoding for
+ this byte stream, or None if unknown."""
+ return self.__bytefile
+
+ def setCharacterStream(self, charfile):
+ """Set the character stream for this input source. (The stream
+ must be a Python 2.0 Unicode-wrapped file-like that performs
+ conversion to Unicode strings.)
+
+ If there is a character stream specified, the SAX parser will
+ ignore any byte stream and will not attempt to open a URI
+ connection to the system identifier."""
+ self.__charfile = charfile
+
+ def getCharacterStream(self):
+ "Get the character stream for this input source."
+ return self.__charfile
+
+# ===== ATTRIBUTESIMPL =====
+
+class AttributesImpl:
+
+ def __init__(self, attrs):
+ """Non-NS-aware implementation.
+
+ attrs should be of the form {name : value}."""
+ self._attrs = attrs
+
+ def getLength(self):
+ return len(self._attrs)
+
+ def getType(self, name):
+ return "CDATA"
+
+ def getValue(self, name):
+ return self._attrs[name]
+
+ def getValueByQName(self, name):
+ return self._attrs[name]
+
+ def getNameByQName(self, name):
+ if not self._attrs.has_key(name):
+ raise KeyError, name
+ return name
+
+ def getQNameByName(self, name):
+ if not self._attrs.has_key(name):
+ raise KeyError, name
+ return name
+
+ def getNames(self):
+ return self._attrs.keys()
+
+ def getQNames(self):
+ return self._attrs.keys()
+
+ def __len__(self):
+ return len(self._attrs)
+
+ def __getitem__(self, name):
+ return self._attrs[name]
+
+ def keys(self):
+ return self._attrs.keys()
+
+ def has_key(self, name):
+ return self._attrs.has_key(name)
+
+ def get(self, name, alternative=None):
+ return self._attrs.get(name, alternative)
+
+ def copy(self):
+ return self.__class__(self._attrs)
+
+ def items(self):
+ return self._attrs.items()
+
+ def values(self):
+ return self._attrs.values()
+
+# ===== ATTRIBUTESNSIMPL =====
+
+class AttributesNSImpl(AttributesImpl):
+
+ def __init__(self, attrs, qnames):
+ """NS-aware implementation.
+
+ attrs should be of the form {(ns_uri, lname): value, ...}.
+ qnames of the form {(ns_uri, lname): qname, ...}."""
+ self._attrs = attrs
+ self._qnames = qnames
+
+ def getValueByQName(self, name):
+ for (nsname, qname) in self._qnames.items():
+ if qname == name:
+ return self._attrs[nsname]
+
+ raise KeyError, name
+
+ def getNameByQName(self, name):
+ for (nsname, qname) in self._qnames.items():
+ if qname == name:
+ return nsname
+
+ raise KeyError, name
+
+ def getQNameByName(self, name):
+ return self._qnames[name]
+
+ def getQNames(self):
+ return self._qnames.values()
+
+ def copy(self):
+ return self.__class__(self._attrs, self._qnames)
+
+
+def _test():
+ XMLReader()
+ IncrementalParser()
+ Locator()
+
+if __name__ == "__main__":
+ _test()
diff --git a/lib/jython/Lib/xml/utils/__init__.py b/lib/jython/Lib/xml/utils/__init__.py new file mode 100644 index 000000000..978a1c22b --- /dev/null +++ b/lib/jython/Lib/xml/utils/__init__.py @@ -0,0 +1 @@ +__all__ = ['iso8601']
diff --git a/lib/jython/Lib/xml/utils/iso8601.py b/lib/jython/Lib/xml/utils/iso8601.py new file mode 100644 index 000000000..1348d78e2 --- /dev/null +++ b/lib/jython/Lib/xml/utils/iso8601.py @@ -0,0 +1,188 @@ +"""ISO-8601 date format support, sufficient for the profile defined in
+<http://www.w3.org/TR/NOTE-datetime>.
+
+The parser is more flexible on the input format than is required to support
+the W3C profile, but all accepted date/time values are legal ISO 8601 dates.
+The tostring() method only generates formatted dates that are conformant to
+the profile.
+
+This module was written by Fred L. Drake, Jr. <fdrake@acm.org>.
+"""
+
+__version__ = '1.0'
+
+import string
+import time
+
+
+def parse(s):
+ """Parse an ISO-8601 date/time string, returning the value in seconds
+ since the epoch."""
+ m = __datetime_rx.match(s)
+ if m is None or m.group() != s:
+ raise ValueError, "unknown or illegal ISO-8601 date format: " + `s`
+ gmt = __extract_date(m) + __extract_time(m) + (0, 0, 0)
+ return time.mktime(gmt) + __extract_tzd(m) - time.timezone
+
+
+def parse_timezone(timezone):
+ """Parse an ISO-8601 time zone designator, returning the value in seconds
+ relative to UTC."""
+ m = __tzd_rx.match(timezone)
+ if not m:
+ raise ValueError, "unknown timezone specifier: " + `timezone`
+ if m.group() != timezone:
+ raise ValueError, "unknown timezone specifier: " + `timezone`
+ return __extract_tzd(m)
+
+
+def tostring(t, timezone=0):
+ """Format a time in ISO-8601 format.
+
+ If `timezone' is specified, the time will be specified for that timezone,
+ otherwise for UTC.
+
+ Some effort is made to avoid adding text for the 'seconds' field, but
+ seconds are supported to the hundredths.
+ """
+ if type(timezone) is type(''):
+ timezone = parse_timezone(timezone)
+ else:
+ timezone = int(timezone)
+ if timezone:
+ sign = (timezone < 0) and "+" or "-"
+ timezone = abs(timezone)
+ hours = timezone / (60 * 60)
+ minutes = (timezone % (60 * 60)) / 60
+ tzspecifier = "%c%02d:%02d" % (sign, hours, minutes)
+ else:
+ tzspecifier = "Z"
+ psecs = t - int(t)
+ t = time.gmtime(int(t) - timezone)
+ year, month, day, hours, minutes, seconds = t[:6]
+ if seconds or psecs:
+ if psecs:
+ psecs = int(round(psecs * 100))
+ f = "%4d-%02d-%02dT%02d:%02d:%02d.%02d%s"
+ v = (year, month, day, hours, minutes, seconds, psecs, tzspecifier)
+ else:
+ f = "%4d-%02d-%02dT%02d:%02d:%02d%s"
+ v = (year, month, day, hours, minutes, seconds, tzspecifier)
+ else:
+ f = "%4d-%02d-%02dT%02d:%02d%s"
+ v = (year, month, day, hours, minutes, tzspecifier)
+ return f % v
+
+
+def ctime(t):
+ """Similar to time.ctime(), but using ISO-8601 format."""
+ return tostring(t, time.timezone)
+
+
+# Internal data and functions:
+
+import re
+
+__date_re = ("(?P<year>\d\d\d\d)"
+ "(?:(?P<dsep>-|)"
+ "(?:(?P<julian>\d\d\d)"
+ "|(?P<month>\d\d)(?:(?P=dsep)(?P<day>\d\d))?))?")
+__tzd_re = "(?P<tzd>[-+](?P<tzdhours>\d\d)(?::?(?P<tzdminutes>\d\d))|Z)"
+__tzd_rx = re.compile(__tzd_re)
+__time_re = ("(?P<hours>\d\d)(?P<tsep>:|)(?P<minutes>\d\d)"
+ "(?:(?P=tsep)(?P<seconds>\d\d(?:[.,]\d+)?))?"
+ + __tzd_re)
+
+__datetime_re = "%s(?:T%s)?" % (__date_re, __time_re)
+__datetime_rx = re.compile(__datetime_re)
+
+del re
+
+
+def __extract_date(m):
+ year = string.atoi(m.group("year"), 10)
+ julian = m.group("julian")
+ if julian:
+ return __find_julian(year, string.atoi(julian, 10))
+ month = m.group("month")
+ day = 1
+ if month is None:
+ month = 1
+ else:
+ month = string.atoi(month, 10)
+ if not 1 <= month <= 12:
+ raise ValueError, "illegal month number: " + m.group("month")
+ else:
+ day = m.group("day")
+ if day:
+ day = string.atoi(day)
+ if not 1 <= day <= 31:
+ raise ValueError, "illegal day number: " + m.group("day")
+ else:
+ day = 1
+ return year, month, day
+
+
+def __extract_time(m):
+ if not m:
+ return 0, 0, 0
+ hours = m.group("hours")
+ if not hours:
+ return 0, 0, 0
+ hours = string.atoi(hours, 10)
+ if not 0 <= hours <= 23:
+ raise ValueError, "illegal hour number: " + m.group("hours")
+ minutes = string.atoi(m.group("minutes"), 10)
+ if not 0 <= minutes <= 59:
+ raise ValueError, "illegal minutes number: " + m.group("minutes")
+ seconds = m.group("seconds")
+ if seconds:
+ seconds = string.atof(seconds)
+ if not 0 <= seconds <= 59:
+ raise ValueError, "illegal seconds number: " + m.group("seconds")
+ else:
+ seconds = 0
+ return hours, minutes, seconds
+
+
+def __extract_tzd(m):
+ """Return the Time Zone Designator as an offset in seconds from UTC."""
+ if not m:
+ return 0
+ tzd = m.group("tzd")
+ if not tzd:
+ return 0
+ if tzd == "Z":
+ return 0
+ hours = string.atoi(m.group("tzdhours"), 10)
+ minutes = m.group("tzdminutes")
+ if minutes:
+ minutes = string.atoi(minutes, 10)
+ else:
+ minutes = 0
+ offset = (hours*60 + minutes) * 60
+ if tzd[0] == "+":
+ return -offset
+ return offset
+
+
+def __find_julian(year, julian):
+ month = julian / 30 + 1
+ day = julian % 30 + 1
+ jday = None
+ while jday != julian:
+ t = time.mktime((year, month, day, 0, 0, 0, 0, 0, 0))
+ jday = time.gmtime(t)[-2]
+ diff = abs(jday - julian)
+ if jday > julian:
+ if diff < day:
+ day = day - diff
+ else:
+ month = month - 1
+ day = 31
+ elif jday < julian:
+ if day + diff < 28:
+ day = day + diff
+ else:
+ month = month + 1
+ return year, month, day
diff --git a/lib/jython/Lib/xml/utils/qp_xml.py b/lib/jython/Lib/xml/utils/qp_xml.py new file mode 100644 index 000000000..17b2dc22a --- /dev/null +++ b/lib/jython/Lib/xml/utils/qp_xml.py @@ -0,0 +1,242 @@ +#
+# qp_xml: Quick Parsing for XML
+#
+# Written by Greg Stein. Public Domain.
+# No Copyright, no Rights Reserved, and no Warranties.
+#
+# This module is maintained by Greg and is available as part of the XML-SIG
+# distribution. This module and its changelog can be fetched at:
+# http://www.lyra.org/cgi-bin/viewcvs.cgi/xml/xml/utils/qp_xml.py
+#
+# Additional information can be found on Greg's Python page at:
+# http://www.lyra.org/greg/python/
+#
+# This module was added to the XML-SIG distribution on February 14, 2000.
+# As part of that distribution, it falls under the XML distribution license.
+#
+
+import string
+
+try:
+ import pyexpat
+except ImportError:
+ from xml.parsers import pyexpat
+
+error = __name__ + '.error'
+
+
+#
+# The parsing class. Instantiate and pass a string/file to .parse()
+#
+class Parser:
+ def __init__(self):
+ self.reset()
+
+ def reset(self):
+ self.root = None
+ self.cur_elem = None
+
+ def find_prefix(self, prefix):
+ elem = self.cur_elem
+ while elem:
+ if elem.ns_scope.has_key(prefix):
+ return elem.ns_scope[prefix]
+ elem = elem.parent
+
+ if prefix == '':
+ return '' # empty URL for "no namespace"
+
+ return None
+
+ def process_prefix(self, name, use_default):
+ idx = string.find(name, ':')
+ if idx == -1:
+ if use_default:
+ return self.find_prefix(''), name
+ return '', name # no namespace
+
+ if string.lower(name[:3]) == 'xml':
+ return '', name # name is reserved by XML. don't break out a NS.
+
+ ns = self.find_prefix(name[:idx])
+ if ns is None:
+ raise error, 'namespace prefix not found'
+
+ return ns, name[idx+1:]
+
+ def start(self, name, attrs):
+ elem = _element(name=name, lang=None, parent=None,
+ children=[], ns_scope={}, attrs={},
+ first_cdata='', following_cdata='')
+
+ if self.cur_elem:
+ elem.parent = self.cur_elem
+ elem.parent.children.append(elem)
+ self.cur_elem = elem
+ else:
+ self.cur_elem = self.root = elem
+
+ work_attrs = [ ]
+
+ # scan for namespace declarations (and xml:lang while we're at it)
+ for name, value in attrs.items():
+ if name == 'xmlns':
+ elem.ns_scope[''] = value
+ elif name[:6] == 'xmlns:':
+ elem.ns_scope[name[6:]] = value
+ elif name == 'xml:lang':
+ elem.lang = value
+ else:
+ work_attrs.append((name, value))
+
+ # inherit xml:lang from parent
+ if elem.lang is None and elem.parent:
+ elem.lang = elem.parent.lang
+
+ # process prefix of the element name
+ elem.ns, elem.name = self.process_prefix(elem.name, 1)
+
+ # process attributes' namespace prefixes
+ for name, value in work_attrs:
+ elem.attrs[self.process_prefix(name, 0)] = value
+
+ def end(self, name):
+ parent = self.cur_elem.parent
+
+ del self.cur_elem.ns_scope
+ del self.cur_elem.parent
+
+ self.cur_elem = parent
+
+ def cdata(self, data):
+ elem = self.cur_elem
+ if elem.children:
+ last = elem.children[-1]
+ last.following_cdata = last.following_cdata + data
+ else:
+ elem.first_cdata = elem.first_cdata + data
+
+ def parse(self, input):
+ self.reset()
+
+ p = pyexpat.ParserCreate()
+ p.StartElementHandler = self.start
+ p.EndElementHandler = self.end
+ p.CharacterDataHandler = self.cdata
+
+ try:
+ if type(input) == type(''):
+ p.Parse(input, 1)
+ else:
+ while 1:
+ s = input.read(_BLOCKSIZE)
+ if not s:
+ p.Parse('', 1)
+ break
+
+ p.Parse(s, 0)
+
+ finally:
+ if self.root:
+ _clean_tree(self.root)
+
+ return self.root
+
+
+#
+# handy function for dumping a tree that is returned by Parser
+#
+def dump(f, root):
+ f.write('<?xml version="1.0"?>\n')
+ namespaces = _collect_ns(root)
+ _dump_recurse(f, root, namespaces, dump_ns=1)
+ f.write('\n')
+
+
+#
+# This function returns the element's CDATA. Note: this is not recursive --
+# it only returns the CDATA immediately within the element, excluding the
+# CDATA in child elements.
+#
+def textof(elem):
+ return elem.textof()
+
+
+#########################################################################
+#
+# private stuff for qp_xml
+#
+
+_BLOCKSIZE = 16384 # chunk size for parsing input
+
+class _element:
+ def __init__(self, **kw):
+ self.__dict__.update(kw)
+
+ def textof(self):
+ '''Return the CDATA of this element.
+
+ Note: this is not recursive -- it only returns the CDATA immediately
+ within the element, excluding the CDATA in child elements.
+ '''
+ s = self.first_cdata
+ for child in self.children:
+ s = s + child.following_cdata
+ return s
+
+ def find(self, name, ns=''):
+ for elem in self.children:
+ if elem.name == name and elem.ns == ns:
+ return elem
+ return None
+
+
+def _clean_tree(elem):
+ elem.parent = None
+ del elem.parent
+ map(_clean_tree, elem.children)
+
+
+def _collect_recurse(elem, dict):
+ dict[elem.ns] = None
+ for ns, name in elem.attrs.keys():
+ dict[ns] = None
+ for child in elem.children:
+ _collect_recurse(child, dict)
+
+def _collect_ns(elem):
+ "Collect all namespaces into a NAMESPACE -> PREFIX mapping."
+ d = { '' : None }
+ _collect_recurse(elem, d)
+ del d[''] # make sure we don't pick up no-namespace entries
+ keys = d.keys()
+ for i in range(len(keys)):
+ d[keys[i]] = i
+ return d
+
+def _dump_recurse(f, elem, namespaces, lang=None, dump_ns=0):
+ if elem.ns:
+ f.write('<ns%d:%s' % (namespaces[elem.ns], elem.name))
+ else:
+ f.write('<' + elem.name)
+ for (ns, name), value in elem.attrs.items():
+ if ns:
+ f.write(' ns%d:%s="%s"' % (namespaces[ns], name, value))
+ else:
+ f.write(' %s="%s"' % (name, value))
+ if dump_ns:
+ for ns, id in namespaces.items():
+ f.write(' xmlns:ns%d="%s"' % (id, ns))
+ if elem.lang != lang:
+ f.write(' xml:lang="%s"' % elem.lang)
+ if elem.children or elem.first_cdata:
+ f.write('>' + elem.first_cdata)
+ for child in elem.children:
+ _dump_recurse(f, child, namespaces, elem.lang)
+ f.write(child.following_cdata)
+ if elem.ns:
+ f.write('</ns%d:%s>' % (namespaces[elem.ns], elem.name))
+ else:
+ f.write('</%s>' % elem.name)
+ else:
+ f.write('/>')
diff --git a/lib/jython/Lib/xmllib.py b/lib/jython/Lib/xmllib.py new file mode 100644 index 000000000..b5e58560c --- /dev/null +++ b/lib/jython/Lib/xmllib.py @@ -0,0 +1,929 @@ +"""A parser for XML, using the derived class as static DTD."""
+
+# Author: Sjoerd Mullender.
+
+import re
+import string
+
+
+version = '0.3'
+
+class Error(RuntimeError):
+ pass
+
+# Regular expressions used for parsing
+
+_S = '[ \t\r\n]+' # white space
+_opS = '[ \t\r\n]*' # optional white space
+_Name = '[a-zA-Z_:][-a-zA-Z0-9._:]*' # valid XML name
+_QStr = "(?:'[^']*'|\"[^\"]*\")" # quoted XML string
+illegal = re.compile('[^\t\r\n -\176\240-\377]') # illegal chars in content
+interesting = re.compile('[]&<]')
+
+amp = re.compile('&')
+ref = re.compile('&(' + _Name + '|#[0-9]+|#x[0-9a-fA-F]+)[^-a-zA-Z0-9._:]')
+entityref = re.compile('&(?P<name>' + _Name + ')[^-a-zA-Z0-9._:]')
+charref = re.compile('&#(?P<char>[0-9]+[^0-9]|x[0-9a-fA-F]+[^0-9a-fA-F])')
+space = re.compile(_S + '$')
+newline = re.compile('\n')
+
+attrfind = re.compile(
+ _S + '(?P<name>' + _Name + ')'
+ '(' + _opS + '=' + _opS +
+ '(?P<value>'+_QStr+'|[-a-zA-Z0-9.:+*%?!\(\)_#=~]+))?')
+starttagopen = re.compile('<' + _Name)
+starttagend = re.compile(_opS + '(?P<slash>/?)>')
+starttagmatch = re.compile('<(?P<tagname>'+_Name+')'
+ '(?P<attrs>(?:'+attrfind.pattern+')*)'+
+ starttagend.pattern)
+endtagopen = re.compile('</')
+endbracket = re.compile(_opS + '>')
+endbracketfind = re.compile('(?:[^>\'"]|'+_QStr+')*>')
+tagfind = re.compile(_Name)
+cdataopen = re.compile(r'<!\[CDATA\[')
+cdataclose = re.compile(r'\]\]>')
+# this matches one of the following:
+# SYSTEM SystemLiteral
+# PUBLIC PubidLiteral SystemLiteral
+_SystemLiteral = '(?P<%s>'+_QStr+')'
+_PublicLiteral = '(?P<%s>"[-\'\(\)+,./:=?;!*#@$_%% \n\ra-zA-Z0-9]*"|' \
+ "'[-\(\)+,./:=?;!*#@$_%% \n\ra-zA-Z0-9]*')"
+_ExternalId = '(?:SYSTEM|' \
+ 'PUBLIC'+_S+_PublicLiteral%'pubid'+ \
+ ')'+_S+_SystemLiteral%'syslit'
+doctype = re.compile('<!DOCTYPE'+_S+'(?P<name>'+_Name+')'
+ '(?:'+_S+_ExternalId+')?'+_opS)
+xmldecl = re.compile('<\?xml'+_S+
+ 'version'+_opS+'='+_opS+'(?P<version>'+_QStr+')'+
+ '(?:'+_S+'encoding'+_opS+'='+_opS+
+ "(?P<encoding>'[A-Za-z][-A-Za-z0-9._]*'|"
+ '"[A-Za-z][-A-Za-z0-9._]*"))?'
+ '(?:'+_S+'standalone'+_opS+'='+_opS+
+ '(?P<standalone>\'(?:yes|no)\'|"(?:yes|no)"))?'+
+ _opS+'\?>')
+procopen = re.compile(r'<\?(?P<proc>' + _Name + ')' + _opS)
+procclose = re.compile(_opS + r'\?>')
+commentopen = re.compile('<!--')
+commentclose = re.compile('-->')
+doubledash = re.compile('--')
+attrtrans = string.maketrans(' \r\n\t', ' ')
+
+# definitions for XML namespaces
+_NCName = '[a-zA-Z_][-a-zA-Z0-9._]*' # XML Name, minus the ":"
+ncname = re.compile(_NCName + '$')
+qname = re.compile('(?:(?P<prefix>' + _NCName + '):)?' # optional prefix
+ '(?P<local>' + _NCName + ')$')
+
+xmlns = re.compile('xmlns(?::(?P<ncname>'+_NCName+'))?$')
+
+# XML parser base class -- find tags and call handler functions.
+# Usage: p = XMLParser(); p.feed(data); ...; p.close().
+# The dtd is defined by deriving a class which defines methods with
+# special names to handle tags: start_foo and end_foo to handle <foo>
+# and </foo>, respectively. The data between tags is passed to the
+# parser by calling self.handle_data() with some data as argument (the
+# data may be split up in arbitrary chunks).
+
+class XMLParser:
+ attributes = {} # default, to be overridden
+ elements = {} # default, to be overridden
+
+ # parsing options, settable using keyword args in __init__
+ __accept_unquoted_attributes = 0
+ __accept_missing_endtag_name = 0
+ __map_case = 0
+ __accept_utf8 = 0
+ __translate_attribute_references = 1
+
+ # Interface -- initialize and reset this instance
+ def __init__(self, **kw):
+ self.__fixed = 0
+ if kw.has_key('accept_unquoted_attributes'):
+ self.__accept_unquoted_attributes = kw['accept_unquoted_attributes']
+ if kw.has_key('accept_missing_endtag_name'):
+ self.__accept_missing_endtag_name = kw['accept_missing_endtag_name']
+ if kw.has_key('map_case'):
+ self.__map_case = kw['map_case']
+ if kw.has_key('accept_utf8'):
+ self.__accept_utf8 = kw['accept_utf8']
+ if kw.has_key('translate_attribute_references'):
+ self.__translate_attribute_references = kw['translate_attribute_references']
+ self.reset()
+
+ def __fixelements(self):
+ self.__fixed = 1
+ self.elements = {}
+ self.__fixdict(self.__dict__)
+ self.__fixclass(self.__class__)
+
+ def __fixclass(self, kl):
+ self.__fixdict(kl.__dict__)
+ for k in kl.__bases__:
+ self.__fixclass(k)
+
+ def __fixdict(self, dict):
+ for key in dict.keys():
+ if key[:6] == 'start_':
+ tag = key[6:]
+ start, end = self.elements.get(tag, (None, None))
+ if start is None:
+ self.elements[tag] = getattr(self, key), end
+ elif key[:4] == 'end_':
+ tag = key[4:]
+ start, end = self.elements.get(tag, (None, None))
+ if end is None:
+ self.elements[tag] = start, getattr(self, key)
+
+ # Interface -- reset this instance. Loses all unprocessed data
+ def reset(self):
+ self.rawdata = ''
+ self.stack = []
+ self.nomoretags = 0
+ self.literal = 0
+ self.lineno = 1
+ self.__at_start = 1
+ self.__seen_doctype = None
+ self.__seen_starttag = 0
+ self.__use_namespaces = 0
+ self.__namespaces = {'xml':None} # xml is implicitly declared
+ # backward compatibility hack: if elements not overridden,
+ # fill it in ourselves
+ if self.elements is XMLParser.elements:
+ self.__fixelements()
+
+ # For derived classes only -- enter literal mode (CDATA) till EOF
+ def setnomoretags(self):
+ self.nomoretags = self.literal = 1
+
+ # For derived classes only -- enter literal mode (CDATA)
+ def setliteral(self, *args):
+ self.literal = 1
+
+ # Interface -- feed some data to the parser. Call this as
+ # often as you want, with as little or as much text as you
+ # want (may include '\n'). (This just saves the text, all the
+ # processing is done by goahead().)
+ def feed(self, data):
+ self.rawdata = self.rawdata + data
+ self.goahead(0)
+
+ # Interface -- handle the remaining data
+ def close(self):
+ self.goahead(1)
+ if self.__fixed:
+ self.__fixed = 0
+ # remove self.elements so that we don't leak
+ del self.elements
+
+ # Interface -- translate references
+ def translate_references(self, data, all = 1):
+ if not self.__translate_attribute_references:
+ return data
+ i = 0
+ while 1:
+ res = amp.search(data, i)
+ if res is None:
+ return data
+ s = res.start(0)
+ res = ref.match(data, s)
+ if res is None:
+ self.syntax_error("bogus `&'")
+ i = s+1
+ continue
+ i = res.end(0)
+ str = res.group(1)
+ rescan = 0
+ if str[0] == '#':
+ if str[1] == 'x':
+ str = chr(int(str[2:], 16))
+ else:
+ str = chr(int(str[1:]))
+ if data[i - 1] != ';':
+ self.syntax_error("`;' missing after char reference")
+ i = i-1
+ elif all:
+ if self.entitydefs.has_key(str):
+ str = self.entitydefs[str]
+ rescan = 1
+ elif data[i - 1] != ';':
+ self.syntax_error("bogus `&'")
+ i = s + 1 # just past the &
+ continue
+ else:
+ self.syntax_error("reference to unknown entity `&%s;'" % str)
+ str = '&' + str + ';'
+ elif data[i - 1] != ';':
+ self.syntax_error("bogus `&'")
+ i = s + 1 # just past the &
+ continue
+
+ # when we get here, str contains the translated text and i points
+ # to the end of the string that is to be replaced
+ data = data[:s] + str + data[i:]
+ if rescan:
+ i = s
+ else:
+ i = s + len(str)
+
+ # Interface - return a dictionary of all namespaces currently valid
+ def getnamespace(self):
+ nsdict = {}
+ for t, d, nst in self.stack:
+ nsdict.update(d)
+ return nsdict
+
+ # Internal -- handle data as far as reasonable. May leave state
+ # and data to be processed by a subsequent call. If 'end' is
+ # true, force handling all data as if followed by EOF marker.
+ def goahead(self, end):
+ rawdata = self.rawdata
+ i = 0
+ n = len(rawdata)
+ while i < n:
+ if i > 0:
+ self.__at_start = 0
+ if self.nomoretags:
+ data = rawdata[i:n]
+ self.handle_data(data)
+ self.lineno = self.lineno + data.count('\n')
+ i = n
+ break
+ res = interesting.search(rawdata, i)
+ if res:
+ j = res.start(0)
+ else:
+ j = n
+ if i < j:
+ data = rawdata[i:j]
+ if self.__at_start and space.match(data) is None:
+ self.syntax_error('illegal data at start of file')
+ self.__at_start = 0
+ if not self.stack and space.match(data) is None:
+ self.syntax_error('data not in content')
+ if not self.__accept_utf8 and illegal.search(data):
+ self.syntax_error('illegal character in content')
+ self.handle_data(data)
+ self.lineno = self.lineno + data.count('\n')
+ i = j
+ if i == n: break
+ if rawdata[i] == '<':
+ if starttagopen.match(rawdata, i):
+ if self.literal:
+ data = rawdata[i]
+ self.handle_data(data)
+ self.lineno = self.lineno + data.count('\n')
+ i = i+1
+ continue
+ k = self.parse_starttag(i)
+ if k < 0: break
+ self.__seen_starttag = 1
+ self.lineno = self.lineno + rawdata[i:k].count('\n')
+ i = k
+ continue
+ if endtagopen.match(rawdata, i):
+ k = self.parse_endtag(i)
+ if k < 0: break
+ self.lineno = self.lineno + rawdata[i:k].count('\n')
+ i = k
+ continue
+ if commentopen.match(rawdata, i):
+ if self.literal:
+ data = rawdata[i]
+ self.handle_data(data)
+ self.lineno = self.lineno + data.count('\n')
+ i = i+1
+ continue
+ k = self.parse_comment(i)
+ if k < 0: break
+ self.lineno = self.lineno + rawdata[i:k].count('\n')
+ i = k
+ continue
+ if cdataopen.match(rawdata, i):
+ k = self.parse_cdata(i)
+ if k < 0: break
+ self.lineno = self.lineno + rawdata[i:k].count('\n')
+ i = k
+ continue
+ res = xmldecl.match(rawdata, i)
+ if res:
+ if not self.__at_start:
+ self.syntax_error("<?xml?> declaration not at start of document")
+ version, encoding, standalone = res.group('version',
+ 'encoding',
+ 'standalone')
+ if version[1:-1] != '1.0':
+ raise Error('only XML version 1.0 supported')
+ if encoding: encoding = encoding[1:-1]
+ if standalone: standalone = standalone[1:-1]
+ self.handle_xml(encoding, standalone)
+ i = res.end(0)
+ continue
+ res = procopen.match(rawdata, i)
+ if res:
+ k = self.parse_proc(i)
+ if k < 0: break
+ self.lineno = self.lineno + rawdata[i:k].count('\n')
+ i = k
+ continue
+ res = doctype.match(rawdata, i)
+ if res:
+ if self.literal:
+ data = rawdata[i]
+ self.handle_data(data)
+ self.lineno = self.lineno + data.count('\n')
+ i = i+1
+ continue
+ if self.__seen_doctype:
+ self.syntax_error('multiple DOCTYPE elements')
+ if self.__seen_starttag:
+ self.syntax_error('DOCTYPE not at beginning of document')
+ k = self.parse_doctype(res)
+ if k < 0: break
+ self.__seen_doctype = res.group('name')
+ if self.__map_case:
+ self.__seen_doctype = self.__seen_doctype.lower()
+ self.lineno = self.lineno + rawdata[i:k].count('\n')
+ i = k
+ continue
+ elif rawdata[i] == '&':
+ if self.literal:
+ data = rawdata[i]
+ self.handle_data(data)
+ i = i+1
+ continue
+ res = charref.match(rawdata, i)
+ if res is not None:
+ i = res.end(0)
+ if rawdata[i-1] != ';':
+ self.syntax_error("`;' missing in charref")
+ i = i-1
+ if not self.stack:
+ self.syntax_error('data not in content')
+ self.handle_charref(res.group('char')[:-1])
+ self.lineno = self.lineno + res.group(0).count('\n')
+ continue
+ res = entityref.match(rawdata, i)
+ if res is not None:
+ i = res.end(0)
+ if rawdata[i-1] != ';':
+ self.syntax_error("`;' missing in entityref")
+ i = i-1
+ name = res.group('name')
+ if self.__map_case:
+ name = name.lower()
+ if self.entitydefs.has_key(name):
+ self.rawdata = rawdata = rawdata[:res.start(0)] + self.entitydefs[name] + rawdata[i:]
+ n = len(rawdata)
+ i = res.start(0)
+ else:
+ self.unknown_entityref(name)
+ self.lineno = self.lineno + res.group(0).count('\n')
+ continue
+ elif rawdata[i] == ']':
+ if self.literal:
+ data = rawdata[i]
+ self.handle_data(data)
+ i = i+1
+ continue
+ if n-i < 3:
+ break
+ if cdataclose.match(rawdata, i):
+ self.syntax_error("bogus `]]>'")
+ self.handle_data(rawdata[i])
+ i = i+1
+ continue
+ else:
+ raise Error('neither < nor & ??')
+ # We get here only if incomplete matches but
+ # nothing else
+ break
+ # end while
+ if i > 0:
+ self.__at_start = 0
+ if end and i < n:
+ data = rawdata[i]
+ self.syntax_error("bogus `%s'" % data)
+ if not self.__accept_utf8 and illegal.search(data):
+ self.syntax_error('illegal character in content')
+ self.handle_data(data)
+ self.lineno = self.lineno + data.count('\n')
+ self.rawdata = rawdata[i+1:]
+ return self.goahead(end)
+ self.rawdata = rawdata[i:]
+ if end:
+ if not self.__seen_starttag:
+ self.syntax_error('no elements in file')
+ if self.stack:
+ self.syntax_error('missing end tags')
+ while self.stack:
+ self.finish_endtag(self.stack[-1][0])
+
+ # Internal -- parse comment, return length or -1 if not terminated
+ def parse_comment(self, i):
+ rawdata = self.rawdata
+ if rawdata[i:i+4] != '<!--':
+ raise Error('unexpected call to handle_comment')
+ res = commentclose.search(rawdata, i+4)
+ if res is None:
+ return -1
+ if doubledash.search(rawdata, i+4, res.start(0)):
+ self.syntax_error("`--' inside comment")
+ if rawdata[res.start(0)-1] == '-':
+ self.syntax_error('comment cannot end in three dashes')
+ if not self.__accept_utf8 and \
+ illegal.search(rawdata, i+4, res.start(0)):
+ self.syntax_error('illegal character in comment')
+ self.handle_comment(rawdata[i+4: res.start(0)])
+ return res.end(0)
+
+ # Internal -- handle DOCTYPE tag, return length or -1 if not terminated
+ def parse_doctype(self, res):
+ rawdata = self.rawdata
+ n = len(rawdata)
+ name = res.group('name')
+ if self.__map_case:
+ name = name.lower()
+ pubid, syslit = res.group('pubid', 'syslit')
+ if pubid is not None:
+ pubid = pubid[1:-1] # remove quotes
+ pubid = ' '.join(pubid.split()) # normalize
+ if syslit is not None: syslit = syslit[1:-1] # remove quotes
+ j = k = res.end(0)
+ if k >= n:
+ return -1
+ if rawdata[k] == '[':
+ level = 0
+ k = k+1
+ dq = sq = 0
+ while k < n:
+ c = rawdata[k]
+ if not sq and c == '"':
+ dq = not dq
+ elif not dq and c == "'":
+ sq = not sq
+ elif sq or dq:
+ pass
+ elif level <= 0 and c == ']':
+ res = endbracket.match(rawdata, k+1)
+ if res is None:
+ return -1
+ self.handle_doctype(name, pubid, syslit, rawdata[j+1:k])
+ return res.end(0)
+ elif c == '<':
+ level = level + 1
+ elif c == '>':
+ level = level - 1
+ if level < 0:
+ self.syntax_error("bogus `>' in DOCTYPE")
+ k = k+1
+ res = endbracketfind.match(rawdata, k)
+ if res is None:
+ return -1
+ if endbracket.match(rawdata, k) is None:
+ self.syntax_error('garbage in DOCTYPE')
+ self.handle_doctype(name, pubid, syslit, None)
+ return res.end(0)
+
+ # Internal -- handle CDATA tag, return length or -1 if not terminated
+ def parse_cdata(self, i):
+ rawdata = self.rawdata
+ if rawdata[i:i+9] != '<![CDATA[':
+ raise Error('unexpected call to parse_cdata')
+ res = cdataclose.search(rawdata, i+9)
+ if res is None:
+ return -1
+ if not self.__accept_utf8 and \
+ illegal.search(rawdata, i+9, res.start(0)):
+ self.syntax_error('illegal character in CDATA')
+ if not self.stack:
+ self.syntax_error('CDATA not in content')
+ self.handle_cdata(rawdata[i+9:res.start(0)])
+ return res.end(0)
+
+ __xml_namespace_attributes = {'ns':None, 'src':None, 'prefix':None}
+ # Internal -- handle a processing instruction tag
+ def parse_proc(self, i):
+ rawdata = self.rawdata
+ end = procclose.search(rawdata, i)
+ if end is None:
+ return -1
+ j = end.start(0)
+ if not self.__accept_utf8 and illegal.search(rawdata, i+2, j):
+ self.syntax_error('illegal character in processing instruction')
+ res = tagfind.match(rawdata, i+2)
+ if res is None:
+ raise Error('unexpected call to parse_proc')
+ k = res.end(0)
+ name = res.group(0)
+ if self.__map_case:
+ name = name.lower()
+ if name == 'xml:namespace':
+ self.syntax_error('old-fashioned namespace declaration')
+ self.__use_namespaces = -1
+ # namespace declaration
+ # this must come after the <?xml?> declaration (if any)
+ # and before the <!DOCTYPE> (if any).
+ if self.__seen_doctype or self.__seen_starttag:
+ self.syntax_error('xml:namespace declaration too late in document')
+ attrdict, namespace, k = self.parse_attributes(name, k, j)
+ if namespace:
+ self.syntax_error('namespace declaration inside namespace declaration')
+ for attrname in attrdict.keys():
+ if not self.__xml_namespace_attributes.has_key(attrname):
+ self.syntax_error("unknown attribute `%s' in xml:namespace tag" % attrname)
+ if not attrdict.has_key('ns') or not attrdict.has_key('prefix'):
+ self.syntax_error('xml:namespace without required attributes')
+ prefix = attrdict.get('prefix')
+ if ncname.match(prefix) is None:
+ self.syntax_error('xml:namespace illegal prefix value')
+ return end.end(0)
+ if self.__namespaces.has_key(prefix):
+ self.syntax_error('xml:namespace prefix not unique')
+ self.__namespaces[prefix] = attrdict['ns']
+ else:
+ if name.lower() == 'xml':
+ self.syntax_error('illegal processing instruction target name')
+ self.handle_proc(name, rawdata[k:j])
+ return end.end(0)
+
+ # Internal -- parse attributes between i and j
+ def parse_attributes(self, tag, i, j):
+ rawdata = self.rawdata
+ attrdict = {}
+ namespace = {}
+ while i < j:
+ res = attrfind.match(rawdata, i)
+ if res is None:
+ break
+ attrname, attrvalue = res.group('name', 'value')
+ if self.__map_case:
+ attrname = attrname.lower()
+ i = res.end(0)
+ if attrvalue is None:
+ self.syntax_error("no value specified for attribute `%s'" % attrname)
+ attrvalue = attrname
+ elif attrvalue[:1] == "'" == attrvalue[-1:] or \
+ attrvalue[:1] == '"' == attrvalue[-1:]:
+ attrvalue = attrvalue[1:-1]
+ elif not self.__accept_unquoted_attributes:
+ self.syntax_error("attribute `%s' value not quoted" % attrname)
+ res = xmlns.match(attrname)
+ if res is not None:
+ # namespace declaration
+ ncname = res.group('ncname')
+ namespace[ncname or ''] = attrvalue or None
+ if not self.__use_namespaces:
+ self.__use_namespaces = len(self.stack)+1
+ continue
+ if '<' in attrvalue:
+ self.syntax_error("`<' illegal in attribute value")
+ if attrdict.has_key(attrname):
+ self.syntax_error("attribute `%s' specified twice" % attrname)
+ attrvalue = attrvalue.translate(attrtrans)
+ attrdict[attrname] = self.translate_references(attrvalue)
+ return attrdict, namespace, i
+
+ # Internal -- handle starttag, return length or -1 if not terminated
+ def parse_starttag(self, i):
+ rawdata = self.rawdata
+ # i points to start of tag
+ end = endbracketfind.match(rawdata, i+1)
+ if end is None:
+ return -1
+ tag = starttagmatch.match(rawdata, i)
+ if tag is None or tag.end(0) != end.end(0):
+ self.syntax_error('garbage in starttag')
+ return end.end(0)
+ nstag = tagname = tag.group('tagname')
+ if self.__map_case:
+ nstag = tagname = nstag.lower()
+ if not self.__seen_starttag and self.__seen_doctype and \
+ tagname != self.__seen_doctype:
+ self.syntax_error('starttag does not match DOCTYPE')
+ if self.__seen_starttag and not self.stack:
+ self.syntax_error('multiple elements on top level')
+ k, j = tag.span('attrs')
+ attrdict, nsdict, k = self.parse_attributes(tagname, k, j)
+ self.stack.append((tagname, nsdict, nstag))
+ if self.__use_namespaces:
+ res = qname.match(tagname)
+ else:
+ res = None
+ if res is not None:
+ prefix, nstag = res.group('prefix', 'local')
+ if prefix is None:
+ prefix = ''
+ ns = None
+ for t, d, nst in self.stack:
+ if d.has_key(prefix):
+ ns = d[prefix]
+ if ns is None and prefix != '':
+ ns = self.__namespaces.get(prefix)
+ if ns is not None:
+ nstag = ns + ' ' + nstag
+ elif prefix != '':
+ nstag = prefix + ':' + nstag # undo split
+ self.stack[-1] = tagname, nsdict, nstag
+ # translate namespace of attributes
+ attrnamemap = {} # map from new name to old name (used for error reporting)
+ for key in attrdict.keys():
+ attrnamemap[key] = key
+ if self.__use_namespaces:
+ nattrdict = {}
+ for key, val in attrdict.items():
+ okey = key
+ res = qname.match(key)
+ if res is not None:
+ aprefix, key = res.group('prefix', 'local')
+ if self.__map_case:
+ key = key.lower()
+ if aprefix is None:
+ aprefix = ''
+ ans = None
+ for t, d, nst in self.stack:
+ if d.has_key(aprefix):
+ ans = d[aprefix]
+ if ans is None and aprefix != '':
+ ans = self.__namespaces.get(aprefix)
+ if ans is not None:
+ key = ans + ' ' + key
+ elif aprefix != '':
+ key = aprefix + ':' + key
+ elif ns is not None:
+ key = ns + ' ' + key
+ nattrdict[key] = val
+ attrnamemap[key] = okey
+ attrdict = nattrdict
+ attributes = self.attributes.get(nstag)
+ if attributes is not None:
+ for key in attrdict.keys():
+ if not attributes.has_key(key):
+ self.syntax_error("unknown attribute `%s' in tag `%s'" % (attrnamemap[key], tagname))
+ for key, val in attributes.items():
+ if val is not None and not attrdict.has_key(key):
+ attrdict[key] = val
+ method = self.elements.get(nstag, (None, None))[0]
+ self.finish_starttag(nstag, attrdict, method)
+ if tag.group('slash') == '/':
+ self.finish_endtag(tagname)
+ return tag.end(0)
+
+ # Internal -- parse endtag
+ def parse_endtag(self, i):
+ rawdata = self.rawdata
+ end = endbracketfind.match(rawdata, i+1)
+ if end is None:
+ return -1
+ res = tagfind.match(rawdata, i+2)
+ if res is None:
+ if self.literal:
+ self.handle_data(rawdata[i])
+ return i+1
+ if not self.__accept_missing_endtag_name:
+ self.syntax_error('no name specified in end tag')
+ tag = self.stack[-1][0]
+ k = i+2
+ else:
+ tag = res.group(0)
+ if self.__map_case:
+ tag = tag.lower()
+ if self.literal:
+ if not self.stack or tag != self.stack[-1][0]:
+ self.handle_data(rawdata[i])
+ return i+1
+ k = res.end(0)
+ if endbracket.match(rawdata, k) is None:
+ self.syntax_error('garbage in end tag')
+ self.finish_endtag(tag)
+ return end.end(0)
+
+ # Internal -- finish processing of start tag
+ def finish_starttag(self, tagname, attrdict, method):
+ if method is not None:
+ self.handle_starttag(tagname, method, attrdict)
+ else:
+ self.unknown_starttag(tagname, attrdict)
+
+ # Internal -- finish processing of end tag
+ def finish_endtag(self, tag):
+ self.literal = 0
+ if not tag:
+ self.syntax_error('name-less end tag')
+ found = len(self.stack) - 1
+ if found < 0:
+ self.unknown_endtag(tag)
+ return
+ else:
+ found = -1
+ for i in range(len(self.stack)):
+ if tag == self.stack[i][0]:
+ found = i
+ if found == -1:
+ self.syntax_error('unopened end tag')
+ return
+ while len(self.stack) > found:
+ if found < len(self.stack) - 1:
+ self.syntax_error('missing close tag for %s' % self.stack[-1][2])
+ nstag = self.stack[-1][2]
+ method = self.elements.get(nstag, (None, None))[1]
+ if method is not None:
+ self.handle_endtag(nstag, method)
+ else:
+ self.unknown_endtag(nstag)
+ if self.__use_namespaces == len(self.stack):
+ self.__use_namespaces = 0
+ del self.stack[-1]
+
+ # Overridable -- handle xml processing instruction
+ def handle_xml(self, encoding, standalone):
+ pass
+
+ # Overridable -- handle DOCTYPE
+ def handle_doctype(self, tag, pubid, syslit, data):
+ pass
+
+ # Overridable -- handle start tag
+ def handle_starttag(self, tag, method, attrs):
+ method(attrs)
+
+ # Overridable -- handle end tag
+ def handle_endtag(self, tag, method):
+ method()
+
+ # Example -- handle character reference, no need to override
+ def handle_charref(self, name):
+ try:
+ if name[0] == 'x':
+ n = int(name[1:], 16)
+ else:
+ n = int(name)
+ except ValueError:
+ self.unknown_charref(name)
+ return
+ if not 0 <= n <= 255:
+ self.unknown_charref(name)
+ return
+ self.handle_data(chr(n))
+
+ # Definition of entities -- derived classes may override
+ entitydefs = {'lt': '<', # must use charref
+ 'gt': '>',
+ 'amp': '&', # must use charref
+ 'quot': '"',
+ 'apos': ''',
+ }
+
+ # Example -- handle data, should be overridden
+ def handle_data(self, data):
+ pass
+
+ # Example -- handle cdata, could be overridden
+ def handle_cdata(self, data):
+ pass
+
+ # Example -- handle comment, could be overridden
+ def handle_comment(self, data):
+ pass
+
+ # Example -- handle processing instructions, could be overridden
+ def handle_proc(self, name, data):
+ pass
+
+ # Example -- handle relatively harmless syntax errors, could be overridden
+ def syntax_error(self, message):
+ raise Error('Syntax error at line %d: %s' % (self.lineno, message))
+
+ # To be overridden -- handlers for unknown objects
+ def unknown_starttag(self, tag, attrs): pass
+ def unknown_endtag(self, tag): pass
+ def unknown_charref(self, ref): pass
+ def unknown_entityref(self, name):
+ self.syntax_error("reference to unknown entity `&%s;'" % name)
+
+
+class TestXMLParser(XMLParser):
+
+ def __init__(self, **kw):
+ self.testdata = ""
+ apply(XMLParser.__init__, (self,), kw)
+
+ def handle_xml(self, encoding, standalone):
+ self.flush()
+ print 'xml: encoding =',encoding,'standalone =',standalone
+
+ def handle_doctype(self, tag, pubid, syslit, data):
+ self.flush()
+ print 'DOCTYPE:',tag, `data`
+
+ def handle_data(self, data):
+ self.testdata = self.testdata + data
+ if len(`self.testdata`) >= 70:
+ self.flush()
+
+ def flush(self):
+ data = self.testdata
+ if data:
+ self.testdata = ""
+ print 'data:', `data`
+
+ def handle_cdata(self, data):
+ self.flush()
+ print 'cdata:', `data`
+
+ def handle_proc(self, name, data):
+ self.flush()
+ print 'processing:',name,`data`
+
+ def handle_comment(self, data):
+ self.flush()
+ r = `data`
+ if len(r) > 68:
+ r = r[:32] + '...' + r[-32:]
+ print 'comment:', r
+
+ def syntax_error(self, message):
+ print 'error at line %d:' % self.lineno, message
+
+ def unknown_starttag(self, tag, attrs):
+ self.flush()
+ if not attrs:
+ print 'start tag: <' + tag + '>'
+ else:
+ print 'start tag: <' + tag,
+ for name, value in attrs.items():
+ print name + '=' + '"' + value + '"',
+ print '>'
+
+ def unknown_endtag(self, tag):
+ self.flush()
+ print 'end tag: </' + tag + '>'
+
+ def unknown_entityref(self, ref):
+ self.flush()
+ print '*** unknown entity ref: &' + ref + ';'
+
+ def unknown_charref(self, ref):
+ self.flush()
+ print '*** unknown char ref: &#' + ref + ';'
+
+ def close(self):
+ XMLParser.close(self)
+ self.flush()
+
+def test(args = None):
+ import sys, getopt
+ from time import time
+
+ if not args:
+ args = sys.argv[1:]
+
+ opts, args = getopt.getopt(args, 'st')
+ klass = TestXMLParser
+ do_time = 0
+ for o, a in opts:
+ if o == '-s':
+ klass = XMLParser
+ elif o == '-t':
+ do_time = 1
+
+ if args:
+ file = args[0]
+ else:
+ file = 'test.xml'
+
+ if file == '-':
+ f = sys.stdin
+ else:
+ try:
+ f = open(file, 'r')
+ except IOError, msg:
+ print file, ":", msg
+ sys.exit(1)
+
+ data = f.read()
+ if f is not sys.stdin:
+ f.close()
+
+ x = klass()
+ t0 = time()
+ try:
+ if do_time:
+ x.feed(data)
+ x.close()
+ else:
+ for c in data:
+ x.feed(c)
+ x.close()
+ except Error, msg:
+ t1 = time()
+ print msg
+ if do_time:
+ print 'total time: %g' % (t1-t0)
+ sys.exit(1)
+ t1 = time()
+ if do_time:
+ print 'total time: %g' % (t1-t0)
+
+
+if __name__ == '__main__':
+ test()
diff --git a/lib/jython/Lib/zipfile.py b/lib/jython/Lib/zipfile.py new file mode 100644 index 000000000..9759b1f17 --- /dev/null +++ b/lib/jython/Lib/zipfile.py @@ -0,0 +1,574 @@ +"Read and write ZIP files."
+# Written by James C. Ahlstrom jim@interet.com
+# All rights transferred to CNRI pursuant to the Python contribution agreement
+
+import struct, os, time
+import binascii
+
+try:
+ import zlib # We may need its compression method
+except ImportError:
+ zlib = None
+
+__all__ = ["BadZipfile", "error", "ZIP_STORED", "ZIP_DEFLATED", "is_zipfile",
+ "ZipInfo", "ZipFile", "PyZipFile"]
+
+class BadZipfile(Exception):
+ pass
+error = BadZipfile # The exception raised by this module
+
+# constants for Zip file compression methods
+ZIP_STORED = 0
+ZIP_DEFLATED = 8
+# Other ZIP compression methods not supported
+
+# Here are some struct module formats for reading headers
+structEndArchive = "<4s4H2lH" # 9 items, end of archive, 22 bytes
+stringEndArchive = "PK\005\006" # magic number for end of archive record
+structCentralDir = "<4s4B4H3l5H2l"# 19 items, central directory, 46 bytes
+stringCentralDir = "PK\001\002" # magic number for central directory
+structFileHeader = "<4s2B4H3l2H" # 12 items, file header record, 30 bytes
+stringFileHeader = "PK\003\004" # magic number for file header
+
+# indexes of entries in the central directory structure
+_CD_SIGNATURE = 0
+_CD_CREATE_VERSION = 1
+_CD_CREATE_SYSTEM = 2
+_CD_EXTRACT_VERSION = 3
+_CD_EXTRACT_SYSTEM = 4 # is this meaningful?
+_CD_FLAG_BITS = 5
+_CD_COMPRESS_TYPE = 6
+_CD_TIME = 7
+_CD_DATE = 8
+_CD_CRC = 9
+_CD_COMPRESSED_SIZE = 10
+_CD_UNCOMPRESSED_SIZE = 11
+_CD_FILENAME_LENGTH = 12
+_CD_EXTRA_FIELD_LENGTH = 13
+_CD_COMMENT_LENGTH = 14
+_CD_DISK_NUMBER_START = 15
+_CD_INTERNAL_FILE_ATTRIBUTES = 16
+_CD_EXTERNAL_FILE_ATTRIBUTES = 17
+_CD_LOCAL_HEADER_OFFSET = 18
+
+# indexes of entries in the local file header structure
+_FH_SIGNATURE = 0
+_FH_EXTRACT_VERSION = 1
+_FH_EXTRACT_SYSTEM = 2 # is this meaningful?
+_FH_GENERAL_PURPOSE_FLAG_BITS = 3
+_FH_COMPRESSION_METHOD = 4
+_FH_LAST_MOD_TIME = 5
+_FH_LAST_MOD_DATE = 6
+_FH_CRC = 7
+_FH_COMPRESSED_SIZE = 8
+_FH_UNCOMPRESSED_SIZE = 9
+_FH_FILENAME_LENGTH = 10
+_FH_EXTRA_FIELD_LENGTH = 11
+
+# Used to compare file passed to ZipFile
+_STRING_TYPES = (type('s'), type(u's'))
+
+
+def is_zipfile(filename):
+ """Quickly see if file is a ZIP file by checking the magic number.
+
+ Will not accept a ZIP archive with an ending comment.
+ """
+ try:
+ fpin = open(filename, "rb")
+ fpin.seek(-22, 2) # Seek to end-of-file record
+ endrec = fpin.read()
+ fpin.close()
+ if endrec[0:4] == "PK\005\006" and endrec[-2:] == "\000\000":
+ return 1 # file has correct magic number
+ except:
+ pass
+
+
+class ZipInfo:
+ """Class with attributes describing each file in the ZIP archive."""
+
+ def __init__(self, filename="NoName", date_time=(1980,1,1,0,0,0)):
+ self.filename = filename # Name of the file in the archive
+ self.date_time = date_time # year, month, day, hour, min, sec
+ # Standard values:
+ self.compress_type = ZIP_STORED # Type of compression for the file
+ self.comment = "" # Comment for each file
+ self.extra = "" # ZIP extra data
+ self.create_system = 0 # System which created ZIP archive
+ self.create_version = 20 # Version which created ZIP archive
+ self.extract_version = 20 # Version needed to extract archive
+ self.reserved = 0 # Must be zero
+ self.flag_bits = 0 # ZIP flag bits
+ self.volume = 0 # Volume number of file header
+ self.internal_attr = 0 # Internal attributes
+ self.external_attr = 0 # External file attributes
+ # Other attributes are set by class ZipFile:
+ # header_offset Byte offset to the file header
+ # file_offset Byte offset to the start of the file data
+ # CRC CRC-32 of the uncompressed file
+ # compress_size Size of the compressed file
+ # file_size Size of the uncompressed file
+
+ def FileHeader(self):
+ """Return the per-file header as a string."""
+ dt = self.date_time
+ dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2]
+ dostime = dt[3] << 11 | dt[4] << 5 | dt[5] / 2
+ if self.flag_bits & 0x08:
+ # Set these to zero because we write them after the file data
+ CRC = compress_size = file_size = 0
+ else:
+ CRC = self.CRC
+ compress_size = self.compress_size
+ file_size = self.file_size
+ header = struct.pack(structFileHeader, stringFileHeader,
+ self.extract_version, self.reserved, self.flag_bits,
+ self.compress_type, dostime, dosdate, CRC,
+ compress_size, file_size,
+ len(self.filename), len(self.extra))
+ return header + self.filename + self.extra
+
+
+class ZipFile:
+ """ Class with methods to open, read, write, close, list zip files.
+
+ z = ZipFile(file, mode="r", compression=ZIP_STORED)
+
+ file: Either the path to the file, or a file-like object.
+ If it is a path, the file will be opened and closed by ZipFile.
+ mode: The mode can be either read "r", write "w" or append "a".
+ compression: ZIP_STORED (no compression) or ZIP_DEFLATED (requires zlib).
+ """
+
+ fp = None # Set here since __del__ checks it
+
+ def __init__(self, file, mode="r", compression=ZIP_STORED):
+ """Open the ZIP file with mode read "r", write "w" or append "a"."""
+ if compression == ZIP_STORED:
+ pass
+ elif compression == ZIP_DEFLATED:
+ if not zlib:
+ raise RuntimeError,\
+ "Compression requires the (missing) zlib module"
+ else:
+ raise RuntimeError, "That compression method is not supported"
+ self.debug = 0 # Level of printing: 0 through 3
+ self.NameToInfo = {} # Find file info given name
+ self.filelist = [] # List of ZipInfo instances for archive
+ self.compression = compression # Method of compression
+ self.mode = key = mode[0]
+
+ # Check if we were passed a file-like object
+ if type(file) in _STRING_TYPES:
+ self._filePassed = 0
+ self.filename = file
+ modeDict = {'r' : 'rb', 'w': 'wb', 'a' : 'r+b'}
+ self.fp = open(file, modeDict[mode])
+ else:
+ self._filePassed = 1
+ self.fp = file
+ self.filename = getattr(file, 'name', None)
+
+ if key == 'r':
+ self._GetContents()
+ elif key == 'w':
+ pass
+ elif key == 'a':
+ fp = self.fp
+ fp.seek(-22, 2) # Seek to end-of-file record
+ endrec = fp.read()
+ if endrec[0:4] == stringEndArchive and \
+ endrec[-2:] == "\000\000":
+ self._GetContents() # file is a zip file
+ # seek to start of directory and overwrite
+ fp.seek(self.start_dir, 0)
+ else: # file is not a zip file, just append
+ fp.seek(0, 2)
+ else:
+ if not self._filePassed:
+ self.fp.close()
+ self.fp = None
+ raise RuntimeError, 'Mode must be "r", "w" or "a"'
+
+ def _GetContents(self):
+ """Read the directory, making sure we close the file if the format
+ is bad."""
+ try:
+ self._RealGetContents()
+ except BadZipfile:
+ if not self._filePassed:
+ self.fp.close()
+ self.fp = None
+ raise
+
+ def _RealGetContents(self):
+ """Read in the table of contents for the ZIP file."""
+ fp = self.fp
+ fp.seek(-22, 2) # Start of end-of-archive record
+ filesize = fp.tell() + 22 # Get file size
+ endrec = fp.read(22) # Archive must not end with a comment!
+ if endrec[0:4] != stringEndArchive or endrec[-2:] != "\000\000":
+ raise BadZipfile, "File is not a zip file, or ends with a comment"
+ endrec = struct.unpack(structEndArchive, endrec)
+ if self.debug > 1:
+ print endrec
+ size_cd = endrec[5] # bytes in central directory
+ offset_cd = endrec[6] # offset of central directory
+ x = filesize - 22 - size_cd
+ # "concat" is zero, unless zip was concatenated to another file
+ concat = x - offset_cd
+ if self.debug > 2:
+ print "given, inferred, offset", offset_cd, x, concat
+ # self.start_dir: Position of start of central directory
+ self.start_dir = offset_cd + concat
+ fp.seek(self.start_dir, 0)
+ total = 0
+ while total < size_cd:
+ centdir = fp.read(46)
+ total = total + 46
+ if centdir[0:4] != stringCentralDir:
+ raise BadZipfile, "Bad magic number for central directory"
+ centdir = struct.unpack(structCentralDir, centdir)
+ if self.debug > 2:
+ print centdir
+ filename = fp.read(centdir[_CD_FILENAME_LENGTH])
+ # Create ZipInfo instance to store file information
+ x = ZipInfo(filename)
+ x.extra = fp.read(centdir[_CD_EXTRA_FIELD_LENGTH])
+ x.comment = fp.read(centdir[_CD_COMMENT_LENGTH])
+ total = (total + centdir[_CD_FILENAME_LENGTH]
+ + centdir[_CD_EXTRA_FIELD_LENGTH]
+ + centdir[_CD_COMMENT_LENGTH])
+ x.header_offset = centdir[_CD_LOCAL_HEADER_OFFSET] + concat
+ # file_offset must be computed below...
+ (x.create_version, x.create_system, x.extract_version, x.reserved,
+ x.flag_bits, x.compress_type, t, d,
+ x.CRC, x.compress_size, x.file_size) = centdir[1:12]
+ x.volume, x.internal_attr, x.external_attr = centdir[15:18]
+ # Convert date/time code to (year, month, day, hour, min, sec)
+ x.date_time = ( (d>>9)+1980, (d>>5)&0xF, d&0x1F,
+ t>>11, (t>>5)&0x3F, (t&0x1F) * 2 )
+ self.filelist.append(x)
+ self.NameToInfo[x.filename] = x
+ if self.debug > 2:
+ print "total", total
+ for data in self.filelist:
+ fp.seek(data.header_offset, 0)
+ fheader = fp.read(30)
+ if fheader[0:4] != stringFileHeader:
+ raise BadZipfile, "Bad magic number for file header"
+ fheader = struct.unpack(structFileHeader, fheader)
+ # file_offset is computed here, since the extra field for
+ # the central directory and for the local file header
+ # refer to different fields, and they can have different
+ # lengths
+ data.file_offset = (data.header_offset + 30
+ + fheader[_FH_FILENAME_LENGTH]
+ + fheader[_FH_EXTRA_FIELD_LENGTH])
+ fname = fp.read(fheader[_FH_FILENAME_LENGTH])
+ if fname != data.filename:
+ raise RuntimeError, \
+ 'File name in directory "%s" and header "%s" differ.' % (
+ data.filename, fname)
+
+ def namelist(self):
+ """Return a list of file names in the archive."""
+ l = []
+ for data in self.filelist:
+ l.append(data.filename)
+ return l
+
+ def infolist(self):
+ """Return a list of class ZipInfo instances for files in the
+ archive."""
+ return self.filelist
+
+ def printdir(self):
+ """Print a table of contents for the zip file."""
+ print "%-46s %19s %12s" % ("File Name", "Modified ", "Size")
+ for zinfo in self.filelist:
+ date = "%d-%02d-%02d %02d:%02d:%02d" % zinfo.date_time
+ print "%-46s %s %12d" % (zinfo.filename, date, zinfo.file_size)
+
+ def testzip(self):
+ """Read all the files and check the CRC."""
+ for zinfo in self.filelist:
+ try:
+ self.read(zinfo.filename) # Check CRC-32
+ except:
+ return zinfo.filename
+
+ def getinfo(self, name):
+ """Return the instance of ZipInfo given 'name'."""
+ return self.NameToInfo[name]
+
+ def read(self, name):
+ """Return file bytes (as a string) for name."""
+ if self.mode not in ("r", "a"):
+ raise RuntimeError, 'read() requires mode "r" or "a"'
+ if not self.fp:
+ raise RuntimeError, \
+ "Attempt to read ZIP archive that was already closed"
+ zinfo = self.getinfo(name)
+ filepos = self.fp.tell()
+ self.fp.seek(zinfo.file_offset, 0)
+ bytes = self.fp.read(zinfo.compress_size)
+ self.fp.seek(filepos, 0)
+ if zinfo.compress_type == ZIP_STORED:
+ pass
+ elif zinfo.compress_type == ZIP_DEFLATED:
+ if not zlib:
+ raise RuntimeError, \
+ "De-compression requires the (missing) zlib module"
+ # zlib compress/decompress code by Jeremy Hylton of CNRI
+ dc = zlib.decompressobj(-15)
+ bytes = dc.decompress(bytes)
+ # need to feed in unused pad byte so that zlib won't choke
+ ex = dc.decompress('Z') + dc.flush()
+ if ex:
+ bytes = bytes + ex
+ else:
+ raise BadZipfile, \
+ "Unsupported compression method %d for file %s" % \
+ (zinfo.compress_type, name)
+ crc = binascii.crc32(bytes)
+ if crc != zinfo.CRC:
+ raise BadZipfile, "Bad CRC-32 for file %s" % name
+ return bytes
+
+ def _writecheck(self, zinfo):
+ """Check for errors before writing a file to the archive."""
+ if self.NameToInfo.has_key(zinfo.filename):
+ if self.debug: # Warning for duplicate names
+ print "Duplicate name:", zinfo.filename
+ if self.mode not in ("w", "a"):
+ raise RuntimeError, 'write() requires mode "w" or "a"'
+ if not self.fp:
+ raise RuntimeError, \
+ "Attempt to write ZIP archive that was already closed"
+ if zinfo.compress_type == ZIP_DEFLATED and not zlib:
+ raise RuntimeError, \
+ "Compression requires the (missing) zlib module"
+ if zinfo.compress_type not in (ZIP_STORED, ZIP_DEFLATED):
+ raise RuntimeError, \
+ "That compression method is not supported"
+
+ def write(self, filename, arcname=None, compress_type=None):
+ """Put the bytes from filename into the archive under the name
+ arcname."""
+ st = os.stat(filename)
+ mtime = time.localtime(st[8])
+ date_time = mtime[0:6]
+ # Create ZipInfo instance to store file information
+ if arcname is None:
+ zinfo = ZipInfo(filename, date_time)
+ else:
+ zinfo = ZipInfo(arcname, date_time)
+ zinfo.external_attr = st[0] << 16 # Unix attributes
+ if compress_type is None:
+ zinfo.compress_type = self.compression
+ else:
+ zinfo.compress_type = compress_type
+ self._writecheck(zinfo)
+ fp = open(filename, "rb")
+ zinfo.flag_bits = 0x00
+ zinfo.header_offset = self.fp.tell() # Start of header bytes
+ # Must overwrite CRC and sizes with correct data later
+ zinfo.CRC = CRC = 0
+ zinfo.compress_size = compress_size = 0
+ zinfo.file_size = file_size = 0
+ self.fp.write(zinfo.FileHeader())
+ zinfo.file_offset = self.fp.tell() # Start of file bytes
+ if zinfo.compress_type == ZIP_DEFLATED:
+ cmpr = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,
+ zlib.DEFLATED, -15)
+ else:
+ cmpr = None
+ while 1:
+ buf = fp.read(1024 * 8)
+ if not buf:
+ break
+ file_size = file_size + len(buf)
+ CRC = binascii.crc32(buf, CRC)
+ if cmpr:
+ buf = cmpr.compress(buf)
+ compress_size = compress_size + len(buf)
+ self.fp.write(buf)
+ fp.close()
+ if cmpr:
+ buf = cmpr.flush()
+ compress_size = compress_size + len(buf)
+ self.fp.write(buf)
+ zinfo.compress_size = compress_size
+ else:
+ zinfo.compress_size = file_size
+ zinfo.CRC = CRC
+ zinfo.file_size = file_size
+ # Seek backwards and write CRC and file sizes
+ position = self.fp.tell() # Preserve current position in file
+ self.fp.seek(zinfo.header_offset + 14, 0)
+ self.fp.write(struct.pack("<lll", zinfo.CRC, zinfo.compress_size,
+ zinfo.file_size))
+ self.fp.seek(position, 0)
+ self.filelist.append(zinfo)
+ self.NameToInfo[zinfo.filename] = zinfo
+
+ def writestr(self, zinfo, bytes):
+ """Write a file into the archive. The contents is the string
+ 'bytes'."""
+ self._writecheck(zinfo)
+ zinfo.file_size = len(bytes) # Uncompressed size
+ zinfo.CRC = binascii.crc32(bytes) # CRC-32 checksum
+ if zinfo.compress_type == ZIP_DEFLATED:
+ co = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,
+ zlib.DEFLATED, -15)
+ bytes = co.compress(bytes) + co.flush()
+ zinfo.compress_size = len(bytes) # Compressed size
+ else:
+ zinfo.compress_size = zinfo.file_size
+ zinfo.header_offset = self.fp.tell() # Start of header bytes
+ self.fp.write(zinfo.FileHeader())
+ zinfo.file_offset = self.fp.tell() # Start of file bytes
+ self.fp.write(bytes)
+ if zinfo.flag_bits & 0x08:
+ # Write CRC and file sizes after the file data
+ self.fp.write(struct.pack("<lll", zinfo.CRC, zinfo.compress_size,
+ zinfo.file_size))
+ self.filelist.append(zinfo)
+ self.NameToInfo[zinfo.filename] = zinfo
+
+ def __del__(self):
+ """Call the "close()" method in case the user forgot."""
+ if self.fp and not self._filePassed:
+ self.fp.close()
+ self.fp = None
+
+ def close(self):
+ """Close the file, and for mode "w" and "a" write the ending
+ records."""
+ if self.mode in ("w", "a"): # write ending records
+ count = 0
+ pos1 = self.fp.tell()
+ for zinfo in self.filelist: # write central directory
+ count = count + 1
+ dt = zinfo.date_time
+ dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2]
+ dostime = dt[3] << 11 | dt[4] << 5 | dt[5] / 2
+ centdir = struct.pack(structCentralDir,
+ stringCentralDir, zinfo.create_version,
+ zinfo.create_system, zinfo.extract_version, zinfo.reserved,
+ zinfo.flag_bits, zinfo.compress_type, dostime, dosdate,
+ zinfo.CRC, zinfo.compress_size, zinfo.file_size,
+ len(zinfo.filename), len(zinfo.extra), len(zinfo.comment),
+ 0, zinfo.internal_attr, zinfo.external_attr,
+ zinfo.header_offset)
+ self.fp.write(centdir)
+ self.fp.write(zinfo.filename)
+ self.fp.write(zinfo.extra)
+ self.fp.write(zinfo.comment)
+ pos2 = self.fp.tell()
+ # Write end-of-zip-archive record
+ endrec = struct.pack(structEndArchive, stringEndArchive,
+ 0, 0, count, count, pos2 - pos1, pos1, 0)
+ self.fp.write(endrec)
+ self.fp.flush()
+ if not self._filePassed:
+ self.fp.close()
+ self.fp = None
+
+
+class PyZipFile(ZipFile):
+ """Class to create ZIP archives with Python library files and packages."""
+
+ def writepy(self, pathname, basename = ""):
+ """Add all files from "pathname" to the ZIP archive.
+
+ If pathname is a package directory, search the directory and
+ all package subdirectories recursively for all *.py and enter
+ the modules into the archive. If pathname is a plain
+ directory, listdir *.py and enter all modules. Else, pathname
+ must be a Python *.py file and the module will be put into the
+ archive. Added modules are always module.pyo or module.pyc.
+ This method will compile the module.py into module.pyc if
+ necessary.
+ """
+ dir, name = os.path.split(pathname)
+ if os.path.isdir(pathname):
+ initname = os.path.join(pathname, "__init__.py")
+ if os.path.isfile(initname):
+ # This is a package directory, add it
+ if basename:
+ basename = "%s/%s" % (basename, name)
+ else:
+ basename = name
+ if self.debug:
+ print "Adding package in", pathname, "as", basename
+ fname, arcname = self._get_codename(initname[0:-3], basename)
+ if self.debug:
+ print "Adding", arcname
+ self.write(fname, arcname)
+ dirlist = os.listdir(pathname)
+ dirlist.remove("__init__.py")
+ # Add all *.py files and package subdirectories
+ for filename in dirlist:
+ path = os.path.join(pathname, filename)
+ root, ext = os.path.splitext(filename)
+ if os.path.isdir(path):
+ if os.path.isfile(os.path.join(path, "__init__.py")):
+ # This is a package directory, add it
+ self.writepy(path, basename) # Recursive call
+ elif ext == ".py":
+ fname, arcname = self._get_codename(path[0:-3],
+ basename)
+ if self.debug:
+ print "Adding", arcname
+ self.write(fname, arcname)
+ else:
+ # This is NOT a package directory, add its files at top level
+ if self.debug:
+ print "Adding files from directory", pathname
+ for filename in os.listdir(pathname):
+ path = os.path.join(pathname, filename)
+ root, ext = os.path.splitext(filename)
+ if ext == ".py":
+ fname, arcname = self._get_codename(path[0:-3],
+ basename)
+ if self.debug:
+ print "Adding", arcname
+ self.write(fname, arcname)
+ else:
+ if pathname[-3:] != ".py":
+ raise RuntimeError, \
+ 'Files added with writepy() must end with ".py"'
+ fname, arcname = self._get_codename(pathname[0:-3], basename)
+ if self.debug:
+ print "Adding file", arcname
+ self.write(fname, arcname)
+
+ def _get_codename(self, pathname, basename):
+ """Return (filename, archivename) for the path.
+
+ Given a module name path, return the correct file path and
+ archive name, compiling if necessary. For example, given
+ /python/lib/string, return (/python/lib/string.pyc, string).
+ """
+ file_py = pathname + ".py"
+ file_pyc = pathname + ".pyc"
+ file_pyo = pathname + ".pyo"
+ if os.path.isfile(file_pyo) and \
+ os.stat(file_pyo)[8] >= os.stat(file_py)[8]:
+ fname = file_pyo # Use .pyo file
+ elif not os.path.isfile(file_pyc) or \
+ os.stat(file_pyc)[8] < os.stat(file_py)[8]:
+ import py_compile
+ if self.debug:
+ print "Compiling", file_py
+ py_compile.compile(file_py, file_pyc)
+ fname = file_pyc
+ else:
+ fname = file_pyc
+ archivename = os.path.split(fname)[1]
+ if basename:
+ archivename = "%s/%s" % (basename, archivename)
+ return (fname, archivename)
diff --git a/lib/jython/Lib/zlib.py b/lib/jython/Lib/zlib.py new file mode 100644 index 000000000..fdb7ffe54 --- /dev/null +++ b/lib/jython/Lib/zlib.py @@ -0,0 +1,112 @@ +
+from java import util, lang
+import jarray, binascii
+
+class error(Exception):
+ pass
+
+
+DEFLATED = 8
+MAX_WBITS = 15
+DEF_MEM_LEVEL = 8
+ZLIB_VERSION = "1.1.3"
+Z_BEST_COMPRESSION = 9
+Z_BEST_SPEED = 1
+
+Z_FILTERED = 1
+Z_HUFFMAN_ONLY = 2
+
+Z_DEFAULT_COMPRESSION = -1
+Z_DEFAULT_STRATEGY = 0
+
+# Most options are removed because java does not support them
+# Z_NO_FLUSH = 0
+# Z_SYNC_FLUSH = 2
+# Z_FULL_FLUSH = 3
+Z_FINISH = 4
+
+def adler32(string, value=1):
+ if value != 1:
+ raise ValueError, "adler32 only support start value of 1"
+ checksum = util.zip.Adler32()
+ checksum.update(lang.String.getBytes(string))
+ return lang.Long(checksum.getValue()).intValue()
+
+def crc32(string, value=0):
+ return binascii.crc32(string, value)
+
+
+def compress(string, level=6):
+ if level < Z_BEST_SPEED or level > Z_BEST_COMPRESSION:
+ raise error, "Bad compression level"
+ deflater = util.zip.Deflater(level, 0)
+ deflater.setInput(string, 0, len(string))
+ deflater.finish()
+ return _get_deflate_data(deflater)
+
+def decompress(string, wbits=0, bufsize=16384):
+ inflater = util.zip.Inflater(wbits < 0)
+ inflater.setInput(string)
+ return _get_inflate_data(inflater)
+
+
+class compressobj:
+ def __init__(self, level=6, method=DEFLATED, wbits=MAX_WBITS,
+ memLevel=0, strategy=0):
+ if abs(wbits) > MAX_WBITS or abs(wbits) < 8:
+ raise ValueError, "Invalid initialization option"
+ self.deflater = util.zip.Deflater(level, wbits < 0)
+ self.deflater.setStrategy(strategy)
+ if wbits < 0:
+ _get_deflate_data(self.deflater)
+
+ def compress(self, string):
+ self.deflater.setInput(string, 0, len(string))
+ return _get_deflate_data(self.deflater)
+
+ def flush(self, mode=Z_FINISH):
+ if mode != Z_FINISH:
+ raise ValueError, "Invalid flush option"
+ self.deflater.finish()
+ return _get_deflate_data(self.deflater)
+
+class decompressobj:
+ def __init__(self, wbits=0):
+ if abs(wbits) > MAX_WBITS or abs(wbits) < 8:
+ raise ValueError, "Invalid initialization option"
+ self.inflater = util.zip.Inflater(wbits < 0)
+ self.unused_data = ""
+
+ def decompress(self, string):
+ self.inflater.setInput(string)
+ r = _get_inflate_data(self.inflater)
+ # Arrgh. This suck.
+ self.unused_data = " " * self.inflater.getRemaining()
+ return r
+
+ def flush(self):
+ #self.inflater.finish()
+ return _get_inflate_data(self.inflater)
+
+
+def _get_deflate_data(deflater):
+ buf = jarray.zeros(1024, 'b')
+ sb = lang.StringBuffer()
+ while not deflater.finished():
+ l = deflater.deflate(buf)
+ if l == 0:
+ break
+ sb.append(lang.String(buf, 0, 0, l))
+ return sb.toString()
+
+
+def _get_inflate_data(inflater):
+ buf = jarray.zeros(1024, 'b')
+ sb = lang.StringBuffer()
+ while not inflater.finished():
+ l = inflater.inflate(buf)
+ if l == 0:
+ break
+ sb.append(lang.String(buf, 0, 0, l))
+ return sb.toString()
+
diff --git a/lib/jython/README.txt b/lib/jython/README.txt new file mode 100644 index 000000000..388c258ee --- /dev/null +++ b/lib/jython/README.txt @@ -0,0 +1,17 @@ +Welcome to Jython 2.1 +======================= + +Important: The format of both compiled ($py.class) and frozen module +has changed from version 2.0. It is necesary to delete existing +$py.class files and recompile frozen applications when upgrading +to Jython-2.1. + +Other backward incompatible changes include: + +- The case of module names are now important, even on case ignoring + filesystems like windows. This matches CPython behaviour. + +- The way .zip and .jar files is added to sys.path is changed from 2.1a3. + Use the form: sys.path.append("/path/to/file.zip/Lib") to search for + modules with the zipped named of "Lib/module.py" + diff --git a/lib/jython/jython.jar b/lib/jython/jython.jar Binary files differnew file mode 100644 index 000000000..517c60dd0 --- /dev/null +++ b/lib/jython/jython.jar |