port 2P step 1: vendor CPython 2.7.18 as the mtpython static library
The embedded 40250 script layer needs its own interpreter on five platforms. 2.7 is end-of-life, so nothing can be fetched from the target SDKs and the source is vendored (official 2.7.18 tarball, trimmed to 25MB; Lib/ stays for step 3's python27.zip). cpython-2.7.18/CMakeLists.txt builds one `mtpython` static library from exactly the 133 objects the reference libpython2.7.a contains, off by default behind -DMTGODOT_EMBED_PYTHON=ON. The source list and the built-in module table (config/config.c, 39 entries) are shared; pyconfig.h is a probe result and is not, so each platform keeps its own under config/<platform>/, regenerated by tools/py_embed/gen_pyconfig.sh and checked against the shared table. Three vendor patches, documented in docs/THIRD-PARTY.md: configure/configure.ac learn arm64 on macOS, and posixmodule.c undefines the process-control calls it hard-defines past pyconfig.h when building for iOS. macOS (ctest python.embed: every builtin imports, codecs and pickle work off the vendored Lib/), Android arm64 and iOS arm64 build. Linux needs a Linux host and Windows needs a MinGW-vs-MSVC decision; both are noted for step 4. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
# This file is transmogrified into Setup.config by config.status.
|
||||
|
||||
# The purpose of this file is to conditionally enable certain modules
|
||||
# based on configure-time options.
|
||||
|
||||
# Threading
|
||||
@USE_THREAD_MODULE@thread threadmodule.c
|
||||
|
||||
# The signal module
|
||||
@USE_SIGNAL_MODULE@signal signalmodule.c
|
||||
|
||||
# The rest of the modules previously listed in this file are built
|
||||
# by the setup.py script in Python 2.1 and later.
|
||||
@@ -0,0 +1,491 @@
|
||||
# -*- makefile -*-
|
||||
# The file Setup is used by the makesetup script to construct the files
|
||||
# Makefile and config.c, from Makefile.pre and config.c.in,
|
||||
# respectively. The file Setup itself is initially copied from
|
||||
# Setup.dist; once it exists it will not be overwritten, so you can edit
|
||||
# Setup to your heart's content. Note that Makefile.pre is created
|
||||
# from Makefile.pre.in by the toplevel configure script.
|
||||
|
||||
# (VPATH notes: Setup and Makefile.pre are in the build directory, as
|
||||
# are Makefile and config.c; the *.in and *.dist files are in the source
|
||||
# directory.)
|
||||
|
||||
# Each line in this file describes one or more optional modules.
|
||||
# Modules enabled here will not be compiled by the setup.py script,
|
||||
# so the file can be used to override setup.py's behavior.
|
||||
|
||||
# Lines have the following structure:
|
||||
#
|
||||
# <module> ... [<sourcefile> ...] [<cpparg> ...] [<library> ...]
|
||||
#
|
||||
# <sourcefile> is anything ending in .c (.C, .cc, .c++ are C++ files)
|
||||
# <cpparg> is anything starting with -I, -D, -U or -C
|
||||
# <library> is anything ending in .a or beginning with -l or -L
|
||||
# <module> is anything else but should be a valid Python
|
||||
# identifier (letters, digits, underscores, beginning with non-digit)
|
||||
#
|
||||
# (As the makesetup script changes, it may recognize some other
|
||||
# arguments as well, e.g. *.so and *.sl as libraries. See the big
|
||||
# case statement in the makesetup script.)
|
||||
#
|
||||
# Lines can also have the form
|
||||
#
|
||||
# <name> = <value>
|
||||
#
|
||||
# which defines a Make variable definition inserted into Makefile.in
|
||||
#
|
||||
# Finally, if a line contains just the word "*shared*" (without the
|
||||
# quotes but with the stars), then the following modules will not be
|
||||
# built statically. The build process works like this:
|
||||
#
|
||||
# 1. Build all modules that are declared as static in Modules/Setup,
|
||||
# combine them into libpythonxy.a, combine that into python.
|
||||
# 2. Build all modules that are listed as shared in Modules/Setup.
|
||||
# 3. Invoke setup.py. That builds all modules that
|
||||
# a) are not builtin, and
|
||||
# b) are not listed in Modules/Setup, and
|
||||
# c) can be build on the target
|
||||
#
|
||||
# Therefore, modules declared to be shared will not be
|
||||
# included in the config.c file, nor in the list of objects to be
|
||||
# added to the library archive, and their linker options won't be
|
||||
# added to the linker options. Rules to create their .o files and
|
||||
# their shared libraries will still be added to the Makefile, and
|
||||
# their names will be collected in the Make variable SHAREDMODS. This
|
||||
# is used to build modules as shared libraries. (They can be
|
||||
# installed using "make sharedinstall", which is implied by the
|
||||
# toplevel "make install" target.) (For compatibility,
|
||||
# *noconfig* has the same effect as *shared*.)
|
||||
#
|
||||
# In addition, *static* explicitly declares the following modules to
|
||||
# be static. Lines containing "*static*" and "*shared*" may thus
|
||||
# alternate throughout this file.
|
||||
|
||||
# NOTE: As a standard policy, as many modules as can be supported by a
|
||||
# platform should be present. The distribution comes with all modules
|
||||
# enabled that are supported by most platforms and don't require you
|
||||
# to ftp sources from elsewhere.
|
||||
|
||||
|
||||
# Some special rules to define PYTHONPATH.
|
||||
# Edit the definitions below to indicate which options you are using.
|
||||
# Don't add any whitespace or comments!
|
||||
|
||||
# Directories where library files get installed.
|
||||
# DESTLIB is for Python modules; MACHDESTLIB for shared libraries.
|
||||
DESTLIB=$(LIBDEST)
|
||||
MACHDESTLIB=$(BINLIBDEST)
|
||||
|
||||
# NOTE: all the paths are now relative to the prefix that is computed
|
||||
# at run time!
|
||||
|
||||
# Standard path -- don't edit.
|
||||
# No leading colon since this is the first entry.
|
||||
# Empty since this is now just the runtime prefix.
|
||||
DESTPATH=
|
||||
|
||||
# Site specific path components -- should begin with : if non-empty
|
||||
SITEPATH=
|
||||
|
||||
# Standard path components for test modules
|
||||
TESTPATH=
|
||||
|
||||
# Path components for machine- or system-dependent modules and shared libraries
|
||||
MACHDEPPATH=:$(PLATDIR)
|
||||
EXTRAMACHDEPPATH=
|
||||
|
||||
# Path component for the Tkinter-related modules
|
||||
# The TKPATH variable is always enabled, to save you the effort.
|
||||
TKPATH=:lib-tk
|
||||
|
||||
# Path component for old modules.
|
||||
OLDPATH=:lib-old
|
||||
|
||||
COREPYTHONPATH=$(DESTPATH)$(SITEPATH)$(TESTPATH)$(MACHDEPPATH)$(EXTRAMACHDEPPATH)$(TKPATH)$(OLDPATH)
|
||||
PYTHONPATH=$(COREPYTHONPATH)
|
||||
|
||||
|
||||
# The modules listed here can't be built as shared libraries for
|
||||
# various reasons; therefore they are listed here instead of in the
|
||||
# normal order.
|
||||
|
||||
# This only contains the minimal set of modules required to run the
|
||||
# setup.py script in the root of the Python source tree.
|
||||
|
||||
posix posixmodule.c # posix (UNIX) system calls
|
||||
errno errnomodule.c # posix (UNIX) errno values
|
||||
pwd pwdmodule.c # this is needed to find out the user's home dir
|
||||
# if $HOME is not set
|
||||
_sre _sre.c # Fredrik Lundh's new regular expressions
|
||||
_codecs _codecsmodule.c # access to the builtin codecs and codec registry
|
||||
_weakref _weakref.c # weak references
|
||||
|
||||
# The zipimport module is always imported at startup. Having it as a
|
||||
# builtin module avoids some bootstrapping problems and reduces overhead.
|
||||
zipimport zipimport.c
|
||||
|
||||
# The rest of the modules listed in this file are all commented out by
|
||||
# default. Usually they can be detected and built as dynamically
|
||||
# loaded modules by the new setup.py script added in Python 2.1. If
|
||||
# you're on a platform that doesn't support dynamic loading, want to
|
||||
# compile modules statically into the Python binary, or need to
|
||||
# specify some odd set of compiler switches, you can uncomment the
|
||||
# appropriate lines below.
|
||||
|
||||
# ======================================================================
|
||||
|
||||
# The Python symtable module depends on .h files that setup.py doesn't track
|
||||
_symtable symtablemodule.c
|
||||
|
||||
# The SGI specific GL module:
|
||||
|
||||
GLHACK=-Dclear=__GLclear
|
||||
#gl glmodule.c cgensupport.c -I$(srcdir) $(GLHACK) -lgl -lX11
|
||||
|
||||
# Pure module. Cannot be linked dynamically.
|
||||
# -DWITH_QUANTIFY, -DWITH_PURIFY, or -DWITH_ALL_PURE
|
||||
#WHICH_PURE_PRODUCTS=-DWITH_ALL_PURE
|
||||
#PURE_INCLS=-I/usr/local/include
|
||||
#PURE_STUBLIBS=-L/usr/local/lib -lpurify_stubs -lquantify_stubs
|
||||
#pure puremodule.c $(WHICH_PURE_PRODUCTS) $(PURE_INCLS) $(PURE_STUBLIBS)
|
||||
|
||||
# Uncommenting the following line tells makesetup that all following
|
||||
# modules are to be built as shared libraries (see above for more
|
||||
# detail; also note that *static* reverses this effect):
|
||||
|
||||
#*shared*
|
||||
|
||||
# GNU readline. Unlike previous Python incarnations, GNU readline is
|
||||
# now incorporated in an optional module, configured in the Setup file
|
||||
# instead of by a configure script switch. You may have to insert a
|
||||
# -L option pointing to the directory where libreadline.* lives,
|
||||
# and you may have to change -ltermcap to -ltermlib or perhaps remove
|
||||
# it, depending on your system -- see the GNU readline instructions.
|
||||
# It's okay for this to be a shared library, too.
|
||||
|
||||
#readline readline.c -lreadline -ltermcap
|
||||
|
||||
|
||||
# Modules that should always be present (non UNIX dependent):
|
||||
|
||||
#array arraymodule.c # array objects
|
||||
#cmath cmathmodule.c _math.c # -lm # complex math library functions
|
||||
#math mathmodule.c _math.c # -lm # math library functions, e.g. sin()
|
||||
#_struct _struct.c # binary structure packing/unpacking
|
||||
#time timemodule.c # -lm # time operations and variables
|
||||
#operator operator.c # operator.add() and similar goodies
|
||||
#_testcapi _testcapimodule.c # Python C API test module
|
||||
#_random _randommodule.c # Random number generator
|
||||
#_collections _collectionsmodule.c # Container types
|
||||
#_heapq _heapqmodule.c # Heapq type
|
||||
#itertools itertoolsmodule.c # Functions creating iterators for efficient looping
|
||||
#strop stropmodule.c # String manipulations
|
||||
#_functools _functoolsmodule.c # Tools for working with functions and callable objects
|
||||
#_elementtree -I$(srcdir)/Modules/expat -DHAVE_EXPAT_CONFIG_H -DUSE_PYEXPAT_CAPI _elementtree.c # elementtree accelerator
|
||||
#_pickle _pickle.c # pickle accelerator
|
||||
#datetime datetimemodule.c # date/time type
|
||||
#_bisect _bisectmodule.c # Bisection algorithms
|
||||
|
||||
#unicodedata unicodedata.c # static Unicode character database
|
||||
|
||||
# access to ISO C locale support
|
||||
#_locale _localemodule.c # -lintl
|
||||
|
||||
# Standard I/O baseline
|
||||
#_io -I$(srcdir)/Modules/_io _io/bufferedio.c _io/bytesio.c _io/fileio.c _io/iobase.c _io/_iomodule.c _io/stringio.c _io/textio.c
|
||||
|
||||
|
||||
# Modules with some UNIX dependencies -- on by default:
|
||||
# (If you have a really backward UNIX, select and socket may not be
|
||||
# supported...)
|
||||
|
||||
#fcntl fcntlmodule.c # fcntl(2) and ioctl(2)
|
||||
#spwd spwdmodule.c # spwd(3)
|
||||
#grp grpmodule.c # grp(3)
|
||||
#select selectmodule.c # select(2); not on ancient System V
|
||||
|
||||
# Memory-mapped files (also works on Win32).
|
||||
#mmap mmapmodule.c
|
||||
|
||||
# CSV file helper
|
||||
#_csv _csv.c
|
||||
|
||||
# Socket module helper for socket(2)
|
||||
#_socket socketmodule.c timemodule.c
|
||||
|
||||
# Socket module helper for SSL support; you must comment out the other
|
||||
# socket line above, and possibly edit the SSL variable:
|
||||
#SSL=/usr/local/ssl
|
||||
#_ssl _ssl.c \
|
||||
# -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \
|
||||
# -L$(SSL)/lib -lssl -lcrypto
|
||||
|
||||
# The crypt module is now disabled by default because it breaks builds
|
||||
# on many systems (where -lcrypt is needed), e.g. Linux (I believe).
|
||||
#
|
||||
# First, look at Setup.config; configure may have set this for you.
|
||||
|
||||
#crypt cryptmodule.c # -lcrypt # crypt(3); needs -lcrypt on some systems
|
||||
|
||||
|
||||
# Some more UNIX dependent modules -- off by default, since these
|
||||
# are not supported by all UNIX systems:
|
||||
|
||||
#nis nismodule.c -lnsl # Sun yellow pages -- not everywhere
|
||||
#termios termios.c # Steen Lumholt's termios module
|
||||
#resource resource.c # Jeremy Hylton's rlimit interface
|
||||
|
||||
|
||||
# Multimedia modules -- off by default.
|
||||
# These don't work for 64-bit platforms!!!
|
||||
# #993173 says audioop works on 64-bit platforms, though.
|
||||
# These represent audio samples or images as strings:
|
||||
|
||||
#audioop audioop.c # Operations on audio samples
|
||||
#imageop imageop.c # Operations on images
|
||||
|
||||
|
||||
# Note that the _md5 and _sha modules are normally only built if the
|
||||
# system does not have the OpenSSL libs containing an optimized version.
|
||||
|
||||
# The _md5 module implements the RSA Data Security, Inc. MD5
|
||||
# Message-Digest Algorithm, described in RFC 1321. The necessary files
|
||||
# md5.c and md5.h are included here.
|
||||
|
||||
#_md5 md5module.c md5.c
|
||||
|
||||
|
||||
# The _sha module implements the SHA checksum algorithms.
|
||||
# (NIST's Secure Hash Algorithms.)
|
||||
#_sha shamodule.c
|
||||
#_sha256 sha256module.c
|
||||
#_sha512 sha512module.c
|
||||
|
||||
|
||||
# SGI IRIX specific modules -- off by default.
|
||||
|
||||
# These module work on any SGI machine:
|
||||
|
||||
# *** gl must be enabled higher up in this file ***
|
||||
#fm fmmodule.c $(GLHACK) -lfm -lgl # Font Manager
|
||||
#sgi sgimodule.c # sgi.nap() and a few more
|
||||
|
||||
# This module requires the header file
|
||||
# /usr/people/4Dgifts/iristools/include/izoom.h:
|
||||
#imgfile imgfile.c -limage -lgutil -lgl -lm # Image Processing Utilities
|
||||
|
||||
|
||||
# These modules require the Multimedia Development Option (I think):
|
||||
|
||||
#al almodule.c -laudio # Audio Library
|
||||
#cd cdmodule.c -lcdaudio -lds -lmediad # CD Audio Library
|
||||
#cl clmodule.c -lcl -lawareaudio # Compression Library
|
||||
#sv svmodule.c yuvconvert.c -lsvideo -lXext -lX11 # Starter Video
|
||||
|
||||
|
||||
# The FORMS library, by Mark Overmars, implements user interface
|
||||
# components such as dialogs and buttons using SGI's GL and FM
|
||||
# libraries. You must ftp the FORMS library separately from
|
||||
# ftp://ftp.cs.ruu.nl/pub/SGI/FORMS. It was tested with FORMS 2.2a.
|
||||
# NOTE: if you want to be able to use FORMS and curses simultaneously
|
||||
# (or both link them statically into the same binary), you must
|
||||
# compile all of FORMS with the cc option "-Dclear=__GLclear".
|
||||
|
||||
# The FORMS variable must point to the FORMS subdirectory of the forms
|
||||
# toplevel directory:
|
||||
|
||||
#FORMS=/ufs/guido/src/forms/FORMS
|
||||
#fl flmodule.c -I$(FORMS) $(GLHACK) $(FORMS)/libforms.a -lfm -lgl
|
||||
|
||||
|
||||
# SunOS specific modules -- off by default:
|
||||
|
||||
#sunaudiodev sunaudiodev.c
|
||||
|
||||
|
||||
# A Linux specific module -- off by default; this may also work on
|
||||
# some *BSDs.
|
||||
|
||||
#linuxaudiodev linuxaudiodev.c
|
||||
|
||||
|
||||
# George Neville-Neil's timing module:
|
||||
|
||||
#timing timingmodule.c
|
||||
|
||||
|
||||
# The _tkinter module.
|
||||
#
|
||||
# The command for _tkinter is long and site specific. Please
|
||||
# uncomment and/or edit those parts as indicated. If you don't have a
|
||||
# specific extension (e.g. Tix or BLT), leave the corresponding line
|
||||
# commented out. (Leave the trailing backslashes in! If you
|
||||
# experience strange errors, you may want to join all uncommented
|
||||
# lines and remove the backslashes -- the backslash interpretation is
|
||||
# done by the shell's "read" command and it may not be implemented on
|
||||
# every system.
|
||||
|
||||
# *** Always uncomment this (leave the leading underscore in!):
|
||||
# _tkinter _tkinter.c tkappinit.c -DWITH_APPINIT \
|
||||
# *** Uncomment and edit to reflect where your Tcl/Tk libraries are:
|
||||
# -L/usr/local/lib \
|
||||
# *** Uncomment and edit to reflect where your Tcl/Tk headers are:
|
||||
# -I/usr/local/include \
|
||||
# *** Uncomment and edit to reflect where your X11 header files are:
|
||||
# -I/usr/X11R6/include \
|
||||
# *** Or uncomment this for Solaris:
|
||||
# -I/usr/openwin/include \
|
||||
# *** Uncomment and edit for Tix extension only:
|
||||
# -DWITH_TIX -ltix8.1.8.2 \
|
||||
# *** Uncomment and edit for BLT extension only:
|
||||
# -DWITH_BLT -I/usr/local/blt/blt8.0-unoff/include -lBLT8.0 \
|
||||
# *** Uncomment and edit for PIL (TkImaging) extension only:
|
||||
# (See http://www.pythonware.com/products/pil/ for more info)
|
||||
# -DWITH_PIL -I../Extensions/Imaging/libImaging tkImaging.c \
|
||||
# *** Uncomment and edit for TOGL extension only:
|
||||
# -DWITH_TOGL togl.c \
|
||||
# *** Uncomment and edit to reflect your Tcl/Tk versions:
|
||||
# -ltk8.2 -ltcl8.2 \
|
||||
# *** Uncomment and edit to reflect where your X11 libraries are:
|
||||
# -L/usr/X11R6/lib \
|
||||
# *** Or uncomment this for Solaris:
|
||||
# -L/usr/openwin/lib \
|
||||
# *** Uncomment these for TOGL extension only:
|
||||
# -lGL -lGLU -lXext -lXmu \
|
||||
# *** Uncomment for AIX:
|
||||
# -lld \
|
||||
# *** Always uncomment this; X11 libraries to link with:
|
||||
# -lX11
|
||||
|
||||
# Lance Ellinghaus's syslog module
|
||||
#syslog syslogmodule.c # syslog daemon interface
|
||||
|
||||
|
||||
# Curses support, requring the System V version of curses, often
|
||||
# provided by the ncurses library. e.g. on Linux, link with -lncurses
|
||||
# instead of -lcurses).
|
||||
#
|
||||
# First, look at Setup.config; configure may have set this for you.
|
||||
|
||||
#_curses _cursesmodule.c -lcurses -ltermcap
|
||||
# Wrapper for the panel library that's part of ncurses and SYSV curses.
|
||||
#_curses_panel _curses_panel.c -lpanel -lncurses
|
||||
|
||||
|
||||
# Generic (SunOS / SVR4) dynamic loading module.
|
||||
# This is not needed for dynamic loading of Python modules --
|
||||
# it is a highly experimental and dangerous device for calling
|
||||
# *arbitrary* C functions in *arbitrary* shared libraries:
|
||||
|
||||
#dl dlmodule.c
|
||||
|
||||
|
||||
# Modules that provide persistent dictionary-like semantics. You will
|
||||
# probably want to arrange for at least one of them to be available on
|
||||
# your machine, though none are defined by default because of library
|
||||
# dependencies. The Python module anydbm.py provides an
|
||||
# implementation independent wrapper for these; dumbdbm.py provides
|
||||
# similar functionality (but slower of course) implemented in Python.
|
||||
|
||||
# The standard Unix dbm module has been moved to Setup.config so that
|
||||
# it will be compiled as a shared library by default. Compiling it as
|
||||
# a built-in module causes conflicts with the pybsddb3 module since it
|
||||
# creates a static dependency on an out-of-date version of db.so.
|
||||
#
|
||||
# First, look at Setup.config; configure may have set this for you.
|
||||
|
||||
#dbm dbmmodule.c # dbm(3) may require -lndbm or similar
|
||||
|
||||
# Anthony Baxter's gdbm module. GNU dbm(3) will require -lgdbm:
|
||||
#
|
||||
# First, look at Setup.config; configure may have set this for you.
|
||||
|
||||
#gdbm gdbmmodule.c -I/usr/local/include -L/usr/local/lib -lgdbm
|
||||
|
||||
|
||||
# Sleepycat Berkeley DB interface.
|
||||
#
|
||||
# This requires the Sleepycat DB code, see http://www.sleepycat.com/
|
||||
# The earliest supported version of that library is 3.0, the latest
|
||||
# supported version is 4.0 (4.1 is specifically not supported, as that
|
||||
# changes the semantics of transactional databases). A list of available
|
||||
# releases can be found at
|
||||
#
|
||||
# http://www.sleepycat.com/update/index.html
|
||||
#
|
||||
# Edit the variables DB and DBLIBVERto point to the db top directory
|
||||
# and the subdirectory of PORT where you built it.
|
||||
#DB=/usr/local/BerkeleyDB.4.0
|
||||
#DBLIBVER=4.0
|
||||
#DBINC=$(DB)/include
|
||||
#DBLIB=$(DB)/lib
|
||||
#_bsddb _bsddb.c -I$(DBINC) -L$(DBLIB) -ldb-$(DBLIBVER)
|
||||
|
||||
# Historical Berkeley DB 1.85
|
||||
#
|
||||
# This module is deprecated; the 1.85 version of the Berkeley DB library has
|
||||
# bugs that can cause data corruption. If you can, use later versions of the
|
||||
# library instead, available from <http://www.sleepycat.com/>.
|
||||
|
||||
#DB=/depot/sundry/src/berkeley-db/db.1.85
|
||||
#DBPORT=$(DB)/PORT/irix.5.3
|
||||
#bsddb185 bsddbmodule.c -I$(DBPORT)/include -I$(DBPORT) $(DBPORT)/libdb.a
|
||||
|
||||
|
||||
|
||||
# Helper module for various ascii-encoders
|
||||
#binascii binascii.c
|
||||
|
||||
# Fred Drake's interface to the Python parser
|
||||
#parser parsermodule.c
|
||||
|
||||
# cStringIO and cPickle
|
||||
#cStringIO cStringIO.c
|
||||
#cPickle cPickle.c
|
||||
|
||||
|
||||
# Lee Busby's SIGFPE modules.
|
||||
# The library to link fpectl with is platform specific.
|
||||
# Choose *one* of the options below for fpectl:
|
||||
|
||||
# For SGI IRIX (tested on 5.3):
|
||||
#fpectl fpectlmodule.c -lfpe
|
||||
|
||||
# For Solaris with SunPro compiler (tested on Solaris 2.5 with SunPro C 4.2):
|
||||
# (Without the compiler you don't have -lsunmath.)
|
||||
#fpectl fpectlmodule.c -R/opt/SUNWspro/lib -lsunmath -lm
|
||||
|
||||
# For other systems: see instructions in fpectlmodule.c.
|
||||
#fpectl fpectlmodule.c ...
|
||||
|
||||
# Test module for fpectl. No extra libraries needed.
|
||||
#fpetest fpetestmodule.c
|
||||
|
||||
# Andrew Kuchling's zlib module.
|
||||
# This require zlib 1.1.3 (or later).
|
||||
# See http://www.gzip.org/zlib/
|
||||
#zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib -lz
|
||||
|
||||
# Interface to the Expat XML parser
|
||||
# More information on Expat can be found at www.libexpat.org.
|
||||
#
|
||||
#pyexpat expat/xmlparse.c expat/xmlrole.c expat/xmltok.c pyexpat.c -I$(srcdir)/Modules/expat -DHAVE_EXPAT_CONFIG_H -DXML_POOR_ENTROPY=1 -DUSE_PYEXPAT_CAPI
|
||||
|
||||
|
||||
# Hye-Shik Chang's CJKCodecs
|
||||
|
||||
# multibytecodec is required for all the other CJK codec modules
|
||||
#_multibytecodec cjkcodecs/multibytecodec.c
|
||||
|
||||
#_codecs_cn cjkcodecs/_codecs_cn.c
|
||||
#_codecs_hk cjkcodecs/_codecs_hk.c
|
||||
#_codecs_iso2022 cjkcodecs/_codecs_iso2022.c
|
||||
#_codecs_jp cjkcodecs/_codecs_jp.c
|
||||
#_codecs_kr cjkcodecs/_codecs_kr.c
|
||||
#_codecs_tw cjkcodecs/_codecs_tw.c
|
||||
|
||||
# Example -- included for reference only:
|
||||
# xx xxmodule.c
|
||||
|
||||
# Another example -- the 'xxsubtype' module shows C-level subtyping in action
|
||||
xxsubtype xxsubtype.c
|
||||
@@ -0,0 +1,246 @@
|
||||
/* Bisection algorithms. Drop in replacement for bisect.py
|
||||
|
||||
Converted to C by Dmitry Vasiliev (dima at hlabs.spb.ru).
|
||||
*/
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
static Py_ssize_t
|
||||
internal_bisect_right(PyObject *list, PyObject *item, Py_ssize_t lo, Py_ssize_t hi)
|
||||
{
|
||||
PyObject *litem;
|
||||
Py_ssize_t mid, res;
|
||||
|
||||
if (lo < 0) {
|
||||
PyErr_SetString(PyExc_ValueError, "lo must be non-negative");
|
||||
return -1;
|
||||
}
|
||||
if (hi == -1) {
|
||||
hi = PySequence_Size(list);
|
||||
if (hi < 0)
|
||||
return -1;
|
||||
}
|
||||
while (lo < hi) {
|
||||
/* The (size_t)cast ensures that the addition and subsequent division
|
||||
are performed as unsigned operations, avoiding difficulties from
|
||||
signed overflow. (See issue 13496.) */
|
||||
mid = ((size_t)lo + hi) / 2;
|
||||
litem = PySequence_GetItem(list, mid);
|
||||
if (litem == NULL)
|
||||
return -1;
|
||||
res = PyObject_RichCompareBool(item, litem, Py_LT);
|
||||
Py_DECREF(litem);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
if (res)
|
||||
hi = mid;
|
||||
else
|
||||
lo = mid + 1;
|
||||
}
|
||||
return lo;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
bisect_right(PyObject *self, PyObject *args, PyObject *kw)
|
||||
{
|
||||
PyObject *list, *item;
|
||||
Py_ssize_t lo = 0;
|
||||
Py_ssize_t hi = -1;
|
||||
Py_ssize_t index;
|
||||
static char *keywords[] = {"a", "x", "lo", "hi", NULL};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "OO|nn:bisect_right",
|
||||
keywords, &list, &item, &lo, &hi))
|
||||
return NULL;
|
||||
index = internal_bisect_right(list, item, lo, hi);
|
||||
if (index < 0)
|
||||
return NULL;
|
||||
return PyInt_FromSsize_t(index);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bisect_right_doc,
|
||||
"bisect(a, x[, lo[, hi]]) -> index\n\
|
||||
bisect_right(a, x[, lo[, hi]]) -> index\n\
|
||||
\n\
|
||||
Return the index where to insert item x in list a, assuming a is sorted.\n\
|
||||
\n\
|
||||
The return value i is such that all e in a[:i] have e <= x, and all e in\n\
|
||||
a[i:] have e > x. So if x already appears in the list, i points just\n\
|
||||
beyond the rightmost x already there\n\
|
||||
\n\
|
||||
Optional args lo (default 0) and hi (default len(a)) bound the\n\
|
||||
slice of a to be searched.\n");
|
||||
|
||||
static PyObject *
|
||||
insort_right(PyObject *self, PyObject *args, PyObject *kw)
|
||||
{
|
||||
PyObject *list, *item, *result;
|
||||
Py_ssize_t lo = 0;
|
||||
Py_ssize_t hi = -1;
|
||||
Py_ssize_t index;
|
||||
static char *keywords[] = {"a", "x", "lo", "hi", NULL};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "OO|nn:insort_right",
|
||||
keywords, &list, &item, &lo, &hi))
|
||||
return NULL;
|
||||
index = internal_bisect_right(list, item, lo, hi);
|
||||
if (index < 0)
|
||||
return NULL;
|
||||
if (PyList_CheckExact(list)) {
|
||||
if (PyList_Insert(list, index, item) < 0)
|
||||
return NULL;
|
||||
} else {
|
||||
result = PyObject_CallMethod(list, "insert", "nO",
|
||||
index, item);
|
||||
if (result == NULL)
|
||||
return NULL;
|
||||
Py_DECREF(result);
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(insort_right_doc,
|
||||
"insort(a, x[, lo[, hi]])\n\
|
||||
insort_right(a, x[, lo[, hi]])\n\
|
||||
\n\
|
||||
Insert item x in list a, and keep it sorted assuming a is sorted.\n\
|
||||
\n\
|
||||
If x is already in a, insert it to the right of the rightmost x.\n\
|
||||
\n\
|
||||
Optional args lo (default 0) and hi (default len(a)) bound the\n\
|
||||
slice of a to be searched.\n");
|
||||
|
||||
static Py_ssize_t
|
||||
internal_bisect_left(PyObject *list, PyObject *item, Py_ssize_t lo, Py_ssize_t hi)
|
||||
{
|
||||
PyObject *litem;
|
||||
Py_ssize_t mid, res;
|
||||
|
||||
if (lo < 0) {
|
||||
PyErr_SetString(PyExc_ValueError, "lo must be non-negative");
|
||||
return -1;
|
||||
}
|
||||
if (hi == -1) {
|
||||
hi = PySequence_Size(list);
|
||||
if (hi < 0)
|
||||
return -1;
|
||||
}
|
||||
while (lo < hi) {
|
||||
/* The (size_t)cast ensures that the addition and subsequent division
|
||||
are performed as unsigned operations, avoiding difficulties from
|
||||
signed overflow. (See issue 13496.) */
|
||||
mid = ((size_t)lo + hi) / 2;
|
||||
litem = PySequence_GetItem(list, mid);
|
||||
if (litem == NULL)
|
||||
return -1;
|
||||
res = PyObject_RichCompareBool(litem, item, Py_LT);
|
||||
Py_DECREF(litem);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
if (res)
|
||||
lo = mid + 1;
|
||||
else
|
||||
hi = mid;
|
||||
}
|
||||
return lo;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
bisect_left(PyObject *self, PyObject *args, PyObject *kw)
|
||||
{
|
||||
PyObject *list, *item;
|
||||
Py_ssize_t lo = 0;
|
||||
Py_ssize_t hi = -1;
|
||||
Py_ssize_t index;
|
||||
static char *keywords[] = {"a", "x", "lo", "hi", NULL};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "OO|nn:bisect_left",
|
||||
keywords, &list, &item, &lo, &hi))
|
||||
return NULL;
|
||||
index = internal_bisect_left(list, item, lo, hi);
|
||||
if (index < 0)
|
||||
return NULL;
|
||||
return PyInt_FromSsize_t(index);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bisect_left_doc,
|
||||
"bisect_left(a, x[, lo[, hi]]) -> index\n\
|
||||
\n\
|
||||
Return the index where to insert item x in list a, assuming a is sorted.\n\
|
||||
\n\
|
||||
The return value i is such that all e in a[:i] have e < x, and all e in\n\
|
||||
a[i:] have e >= x. So if x already appears in the list, i points just\n\
|
||||
before the leftmost x already there.\n\
|
||||
\n\
|
||||
Optional args lo (default 0) and hi (default len(a)) bound the\n\
|
||||
slice of a to be searched.\n");
|
||||
|
||||
static PyObject *
|
||||
insort_left(PyObject *self, PyObject *args, PyObject *kw)
|
||||
{
|
||||
PyObject *list, *item, *result;
|
||||
Py_ssize_t lo = 0;
|
||||
Py_ssize_t hi = -1;
|
||||
Py_ssize_t index;
|
||||
static char *keywords[] = {"a", "x", "lo", "hi", NULL};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "OO|nn:insort_left",
|
||||
keywords, &list, &item, &lo, &hi))
|
||||
return NULL;
|
||||
index = internal_bisect_left(list, item, lo, hi);
|
||||
if (index < 0)
|
||||
return NULL;
|
||||
if (PyList_CheckExact(list)) {
|
||||
if (PyList_Insert(list, index, item) < 0)
|
||||
return NULL;
|
||||
} else {
|
||||
result = PyObject_CallMethod(list, "insert", "nO",
|
||||
index, item);
|
||||
if (result == NULL)
|
||||
return NULL;
|
||||
Py_DECREF(result);
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(insort_left_doc,
|
||||
"insort_left(a, x[, lo[, hi]])\n\
|
||||
\n\
|
||||
Insert item x in list a, and keep it sorted assuming a is sorted.\n\
|
||||
\n\
|
||||
If x is already in a, insert it to the left of the leftmost x.\n\
|
||||
\n\
|
||||
Optional args lo (default 0) and hi (default len(a)) bound the\n\
|
||||
slice of a to be searched.\n");
|
||||
|
||||
static PyMethodDef bisect_methods[] = {
|
||||
{"bisect_right", (PyCFunction)bisect_right,
|
||||
METH_VARARGS|METH_KEYWORDS, bisect_right_doc},
|
||||
{"bisect", (PyCFunction)bisect_right,
|
||||
METH_VARARGS|METH_KEYWORDS, bisect_right_doc},
|
||||
{"insort_right", (PyCFunction)insort_right,
|
||||
METH_VARARGS|METH_KEYWORDS, insort_right_doc},
|
||||
{"insort", (PyCFunction)insort_right,
|
||||
METH_VARARGS|METH_KEYWORDS, insort_right_doc},
|
||||
{"bisect_left", (PyCFunction)bisect_left,
|
||||
METH_VARARGS|METH_KEYWORDS, bisect_left_doc},
|
||||
{"insort_left", (PyCFunction)insort_left,
|
||||
METH_VARARGS|METH_KEYWORDS, insort_left_doc},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(module_doc,
|
||||
"Bisection algorithms.\n\
|
||||
\n\
|
||||
This module provides support for maintaining a list in sorted order without\n\
|
||||
having to sort the list after each insertion. For long lists of items with\n\
|
||||
expensive comparison operations, this can be an improvement over the more\n\
|
||||
common approach.\n");
|
||||
|
||||
PyMODINIT_FUNC
|
||||
init_bisect(void)
|
||||
{
|
||||
Py_InitModule3("_bisect", bisect_methods, module_doc);
|
||||
}
|
||||
+10376
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1641
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,495 @@
|
||||
/*
|
||||
* Interface to the ncurses panel library
|
||||
*
|
||||
* Original version by Thomas Gellekum
|
||||
*/
|
||||
|
||||
/* Release Number */
|
||||
|
||||
static char *PyCursesVersion = "2.1";
|
||||
|
||||
/* Includes */
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
#include "py_curses.h"
|
||||
|
||||
#include <panel.h>
|
||||
|
||||
static PyObject *PyCursesError;
|
||||
|
||||
|
||||
/* Utility Functions */
|
||||
|
||||
/*
|
||||
* Check the return code from a curses function and return None
|
||||
* or raise an exception as appropriate.
|
||||
*/
|
||||
|
||||
static PyObject *
|
||||
PyCursesCheckERR(int code, char *fname)
|
||||
{
|
||||
if (code != ERR) {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
} else {
|
||||
if (fname == NULL) {
|
||||
PyErr_SetString(PyCursesError, catchall_ERR);
|
||||
} else {
|
||||
PyErr_Format(PyCursesError, "%s() returned ERR", fname);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
The Panel Object
|
||||
******************************************************************************/
|
||||
|
||||
/* Definition of the panel object and panel type */
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PANEL *pan;
|
||||
PyCursesWindowObject *wo; /* for reference counts */
|
||||
} PyCursesPanelObject;
|
||||
|
||||
PyTypeObject PyCursesPanel_Type;
|
||||
|
||||
#define PyCursesPanel_Check(v) (Py_TYPE(v) == &PyCursesPanel_Type)
|
||||
|
||||
/* Some helper functions. The problem is that there's always a window
|
||||
associated with a panel. To ensure that Python's GC doesn't pull
|
||||
this window from under our feet we need to keep track of references
|
||||
to the corresponding window object within Python. We can't use
|
||||
dupwin(oldwin) to keep a copy of the curses WINDOW because the
|
||||
contents of oldwin is copied only once; code like
|
||||
|
||||
win = newwin(...)
|
||||
pan = win.panel()
|
||||
win.addstr(some_string)
|
||||
pan.window().addstr(other_string)
|
||||
|
||||
will fail. */
|
||||
|
||||
/* We keep a linked list of PyCursesPanelObjects, lop. A list should
|
||||
suffice, I don't expect more than a handful or at most a few
|
||||
dozens of panel objects within a typical program. */
|
||||
typedef struct _list_of_panels {
|
||||
PyCursesPanelObject *po;
|
||||
struct _list_of_panels *next;
|
||||
} list_of_panels;
|
||||
|
||||
/* list anchor */
|
||||
static list_of_panels *lop;
|
||||
|
||||
/* Insert a new panel object into lop */
|
||||
static int
|
||||
insert_lop(PyCursesPanelObject *po)
|
||||
{
|
||||
list_of_panels *new;
|
||||
|
||||
if ((new = (list_of_panels *)malloc(sizeof(list_of_panels))) == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return -1;
|
||||
}
|
||||
new->po = po;
|
||||
new->next = lop;
|
||||
lop = new;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remove the panel object from lop */
|
||||
static void
|
||||
remove_lop(PyCursesPanelObject *po)
|
||||
{
|
||||
list_of_panels *temp, *n;
|
||||
|
||||
temp = lop;
|
||||
if (temp->po == po) {
|
||||
lop = temp->next;
|
||||
free(temp);
|
||||
return;
|
||||
}
|
||||
while (temp->next == NULL || temp->next->po != po) {
|
||||
if (temp->next == NULL) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"remove_lop: can't find Panel Object");
|
||||
return;
|
||||
}
|
||||
temp = temp->next;
|
||||
}
|
||||
n = temp->next->next;
|
||||
free(temp->next);
|
||||
temp->next = n;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Return the panel object that corresponds to pan */
|
||||
static PyCursesPanelObject *
|
||||
find_po(PANEL *pan)
|
||||
{
|
||||
list_of_panels *temp;
|
||||
for (temp = lop; temp->po->pan != pan; temp = temp->next)
|
||||
if (temp->next == NULL) return NULL; /* not found!? */
|
||||
return temp->po;
|
||||
}
|
||||
|
||||
/* Function Prototype Macros - They are ugly but very, very useful. ;-)
|
||||
|
||||
X - function name
|
||||
TYPE - parameter Type
|
||||
ERGSTR - format string for construction of the return value
|
||||
PARSESTR - format string for argument parsing */
|
||||
|
||||
#define Panel_NoArgNoReturnFunction(X) \
|
||||
static PyObject *PyCursesPanel_##X(PyCursesPanelObject *self) \
|
||||
{ return PyCursesCheckERR(X(self->pan), # X); }
|
||||
|
||||
#define Panel_NoArgTrueFalseFunction(X) \
|
||||
static PyObject *PyCursesPanel_##X(PyCursesPanelObject *self) \
|
||||
{ \
|
||||
if (X (self->pan) == FALSE) { Py_INCREF(Py_False); return Py_False; } \
|
||||
else { Py_INCREF(Py_True); return Py_True; } }
|
||||
|
||||
#define Panel_TwoArgNoReturnFunction(X, TYPE, PARSESTR) \
|
||||
static PyObject *PyCursesPanel_##X(PyCursesPanelObject *self, PyObject *args) \
|
||||
{ \
|
||||
TYPE arg1, arg2; \
|
||||
if (!PyArg_ParseTuple(args, PARSESTR, &arg1, &arg2)) return NULL; \
|
||||
return PyCursesCheckERR(X(self->pan, arg1, arg2), # X); }
|
||||
|
||||
/* ------------- PANEL routines --------------- */
|
||||
|
||||
Panel_NoArgNoReturnFunction(bottom_panel)
|
||||
Panel_NoArgNoReturnFunction(hide_panel)
|
||||
Panel_NoArgNoReturnFunction(show_panel)
|
||||
Panel_NoArgNoReturnFunction(top_panel)
|
||||
Panel_NoArgTrueFalseFunction(panel_hidden)
|
||||
Panel_TwoArgNoReturnFunction(move_panel, int, "ii;y,x")
|
||||
|
||||
/* Allocation and deallocation of Panel Objects */
|
||||
|
||||
static PyObject *
|
||||
PyCursesPanel_New(PANEL *pan, PyCursesWindowObject *wo)
|
||||
{
|
||||
PyCursesPanelObject *po;
|
||||
|
||||
po = PyObject_NEW(PyCursesPanelObject, &PyCursesPanel_Type);
|
||||
if (po == NULL) return NULL;
|
||||
po->pan = pan;
|
||||
if (insert_lop(po) < 0) {
|
||||
po->wo = NULL;
|
||||
Py_DECREF(po);
|
||||
return NULL;
|
||||
}
|
||||
po->wo = wo;
|
||||
Py_INCREF(wo);
|
||||
return (PyObject *)po;
|
||||
}
|
||||
|
||||
static void
|
||||
PyCursesPanel_Dealloc(PyCursesPanelObject *po)
|
||||
{
|
||||
PyObject *obj = (PyObject *) panel_userptr(po->pan);
|
||||
if (obj) {
|
||||
(void)set_panel_userptr(po->pan, NULL);
|
||||
Py_DECREF(obj);
|
||||
}
|
||||
(void)del_panel(po->pan);
|
||||
if (po->wo != NULL) {
|
||||
Py_DECREF(po->wo);
|
||||
remove_lop(po);
|
||||
}
|
||||
PyObject_DEL(po);
|
||||
}
|
||||
|
||||
/* panel_above(NULL) returns the bottom panel in the stack. To get
|
||||
this behaviour we use curses.panel.bottom_panel(). */
|
||||
static PyObject *
|
||||
PyCursesPanel_above(PyCursesPanelObject *self)
|
||||
{
|
||||
PANEL *pan;
|
||||
PyCursesPanelObject *po;
|
||||
|
||||
pan = panel_above(self->pan);
|
||||
|
||||
if (pan == NULL) { /* valid output, it means the calling panel
|
||||
is on top of the stack */
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
po = find_po(pan);
|
||||
if (po == NULL) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"panel_above: can't find Panel Object");
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(po);
|
||||
return (PyObject *)po;
|
||||
}
|
||||
|
||||
/* panel_below(NULL) returns the top panel in the stack. To get
|
||||
this behaviour we use curses.panel.top_panel(). */
|
||||
static PyObject *
|
||||
PyCursesPanel_below(PyCursesPanelObject *self)
|
||||
{
|
||||
PANEL *pan;
|
||||
PyCursesPanelObject *po;
|
||||
|
||||
pan = panel_below(self->pan);
|
||||
|
||||
if (pan == NULL) { /* valid output, it means the calling panel
|
||||
is on the bottom of the stack */
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
po = find_po(pan);
|
||||
if (po == NULL) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"panel_below: can't find Panel Object");
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(po);
|
||||
return (PyObject *)po;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
PyCursesPanel_window(PyCursesPanelObject *self)
|
||||
{
|
||||
Py_INCREF(self->wo);
|
||||
return (PyObject *)self->wo;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
PyCursesPanel_replace_panel(PyCursesPanelObject *self, PyObject *args)
|
||||
{
|
||||
PyCursesPanelObject *po;
|
||||
PyCursesWindowObject *temp;
|
||||
int rtn;
|
||||
|
||||
if (PyTuple_Size(args) != 1) {
|
||||
PyErr_SetString(PyExc_TypeError, "replace requires one argument");
|
||||
return NULL;
|
||||
}
|
||||
if (!PyArg_ParseTuple(args, "O!;window object",
|
||||
&PyCursesWindow_Type, &temp))
|
||||
return NULL;
|
||||
|
||||
po = find_po(self->pan);
|
||||
if (po == NULL) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"replace_panel: can't find Panel Object");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rtn = replace_panel(self->pan, temp->win);
|
||||
if (rtn == ERR) {
|
||||
PyErr_SetString(PyCursesError, "replace_panel() returned ERR");
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(temp);
|
||||
Py_SETREF(po->wo, temp);
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
PyCursesPanel_set_panel_userptr(PyCursesPanelObject *self, PyObject *obj)
|
||||
{
|
||||
PyObject *oldobj;
|
||||
int rc;
|
||||
PyCursesInitialised;
|
||||
Py_INCREF(obj);
|
||||
oldobj = (PyObject *) panel_userptr(self->pan);
|
||||
rc = set_panel_userptr(self->pan, (void*)obj);
|
||||
if (rc == ERR) {
|
||||
/* In case of an ncurses error, decref the new object again */
|
||||
Py_DECREF(obj);
|
||||
}
|
||||
Py_XDECREF(oldobj);
|
||||
return PyCursesCheckERR(rc, "set_panel_userptr");
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
PyCursesPanel_userptr(PyCursesPanelObject *self)
|
||||
{
|
||||
PyObject *obj;
|
||||
PyCursesInitialised;
|
||||
obj = (PyObject *) panel_userptr(self->pan);
|
||||
if (obj == NULL) {
|
||||
PyErr_SetString(PyCursesError, "no userptr set");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_INCREF(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
/* Module interface */
|
||||
|
||||
static PyMethodDef PyCursesPanel_Methods[] = {
|
||||
{"above", (PyCFunction)PyCursesPanel_above, METH_NOARGS},
|
||||
{"below", (PyCFunction)PyCursesPanel_below, METH_NOARGS},
|
||||
{"bottom", (PyCFunction)PyCursesPanel_bottom_panel, METH_NOARGS},
|
||||
{"hidden", (PyCFunction)PyCursesPanel_panel_hidden, METH_NOARGS},
|
||||
{"hide", (PyCFunction)PyCursesPanel_hide_panel, METH_NOARGS},
|
||||
{"move", (PyCFunction)PyCursesPanel_move_panel, METH_VARARGS},
|
||||
{"replace", (PyCFunction)PyCursesPanel_replace_panel, METH_VARARGS},
|
||||
{"set_userptr", (PyCFunction)PyCursesPanel_set_panel_userptr, METH_O},
|
||||
{"show", (PyCFunction)PyCursesPanel_show_panel, METH_NOARGS},
|
||||
{"top", (PyCFunction)PyCursesPanel_top_panel, METH_NOARGS},
|
||||
{"userptr", (PyCFunction)PyCursesPanel_userptr, METH_NOARGS},
|
||||
{"window", (PyCFunction)PyCursesPanel_window, METH_NOARGS},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
PyCursesPanel_GetAttr(PyCursesPanelObject *self, char *name)
|
||||
{
|
||||
return Py_FindMethod(PyCursesPanel_Methods, (PyObject *)self, name);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------*/
|
||||
|
||||
PyTypeObject PyCursesPanel_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"_curses_panel.curses panel", /*tp_name*/
|
||||
sizeof(PyCursesPanelObject), /*tp_basicsize*/
|
||||
0, /*tp_itemsize*/
|
||||
/* methods */
|
||||
(destructor)PyCursesPanel_Dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
(getattrfunc)PyCursesPanel_GetAttr, /*tp_getattr*/
|
||||
(setattrfunc)0, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
0, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
0, /*tp_hash*/
|
||||
};
|
||||
|
||||
/* Wrapper for panel_above(NULL). This function returns the bottom
|
||||
panel of the stack, so it's renamed to bottom_panel().
|
||||
panel.above() *requires* a panel object in the first place which
|
||||
may be undesirable. */
|
||||
static PyObject *
|
||||
PyCurses_bottom_panel(PyObject *self)
|
||||
{
|
||||
PANEL *pan;
|
||||
PyCursesPanelObject *po;
|
||||
|
||||
PyCursesInitialised;
|
||||
|
||||
pan = panel_above(NULL);
|
||||
|
||||
if (pan == NULL) { /* valid output, it means
|
||||
there's no panel at all */
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
po = find_po(pan);
|
||||
if (po == NULL) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"panel_above: can't find Panel Object");
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(po);
|
||||
return (PyObject *)po;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
PyCurses_new_panel(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyCursesWindowObject *win;
|
||||
PANEL *pan;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O!", &PyCursesWindow_Type, &win))
|
||||
return NULL;
|
||||
pan = new_panel(win->win);
|
||||
if (pan == NULL) {
|
||||
PyErr_SetString(PyCursesError, catchall_NULL);
|
||||
return NULL;
|
||||
}
|
||||
return (PyObject *)PyCursesPanel_New(pan, win);
|
||||
}
|
||||
|
||||
|
||||
/* Wrapper for panel_below(NULL). This function returns the top panel
|
||||
of the stack, so it's renamed to top_panel(). panel.below()
|
||||
*requires* a panel object in the first place which may be
|
||||
undesirable. */
|
||||
static PyObject *
|
||||
PyCurses_top_panel(PyObject *self)
|
||||
{
|
||||
PANEL *pan;
|
||||
PyCursesPanelObject *po;
|
||||
|
||||
PyCursesInitialised;
|
||||
|
||||
pan = panel_below(NULL);
|
||||
|
||||
if (pan == NULL) { /* valid output, it means
|
||||
there's no panel at all */
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
po = find_po(pan);
|
||||
if (po == NULL) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"panel_below: can't find Panel Object");
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(po);
|
||||
return (PyObject *)po;
|
||||
}
|
||||
|
||||
static PyObject *PyCurses_update_panels(PyObject *self)
|
||||
{
|
||||
PyCursesInitialised;
|
||||
update_panels();
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
/* List of functions defined in the module */
|
||||
|
||||
static PyMethodDef PyCurses_methods[] = {
|
||||
{"bottom_panel", (PyCFunction)PyCurses_bottom_panel, METH_NOARGS},
|
||||
{"new_panel", (PyCFunction)PyCurses_new_panel, METH_VARARGS},
|
||||
{"top_panel", (PyCFunction)PyCurses_top_panel, METH_NOARGS},
|
||||
{"update_panels", (PyCFunction)PyCurses_update_panels, METH_NOARGS},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
/* Initialization function for the module */
|
||||
|
||||
PyMODINIT_FUNC
|
||||
init_curses_panel(void)
|
||||
{
|
||||
PyObject *m, *d, *v;
|
||||
|
||||
/* Initialize object type */
|
||||
Py_TYPE(&PyCursesPanel_Type) = &PyType_Type;
|
||||
|
||||
import_curses();
|
||||
|
||||
/* Create the module and add the functions */
|
||||
m = Py_InitModule("_curses_panel", PyCurses_methods);
|
||||
if (m == NULL)
|
||||
return;
|
||||
d = PyModule_GetDict(m);
|
||||
|
||||
/* For exception _curses_panel.error */
|
||||
PyCursesError = PyErr_NewException("_curses_panel.error", NULL, NULL);
|
||||
PyDict_SetItemString(d, "error", PyCursesError);
|
||||
|
||||
/* Make the version available */
|
||||
v = PyString_FromString(PyCursesVersion);
|
||||
PyDict_SetItemString(d, "version", v);
|
||||
PyDict_SetItemString(d, "__version__", v);
|
||||
Py_DECREF(v);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,415 @@
|
||||
|
||||
#include "Python.h"
|
||||
#include "structmember.h"
|
||||
|
||||
/* _functools module written and maintained
|
||||
by Hye-Shik Chang <perky@FreeBSD.org>
|
||||
with adaptations by Raymond Hettinger <python@rcn.com>
|
||||
Copyright (c) 2004, 2005, 2006 Python Software Foundation.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
/* reduce() *************************************************************/
|
||||
|
||||
static PyObject *
|
||||
functools_reduce(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *seq, *func, *result = NULL, *it;
|
||||
|
||||
if (!PyArg_UnpackTuple(args, "reduce", 2, 3, &func, &seq, &result))
|
||||
return NULL;
|
||||
if (result != NULL)
|
||||
Py_INCREF(result);
|
||||
|
||||
it = PyObject_GetIter(seq);
|
||||
if (it == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"reduce() arg 2 must support iteration");
|
||||
Py_XDECREF(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((args = PyTuple_New(2)) == NULL)
|
||||
goto Fail;
|
||||
|
||||
for (;;) {
|
||||
PyObject *op2;
|
||||
|
||||
if (args->ob_refcnt > 1) {
|
||||
Py_DECREF(args);
|
||||
if ((args = PyTuple_New(2)) == NULL)
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
op2 = PyIter_Next(it);
|
||||
if (op2 == NULL) {
|
||||
if (PyErr_Occurred())
|
||||
goto Fail;
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == NULL)
|
||||
result = op2;
|
||||
else {
|
||||
PyTuple_SetItem(args, 0, result);
|
||||
PyTuple_SetItem(args, 1, op2);
|
||||
if ((result = PyEval_CallObject(func, args)) == NULL)
|
||||
goto Fail;
|
||||
}
|
||||
}
|
||||
|
||||
Py_DECREF(args);
|
||||
|
||||
if (result == NULL)
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"reduce() of empty sequence with no initial value");
|
||||
|
||||
Py_DECREF(it);
|
||||
return result;
|
||||
|
||||
Fail:
|
||||
Py_XDECREF(args);
|
||||
Py_XDECREF(result);
|
||||
Py_DECREF(it);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(reduce_doc,
|
||||
"reduce(function, sequence[, initial]) -> value\n\
|
||||
\n\
|
||||
Apply a function of two arguments cumulatively to the items of a sequence,\n\
|
||||
from left to right, so as to reduce the sequence to a single value.\n\
|
||||
For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\
|
||||
((((1+2)+3)+4)+5). If initial is present, it is placed before the items\n\
|
||||
of the sequence in the calculation, and serves as a default when the\n\
|
||||
sequence is empty.");
|
||||
|
||||
|
||||
|
||||
|
||||
/* partial object **********************************************************/
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PyObject *fn;
|
||||
PyObject *args;
|
||||
PyObject *kw;
|
||||
PyObject *dict;
|
||||
PyObject *weakreflist; /* List of weak references */
|
||||
} partialobject;
|
||||
|
||||
static PyTypeObject partial_type;
|
||||
|
||||
static PyObject *
|
||||
partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||
{
|
||||
PyObject *func;
|
||||
partialobject *pto;
|
||||
|
||||
if (PyTuple_GET_SIZE(args) < 1) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"type 'partial' takes at least one argument");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
func = PyTuple_GET_ITEM(args, 0);
|
||||
if (!PyCallable_Check(func)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"the first argument must be callable");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* create partialobject structure */
|
||||
pto = (partialobject *)type->tp_alloc(type, 0);
|
||||
if (pto == NULL)
|
||||
return NULL;
|
||||
|
||||
pto->fn = func;
|
||||
Py_INCREF(func);
|
||||
pto->args = PyTuple_GetSlice(args, 1, PY_SSIZE_T_MAX);
|
||||
if (pto->args == NULL) {
|
||||
Py_DECREF(pto);
|
||||
return NULL;
|
||||
}
|
||||
pto->kw = (kw != NULL) ? PyDict_Copy(kw) : PyDict_New();
|
||||
if (pto->kw == NULL) {
|
||||
Py_DECREF(pto);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (PyObject *)pto;
|
||||
}
|
||||
|
||||
static void
|
||||
partial_dealloc(partialobject *pto)
|
||||
{
|
||||
/* bpo-31095: UnTrack is needed before calling any callbacks */
|
||||
PyObject_GC_UnTrack(pto);
|
||||
if (pto->weakreflist != NULL)
|
||||
PyObject_ClearWeakRefs((PyObject *) pto);
|
||||
Py_XDECREF(pto->fn);
|
||||
Py_XDECREF(pto->args);
|
||||
Py_XDECREF(pto->kw);
|
||||
Py_XDECREF(pto->dict);
|
||||
Py_TYPE(pto)->tp_free(pto);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
partial_call(partialobject *pto, PyObject *args, PyObject *kw)
|
||||
{
|
||||
PyObject *ret;
|
||||
PyObject *argappl, *kwappl;
|
||||
|
||||
assert (PyCallable_Check(pto->fn));
|
||||
assert (PyTuple_Check(pto->args));
|
||||
assert (PyDict_Check(pto->kw));
|
||||
|
||||
if (PyTuple_GET_SIZE(pto->args) == 0) {
|
||||
argappl = args;
|
||||
Py_INCREF(args);
|
||||
} else if (PyTuple_GET_SIZE(args) == 0) {
|
||||
argappl = pto->args;
|
||||
Py_INCREF(pto->args);
|
||||
} else {
|
||||
argappl = PySequence_Concat(pto->args, args);
|
||||
if (argappl == NULL)
|
||||
return NULL;
|
||||
assert(PyTuple_Check(argappl));
|
||||
}
|
||||
|
||||
if (PyDict_Size(pto->kw) == 0) {
|
||||
kwappl = kw;
|
||||
Py_XINCREF(kwappl);
|
||||
} else {
|
||||
kwappl = PyDict_Copy(pto->kw);
|
||||
if (kwappl == NULL) {
|
||||
Py_DECREF(argappl);
|
||||
return NULL;
|
||||
}
|
||||
if (kw != NULL) {
|
||||
if (PyDict_Merge(kwappl, kw, 1) != 0) {
|
||||
Py_DECREF(argappl);
|
||||
Py_DECREF(kwappl);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = PyObject_Call(pto->fn, argappl, kwappl);
|
||||
Py_DECREF(argappl);
|
||||
Py_XDECREF(kwappl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
partial_traverse(partialobject *pto, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(pto->fn);
|
||||
Py_VISIT(pto->args);
|
||||
Py_VISIT(pto->kw);
|
||||
Py_VISIT(pto->dict);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(partial_doc,
|
||||
"partial(func, *args, **keywords) - new function with partial application\n\
|
||||
of the given arguments and keywords.\n");
|
||||
|
||||
#define OFF(x) offsetof(partialobject, x)
|
||||
static PyMemberDef partial_memberlist[] = {
|
||||
{"func", T_OBJECT, OFF(fn), READONLY,
|
||||
"function object to use in future partial calls"},
|
||||
{"args", T_OBJECT, OFF(args), READONLY,
|
||||
"tuple of arguments to future partial calls"},
|
||||
{"keywords", T_OBJECT, OFF(kw), READONLY,
|
||||
"dictionary of keyword arguments to future partial calls"},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
partial_get_dict(partialobject *pto)
|
||||
{
|
||||
if (pto->dict == NULL) {
|
||||
pto->dict = PyDict_New();
|
||||
if (pto->dict == NULL)
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(pto->dict);
|
||||
return pto->dict;
|
||||
}
|
||||
|
||||
static int
|
||||
partial_set_dict(partialobject *pto, PyObject *value)
|
||||
{
|
||||
PyObject *tmp;
|
||||
|
||||
/* It is illegal to del p.__dict__ */
|
||||
if (value == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"a partial object's dictionary may not be deleted");
|
||||
return -1;
|
||||
}
|
||||
/* Can only set __dict__ to a dictionary */
|
||||
if (!PyDict_Check(value)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"setting partial object's dictionary to a non-dict");
|
||||
return -1;
|
||||
}
|
||||
tmp = pto->dict;
|
||||
Py_INCREF(value);
|
||||
pto->dict = value;
|
||||
Py_XDECREF(tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyGetSetDef partial_getsetlist[] = {
|
||||
{"__dict__", (getter)partial_get_dict, (setter)partial_set_dict},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
/* Pickle strategy:
|
||||
__reduce__ by itself doesn't support getting kwargs in the unpickle
|
||||
operation so we define a __setstate__ that replaces all the information
|
||||
about the partial. If we only replaced part of it someone would use
|
||||
it as a hook to do strange things.
|
||||
*/
|
||||
|
||||
PyObject *
|
||||
partial_reduce(partialobject *pto, PyObject *unused)
|
||||
{
|
||||
return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto), pto->fn, pto->fn,
|
||||
pto->args, pto->kw,
|
||||
pto->dict ? pto->dict : Py_None);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
partial_setstate(partialobject *pto, PyObject *state)
|
||||
{
|
||||
PyObject *fn, *fnargs, *kw, *dict;
|
||||
|
||||
if (!PyTuple_Check(state) ||
|
||||
!PyArg_ParseTuple(state, "OOOO", &fn, &fnargs, &kw, &dict) ||
|
||||
!PyCallable_Check(fn) ||
|
||||
!PyTuple_Check(fnargs) ||
|
||||
(kw != Py_None && !PyDict_Check(kw)))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "invalid partial state");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!PyTuple_CheckExact(fnargs))
|
||||
fnargs = PySequence_Tuple(fnargs);
|
||||
else
|
||||
Py_INCREF(fnargs);
|
||||
if (fnargs == NULL)
|
||||
return NULL;
|
||||
|
||||
if (kw == Py_None)
|
||||
kw = PyDict_New();
|
||||
else if(!PyDict_CheckExact(kw))
|
||||
kw = PyDict_Copy(kw);
|
||||
else
|
||||
Py_INCREF(kw);
|
||||
if (kw == NULL) {
|
||||
Py_DECREF(fnargs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_INCREF(fn);
|
||||
if (dict == Py_None)
|
||||
dict = NULL;
|
||||
else
|
||||
Py_INCREF(dict);
|
||||
|
||||
Py_SETREF(pto->fn, fn);
|
||||
Py_SETREF(pto->args, fnargs);
|
||||
Py_SETREF(pto->kw, kw);
|
||||
Py_XSETREF(pto->dict, dict);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyMethodDef partial_methods[] = {
|
||||
{"__reduce__", (PyCFunction)partial_reduce, METH_NOARGS},
|
||||
{"__setstate__", (PyCFunction)partial_setstate, METH_O},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static PyTypeObject partial_type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"functools.partial", /* tp_name */
|
||||
sizeof(partialobject), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
/* methods */
|
||||
(destructor)partial_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
0, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
(ternaryfunc)partial_call, /* tp_call */
|
||||
0, /* tp_str */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
PyObject_GenericSetAttr, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
|
||||
Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */
|
||||
partial_doc, /* tp_doc */
|
||||
(traverseproc)partial_traverse, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
offsetof(partialobject, weakreflist), /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
partial_methods, /* tp_methods */
|
||||
partial_memberlist, /* tp_members */
|
||||
partial_getsetlist, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
offsetof(partialobject, dict), /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
partial_new, /* tp_new */
|
||||
PyObject_GC_Del, /* tp_free */
|
||||
};
|
||||
|
||||
|
||||
/* module level code ********************************************************/
|
||||
|
||||
PyDoc_STRVAR(module_doc,
|
||||
"Tools that operate on functions.");
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
{"reduce", functools_reduce, METH_VARARGS, reduce_doc},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC
|
||||
init_functools(void)
|
||||
{
|
||||
int i;
|
||||
PyObject *m;
|
||||
char *name;
|
||||
PyTypeObject *typelist[] = {
|
||||
&partial_type,
|
||||
NULL
|
||||
};
|
||||
|
||||
m = Py_InitModule3("_functools", module_methods, module_doc);
|
||||
if (m == NULL)
|
||||
return;
|
||||
|
||||
for (i=0 ; typelist[i] != NULL ; i++) {
|
||||
if (PyType_Ready(typelist[i]) < 0)
|
||||
return;
|
||||
name = strchr(typelist[i]->tp_name, '.');
|
||||
assert (name != NULL);
|
||||
Py_INCREF(typelist[i]);
|
||||
PyModule_AddObject(m, name+1, (PyObject *)typelist[i]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,945 @@
|
||||
/* Module that wraps all OpenSSL hash algorithms */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Gregory P. Smith (greg@krypto.org)
|
||||
* Licensed to PSF under a Contributor Agreement.
|
||||
*
|
||||
* Derived from a skeleton of shamodule.c containing work performed by:
|
||||
*
|
||||
* Andrew Kuchling (amk@amk.ca)
|
||||
* Greg Stein (gstein@lyra.org)
|
||||
*
|
||||
*/
|
||||
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
|
||||
#include "Python.h"
|
||||
#include "structmember.h"
|
||||
|
||||
#ifdef WITH_THREAD
|
||||
#include "pythread.h"
|
||||
#define ENTER_HASHLIB(obj) \
|
||||
if ((obj)->lock) { \
|
||||
if (!PyThread_acquire_lock((obj)->lock, 0)) { \
|
||||
Py_BEGIN_ALLOW_THREADS \
|
||||
PyThread_acquire_lock((obj)->lock, 1); \
|
||||
Py_END_ALLOW_THREADS \
|
||||
} \
|
||||
}
|
||||
#define LEAVE_HASHLIB(obj) \
|
||||
if ((obj)->lock) { \
|
||||
PyThread_release_lock((obj)->lock); \
|
||||
}
|
||||
#else
|
||||
#define ENTER_HASHLIB(obj)
|
||||
#define LEAVE_HASHLIB(obj)
|
||||
#endif
|
||||
|
||||
/* EVP is the preferred interface to hashing in OpenSSL */
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
/* We use the object interface to discover what hashes OpenSSL supports. */
|
||||
#include <openssl/objects.h>
|
||||
#include "openssl/err.h"
|
||||
|
||||
#define MUNCH_SIZE INT_MAX
|
||||
|
||||
/* TODO(gps): We should probably make this a module or EVPobject attribute
|
||||
* to allow the user to optimize based on the platform they're using. */
|
||||
#define HASHLIB_GIL_MINSIZE 2048
|
||||
|
||||
#ifndef HASH_OBJ_CONSTRUCTOR
|
||||
#define HASH_OBJ_CONSTRUCTOR 0
|
||||
#endif
|
||||
|
||||
#if defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x00908000)
|
||||
#define _OPENSSL_SUPPORTS_SHA2
|
||||
#endif
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
|
||||
/* OpenSSL < 1.1.0 */
|
||||
#define EVP_MD_CTX_new EVP_MD_CTX_create
|
||||
#define EVP_MD_CTX_free EVP_MD_CTX_destroy
|
||||
#define HAS_FAST_PKCS5_PBKDF2_HMAC 0
|
||||
#include <openssl/hmac.h>
|
||||
#else
|
||||
/* OpenSSL >= 1.1.0 */
|
||||
#define HAS_FAST_PKCS5_PBKDF2_HMAC 1
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PyObject *name; /* name of this hash algorithm */
|
||||
EVP_MD_CTX *ctx; /* OpenSSL message digest context */
|
||||
#ifdef WITH_THREAD
|
||||
PyThread_type_lock lock; /* OpenSSL context lock */
|
||||
#endif
|
||||
} EVPobject;
|
||||
|
||||
|
||||
static PyTypeObject EVPtype;
|
||||
|
||||
|
||||
#define DEFINE_CONSTS_FOR_NEW(Name) \
|
||||
static PyObject *CONST_ ## Name ## _name_obj = NULL; \
|
||||
static EVP_MD_CTX *CONST_new_ ## Name ## _ctx_p = NULL;
|
||||
|
||||
DEFINE_CONSTS_FOR_NEW(md5)
|
||||
DEFINE_CONSTS_FOR_NEW(sha1)
|
||||
#ifdef _OPENSSL_SUPPORTS_SHA2
|
||||
DEFINE_CONSTS_FOR_NEW(sha224)
|
||||
DEFINE_CONSTS_FOR_NEW(sha256)
|
||||
DEFINE_CONSTS_FOR_NEW(sha384)
|
||||
DEFINE_CONSTS_FOR_NEW(sha512)
|
||||
#endif
|
||||
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
static PyObject *
|
||||
_setException(PyObject *exc)
|
||||
{
|
||||
unsigned long errcode;
|
||||
const char *lib, *func, *reason;
|
||||
|
||||
errcode = ERR_peek_last_error();
|
||||
if (!errcode) {
|
||||
PyErr_SetString(exc, "unknown reasons");
|
||||
return NULL;
|
||||
}
|
||||
ERR_clear_error();
|
||||
|
||||
lib = ERR_lib_error_string(errcode);
|
||||
func = ERR_func_error_string(errcode);
|
||||
reason = ERR_reason_error_string(errcode);
|
||||
|
||||
if (lib && func) {
|
||||
PyErr_Format(exc, "[%s: %s] %s", lib, func, reason);
|
||||
}
|
||||
else if (lib) {
|
||||
PyErr_Format(exc, "[%s] %s", lib, reason);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(exc, reason);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
/* LCOV_EXCL_STOP */
|
||||
|
||||
static EVPobject *
|
||||
newEVPobject(PyObject *name)
|
||||
{
|
||||
EVPobject *retval = (EVPobject *)PyObject_New(EVPobject, &EVPtype);
|
||||
if (retval == NULL)
|
||||
return NULL;
|
||||
|
||||
/* save the name for .name to return */
|
||||
Py_INCREF(name);
|
||||
retval->name = name;
|
||||
#ifdef WITH_THREAD
|
||||
retval->lock = NULL;
|
||||
#endif
|
||||
|
||||
retval->ctx = EVP_MD_CTX_new();
|
||||
if (retval->ctx == NULL) {
|
||||
Py_DECREF(retval);
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void
|
||||
EVP_hash(EVPobject *self, const void *vp, Py_ssize_t len)
|
||||
{
|
||||
unsigned int process;
|
||||
const unsigned char *cp = (const unsigned char *)vp;
|
||||
while (0 < len)
|
||||
{
|
||||
if (len > (Py_ssize_t)MUNCH_SIZE)
|
||||
process = MUNCH_SIZE;
|
||||
else
|
||||
process = Py_SAFE_DOWNCAST(len, Py_ssize_t, unsigned int);
|
||||
EVP_DigestUpdate(self->ctx, (const void*)cp, process);
|
||||
len -= process;
|
||||
cp += process;
|
||||
}
|
||||
}
|
||||
|
||||
/* Internal methods for a hash object */
|
||||
|
||||
static void
|
||||
EVP_dealloc(EVPobject *self)
|
||||
{
|
||||
#ifdef WITH_THREAD
|
||||
if (self->lock != NULL)
|
||||
PyThread_free_lock(self->lock);
|
||||
#endif
|
||||
EVP_MD_CTX_free(self->ctx);
|
||||
Py_XDECREF(self->name);
|
||||
PyObject_Del(self);
|
||||
}
|
||||
|
||||
static int
|
||||
locked_EVP_MD_CTX_copy(EVP_MD_CTX *new_ctx_p, EVPobject *self)
|
||||
{
|
||||
int result;
|
||||
ENTER_HASHLIB(self);
|
||||
/* XXX no error reporting */
|
||||
result = EVP_MD_CTX_copy(new_ctx_p, self->ctx);
|
||||
LEAVE_HASHLIB(self);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* External methods for a hash object */
|
||||
|
||||
PyDoc_STRVAR(EVP_copy__doc__, "Return a copy of the hash object.");
|
||||
|
||||
|
||||
static PyObject *
|
||||
EVP_copy(EVPobject *self, PyObject *unused)
|
||||
{
|
||||
EVPobject *newobj;
|
||||
|
||||
if ( (newobj = newEVPobject(self->name))==NULL)
|
||||
return NULL;
|
||||
|
||||
if (!locked_EVP_MD_CTX_copy(newobj->ctx, self)) {
|
||||
Py_DECREF(newobj);
|
||||
return _setException(PyExc_ValueError);
|
||||
}
|
||||
return (PyObject *)newobj;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(EVP_digest__doc__,
|
||||
"Return the digest value as a string of binary data.");
|
||||
|
||||
static PyObject *
|
||||
EVP_digest(EVPobject *self, PyObject *unused)
|
||||
{
|
||||
unsigned char digest[EVP_MAX_MD_SIZE];
|
||||
EVP_MD_CTX *temp_ctx;
|
||||
PyObject *retval;
|
||||
unsigned int digest_size;
|
||||
|
||||
temp_ctx = EVP_MD_CTX_new();
|
||||
if (temp_ctx == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!locked_EVP_MD_CTX_copy(temp_ctx, self)) {
|
||||
return _setException(PyExc_ValueError);
|
||||
}
|
||||
digest_size = EVP_MD_CTX_size(temp_ctx);
|
||||
EVP_DigestFinal(temp_ctx, digest, NULL);
|
||||
|
||||
retval = PyString_FromStringAndSize((const char *)digest, digest_size);
|
||||
EVP_MD_CTX_free(temp_ctx);
|
||||
return retval;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(EVP_hexdigest__doc__,
|
||||
"Return the digest value as a string of hexadecimal digits.");
|
||||
|
||||
static PyObject *
|
||||
EVP_hexdigest(EVPobject *self, PyObject *unused)
|
||||
{
|
||||
unsigned char digest[EVP_MAX_MD_SIZE];
|
||||
EVP_MD_CTX *temp_ctx;
|
||||
PyObject *retval;
|
||||
char *hex_digest;
|
||||
unsigned int i, j, digest_size;
|
||||
|
||||
temp_ctx = EVP_MD_CTX_new();
|
||||
if (temp_ctx == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get the raw (binary) digest value */
|
||||
if (!locked_EVP_MD_CTX_copy(temp_ctx, self)) {
|
||||
return _setException(PyExc_ValueError);
|
||||
}
|
||||
digest_size = EVP_MD_CTX_size(temp_ctx);
|
||||
EVP_DigestFinal(temp_ctx, digest, NULL);
|
||||
|
||||
EVP_MD_CTX_free(temp_ctx);
|
||||
|
||||
/* Create a new string */
|
||||
/* NOTE: not thread safe! modifying an already created string object */
|
||||
/* (not a problem because we hold the GIL by default) */
|
||||
retval = PyString_FromStringAndSize(NULL, digest_size * 2);
|
||||
if (!retval)
|
||||
return NULL;
|
||||
hex_digest = PyString_AsString(retval);
|
||||
if (!hex_digest) {
|
||||
Py_DECREF(retval);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Make hex version of the digest */
|
||||
for(i=j=0; i<digest_size; i++) {
|
||||
char c;
|
||||
c = (digest[i] >> 4) & 0xf;
|
||||
c = (c>9) ? c+'a'-10 : c + '0';
|
||||
hex_digest[j++] = c;
|
||||
c = (digest[i] & 0xf);
|
||||
c = (c>9) ? c+'a'-10 : c + '0';
|
||||
hex_digest[j++] = c;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(EVP_update__doc__,
|
||||
"Update this hash object's state with the provided string.");
|
||||
|
||||
static PyObject *
|
||||
EVP_update(EVPobject *self, PyObject *args)
|
||||
{
|
||||
Py_buffer view;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s*:update", &view))
|
||||
return NULL;
|
||||
|
||||
#ifdef WITH_THREAD
|
||||
if (self->lock == NULL && view.len >= HASHLIB_GIL_MINSIZE) {
|
||||
self->lock = PyThread_allocate_lock();
|
||||
/* fail? lock = NULL and we fail over to non-threaded code. */
|
||||
}
|
||||
|
||||
if (self->lock != NULL) {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
PyThread_acquire_lock(self->lock, 1);
|
||||
EVP_hash(self, view.buf, view.len);
|
||||
PyThread_release_lock(self->lock);
|
||||
Py_END_ALLOW_THREADS
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
EVP_hash(self, view.buf, view.len);
|
||||
}
|
||||
|
||||
PyBuffer_Release(&view);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyMethodDef EVP_methods[] = {
|
||||
{"update", (PyCFunction)EVP_update, METH_VARARGS, EVP_update__doc__},
|
||||
{"digest", (PyCFunction)EVP_digest, METH_NOARGS, EVP_digest__doc__},
|
||||
{"hexdigest", (PyCFunction)EVP_hexdigest, METH_NOARGS, EVP_hexdigest__doc__},
|
||||
{"copy", (PyCFunction)EVP_copy, METH_NOARGS, EVP_copy__doc__},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
EVP_get_block_size(EVPobject *self, void *closure)
|
||||
{
|
||||
long block_size;
|
||||
block_size = EVP_MD_CTX_block_size(self->ctx);
|
||||
return PyLong_FromLong(block_size);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
EVP_get_digest_size(EVPobject *self, void *closure)
|
||||
{
|
||||
long size;
|
||||
size = EVP_MD_CTX_size(self->ctx);
|
||||
return PyLong_FromLong(size);
|
||||
}
|
||||
|
||||
static PyMemberDef EVP_members[] = {
|
||||
{"name", T_OBJECT, offsetof(EVPobject, name), READONLY, PyDoc_STR("algorithm name.")},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyGetSetDef EVP_getseters[] = {
|
||||
{"digest_size",
|
||||
(getter)EVP_get_digest_size, NULL,
|
||||
NULL,
|
||||
NULL},
|
||||
{"block_size",
|
||||
(getter)EVP_get_block_size, NULL,
|
||||
NULL,
|
||||
NULL},
|
||||
/* the old md5 and sha modules support 'digest_size' as in PEP 247.
|
||||
* the old sha module also supported 'digestsize'. ugh. */
|
||||
{"digestsize",
|
||||
(getter)EVP_get_digest_size, NULL,
|
||||
NULL,
|
||||
NULL},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
||||
static PyObject *
|
||||
EVP_repr(PyObject *self)
|
||||
{
|
||||
char buf[100];
|
||||
PyOS_snprintf(buf, sizeof(buf), "<%s HASH object @ %p>",
|
||||
PyString_AsString(((EVPobject *)self)->name), self);
|
||||
return PyString_FromString(buf);
|
||||
}
|
||||
|
||||
#if HASH_OBJ_CONSTRUCTOR
|
||||
static int
|
||||
EVP_tp_init(EVPobject *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static char *kwlist[] = {"name", "string", NULL};
|
||||
PyObject *name_obj = NULL;
|
||||
Py_buffer view = { 0 };
|
||||
char *nameStr;
|
||||
const EVP_MD *digest;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s*:HASH", kwlist,
|
||||
&name_obj, &view)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!PyArg_Parse(name_obj, "s", &nameStr)) {
|
||||
PyErr_SetString(PyExc_TypeError, "name must be a string");
|
||||
PyBuffer_Release(&view);
|
||||
return -1;
|
||||
}
|
||||
|
||||
digest = EVP_get_digestbyname(nameStr);
|
||||
if (!digest) {
|
||||
PyErr_SetString(PyExc_ValueError, "unknown hash function");
|
||||
PyBuffer_Release(&view);
|
||||
return -1;
|
||||
}
|
||||
EVP_DigestInit(self->ctx, digest);
|
||||
|
||||
self->name = name_obj;
|
||||
Py_INCREF(self->name);
|
||||
|
||||
if (view.obj) {
|
||||
if (view.len >= HASHLIB_GIL_MINSIZE) {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
EVP_hash(self, view.buf, view.len);
|
||||
Py_END_ALLOW_THREADS
|
||||
} else {
|
||||
EVP_hash(self, view.buf, view.len);
|
||||
}
|
||||
PyBuffer_Release(&view);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
PyDoc_STRVAR(hashtype_doc,
|
||||
"A hash represents the object used to calculate a checksum of a\n\
|
||||
string of information.\n\
|
||||
\n\
|
||||
Methods:\n\
|
||||
\n\
|
||||
update() -- updates the current digest with an additional string\n\
|
||||
digest() -- return the current digest value\n\
|
||||
hexdigest() -- return the current digest as a string of hexadecimal digits\n\
|
||||
copy() -- return a copy of the current hash object\n\
|
||||
\n\
|
||||
Attributes:\n\
|
||||
\n\
|
||||
name -- the hash algorithm being used by this object\n\
|
||||
digest_size -- number of bytes in this hashes output\n");
|
||||
|
||||
static PyTypeObject EVPtype = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"_hashlib.HASH", /*tp_name*/
|
||||
sizeof(EVPobject), /*tp_basicsize*/
|
||||
0, /*tp_itemsize*/
|
||||
/* methods */
|
||||
(destructor)EVP_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
EVP_repr, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
0, /*tp_hash*/
|
||||
0, /*tp_call*/
|
||||
0, /*tp_str*/
|
||||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
|
||||
hashtype_doc, /*tp_doc*/
|
||||
0, /*tp_traverse*/
|
||||
0, /*tp_clear*/
|
||||
0, /*tp_richcompare*/
|
||||
0, /*tp_weaklistoffset*/
|
||||
0, /*tp_iter*/
|
||||
0, /*tp_iternext*/
|
||||
EVP_methods, /* tp_methods */
|
||||
EVP_members, /* tp_members */
|
||||
EVP_getseters, /* tp_getset */
|
||||
#if 1
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
#endif
|
||||
#if HASH_OBJ_CONSTRUCTOR
|
||||
(initproc)EVP_tp_init, /* tp_init */
|
||||
#endif
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
EVPnew(PyObject *name_obj,
|
||||
const EVP_MD *digest, const EVP_MD_CTX *initial_ctx,
|
||||
const unsigned char *cp, Py_ssize_t len)
|
||||
{
|
||||
EVPobject *self;
|
||||
|
||||
if (!digest && !initial_ctx) {
|
||||
PyErr_SetString(PyExc_ValueError, "unsupported hash type");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((self = newEVPobject(name_obj)) == NULL)
|
||||
return NULL;
|
||||
|
||||
if (initial_ctx) {
|
||||
EVP_MD_CTX_copy(self->ctx, initial_ctx);
|
||||
} else {
|
||||
EVP_DigestInit(self->ctx, digest);
|
||||
}
|
||||
|
||||
if (cp && len) {
|
||||
if (len >= HASHLIB_GIL_MINSIZE) {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
EVP_hash(self, cp, len);
|
||||
Py_END_ALLOW_THREADS
|
||||
} else {
|
||||
EVP_hash(self, cp, len);
|
||||
}
|
||||
}
|
||||
|
||||
return (PyObject *)self;
|
||||
}
|
||||
|
||||
|
||||
/* The module-level function: new() */
|
||||
|
||||
PyDoc_STRVAR(EVP_new__doc__,
|
||||
"Return a new hash object using the named algorithm.\n\
|
||||
An optional string argument may be provided and will be\n\
|
||||
automatically hashed.\n\
|
||||
\n\
|
||||
The MD5 and SHA1 algorithms are always supported.\n");
|
||||
|
||||
static PyObject *
|
||||
EVP_new(PyObject *self, PyObject *args, PyObject *kwdict)
|
||||
{
|
||||
static char *kwlist[] = {"name", "string", NULL};
|
||||
PyObject *name_obj = NULL;
|
||||
Py_buffer view = { 0 };
|
||||
PyObject *ret_obj;
|
||||
char *name;
|
||||
const EVP_MD *digest;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O|s*:new", kwlist,
|
||||
&name_obj, &view)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!PyArg_Parse(name_obj, "s", &name)) {
|
||||
PyBuffer_Release(&view);
|
||||
PyErr_SetString(PyExc_TypeError, "name must be a string");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
digest = EVP_get_digestbyname(name);
|
||||
|
||||
ret_obj = EVPnew(name_obj, digest, NULL, (unsigned char*)view.buf,
|
||||
view.len);
|
||||
PyBuffer_Release(&view);
|
||||
|
||||
return ret_obj;
|
||||
}
|
||||
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x10000000 && !defined(OPENSSL_NO_HMAC) \
|
||||
&& !defined(OPENSSL_NO_SHA))
|
||||
|
||||
#define PY_PBKDF2_HMAC 1
|
||||
|
||||
#if !HAS_FAST_PKCS5_PBKDF2_HMAC
|
||||
/* Improved implementation of PKCS5_PBKDF2_HMAC()
|
||||
*
|
||||
* PKCS5_PBKDF2_HMAC_fast() hashes the password exactly one time instead of
|
||||
* `iter` times. Today (2013) the iteration count is typically 100,000 or
|
||||
* more. The improved algorithm is not subject to a Denial-of-Service
|
||||
* vulnerability with overly large passwords.
|
||||
*
|
||||
* Also OpenSSL < 1.0 don't provide PKCS5_PBKDF2_HMAC(), only
|
||||
* PKCS5_PBKDF2_SHA1.
|
||||
*/
|
||||
static int
|
||||
PKCS5_PBKDF2_HMAC_fast(const char *pass, int passlen,
|
||||
const unsigned char *salt, int saltlen,
|
||||
int iter, const EVP_MD *digest,
|
||||
int keylen, unsigned char *out)
|
||||
{
|
||||
unsigned char digtmp[EVP_MAX_MD_SIZE], *p, itmp[4];
|
||||
int cplen, j, k, tkeylen, mdlen;
|
||||
unsigned long i = 1;
|
||||
HMAC_CTX hctx_tpl, hctx;
|
||||
|
||||
mdlen = EVP_MD_size(digest);
|
||||
if (mdlen < 0)
|
||||
return 0;
|
||||
|
||||
HMAC_CTX_init(&hctx_tpl);
|
||||
HMAC_CTX_init(&hctx);
|
||||
p = out;
|
||||
tkeylen = keylen;
|
||||
if (!HMAC_Init_ex(&hctx_tpl, pass, passlen, digest, NULL)) {
|
||||
HMAC_CTX_cleanup(&hctx_tpl);
|
||||
return 0;
|
||||
}
|
||||
while (tkeylen) {
|
||||
if (tkeylen > mdlen)
|
||||
cplen = mdlen;
|
||||
else
|
||||
cplen = tkeylen;
|
||||
/* We are unlikely to ever use more than 256 blocks (5120 bits!)
|
||||
* but just in case...
|
||||
*/
|
||||
itmp[0] = (unsigned char)((i >> 24) & 0xff);
|
||||
itmp[1] = (unsigned char)((i >> 16) & 0xff);
|
||||
itmp[2] = (unsigned char)((i >> 8) & 0xff);
|
||||
itmp[3] = (unsigned char)(i & 0xff);
|
||||
if (!HMAC_CTX_copy(&hctx, &hctx_tpl)) {
|
||||
HMAC_CTX_cleanup(&hctx_tpl);
|
||||
return 0;
|
||||
}
|
||||
if (!HMAC_Update(&hctx, salt, saltlen)
|
||||
|| !HMAC_Update(&hctx, itmp, 4)
|
||||
|| !HMAC_Final(&hctx, digtmp, NULL)) {
|
||||
HMAC_CTX_cleanup(&hctx_tpl);
|
||||
HMAC_CTX_cleanup(&hctx);
|
||||
return 0;
|
||||
}
|
||||
HMAC_CTX_cleanup(&hctx);
|
||||
memcpy(p, digtmp, cplen);
|
||||
for (j = 1; j < iter; j++) {
|
||||
if (!HMAC_CTX_copy(&hctx, &hctx_tpl)) {
|
||||
HMAC_CTX_cleanup(&hctx_tpl);
|
||||
return 0;
|
||||
}
|
||||
if (!HMAC_Update(&hctx, digtmp, mdlen)
|
||||
|| !HMAC_Final(&hctx, digtmp, NULL)) {
|
||||
HMAC_CTX_cleanup(&hctx_tpl);
|
||||
HMAC_CTX_cleanup(&hctx);
|
||||
return 0;
|
||||
}
|
||||
HMAC_CTX_cleanup(&hctx);
|
||||
for (k = 0; k < cplen; k++) {
|
||||
p[k] ^= digtmp[k];
|
||||
}
|
||||
}
|
||||
tkeylen-= cplen;
|
||||
i++;
|
||||
p+= cplen;
|
||||
}
|
||||
HMAC_CTX_cleanup(&hctx_tpl);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
PyDoc_STRVAR(pbkdf2_hmac__doc__,
|
||||
"pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None) -> key\n\
|
||||
\n\
|
||||
Password based key derivation function 2 (PKCS #5 v2.0) with HMAC as\n\
|
||||
pseudorandom function.");
|
||||
|
||||
static PyObject *
|
||||
pbkdf2_hmac(PyObject *self, PyObject *args, PyObject *kwdict)
|
||||
{
|
||||
static char *kwlist[] = {"hash_name", "password", "salt", "iterations",
|
||||
"dklen", NULL};
|
||||
PyObject *key_obj = NULL, *dklen_obj = Py_None;
|
||||
char *name, *key;
|
||||
Py_buffer password, salt;
|
||||
long iterations, dklen;
|
||||
int retval;
|
||||
const EVP_MD *digest;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "ss*s*l|O:pbkdf2_hmac",
|
||||
kwlist, &name, &password, &salt,
|
||||
&iterations, &dklen_obj)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
digest = EVP_get_digestbyname(name);
|
||||
if (digest == NULL) {
|
||||
PyErr_SetString(PyExc_ValueError, "unsupported hash type");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (password.len > INT_MAX) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"password is too long.");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (salt.len > INT_MAX) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"salt is too long.");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (iterations < 1) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"iteration value must be greater than 0.");
|
||||
goto end;
|
||||
}
|
||||
if (iterations > INT_MAX) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"iteration value is too great.");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (dklen_obj == Py_None) {
|
||||
dklen = EVP_MD_size(digest);
|
||||
} else {
|
||||
dklen = PyLong_AsLong(dklen_obj);
|
||||
if ((dklen == -1) && PyErr_Occurred()) {
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
if (dklen < 1) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"key length must be greater than 0.");
|
||||
goto end;
|
||||
}
|
||||
if (dklen > INT_MAX) {
|
||||
/* INT_MAX is always smaller than dkLen max (2^32 - 1) * hLen */
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"key length is too great.");
|
||||
goto end;
|
||||
}
|
||||
|
||||
key_obj = PyBytes_FromStringAndSize(NULL, dklen);
|
||||
if (key_obj == NULL) {
|
||||
goto end;
|
||||
}
|
||||
key = PyBytes_AS_STRING(key_obj);
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
#if HAS_FAST_PKCS5_PBKDF2_HMAC
|
||||
retval = PKCS5_PBKDF2_HMAC((char*)password.buf, (int)password.len,
|
||||
(unsigned char *)salt.buf, (int)salt.len,
|
||||
iterations, digest, dklen,
|
||||
(unsigned char *)key);
|
||||
#else
|
||||
retval = PKCS5_PBKDF2_HMAC_fast((char*)password.buf, (int)password.len,
|
||||
(unsigned char *)salt.buf, (int)salt.len,
|
||||
iterations, digest, dklen,
|
||||
(unsigned char *)key);
|
||||
#endif
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (!retval) {
|
||||
Py_CLEAR(key_obj);
|
||||
_setException(PyExc_ValueError);
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
PyBuffer_Release(&password);
|
||||
PyBuffer_Release(&salt);
|
||||
return key_obj;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* State for our callback function so that it can accumulate a result. */
|
||||
typedef struct _internal_name_mapper_state {
|
||||
PyObject *set;
|
||||
int error;
|
||||
} _InternalNameMapperState;
|
||||
|
||||
|
||||
/* A callback function to pass to OpenSSL's OBJ_NAME_do_all(...) */
|
||||
static void
|
||||
_openssl_hash_name_mapper(const OBJ_NAME *openssl_obj_name, void *arg)
|
||||
{
|
||||
_InternalNameMapperState *state = (_InternalNameMapperState *)arg;
|
||||
PyObject *py_name;
|
||||
|
||||
assert(state != NULL);
|
||||
if (openssl_obj_name == NULL)
|
||||
return;
|
||||
/* Ignore aliased names, they pollute the list and OpenSSL appears to
|
||||
* have its own definition of alias as the resulting list still
|
||||
* contains duplicate and alternate names for several algorithms. */
|
||||
if (openssl_obj_name->alias)
|
||||
return;
|
||||
|
||||
py_name = PyString_FromString(openssl_obj_name->name);
|
||||
if (py_name == NULL) {
|
||||
state->error = 1;
|
||||
} else {
|
||||
if (PySet_Add(state->set, py_name) != 0) {
|
||||
state->error = 1;
|
||||
}
|
||||
Py_DECREF(py_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Ask OpenSSL for a list of supported ciphers, filling in a Python set. */
|
||||
static PyObject*
|
||||
generate_hash_name_list(void)
|
||||
{
|
||||
_InternalNameMapperState state;
|
||||
state.set = PyFrozenSet_New(NULL);
|
||||
if (state.set == NULL)
|
||||
return NULL;
|
||||
state.error = 0;
|
||||
|
||||
OBJ_NAME_do_all(OBJ_NAME_TYPE_MD_METH, &_openssl_hash_name_mapper, &state);
|
||||
|
||||
if (state.error) {
|
||||
Py_DECREF(state.set);
|
||||
return NULL;
|
||||
}
|
||||
return state.set;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This macro generates constructor function definitions for specific
|
||||
* hash algorithms. These constructors are much faster than calling
|
||||
* the generic one passing it a python string and are noticeably
|
||||
* faster than calling a python new() wrapper. Thats important for
|
||||
* code that wants to make hashes of a bunch of small strings.
|
||||
*/
|
||||
#define GEN_CONSTRUCTOR(NAME) \
|
||||
static PyObject * \
|
||||
EVP_new_ ## NAME (PyObject *self, PyObject *args) \
|
||||
{ \
|
||||
Py_buffer view = { 0 }; \
|
||||
PyObject *ret_obj; \
|
||||
\
|
||||
if (!PyArg_ParseTuple(args, "|s*:" #NAME , &view)) { \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
ret_obj = EVPnew( \
|
||||
CONST_ ## NAME ## _name_obj, \
|
||||
NULL, \
|
||||
CONST_new_ ## NAME ## _ctx_p, \
|
||||
(unsigned char*)view.buf, view.len); \
|
||||
PyBuffer_Release(&view); \
|
||||
return ret_obj; \
|
||||
}
|
||||
|
||||
/* a PyMethodDef structure for the constructor */
|
||||
#define CONSTRUCTOR_METH_DEF(NAME) \
|
||||
{"openssl_" #NAME, (PyCFunction)EVP_new_ ## NAME, METH_VARARGS, \
|
||||
PyDoc_STR("Returns a " #NAME \
|
||||
" hash object; optionally initialized with a string") \
|
||||
}
|
||||
|
||||
/* used in the init function to setup a constructor: initialize OpenSSL
|
||||
constructor constants if they haven't been initialized already. */
|
||||
#define INIT_CONSTRUCTOR_CONSTANTS(NAME) do { \
|
||||
if (CONST_ ## NAME ## _name_obj == NULL) { \
|
||||
CONST_ ## NAME ## _name_obj = PyString_FromString(#NAME); \
|
||||
if (EVP_get_digestbyname(#NAME)) { \
|
||||
CONST_new_ ## NAME ## _ctx_p = EVP_MD_CTX_new(); \
|
||||
EVP_DigestInit(CONST_new_ ## NAME ## _ctx_p, EVP_get_digestbyname(#NAME)); \
|
||||
} \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
GEN_CONSTRUCTOR(md5)
|
||||
GEN_CONSTRUCTOR(sha1)
|
||||
#ifdef _OPENSSL_SUPPORTS_SHA2
|
||||
GEN_CONSTRUCTOR(sha224)
|
||||
GEN_CONSTRUCTOR(sha256)
|
||||
GEN_CONSTRUCTOR(sha384)
|
||||
GEN_CONSTRUCTOR(sha512)
|
||||
#endif
|
||||
|
||||
/* List of functions exported by this module */
|
||||
|
||||
static struct PyMethodDef EVP_functions[] = {
|
||||
{"new", (PyCFunction)EVP_new, METH_VARARGS|METH_KEYWORDS, EVP_new__doc__},
|
||||
CONSTRUCTOR_METH_DEF(md5),
|
||||
CONSTRUCTOR_METH_DEF(sha1),
|
||||
#ifdef _OPENSSL_SUPPORTS_SHA2
|
||||
CONSTRUCTOR_METH_DEF(sha224),
|
||||
CONSTRUCTOR_METH_DEF(sha256),
|
||||
CONSTRUCTOR_METH_DEF(sha384),
|
||||
CONSTRUCTOR_METH_DEF(sha512),
|
||||
#endif
|
||||
#ifdef PY_PBKDF2_HMAC
|
||||
{"pbkdf2_hmac", (PyCFunction)pbkdf2_hmac, METH_VARARGS|METH_KEYWORDS,
|
||||
pbkdf2_hmac__doc__},
|
||||
#endif
|
||||
{NULL, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
||||
/* Initialize this module. */
|
||||
|
||||
PyMODINIT_FUNC
|
||||
init_hashlib(void)
|
||||
{
|
||||
PyObject *m, *openssl_md_meth_names;
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
|
||||
/* Load all digest algorithms and initialize cpuid */
|
||||
OPENSSL_add_all_algorithms_noconf();
|
||||
ERR_load_crypto_strings();
|
||||
#endif
|
||||
|
||||
/* TODO build EVP_functions openssl_* entries dynamically based
|
||||
* on what hashes are supported rather than listing many
|
||||
* but having some be unsupported. Only init appropriate
|
||||
* constants. */
|
||||
|
||||
Py_TYPE(&EVPtype) = &PyType_Type;
|
||||
if (PyType_Ready(&EVPtype) < 0)
|
||||
return;
|
||||
|
||||
m = Py_InitModule("_hashlib", EVP_functions);
|
||||
if (m == NULL)
|
||||
return;
|
||||
|
||||
openssl_md_meth_names = generate_hash_name_list();
|
||||
if (openssl_md_meth_names == NULL) {
|
||||
return;
|
||||
}
|
||||
if (PyModule_AddObject(m, "openssl_md_meth_names", openssl_md_meth_names)) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if HASH_OBJ_CONSTRUCTOR
|
||||
Py_INCREF(&EVPtype);
|
||||
PyModule_AddObject(m, "HASH", (PyObject *)&EVPtype);
|
||||
#endif
|
||||
|
||||
/* these constants are used by the convenience constructors */
|
||||
INIT_CONSTRUCTOR_CONSTANTS(md5);
|
||||
INIT_CONSTRUCTOR_CONSTANTS(sha1);
|
||||
#ifdef _OPENSSL_SUPPORTS_SHA2
|
||||
INIT_CONSTRUCTOR_CONSTANTS(sha224);
|
||||
INIT_CONSTRUCTOR_CONSTANTS(sha256);
|
||||
INIT_CONSTRUCTOR_CONSTANTS(sha384);
|
||||
INIT_CONSTRUCTOR_CONSTANTS(sha512);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,701 @@
|
||||
/* Drop in replacement for heapq.py
|
||||
|
||||
C implementation derived directly from heapq.py in Py2.3
|
||||
which was written by Kevin O'Connor, augmented by Tim Peters,
|
||||
annotated by François Pinard, and converted to C by Raymond Hettinger.
|
||||
|
||||
*/
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
/* Older implementations of heapq used Py_LE for comparisons. Now, it uses
|
||||
Py_LT so it will match min(), sorted(), and bisect(). Unfortunately, some
|
||||
client code (Twisted for example) relied on Py_LE, so this little function
|
||||
restores compatibility by trying both.
|
||||
*/
|
||||
static int
|
||||
cmp_lt(PyObject *x, PyObject *y)
|
||||
{
|
||||
int cmp;
|
||||
static PyObject *lt = NULL;
|
||||
|
||||
if (lt == NULL) {
|
||||
lt = PyString_FromString("__lt__");
|
||||
if (lt == NULL)
|
||||
return -1;
|
||||
}
|
||||
if (PyObject_HasAttr(x, lt))
|
||||
return PyObject_RichCompareBool(x, y, Py_LT);
|
||||
cmp = PyObject_RichCompareBool(y, x, Py_LE);
|
||||
if (cmp != -1)
|
||||
cmp = 1 - cmp;
|
||||
return cmp;
|
||||
}
|
||||
|
||||
static int
|
||||
_siftdown(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
|
||||
{
|
||||
PyObject *newitem, *parent;
|
||||
Py_ssize_t parentpos, size;
|
||||
int cmp;
|
||||
|
||||
assert(PyList_Check(heap));
|
||||
size = PyList_GET_SIZE(heap);
|
||||
if (pos >= size) {
|
||||
PyErr_SetString(PyExc_IndexError, "index out of range");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Follow the path to the root, moving parents down until finding
|
||||
a place newitem fits. */
|
||||
newitem = PyList_GET_ITEM(heap, pos);
|
||||
while (pos > startpos) {
|
||||
parentpos = (pos - 1) >> 1;
|
||||
parent = PyList_GET_ITEM(heap, parentpos);
|
||||
cmp = cmp_lt(newitem, parent);
|
||||
if (cmp == -1)
|
||||
return -1;
|
||||
if (size != PyList_GET_SIZE(heap)) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"list changed size during iteration");
|
||||
return -1;
|
||||
}
|
||||
if (cmp == 0)
|
||||
break;
|
||||
parent = PyList_GET_ITEM(heap, parentpos);
|
||||
newitem = PyList_GET_ITEM(heap, pos);
|
||||
PyList_SET_ITEM(heap, parentpos, newitem);
|
||||
PyList_SET_ITEM(heap, pos, parent);
|
||||
pos = parentpos;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_siftup(PyListObject *heap, Py_ssize_t pos)
|
||||
{
|
||||
Py_ssize_t startpos, endpos, childpos, rightpos, limit;
|
||||
PyObject *tmp1, *tmp2;
|
||||
int cmp;
|
||||
|
||||
assert(PyList_Check(heap));
|
||||
endpos = PyList_GET_SIZE(heap);
|
||||
startpos = pos;
|
||||
if (pos >= endpos) {
|
||||
PyErr_SetString(PyExc_IndexError, "index out of range");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Bubble up the smaller child until hitting a leaf. */
|
||||
limit = endpos / 2; /* smallest pos that has no child */
|
||||
while (pos < limit) {
|
||||
/* Set childpos to index of smaller child. */
|
||||
childpos = 2*pos + 1; /* leftmost child position */
|
||||
rightpos = childpos + 1;
|
||||
if (rightpos < endpos) {
|
||||
cmp = cmp_lt(
|
||||
PyList_GET_ITEM(heap, childpos),
|
||||
PyList_GET_ITEM(heap, rightpos));
|
||||
if (cmp == -1)
|
||||
return -1;
|
||||
if (cmp == 0)
|
||||
childpos = rightpos;
|
||||
if (endpos != PyList_GET_SIZE(heap)) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"list changed size during iteration");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* Move the smaller child up. */
|
||||
tmp1 = PyList_GET_ITEM(heap, childpos);
|
||||
tmp2 = PyList_GET_ITEM(heap, pos);
|
||||
PyList_SET_ITEM(heap, childpos, tmp2);
|
||||
PyList_SET_ITEM(heap, pos, tmp1);
|
||||
pos = childpos;
|
||||
}
|
||||
/* Bubble it up to its final resting place (by sifting its parents down). */
|
||||
return _siftdown(heap, startpos, pos);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
heappush(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *heap, *item;
|
||||
|
||||
if (!PyArg_UnpackTuple(args, "heappush", 2, 2, &heap, &item))
|
||||
return NULL;
|
||||
|
||||
if (!PyList_Check(heap)) {
|
||||
PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (PyList_Append(heap, item) == -1)
|
||||
return NULL;
|
||||
|
||||
if (_siftdown((PyListObject *)heap, 0, PyList_GET_SIZE(heap)-1) == -1)
|
||||
return NULL;
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(heappush_doc,
|
||||
"heappush(heap, item) -> None. Push item onto heap, maintaining the heap invariant.");
|
||||
|
||||
static PyObject *
|
||||
heappop(PyObject *self, PyObject *heap)
|
||||
{
|
||||
PyObject *lastelt, *returnitem;
|
||||
Py_ssize_t n;
|
||||
|
||||
if (!PyList_Check(heap)) {
|
||||
PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* # raises appropriate IndexError if heap is empty */
|
||||
n = PyList_GET_SIZE(heap);
|
||||
if (n == 0) {
|
||||
PyErr_SetString(PyExc_IndexError, "index out of range");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lastelt = PyList_GET_ITEM(heap, n-1) ;
|
||||
Py_INCREF(lastelt);
|
||||
PyList_SetSlice(heap, n-1, n, NULL);
|
||||
n--;
|
||||
|
||||
if (!n)
|
||||
return lastelt;
|
||||
returnitem = PyList_GET_ITEM(heap, 0);
|
||||
PyList_SET_ITEM(heap, 0, lastelt);
|
||||
if (_siftup((PyListObject *)heap, 0) == -1) {
|
||||
Py_DECREF(returnitem);
|
||||
return NULL;
|
||||
}
|
||||
return returnitem;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(heappop_doc,
|
||||
"Pop the smallest item off the heap, maintaining the heap invariant.");
|
||||
|
||||
static PyObject *
|
||||
heapreplace(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *heap, *item, *returnitem;
|
||||
|
||||
if (!PyArg_UnpackTuple(args, "heapreplace", 2, 2, &heap, &item))
|
||||
return NULL;
|
||||
|
||||
if (!PyList_Check(heap)) {
|
||||
PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (PyList_GET_SIZE(heap) < 1) {
|
||||
PyErr_SetString(PyExc_IndexError, "index out of range");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
returnitem = PyList_GET_ITEM(heap, 0);
|
||||
Py_INCREF(item);
|
||||
PyList_SET_ITEM(heap, 0, item);
|
||||
if (_siftup((PyListObject *)heap, 0) == -1) {
|
||||
Py_DECREF(returnitem);
|
||||
return NULL;
|
||||
}
|
||||
return returnitem;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(heapreplace_doc,
|
||||
"heapreplace(heap, item) -> value. Pop and return the current smallest value, and add the new item.\n\
|
||||
\n\
|
||||
This is more efficient than heappop() followed by heappush(), and can be\n\
|
||||
more appropriate when using a fixed-size heap. Note that the value\n\
|
||||
returned may be larger than item! That constrains reasonable uses of\n\
|
||||
this routine unless written as part of a conditional replacement:\n\n\
|
||||
if item > heap[0]:\n\
|
||||
item = heapreplace(heap, item)\n");
|
||||
|
||||
static PyObject *
|
||||
heappushpop(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *heap, *item, *returnitem;
|
||||
int cmp;
|
||||
|
||||
if (!PyArg_UnpackTuple(args, "heappushpop", 2, 2, &heap, &item))
|
||||
return NULL;
|
||||
|
||||
if (!PyList_Check(heap)) {
|
||||
PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (PyList_GET_SIZE(heap) < 1) {
|
||||
Py_INCREF(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
cmp = cmp_lt(PyList_GET_ITEM(heap, 0), item);
|
||||
if (cmp == -1)
|
||||
return NULL;
|
||||
if (cmp == 0) {
|
||||
Py_INCREF(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
if (PyList_GET_SIZE(heap) == 0) {
|
||||
PyErr_SetString(PyExc_IndexError, "index out of range");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
returnitem = PyList_GET_ITEM(heap, 0);
|
||||
Py_INCREF(item);
|
||||
PyList_SET_ITEM(heap, 0, item);
|
||||
if (_siftup((PyListObject *)heap, 0) == -1) {
|
||||
Py_DECREF(returnitem);
|
||||
return NULL;
|
||||
}
|
||||
return returnitem;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(heappushpop_doc,
|
||||
"heappushpop(heap, item) -> value. Push item on the heap, then pop and return the smallest item\n\
|
||||
from the heap. The combined action runs more efficiently than\n\
|
||||
heappush() followed by a separate call to heappop().");
|
||||
|
||||
static PyObject *
|
||||
heapify(PyObject *self, PyObject *heap)
|
||||
{
|
||||
Py_ssize_t i, n;
|
||||
|
||||
if (!PyList_Check(heap)) {
|
||||
PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
n = PyList_GET_SIZE(heap);
|
||||
/* Transform bottom-up. The largest index there's any point to
|
||||
looking at is the largest with a child index in-range, so must
|
||||
have 2*i + 1 < n, or i < (n-1)/2. If n is even = 2*j, this is
|
||||
(2*j-1)/2 = j-1/2 so j-1 is the largest, which is n//2 - 1. If
|
||||
n is odd = 2*j+1, this is (2*j+1-1)/2 = j so j-1 is the largest,
|
||||
and that's again n//2-1.
|
||||
*/
|
||||
for (i=n/2-1 ; i>=0 ; i--)
|
||||
if(_siftup((PyListObject *)heap, i) == -1)
|
||||
return NULL;
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(heapify_doc,
|
||||
"Transform list into a heap, in-place, in O(len(heap)) time.");
|
||||
|
||||
static PyObject *
|
||||
nlargest(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *heap=NULL, *elem, *iterable, *sol, *it, *oldelem;
|
||||
Py_ssize_t i, n;
|
||||
int cmp;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "nO:nlargest", &n, &iterable))
|
||||
return NULL;
|
||||
|
||||
it = PyObject_GetIter(iterable);
|
||||
if (it == NULL)
|
||||
return NULL;
|
||||
|
||||
heap = PyList_New(0);
|
||||
if (heap == NULL)
|
||||
goto fail;
|
||||
|
||||
for (i=0 ; i<n ; i++ ){
|
||||
elem = PyIter_Next(it);
|
||||
if (elem == NULL) {
|
||||
if (PyErr_Occurred())
|
||||
goto fail;
|
||||
else
|
||||
goto sortit;
|
||||
}
|
||||
if (PyList_Append(heap, elem) == -1) {
|
||||
Py_DECREF(elem);
|
||||
goto fail;
|
||||
}
|
||||
Py_DECREF(elem);
|
||||
}
|
||||
if (PyList_GET_SIZE(heap) == 0)
|
||||
goto sortit;
|
||||
|
||||
for (i=n/2-1 ; i>=0 ; i--)
|
||||
if(_siftup((PyListObject *)heap, i) == -1)
|
||||
goto fail;
|
||||
|
||||
sol = PyList_GET_ITEM(heap, 0);
|
||||
while (1) {
|
||||
elem = PyIter_Next(it);
|
||||
if (elem == NULL) {
|
||||
if (PyErr_Occurred())
|
||||
goto fail;
|
||||
else
|
||||
goto sortit;
|
||||
}
|
||||
cmp = cmp_lt(sol, elem);
|
||||
if (cmp == -1) {
|
||||
Py_DECREF(elem);
|
||||
goto fail;
|
||||
}
|
||||
if (cmp == 0) {
|
||||
Py_DECREF(elem);
|
||||
continue;
|
||||
}
|
||||
oldelem = PyList_GET_ITEM(heap, 0);
|
||||
PyList_SET_ITEM(heap, 0, elem);
|
||||
Py_DECREF(oldelem);
|
||||
if (_siftup((PyListObject *)heap, 0) == -1)
|
||||
goto fail;
|
||||
sol = PyList_GET_ITEM(heap, 0);
|
||||
}
|
||||
sortit:
|
||||
if (PyList_Sort(heap) == -1)
|
||||
goto fail;
|
||||
if (PyList_Reverse(heap) == -1)
|
||||
goto fail;
|
||||
Py_DECREF(it);
|
||||
return heap;
|
||||
|
||||
fail:
|
||||
Py_DECREF(it);
|
||||
Py_XDECREF(heap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(nlargest_doc,
|
||||
"Find the n largest elements in a dataset.\n\
|
||||
\n\
|
||||
Equivalent to: sorted(iterable, reverse=True)[:n]\n");
|
||||
|
||||
static int
|
||||
_siftdownmax(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
|
||||
{
|
||||
PyObject *newitem, *parent;
|
||||
int cmp;
|
||||
Py_ssize_t parentpos;
|
||||
|
||||
assert(PyList_Check(heap));
|
||||
if (pos >= PyList_GET_SIZE(heap)) {
|
||||
PyErr_SetString(PyExc_IndexError, "index out of range");
|
||||
return -1;
|
||||
}
|
||||
|
||||
newitem = PyList_GET_ITEM(heap, pos);
|
||||
Py_INCREF(newitem);
|
||||
/* Follow the path to the root, moving parents down until finding
|
||||
a place newitem fits. */
|
||||
while (pos > startpos){
|
||||
parentpos = (pos - 1) >> 1;
|
||||
parent = PyList_GET_ITEM(heap, parentpos);
|
||||
cmp = cmp_lt(parent, newitem);
|
||||
if (cmp == -1) {
|
||||
Py_DECREF(newitem);
|
||||
return -1;
|
||||
}
|
||||
if (cmp == 0)
|
||||
break;
|
||||
Py_INCREF(parent);
|
||||
Py_DECREF(PyList_GET_ITEM(heap, pos));
|
||||
PyList_SET_ITEM(heap, pos, parent);
|
||||
pos = parentpos;
|
||||
}
|
||||
Py_DECREF(PyList_GET_ITEM(heap, pos));
|
||||
PyList_SET_ITEM(heap, pos, newitem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_siftupmax(PyListObject *heap, Py_ssize_t pos)
|
||||
{
|
||||
Py_ssize_t startpos, endpos, childpos, rightpos, limit;
|
||||
int cmp;
|
||||
PyObject *newitem, *tmp;
|
||||
|
||||
assert(PyList_Check(heap));
|
||||
endpos = PyList_GET_SIZE(heap);
|
||||
startpos = pos;
|
||||
if (pos >= endpos) {
|
||||
PyErr_SetString(PyExc_IndexError, "index out of range");
|
||||
return -1;
|
||||
}
|
||||
newitem = PyList_GET_ITEM(heap, pos);
|
||||
Py_INCREF(newitem);
|
||||
|
||||
/* Bubble up the smaller child until hitting a leaf. */
|
||||
limit = endpos / 2; /* smallest pos that has no child */
|
||||
while (pos < limit) {
|
||||
/* Set childpos to index of smaller child. */
|
||||
childpos = 2*pos + 1; /* leftmost child position */
|
||||
rightpos = childpos + 1;
|
||||
if (rightpos < endpos) {
|
||||
cmp = cmp_lt(
|
||||
PyList_GET_ITEM(heap, rightpos),
|
||||
PyList_GET_ITEM(heap, childpos));
|
||||
if (cmp == -1) {
|
||||
Py_DECREF(newitem);
|
||||
return -1;
|
||||
}
|
||||
if (cmp == 0)
|
||||
childpos = rightpos;
|
||||
}
|
||||
/* Move the smaller child up. */
|
||||
tmp = PyList_GET_ITEM(heap, childpos);
|
||||
Py_INCREF(tmp);
|
||||
Py_DECREF(PyList_GET_ITEM(heap, pos));
|
||||
PyList_SET_ITEM(heap, pos, tmp);
|
||||
pos = childpos;
|
||||
}
|
||||
|
||||
/* The leaf at pos is empty now. Put newitem there, and bubble
|
||||
it up to its final resting place (by sifting its parents down). */
|
||||
Py_DECREF(PyList_GET_ITEM(heap, pos));
|
||||
PyList_SET_ITEM(heap, pos, newitem);
|
||||
return _siftdownmax(heap, startpos, pos);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
nsmallest(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *heap=NULL, *elem, *iterable, *los, *it, *oldelem;
|
||||
Py_ssize_t i, n;
|
||||
int cmp;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "nO:nsmallest", &n, &iterable))
|
||||
return NULL;
|
||||
|
||||
it = PyObject_GetIter(iterable);
|
||||
if (it == NULL)
|
||||
return NULL;
|
||||
|
||||
heap = PyList_New(0);
|
||||
if (heap == NULL)
|
||||
goto fail;
|
||||
|
||||
for (i=0 ; i<n ; i++ ){
|
||||
elem = PyIter_Next(it);
|
||||
if (elem == NULL) {
|
||||
if (PyErr_Occurred())
|
||||
goto fail;
|
||||
else
|
||||
goto sortit;
|
||||
}
|
||||
if (PyList_Append(heap, elem) == -1) {
|
||||
Py_DECREF(elem);
|
||||
goto fail;
|
||||
}
|
||||
Py_DECREF(elem);
|
||||
}
|
||||
n = PyList_GET_SIZE(heap);
|
||||
if (n == 0)
|
||||
goto sortit;
|
||||
|
||||
for (i=n/2-1 ; i>=0 ; i--)
|
||||
if(_siftupmax((PyListObject *)heap, i) == -1)
|
||||
goto fail;
|
||||
|
||||
los = PyList_GET_ITEM(heap, 0);
|
||||
while (1) {
|
||||
elem = PyIter_Next(it);
|
||||
if (elem == NULL) {
|
||||
if (PyErr_Occurred())
|
||||
goto fail;
|
||||
else
|
||||
goto sortit;
|
||||
}
|
||||
cmp = cmp_lt(elem, los);
|
||||
if (cmp == -1) {
|
||||
Py_DECREF(elem);
|
||||
goto fail;
|
||||
}
|
||||
if (cmp == 0) {
|
||||
Py_DECREF(elem);
|
||||
continue;
|
||||
}
|
||||
|
||||
oldelem = PyList_GET_ITEM(heap, 0);
|
||||
PyList_SET_ITEM(heap, 0, elem);
|
||||
Py_DECREF(oldelem);
|
||||
if (_siftupmax((PyListObject *)heap, 0) == -1)
|
||||
goto fail;
|
||||
los = PyList_GET_ITEM(heap, 0);
|
||||
}
|
||||
|
||||
sortit:
|
||||
if (PyList_Sort(heap) == -1)
|
||||
goto fail;
|
||||
Py_DECREF(it);
|
||||
return heap;
|
||||
|
||||
fail:
|
||||
Py_DECREF(it);
|
||||
Py_XDECREF(heap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(nsmallest_doc,
|
||||
"Find the n smallest elements in a dataset.\n\
|
||||
\n\
|
||||
Equivalent to: sorted(iterable)[:n]\n");
|
||||
|
||||
static PyMethodDef heapq_methods[] = {
|
||||
{"heappush", (PyCFunction)heappush,
|
||||
METH_VARARGS, heappush_doc},
|
||||
{"heappushpop", (PyCFunction)heappushpop,
|
||||
METH_VARARGS, heappushpop_doc},
|
||||
{"heappop", (PyCFunction)heappop,
|
||||
METH_O, heappop_doc},
|
||||
{"heapreplace", (PyCFunction)heapreplace,
|
||||
METH_VARARGS, heapreplace_doc},
|
||||
{"heapify", (PyCFunction)heapify,
|
||||
METH_O, heapify_doc},
|
||||
{"nlargest", (PyCFunction)nlargest,
|
||||
METH_VARARGS, nlargest_doc},
|
||||
{"nsmallest", (PyCFunction)nsmallest,
|
||||
METH_VARARGS, nsmallest_doc},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(module_doc,
|
||||
"Heap queue algorithm (a.k.a. priority queue).\n\
|
||||
\n\
|
||||
Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for\n\
|
||||
all k, counting elements from 0. For the sake of comparison,\n\
|
||||
non-existing elements are considered to be infinite. The interesting\n\
|
||||
property of a heap is that a[0] is always its smallest element.\n\
|
||||
\n\
|
||||
Usage:\n\
|
||||
\n\
|
||||
heap = [] # creates an empty heap\n\
|
||||
heappush(heap, item) # pushes a new item on the heap\n\
|
||||
item = heappop(heap) # pops the smallest item from the heap\n\
|
||||
item = heap[0] # smallest item on the heap without popping it\n\
|
||||
heapify(x) # transforms list into a heap, in-place, in linear time\n\
|
||||
item = heapreplace(heap, item) # pops and returns smallest item, and adds\n\
|
||||
# new item; the heap size is unchanged\n\
|
||||
\n\
|
||||
Our API differs from textbook heap algorithms as follows:\n\
|
||||
\n\
|
||||
- We use 0-based indexing. This makes the relationship between the\n\
|
||||
index for a node and the indexes for its children slightly less\n\
|
||||
obvious, but is more suitable since Python uses 0-based indexing.\n\
|
||||
\n\
|
||||
- Our heappop() method returns the smallest item, not the largest.\n\
|
||||
\n\
|
||||
These two make it possible to view the heap as a regular Python list\n\
|
||||
without surprises: heap[0] is the smallest item, and heap.sort()\n\
|
||||
maintains the heap invariant!\n");
|
||||
|
||||
|
||||
PyDoc_STRVAR(__about__,
|
||||
"Heap queues\n\
|
||||
\n\
|
||||
[explanation by François Pinard]\n\
|
||||
\n\
|
||||
Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for\n\
|
||||
all k, counting elements from 0. For the sake of comparison,\n\
|
||||
non-existing elements are considered to be infinite. The interesting\n\
|
||||
property of a heap is that a[0] is always its smallest element.\n"
|
||||
"\n\
|
||||
The strange invariant above is meant to be an efficient memory\n\
|
||||
representation for a tournament. The numbers below are `k', not a[k]:\n\
|
||||
\n\
|
||||
0\n\
|
||||
\n\
|
||||
1 2\n\
|
||||
\n\
|
||||
3 4 5 6\n\
|
||||
\n\
|
||||
7 8 9 10 11 12 13 14\n\
|
||||
\n\
|
||||
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30\n\
|
||||
\n\
|
||||
\n\
|
||||
In the tree above, each cell `k' is topping `2*k+1' and `2*k+2'. In\n\
|
||||
a usual binary tournament we see in sports, each cell is the winner\n\
|
||||
over the two cells it tops, and we can trace the winner down the tree\n\
|
||||
to see all opponents s/he had. However, in many computer applications\n\
|
||||
of such tournaments, we do not need to trace the history of a winner.\n\
|
||||
To be more memory efficient, when a winner is promoted, we try to\n\
|
||||
replace it by something else at a lower level, and the rule becomes\n\
|
||||
that a cell and the two cells it tops contain three different items,\n\
|
||||
but the top cell \"wins\" over the two topped cells.\n"
|
||||
"\n\
|
||||
If this heap invariant is protected at all time, index 0 is clearly\n\
|
||||
the overall winner. The simplest algorithmic way to remove it and\n\
|
||||
find the \"next\" winner is to move some loser (let's say cell 30 in the\n\
|
||||
diagram above) into the 0 position, and then percolate this new 0 down\n\
|
||||
the tree, exchanging values, until the invariant is re-established.\n\
|
||||
This is clearly logarithmic on the total number of items in the tree.\n\
|
||||
By iterating over all items, you get an O(n ln n) sort.\n"
|
||||
"\n\
|
||||
A nice feature of this sort is that you can efficiently insert new\n\
|
||||
items while the sort is going on, provided that the inserted items are\n\
|
||||
not \"better\" than the last 0'th element you extracted. This is\n\
|
||||
especially useful in simulation contexts, where the tree holds all\n\
|
||||
incoming events, and the \"win\" condition means the smallest scheduled\n\
|
||||
time. When an event schedule other events for execution, they are\n\
|
||||
scheduled into the future, so they can easily go into the heap. So, a\n\
|
||||
heap is a good structure for implementing schedulers (this is what I\n\
|
||||
used for my MIDI sequencer :-).\n"
|
||||
"\n\
|
||||
Various structures for implementing schedulers have been extensively\n\
|
||||
studied, and heaps are good for this, as they are reasonably speedy,\n\
|
||||
the speed is almost constant, and the worst case is not much different\n\
|
||||
than the average case. However, there are other representations which\n\
|
||||
are more efficient overall, yet the worst cases might be terrible.\n"
|
||||
"\n\
|
||||
Heaps are also very useful in big disk sorts. You most probably all\n\
|
||||
know that a big sort implies producing \"runs\" (which are pre-sorted\n\
|
||||
sequences, which size is usually related to the amount of CPU memory),\n\
|
||||
followed by a merging passes for these runs, which merging is often\n\
|
||||
very cleverly organised[1]. It is very important that the initial\n\
|
||||
sort produces the longest runs possible. Tournaments are a good way\n\
|
||||
to that. If, using all the memory available to hold a tournament, you\n\
|
||||
replace and percolate items that happen to fit the current run, you'll\n\
|
||||
produce runs which are twice the size of the memory for random input,\n\
|
||||
and much better for input fuzzily ordered.\n"
|
||||
"\n\
|
||||
Moreover, if you output the 0'th item on disk and get an input which\n\
|
||||
may not fit in the current tournament (because the value \"wins\" over\n\
|
||||
the last output value), it cannot fit in the heap, so the size of the\n\
|
||||
heap decreases. The freed memory could be cleverly reused immediately\n\
|
||||
for progressively building a second heap, which grows at exactly the\n\
|
||||
same rate the first heap is melting. When the first heap completely\n\
|
||||
vanishes, you switch heaps and start a new run. Clever and quite\n\
|
||||
effective!\n\
|
||||
\n\
|
||||
In a word, heaps are useful memory structures to know. I use them in\n\
|
||||
a few applications, and I think it is good to keep a `heap' module\n\
|
||||
around. :-)\n"
|
||||
"\n\
|
||||
--------------------\n\
|
||||
[1] The disk balancing algorithms which are current, nowadays, are\n\
|
||||
more annoying than clever, and this is a consequence of the seeking\n\
|
||||
capabilities of the disks. On devices which cannot seek, like big\n\
|
||||
tape drives, the story was quite different, and one had to be very\n\
|
||||
clever to ensure (far in advance) that each tape movement will be the\n\
|
||||
most effective possible (that is, will best participate at\n\
|
||||
\"progressing\" the merge). Some tapes were even able to read\n\
|
||||
backwards, and this was also used to avoid the rewinding time.\n\
|
||||
Believe me, real good tape sorts were quite spectacular to watch!\n\
|
||||
From all times, sorting has always been a Great Art! :-)\n");
|
||||
|
||||
PyMODINIT_FUNC
|
||||
init_heapq(void)
|
||||
{
|
||||
PyObject *m;
|
||||
|
||||
m = Py_InitModule3("_heapq", heapq_methods, module_doc);
|
||||
if (m == NULL)
|
||||
return;
|
||||
PyModule_AddObject(m, "__about__", PyString_FromString(__about__));
|
||||
}
|
||||
|
||||
+1650
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,777 @@
|
||||
/*
|
||||
An implementation of the new I/O lib as defined by PEP 3116 - "New I/O"
|
||||
|
||||
Classes defined here: UnsupportedOperation, BlockingIOError.
|
||||
Functions defined here: open().
|
||||
|
||||
Mostly written by Amaury Forgeot d'Arc
|
||||
*/
|
||||
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include "Python.h"
|
||||
#include "structmember.h"
|
||||
#include "_iomodule.h"
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif /* HAVE_SYS_TYPES_H */
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif /* HAVE_SYS_STAT_H */
|
||||
|
||||
|
||||
/* Various interned strings */
|
||||
|
||||
PyObject *_PyIO_str_close;
|
||||
PyObject *_PyIO_str_closed;
|
||||
PyObject *_PyIO_str_decode;
|
||||
PyObject *_PyIO_str_encode;
|
||||
PyObject *_PyIO_str_fileno;
|
||||
PyObject *_PyIO_str_flush;
|
||||
PyObject *_PyIO_str_getstate;
|
||||
PyObject *_PyIO_str_isatty;
|
||||
PyObject *_PyIO_str_newlines;
|
||||
PyObject *_PyIO_str_nl;
|
||||
PyObject *_PyIO_str_read;
|
||||
PyObject *_PyIO_str_read1;
|
||||
PyObject *_PyIO_str_readable;
|
||||
PyObject *_PyIO_str_readinto;
|
||||
PyObject *_PyIO_str_readline;
|
||||
PyObject *_PyIO_str_reset;
|
||||
PyObject *_PyIO_str_seek;
|
||||
PyObject *_PyIO_str_seekable;
|
||||
PyObject *_PyIO_str_setstate;
|
||||
PyObject *_PyIO_str_tell;
|
||||
PyObject *_PyIO_str_truncate;
|
||||
PyObject *_PyIO_str_writable;
|
||||
PyObject *_PyIO_str_write;
|
||||
|
||||
PyObject *_PyIO_empty_str;
|
||||
PyObject *_PyIO_empty_bytes;
|
||||
PyObject *_PyIO_zero;
|
||||
|
||||
|
||||
PyDoc_STRVAR(module_doc,
|
||||
"The io module provides the Python interfaces to stream handling. The\n"
|
||||
"builtin open function is defined in this module.\n"
|
||||
"\n"
|
||||
"At the top of the I/O hierarchy is the abstract base class IOBase. It\n"
|
||||
"defines the basic interface to a stream. Note, however, that there is no\n"
|
||||
"separation between reading and writing to streams; implementations are\n"
|
||||
"allowed to raise an IOError if they do not support a given operation.\n"
|
||||
"\n"
|
||||
"Extending IOBase is RawIOBase which deals simply with the reading and\n"
|
||||
"writing of raw bytes to a stream. FileIO subclasses RawIOBase to provide\n"
|
||||
"an interface to OS files.\n"
|
||||
"\n"
|
||||
"BufferedIOBase deals with buffering on a raw byte stream (RawIOBase). Its\n"
|
||||
"subclasses, BufferedWriter, BufferedReader, and BufferedRWPair buffer\n"
|
||||
"streams that are readable, writable, and both respectively.\n"
|
||||
"BufferedRandom provides a buffered interface to random access\n"
|
||||
"streams. BytesIO is a simple stream of in-memory bytes.\n"
|
||||
"\n"
|
||||
"Another IOBase subclass, TextIOBase, deals with the encoding and decoding\n"
|
||||
"of streams into text. TextIOWrapper, which extends it, is a buffered text\n"
|
||||
"interface to a buffered raw stream (`BufferedIOBase`). Finally, StringIO\n"
|
||||
"is an in-memory stream for text.\n"
|
||||
"\n"
|
||||
"Argument names are not part of the specification, and only the arguments\n"
|
||||
"of open() are intended to be used as keyword arguments.\n"
|
||||
"\n"
|
||||
"data:\n"
|
||||
"\n"
|
||||
"DEFAULT_BUFFER_SIZE\n"
|
||||
"\n"
|
||||
" An int containing the default buffer size used by the module's buffered\n"
|
||||
" I/O classes. open() uses the file's blksize (as obtained by os.stat) if\n"
|
||||
" possible.\n"
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* BlockingIOError extends IOError
|
||||
*/
|
||||
|
||||
static int
|
||||
blockingioerror_init(PyBlockingIOErrorObject *self, PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
PyObject *myerrno = NULL, *strerror = NULL;
|
||||
PyObject *baseargs = NULL;
|
||||
Py_ssize_t written = 0;
|
||||
|
||||
assert(PyTuple_Check(args));
|
||||
|
||||
self->written = 0;
|
||||
if (!PyArg_ParseTuple(args, "OO|n:BlockingIOError",
|
||||
&myerrno, &strerror, &written))
|
||||
return -1;
|
||||
|
||||
baseargs = PyTuple_Pack(2, myerrno, strerror);
|
||||
if (baseargs == NULL)
|
||||
return -1;
|
||||
/* This will take care of initializing of myerrno and strerror members */
|
||||
if (((PyTypeObject *)PyExc_IOError)->tp_init(
|
||||
(PyObject *)self, baseargs, kwds) == -1) {
|
||||
Py_DECREF(baseargs);
|
||||
return -1;
|
||||
}
|
||||
Py_DECREF(baseargs);
|
||||
|
||||
self->written = written;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyMemberDef blockingioerror_members[] = {
|
||||
{"characters_written", T_PYSSIZET, offsetof(PyBlockingIOErrorObject, written), 0},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyTypeObject _PyExc_BlockingIOError = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"BlockingIOError", /*tp_name*/
|
||||
sizeof(PyBlockingIOErrorObject), /*tp_basicsize*/
|
||||
0, /*tp_itemsize*/
|
||||
0, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare */
|
||||
0, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
0, /*tp_hash */
|
||||
0, /*tp_call*/
|
||||
0, /*tp_str*/
|
||||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
|
||||
PyDoc_STR("Exception raised when I/O would block "
|
||||
"on a non-blocking I/O stream"), /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
blockingioerror_members, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
(initproc)blockingioerror_init, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
0, /* tp_new */
|
||||
};
|
||||
PyObject *PyExc_BlockingIOError = (PyObject *)&_PyExc_BlockingIOError;
|
||||
|
||||
|
||||
/*
|
||||
* The main open() function
|
||||
*/
|
||||
PyDoc_STRVAR(open_doc,
|
||||
"Open file and return a stream. Raise IOError upon failure.\n"
|
||||
"\n"
|
||||
"file is either a text or byte string giving the name (and the path\n"
|
||||
"if the file isn't in the current working directory) of the file to\n"
|
||||
"be opened or an integer file descriptor of the file to be\n"
|
||||
"wrapped. (If a file descriptor is given, it is closed when the\n"
|
||||
"returned I/O object is closed, unless closefd is set to False.)\n"
|
||||
"\n"
|
||||
"mode is an optional string that specifies the mode in which the file\n"
|
||||
"is opened. It defaults to 'r' which means open for reading in text\n"
|
||||
"mode. Other common values are 'w' for writing (truncating the file if\n"
|
||||
"it already exists), and 'a' for appending (which on some Unix systems,\n"
|
||||
"means that all writes append to the end of the file regardless of the\n"
|
||||
"current seek position). In text mode, if encoding is not specified the\n"
|
||||
"encoding used is platform dependent. (For reading and writing raw\n"
|
||||
"bytes use binary mode and leave encoding unspecified.) The available\n"
|
||||
"modes are:\n"
|
||||
"\n"
|
||||
"========= ===============================================================\n"
|
||||
"Character Meaning\n"
|
||||
"--------- ---------------------------------------------------------------\n"
|
||||
"'r' open for reading (default)\n"
|
||||
"'w' open for writing, truncating the file first\n"
|
||||
"'a' open for writing, appending to the end of the file if it exists\n"
|
||||
"'b' binary mode\n"
|
||||
"'t' text mode (default)\n"
|
||||
"'+' open a disk file for updating (reading and writing)\n"
|
||||
"'U' universal newline mode (for backwards compatibility; unneeded\n"
|
||||
" for new code)\n"
|
||||
"========= ===============================================================\n"
|
||||
"\n"
|
||||
"The default mode is 'rt' (open for reading text). For binary random\n"
|
||||
"access, the mode 'w+b' opens and truncates the file to 0 bytes, while\n"
|
||||
"'r+b' opens the file without truncation.\n"
|
||||
"\n"
|
||||
"Python distinguishes between files opened in binary and text modes,\n"
|
||||
"even when the underlying operating system doesn't. Files opened in\n"
|
||||
"binary mode (appending 'b' to the mode argument) return contents as\n"
|
||||
"bytes objects without any decoding. In text mode (the default, or when\n"
|
||||
"'t' is appended to the mode argument), the contents of the file are\n"
|
||||
"returned as strings, the bytes having been first decoded using a\n"
|
||||
"platform-dependent encoding or using the specified encoding if given.\n"
|
||||
"\n"
|
||||
"buffering is an optional integer used to set the buffering policy.\n"
|
||||
"Pass 0 to switch buffering off (only allowed in binary mode), 1 to select\n"
|
||||
"line buffering (only usable in text mode), and an integer > 1 to indicate\n"
|
||||
"the size of a fixed-size chunk buffer. When no buffering argument is\n"
|
||||
"given, the default buffering policy works as follows:\n"
|
||||
"\n"
|
||||
"* Binary files are buffered in fixed-size chunks; the size of the buffer\n"
|
||||
" is chosen using a heuristic trying to determine the underlying device's\n"
|
||||
" \"block size\" and falling back on `io.DEFAULT_BUFFER_SIZE`.\n"
|
||||
" On many systems, the buffer will typically be 4096 or 8192 bytes long.\n"
|
||||
"\n"
|
||||
"* \"Interactive\" text files (files for which isatty() returns True)\n"
|
||||
" use line buffering. Other text files use the policy described above\n"
|
||||
" for binary files.\n"
|
||||
"\n"
|
||||
"encoding is the name of the encoding used to decode or encode the\n"
|
||||
"file. This should only be used in text mode. The default encoding is\n"
|
||||
"platform dependent, but any encoding supported by Python can be\n"
|
||||
"passed. See the codecs module for the list of supported encodings.\n"
|
||||
"\n"
|
||||
"errors is an optional string that specifies how encoding errors are to\n"
|
||||
"be handled---this argument should not be used in binary mode. Pass\n"
|
||||
"'strict' to raise a ValueError exception if there is an encoding error\n"
|
||||
"(the default of None has the same effect), or pass 'ignore' to ignore\n"
|
||||
"errors. (Note that ignoring encoding errors can lead to data loss.)\n"
|
||||
"See the documentation for codecs.register for a list of the permitted\n"
|
||||
"encoding error strings.\n"
|
||||
"\n"
|
||||
"newline controls how universal newlines works (it only applies to text\n"
|
||||
"mode). It can be None, '', '\\n', '\\r', and '\\r\\n'. It works as\n"
|
||||
"follows:\n"
|
||||
"\n"
|
||||
"* On input, if newline is None, universal newlines mode is\n"
|
||||
" enabled. Lines in the input can end in '\\n', '\\r', or '\\r\\n', and\n"
|
||||
" these are translated into '\\n' before being returned to the\n"
|
||||
" caller. If it is '', universal newline mode is enabled, but line\n"
|
||||
" endings are returned to the caller untranslated. If it has any of\n"
|
||||
" the other legal values, input lines are only terminated by the given\n"
|
||||
" string, and the line ending is returned to the caller untranslated.\n"
|
||||
"\n"
|
||||
"* On output, if newline is None, any '\\n' characters written are\n"
|
||||
" translated to the system default line separator, os.linesep. If\n"
|
||||
" newline is '', no translation takes place. If newline is any of the\n"
|
||||
" other legal values, any '\\n' characters written are translated to\n"
|
||||
" the given string.\n"
|
||||
"\n"
|
||||
"If closefd is False, the underlying file descriptor will be kept open\n"
|
||||
"when the file is closed. This does not work when a file name is given\n"
|
||||
"and must be True in that case.\n"
|
||||
"\n"
|
||||
"open() returns a file object whose type depends on the mode, and\n"
|
||||
"through which the standard file operations such as reading and writing\n"
|
||||
"are performed. When open() is used to open a file in a text mode ('w',\n"
|
||||
"'r', 'wt', 'rt', etc.), it returns a TextIOWrapper. When used to open\n"
|
||||
"a file in a binary mode, the returned class varies: in read binary\n"
|
||||
"mode, it returns a BufferedReader; in write binary and append binary\n"
|
||||
"modes, it returns a BufferedWriter, and in read/write mode, it returns\n"
|
||||
"a BufferedRandom.\n"
|
||||
"\n"
|
||||
"It is also possible to use a string or bytearray as a file for both\n"
|
||||
"reading and writing. For strings StringIO can be used like a file\n"
|
||||
"opened in a text mode, and for bytes a BytesIO can be used like a file\n"
|
||||
"opened in a binary mode.\n"
|
||||
);
|
||||
|
||||
static PyObject *
|
||||
io_open(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
char *kwlist[] = {"file", "mode", "buffering",
|
||||
"encoding", "errors", "newline",
|
||||
"closefd", NULL};
|
||||
PyObject *file;
|
||||
char *mode = "r";
|
||||
int buffering = -1, closefd = 1;
|
||||
char *encoding = NULL, *errors = NULL, *newline = NULL;
|
||||
unsigned i;
|
||||
|
||||
int reading = 0, writing = 0, appending = 0, updating = 0;
|
||||
int text = 0, binary = 0, universal = 0;
|
||||
|
||||
char rawmode[5], *m;
|
||||
int line_buffering;
|
||||
long isatty;
|
||||
|
||||
PyObject *raw, *modeobj = NULL, *buffer, *wrapper, *result = NULL;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|sizzzi:open", kwlist,
|
||||
&file, &mode, &buffering,
|
||||
&encoding, &errors, &newline,
|
||||
&closefd)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!PyUnicode_Check(file) &&
|
||||
!PyBytes_Check(file) &&
|
||||
!PyNumber_Check(file)) {
|
||||
PyObject *repr = PyObject_Repr(file);
|
||||
if (repr != NULL) {
|
||||
PyErr_Format(PyExc_TypeError, "invalid file: %s",
|
||||
PyString_AS_STRING(repr));
|
||||
Py_DECREF(repr);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Decode mode */
|
||||
for (i = 0; i < strlen(mode); i++) {
|
||||
char c = mode[i];
|
||||
|
||||
switch (c) {
|
||||
case 'r':
|
||||
reading = 1;
|
||||
break;
|
||||
case 'w':
|
||||
writing = 1;
|
||||
break;
|
||||
case 'a':
|
||||
appending = 1;
|
||||
break;
|
||||
case '+':
|
||||
updating = 1;
|
||||
break;
|
||||
case 't':
|
||||
text = 1;
|
||||
break;
|
||||
case 'b':
|
||||
binary = 1;
|
||||
break;
|
||||
case 'U':
|
||||
universal = 1;
|
||||
reading = 1;
|
||||
break;
|
||||
default:
|
||||
goto invalid_mode;
|
||||
}
|
||||
|
||||
/* c must not be duplicated */
|
||||
if (strchr(mode+i+1, c)) {
|
||||
invalid_mode:
|
||||
PyErr_Format(PyExc_ValueError, "invalid mode: '%s'", mode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m = rawmode;
|
||||
if (reading) *(m++) = 'r';
|
||||
if (writing) *(m++) = 'w';
|
||||
if (appending) *(m++) = 'a';
|
||||
if (updating) *(m++) = '+';
|
||||
*m = '\0';
|
||||
|
||||
/* Parameters validation */
|
||||
if (universal) {
|
||||
if (writing || appending) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"can't use U and writing mode at once");
|
||||
return NULL;
|
||||
}
|
||||
reading = 1;
|
||||
}
|
||||
|
||||
if (text && binary) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"can't have text and binary mode at once");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (reading + writing + appending > 1) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"must have exactly one of read/write/append mode");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (binary && encoding != NULL) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"binary mode doesn't take an encoding argument");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (binary && errors != NULL) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"binary mode doesn't take an errors argument");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (binary && newline != NULL) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"binary mode doesn't take a newline argument");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create the Raw file stream */
|
||||
raw = PyObject_CallFunction((PyObject *)&PyFileIO_Type,
|
||||
"Osi", file, rawmode, closefd);
|
||||
if (raw == NULL)
|
||||
return NULL;
|
||||
result = raw;
|
||||
|
||||
modeobj = PyUnicode_FromString(mode);
|
||||
if (modeobj == NULL)
|
||||
goto error;
|
||||
|
||||
/* buffering */
|
||||
{
|
||||
PyObject *res = PyObject_CallMethod(raw, "isatty", NULL);
|
||||
if (res == NULL)
|
||||
goto error;
|
||||
isatty = PyLong_AsLong(res);
|
||||
Py_DECREF(res);
|
||||
if (isatty == -1 && PyErr_Occurred())
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (buffering == 1 || (buffering < 0 && isatty)) {
|
||||
buffering = -1;
|
||||
line_buffering = 1;
|
||||
}
|
||||
else
|
||||
line_buffering = 0;
|
||||
|
||||
if (buffering < 0) {
|
||||
buffering = DEFAULT_BUFFER_SIZE;
|
||||
#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
|
||||
{
|
||||
struct stat st;
|
||||
int fileno;
|
||||
PyObject *res = PyObject_CallMethod(raw, "fileno", NULL);
|
||||
if (res == NULL)
|
||||
goto error;
|
||||
|
||||
fileno = _PyInt_AsInt(res);
|
||||
Py_DECREF(res);
|
||||
if (fileno == -1 && PyErr_Occurred())
|
||||
goto error;
|
||||
|
||||
if (fstat(fileno, &st) >= 0 && st.st_blksize > 1)
|
||||
buffering = st.st_blksize;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (buffering < 0) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"invalid buffering size");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* if not buffering, returns the raw file object */
|
||||
if (buffering == 0) {
|
||||
if (!binary) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"can't have unbuffered text I/O");
|
||||
goto error;
|
||||
}
|
||||
|
||||
Py_DECREF(modeobj);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* wraps into a buffered file */
|
||||
{
|
||||
PyObject *Buffered_class;
|
||||
|
||||
if (updating)
|
||||
Buffered_class = (PyObject *)&PyBufferedRandom_Type;
|
||||
else if (writing || appending)
|
||||
Buffered_class = (PyObject *)&PyBufferedWriter_Type;
|
||||
else if (reading)
|
||||
Buffered_class = (PyObject *)&PyBufferedReader_Type;
|
||||
else {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"unknown mode: '%s'", mode);
|
||||
goto error;
|
||||
}
|
||||
|
||||
buffer = PyObject_CallFunction(Buffered_class, "Oi", raw, buffering);
|
||||
}
|
||||
if (buffer == NULL)
|
||||
goto error;
|
||||
result = buffer;
|
||||
Py_DECREF(raw);
|
||||
|
||||
|
||||
/* if binary, returns the buffered file */
|
||||
if (binary) {
|
||||
Py_DECREF(modeobj);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* wraps into a TextIOWrapper */
|
||||
wrapper = PyObject_CallFunction((PyObject *)&PyTextIOWrapper_Type,
|
||||
"Osssi",
|
||||
buffer,
|
||||
encoding, errors, newline,
|
||||
line_buffering);
|
||||
if (wrapper == NULL)
|
||||
goto error;
|
||||
result = wrapper;
|
||||
Py_DECREF(buffer);
|
||||
|
||||
if (PyObject_SetAttrString(wrapper, "mode", modeobj) < 0)
|
||||
goto error;
|
||||
Py_DECREF(modeobj);
|
||||
return result;
|
||||
|
||||
error:
|
||||
if (result != NULL) {
|
||||
PyObject *exc, *val, *tb, *close_result;
|
||||
PyErr_Fetch(&exc, &val, &tb);
|
||||
close_result = PyObject_CallMethod(result, "close", NULL);
|
||||
_PyErr_ReplaceException(exc, val, tb);
|
||||
Py_XDECREF(close_result);
|
||||
Py_DECREF(result);
|
||||
}
|
||||
Py_XDECREF(modeobj);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Private helpers for the io module.
|
||||
*/
|
||||
|
||||
Py_off_t
|
||||
PyNumber_AsOff_t(PyObject *item, PyObject *err)
|
||||
{
|
||||
Py_off_t result;
|
||||
PyObject *runerr;
|
||||
PyObject *value = PyNumber_Index(item);
|
||||
if (value == NULL)
|
||||
return -1;
|
||||
|
||||
if (PyInt_Check(value)) {
|
||||
/* We assume a long always fits in a Py_off_t... */
|
||||
result = (Py_off_t) PyInt_AS_LONG(value);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* We're done if PyLong_AsSsize_t() returns without error. */
|
||||
result = PyLong_AsOff_t(value);
|
||||
if (result != -1 || !(runerr = PyErr_Occurred()))
|
||||
goto finish;
|
||||
|
||||
/* Error handling code -- only manage OverflowError differently */
|
||||
if (!PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError))
|
||||
goto finish;
|
||||
|
||||
PyErr_Clear();
|
||||
/* If no error-handling desired then the default clipping
|
||||
is sufficient.
|
||||
*/
|
||||
if (!err) {
|
||||
assert(PyLong_Check(value));
|
||||
/* Whether or not it is less than or equal to
|
||||
zero is determined by the sign of ob_size
|
||||
*/
|
||||
if (_PyLong_Sign(value) < 0)
|
||||
result = PY_OFF_T_MIN;
|
||||
else
|
||||
result = PY_OFF_T_MAX;
|
||||
}
|
||||
else {
|
||||
/* Otherwise replace the error with caller's error object. */
|
||||
PyErr_Format(err,
|
||||
"cannot fit '%.200s' into an offset-sized integer",
|
||||
item->ob_type->tp_name);
|
||||
}
|
||||
|
||||
finish:
|
||||
Py_DECREF(value);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Basically the "n" format code with the ability to turn None into -1. */
|
||||
int
|
||||
_PyIO_ConvertSsize_t(PyObject *obj, void *result) {
|
||||
Py_ssize_t limit;
|
||||
if (obj == Py_None) {
|
||||
limit = -1;
|
||||
}
|
||||
else if (PyNumber_Check(obj)) {
|
||||
limit = PyNumber_AsSsize_t(obj, PyExc_OverflowError);
|
||||
if (limit == -1 && PyErr_Occurred())
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"integer argument expected, got '%.200s'",
|
||||
Py_TYPE(obj)->tp_name);
|
||||
return 0;
|
||||
}
|
||||
*((Py_ssize_t *)result) = limit;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Module definition
|
||||
*/
|
||||
|
||||
PyObject *_PyIO_os_module = NULL;
|
||||
PyObject *_PyIO_locale_module = NULL;
|
||||
PyObject *_PyIO_unsupported_operation = NULL;
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
{"open", (PyCFunction)io_open, METH_VARARGS|METH_KEYWORDS, open_doc},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC
|
||||
init_io(void)
|
||||
{
|
||||
PyObject *m = Py_InitModule4("_io", module_methods,
|
||||
module_doc, NULL, PYTHON_API_VERSION);
|
||||
if (m == NULL)
|
||||
return;
|
||||
|
||||
/* put os in the module state */
|
||||
_PyIO_os_module = PyImport_ImportModule("os");
|
||||
if (_PyIO_os_module == NULL)
|
||||
goto fail;
|
||||
|
||||
#define ADD_TYPE(type, name) \
|
||||
if (PyType_Ready(type) < 0) \
|
||||
goto fail; \
|
||||
Py_INCREF(type); \
|
||||
if (PyModule_AddObject(m, name, (PyObject *)type) < 0) { \
|
||||
Py_DECREF(type); \
|
||||
goto fail; \
|
||||
}
|
||||
|
||||
/* DEFAULT_BUFFER_SIZE */
|
||||
if (PyModule_AddIntMacro(m, DEFAULT_BUFFER_SIZE) < 0)
|
||||
goto fail;
|
||||
|
||||
/* UnsupportedOperation inherits from ValueError and IOError */
|
||||
_PyIO_unsupported_operation = PyObject_CallFunction(
|
||||
(PyObject *)&PyType_Type, "s(OO){}",
|
||||
"UnsupportedOperation", PyExc_ValueError, PyExc_IOError);
|
||||
if (_PyIO_unsupported_operation == NULL)
|
||||
goto fail;
|
||||
Py_INCREF(_PyIO_unsupported_operation);
|
||||
if (PyModule_AddObject(m, "UnsupportedOperation",
|
||||
_PyIO_unsupported_operation) < 0)
|
||||
goto fail;
|
||||
|
||||
/* BlockingIOError */
|
||||
_PyExc_BlockingIOError.tp_base = (PyTypeObject *) PyExc_IOError;
|
||||
ADD_TYPE(&_PyExc_BlockingIOError, "BlockingIOError");
|
||||
|
||||
/* Concrete base types of the IO ABCs.
|
||||
(the ABCs themselves are declared through inheritance in io.py)
|
||||
*/
|
||||
ADD_TYPE(&PyIOBase_Type, "_IOBase");
|
||||
ADD_TYPE(&PyRawIOBase_Type, "_RawIOBase");
|
||||
ADD_TYPE(&PyBufferedIOBase_Type, "_BufferedIOBase");
|
||||
ADD_TYPE(&PyTextIOBase_Type, "_TextIOBase");
|
||||
|
||||
/* Implementation of concrete IO objects. */
|
||||
/* FileIO */
|
||||
PyFileIO_Type.tp_base = &PyRawIOBase_Type;
|
||||
ADD_TYPE(&PyFileIO_Type, "FileIO");
|
||||
|
||||
/* BytesIO */
|
||||
PyBytesIO_Type.tp_base = &PyBufferedIOBase_Type;
|
||||
ADD_TYPE(&PyBytesIO_Type, "BytesIO");
|
||||
|
||||
/* StringIO */
|
||||
PyStringIO_Type.tp_base = &PyTextIOBase_Type;
|
||||
ADD_TYPE(&PyStringIO_Type, "StringIO");
|
||||
|
||||
/* BufferedReader */
|
||||
PyBufferedReader_Type.tp_base = &PyBufferedIOBase_Type;
|
||||
ADD_TYPE(&PyBufferedReader_Type, "BufferedReader");
|
||||
|
||||
/* BufferedWriter */
|
||||
PyBufferedWriter_Type.tp_base = &PyBufferedIOBase_Type;
|
||||
ADD_TYPE(&PyBufferedWriter_Type, "BufferedWriter");
|
||||
|
||||
/* BufferedRWPair */
|
||||
PyBufferedRWPair_Type.tp_base = &PyBufferedIOBase_Type;
|
||||
ADD_TYPE(&PyBufferedRWPair_Type, "BufferedRWPair");
|
||||
|
||||
/* BufferedRandom */
|
||||
PyBufferedRandom_Type.tp_base = &PyBufferedIOBase_Type;
|
||||
ADD_TYPE(&PyBufferedRandom_Type, "BufferedRandom");
|
||||
|
||||
/* TextIOWrapper */
|
||||
PyTextIOWrapper_Type.tp_base = &PyTextIOBase_Type;
|
||||
ADD_TYPE(&PyTextIOWrapper_Type, "TextIOWrapper");
|
||||
|
||||
/* IncrementalNewlineDecoder */
|
||||
ADD_TYPE(&PyIncrementalNewlineDecoder_Type, "IncrementalNewlineDecoder");
|
||||
|
||||
/* Interned strings */
|
||||
if (!(_PyIO_str_close = PyString_InternFromString("close")))
|
||||
goto fail;
|
||||
if (!(_PyIO_str_closed = PyString_InternFromString("closed")))
|
||||
goto fail;
|
||||
if (!(_PyIO_str_decode = PyString_InternFromString("decode")))
|
||||
goto fail;
|
||||
if (!(_PyIO_str_encode = PyString_InternFromString("encode")))
|
||||
goto fail;
|
||||
if (!(_PyIO_str_fileno = PyString_InternFromString("fileno")))
|
||||
goto fail;
|
||||
if (!(_PyIO_str_flush = PyString_InternFromString("flush")))
|
||||
goto fail;
|
||||
if (!(_PyIO_str_getstate = PyString_InternFromString("getstate")))
|
||||
goto fail;
|
||||
if (!(_PyIO_str_isatty = PyString_InternFromString("isatty")))
|
||||
goto fail;
|
||||
if (!(_PyIO_str_newlines = PyString_InternFromString("newlines")))
|
||||
goto fail;
|
||||
if (!(_PyIO_str_nl = PyString_InternFromString("\n")))
|
||||
goto fail;
|
||||
if (!(_PyIO_str_read = PyString_InternFromString("read")))
|
||||
goto fail;
|
||||
if (!(_PyIO_str_read1 = PyString_InternFromString("read1")))
|
||||
goto fail;
|
||||
if (!(_PyIO_str_readable = PyString_InternFromString("readable")))
|
||||
goto fail;
|
||||
if (!(_PyIO_str_readinto = PyString_InternFromString("readinto")))
|
||||
goto fail;
|
||||
if (!(_PyIO_str_readline = PyString_InternFromString("readline")))
|
||||
goto fail;
|
||||
if (!(_PyIO_str_reset = PyString_InternFromString("reset")))
|
||||
goto fail;
|
||||
if (!(_PyIO_str_seek = PyString_InternFromString("seek")))
|
||||
goto fail;
|
||||
if (!(_PyIO_str_seekable = PyString_InternFromString("seekable")))
|
||||
goto fail;
|
||||
if (!(_PyIO_str_setstate = PyString_InternFromString("setstate")))
|
||||
goto fail;
|
||||
if (!(_PyIO_str_tell = PyString_InternFromString("tell")))
|
||||
goto fail;
|
||||
if (!(_PyIO_str_truncate = PyString_InternFromString("truncate")))
|
||||
goto fail;
|
||||
if (!(_PyIO_str_write = PyString_InternFromString("write")))
|
||||
goto fail;
|
||||
if (!(_PyIO_str_writable = PyString_InternFromString("writable")))
|
||||
goto fail;
|
||||
|
||||
if (!(_PyIO_empty_str = PyUnicode_FromStringAndSize(NULL, 0)))
|
||||
goto fail;
|
||||
if (!(_PyIO_empty_bytes = PyBytes_FromStringAndSize(NULL, 0)))
|
||||
goto fail;
|
||||
if (!(_PyIO_zero = PyLong_FromLong(0L)))
|
||||
goto fail;
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
Py_CLEAR(_PyIO_os_module);
|
||||
Py_CLEAR(_PyIO_unsupported_operation);
|
||||
Py_DECREF(m);
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Declarations shared between the different parts of the io module
|
||||
*/
|
||||
|
||||
/* ABCs */
|
||||
extern PyTypeObject PyIOBase_Type;
|
||||
extern PyTypeObject PyRawIOBase_Type;
|
||||
extern PyTypeObject PyBufferedIOBase_Type;
|
||||
extern PyTypeObject PyTextIOBase_Type;
|
||||
|
||||
/* Concrete classes */
|
||||
extern PyTypeObject PyFileIO_Type;
|
||||
extern PyTypeObject PyBytesIO_Type;
|
||||
extern PyTypeObject PyStringIO_Type;
|
||||
extern PyTypeObject PyBufferedReader_Type;
|
||||
extern PyTypeObject PyBufferedWriter_Type;
|
||||
extern PyTypeObject PyBufferedRWPair_Type;
|
||||
extern PyTypeObject PyBufferedRandom_Type;
|
||||
extern PyTypeObject PyTextIOWrapper_Type;
|
||||
extern PyTypeObject PyIncrementalNewlineDecoder_Type;
|
||||
|
||||
|
||||
extern int _PyIO_ConvertSsize_t(PyObject *, void *);
|
||||
|
||||
/* These functions are used as METH_NOARGS methods, are normally called
|
||||
* with args=NULL, and return a new reference.
|
||||
* BUT when args=Py_True is passed, they return a borrowed reference.
|
||||
*/
|
||||
extern PyObject* _PyIOBase_check_readable(PyObject *self, PyObject *args);
|
||||
extern PyObject* _PyIOBase_check_writable(PyObject *self, PyObject *args);
|
||||
extern PyObject* _PyIOBase_check_seekable(PyObject *self, PyObject *args);
|
||||
extern PyObject* _PyIOBase_check_closed(PyObject *self, PyObject *args);
|
||||
|
||||
/* Helper for finalization.
|
||||
This function will revive an object ready to be deallocated and try to
|
||||
close() it. It returns 0 if the object can be destroyed, or -1 if it
|
||||
is alive again. */
|
||||
extern int _PyIOBase_finalize(PyObject *self);
|
||||
|
||||
/* Returns true if the given FileIO object is closed.
|
||||
Doesn't check the argument type, so be careful! */
|
||||
extern int _PyFileIO_closed(PyObject *self);
|
||||
|
||||
/* Shortcut to the core of the IncrementalNewlineDecoder.decode method */
|
||||
extern PyObject *_PyIncrementalNewlineDecoder_decode(
|
||||
PyObject *self, PyObject *input, int final);
|
||||
|
||||
/* Finds the first line ending between `start` and `end`.
|
||||
If found, returns the index after the line ending and doesn't touch
|
||||
`*consumed`.
|
||||
If not found, returns -1 and sets `*consumed` to the number of characters
|
||||
which can be safely put aside until another search.
|
||||
|
||||
NOTE: for performance reasons, `end` must point to a NUL character ('\0').
|
||||
Otherwise, the function will scan further and return garbage.
|
||||
|
||||
There are three modes, in order of priority:
|
||||
* translated: Only find \n (assume newlines already translated)
|
||||
* universal: Use universal newlines algorithm
|
||||
* Otherwise, the line ending is specified by readnl, a str object */
|
||||
extern Py_ssize_t _PyIO_find_line_ending(
|
||||
int translated, int universal, PyObject *readnl,
|
||||
Py_UNICODE *start, Py_UNICODE *end, Py_ssize_t *consumed);
|
||||
|
||||
/* Return 1 if an EnvironmentError with errno == EINTR is set (and then
|
||||
clears the error indicator), 0 otherwise.
|
||||
Should only be called when PyErr_Occurred() is true.
|
||||
*/
|
||||
extern int _PyIO_trap_eintr(void);
|
||||
|
||||
#define DEFAULT_BUFFER_SIZE (8 * 1024) /* bytes */
|
||||
|
||||
typedef struct {
|
||||
/* This is the equivalent of PyException_HEAD in 3.x */
|
||||
PyObject_HEAD
|
||||
PyObject *dict;
|
||||
PyObject *args;
|
||||
PyObject *message;
|
||||
|
||||
PyObject *myerrno;
|
||||
PyObject *strerror;
|
||||
PyObject *filename; /* Not used, but part of the IOError object */
|
||||
Py_ssize_t written;
|
||||
} PyBlockingIOErrorObject;
|
||||
extern PyObject *PyExc_BlockingIOError;
|
||||
|
||||
/*
|
||||
* Offset type for positioning.
|
||||
*/
|
||||
|
||||
/* Printing a variable of type off_t (with e.g., PyString_FromFormat)
|
||||
correctly and without producing compiler warnings is surprisingly painful.
|
||||
We identify an integer type whose size matches off_t and then: (1) cast the
|
||||
off_t to that integer type and (2) use the appropriate conversion
|
||||
specification. The cast is necessary: gcc complains about formatting a
|
||||
long with "%lld" even when both long and long long have the same
|
||||
precision. */
|
||||
|
||||
#if defined(MS_WIN64) || defined(MS_WINDOWS)
|
||||
|
||||
/* Windows uses long long for offsets */
|
||||
typedef PY_LONG_LONG Py_off_t;
|
||||
# define PyLong_AsOff_t PyLong_AsLongLong
|
||||
# define PyLong_FromOff_t PyLong_FromLongLong
|
||||
# define PY_OFF_T_MAX PY_LLONG_MAX
|
||||
# define PY_OFF_T_MIN PY_LLONG_MIN
|
||||
# define PY_OFF_T_COMPAT PY_LONG_LONG /* type compatible with off_t */
|
||||
# define PY_PRIdOFF "lld" /* format to use for that type */
|
||||
|
||||
#else
|
||||
|
||||
/* Other platforms use off_t */
|
||||
typedef off_t Py_off_t;
|
||||
#if (SIZEOF_OFF_T == SIZEOF_SIZE_T)
|
||||
# define PyLong_AsOff_t PyLong_AsSsize_t
|
||||
# define PyLong_FromOff_t PyLong_FromSsize_t
|
||||
# define PY_OFF_T_MAX PY_SSIZE_T_MAX
|
||||
# define PY_OFF_T_MIN PY_SSIZE_T_MIN
|
||||
# define PY_OFF_T_COMPAT Py_ssize_t
|
||||
# define PY_PRIdOFF "zd"
|
||||
#elif (HAVE_LONG_LONG && SIZEOF_OFF_T == SIZEOF_LONG_LONG)
|
||||
# define PyLong_AsOff_t PyLong_AsLongLong
|
||||
# define PyLong_FromOff_t PyLong_FromLongLong
|
||||
# define PY_OFF_T_MAX PY_LLONG_MAX
|
||||
# define PY_OFF_T_MIN PY_LLONG_MIN
|
||||
# define PY_OFF_T_COMPAT PY_LONG_LONG
|
||||
# define PY_PRIdOFF "lld"
|
||||
#elif (SIZEOF_OFF_T == SIZEOF_LONG)
|
||||
# define PyLong_AsOff_t PyLong_AsLong
|
||||
# define PyLong_FromOff_t PyLong_FromLong
|
||||
# define PY_OFF_T_MAX LONG_MAX
|
||||
# define PY_OFF_T_MIN LONG_MIN
|
||||
# define PY_OFF_T_COMPAT long
|
||||
# define PY_PRIdOFF "ld"
|
||||
#else
|
||||
# error off_t does not match either size_t, long, or long long!
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
extern Py_off_t PyNumber_AsOff_t(PyObject *item, PyObject *err);
|
||||
|
||||
/* Implementation details */
|
||||
|
||||
extern PyObject *_PyIO_os_module;
|
||||
extern PyObject *_PyIO_locale_module;
|
||||
extern PyObject *_PyIO_unsupported_operation;
|
||||
|
||||
extern PyObject *_PyIO_str_close;
|
||||
extern PyObject *_PyIO_str_closed;
|
||||
extern PyObject *_PyIO_str_decode;
|
||||
extern PyObject *_PyIO_str_encode;
|
||||
extern PyObject *_PyIO_str_fileno;
|
||||
extern PyObject *_PyIO_str_flush;
|
||||
extern PyObject *_PyIO_str_getstate;
|
||||
extern PyObject *_PyIO_str_isatty;
|
||||
extern PyObject *_PyIO_str_newlines;
|
||||
extern PyObject *_PyIO_str_nl;
|
||||
extern PyObject *_PyIO_str_read;
|
||||
extern PyObject *_PyIO_str_read1;
|
||||
extern PyObject *_PyIO_str_readable;
|
||||
extern PyObject *_PyIO_str_readinto;
|
||||
extern PyObject *_PyIO_str_readline;
|
||||
extern PyObject *_PyIO_str_reset;
|
||||
extern PyObject *_PyIO_str_seek;
|
||||
extern PyObject *_PyIO_str_seekable;
|
||||
extern PyObject *_PyIO_str_setstate;
|
||||
extern PyObject *_PyIO_str_tell;
|
||||
extern PyObject *_PyIO_str_truncate;
|
||||
extern PyObject *_PyIO_str_writable;
|
||||
extern PyObject *_PyIO_str_write;
|
||||
|
||||
extern PyObject *_PyIO_empty_str;
|
||||
extern PyObject *_PyIO_empty_bytes;
|
||||
extern PyObject *_PyIO_zero;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,910 @@
|
||||
#include "Python.h"
|
||||
#include "structmember.h" /* for offsetof() */
|
||||
#include "_iomodule.h"
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
char *buf;
|
||||
Py_ssize_t pos;
|
||||
Py_ssize_t string_size;
|
||||
size_t buf_size;
|
||||
PyObject *dict;
|
||||
PyObject *weakreflist;
|
||||
} bytesio;
|
||||
|
||||
#define CHECK_CLOSED(self) \
|
||||
if ((self)->buf == NULL) { \
|
||||
PyErr_SetString(PyExc_ValueError, \
|
||||
"I/O operation on closed file."); \
|
||||
return NULL; \
|
||||
}
|
||||
|
||||
/* Internal routine to get a line from the buffer of a BytesIO
|
||||
object. Returns the length between the current position to the
|
||||
next newline character. */
|
||||
static Py_ssize_t
|
||||
get_line(bytesio *self, char **output)
|
||||
{
|
||||
char *n;
|
||||
const char *str_end;
|
||||
Py_ssize_t len;
|
||||
|
||||
assert(self->buf != NULL);
|
||||
|
||||
/* Move to the end of the line, up to the end of the string, s. */
|
||||
str_end = self->buf + self->string_size;
|
||||
for (n = self->buf + self->pos;
|
||||
n < str_end && *n != '\n';
|
||||
n++);
|
||||
|
||||
/* Skip the newline character */
|
||||
if (n < str_end)
|
||||
n++;
|
||||
|
||||
/* Get the length from the current position to the end of the line. */
|
||||
len = n - (self->buf + self->pos);
|
||||
*output = self->buf + self->pos;
|
||||
|
||||
assert(len >= 0);
|
||||
assert(self->pos < PY_SSIZE_T_MAX - len);
|
||||
self->pos += len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Internal routine for changing the size of the buffer of BytesIO objects.
|
||||
The caller should ensure that the 'size' argument is non-negative. Returns
|
||||
0 on success, -1 otherwise. */
|
||||
static int
|
||||
resize_buffer(bytesio *self, size_t size)
|
||||
{
|
||||
/* Here, unsigned types are used to avoid dealing with signed integer
|
||||
overflow, which is undefined in C. */
|
||||
size_t alloc = self->buf_size;
|
||||
char *new_buf = NULL;
|
||||
|
||||
assert(self->buf != NULL);
|
||||
|
||||
/* For simplicity, stay in the range of the signed type. Anyway, Python
|
||||
doesn't allow strings to be longer than this. */
|
||||
if (size > PY_SSIZE_T_MAX)
|
||||
goto overflow;
|
||||
|
||||
if (size < alloc / 2) {
|
||||
/* Major downsize; resize down to exact size. */
|
||||
alloc = size + 1;
|
||||
}
|
||||
else if (size < alloc) {
|
||||
/* Within allocated size; quick exit */
|
||||
return 0;
|
||||
}
|
||||
else if (size <= alloc * 1.125) {
|
||||
/* Moderate upsize; overallocate similar to list_resize() */
|
||||
alloc = size + (size >> 3) + (size < 9 ? 3 : 6);
|
||||
}
|
||||
else {
|
||||
/* Major upsize; resize up to exact size */
|
||||
alloc = size + 1;
|
||||
}
|
||||
|
||||
if (alloc > ((size_t)-1) / sizeof(char))
|
||||
goto overflow;
|
||||
new_buf = (char *)PyMem_Realloc(self->buf, alloc * sizeof(char));
|
||||
if (new_buf == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return -1;
|
||||
}
|
||||
self->buf_size = alloc;
|
||||
self->buf = new_buf;
|
||||
|
||||
return 0;
|
||||
|
||||
overflow:
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"new buffer size too large");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Internal routine for writing a string of bytes to the buffer of a BytesIO
|
||||
object. Returns the number of bytes written, or -1 on error. */
|
||||
static Py_ssize_t
|
||||
write_bytes(bytesio *self, const char *bytes, Py_ssize_t len)
|
||||
{
|
||||
assert(self->buf != NULL);
|
||||
assert(self->pos >= 0);
|
||||
assert(len >= 0);
|
||||
|
||||
if ((size_t)self->pos + len > self->buf_size) {
|
||||
if (resize_buffer(self, (size_t)self->pos + len) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (self->pos > self->string_size) {
|
||||
/* In case of overseek, pad with null bytes the buffer region between
|
||||
the end of stream and the current position.
|
||||
|
||||
0 lo string_size hi
|
||||
| |<---used--->|<----------available----------->|
|
||||
| | <--to pad-->|<---to write---> |
|
||||
0 buf position
|
||||
*/
|
||||
memset(self->buf + self->string_size, '\0',
|
||||
(self->pos - self->string_size) * sizeof(char));
|
||||
}
|
||||
|
||||
/* Copy the data to the internal buffer, overwriting some of the existing
|
||||
data if self->pos < self->string_size. */
|
||||
memcpy(self->buf + self->pos, bytes, len);
|
||||
self->pos += len;
|
||||
|
||||
/* Set the new length of the internal string if it has changed. */
|
||||
if (self->string_size < self->pos) {
|
||||
self->string_size = self->pos;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
bytesio_get_closed(bytesio *self)
|
||||
{
|
||||
if (self->buf == NULL) {
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
else {
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(readable_doc,
|
||||
"readable() -> bool. Returns True if the IO object can be read.");
|
||||
|
||||
PyDoc_STRVAR(writable_doc,
|
||||
"writable() -> bool. Returns True if the IO object can be written.");
|
||||
|
||||
PyDoc_STRVAR(seekable_doc,
|
||||
"seekable() -> bool. Returns True if the IO object can be seeked.");
|
||||
|
||||
/* Generic getter for the writable, readable and seekable properties */
|
||||
static PyObject *
|
||||
return_not_closed(bytesio *self)
|
||||
{
|
||||
CHECK_CLOSED(self);
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(flush_doc,
|
||||
"flush() -> None. Does nothing.");
|
||||
|
||||
static PyObject *
|
||||
bytesio_flush(bytesio *self)
|
||||
{
|
||||
CHECK_CLOSED(self);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(getval_doc,
|
||||
"getvalue() -> bytes.\n"
|
||||
"\n"
|
||||
"Retrieve the entire contents of the BytesIO object.");
|
||||
|
||||
static PyObject *
|
||||
bytesio_getvalue(bytesio *self)
|
||||
{
|
||||
CHECK_CLOSED(self);
|
||||
return PyBytes_FromStringAndSize(self->buf, self->string_size);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(isatty_doc,
|
||||
"isatty() -> False.\n"
|
||||
"\n"
|
||||
"Always returns False since BytesIO objects are not connected\n"
|
||||
"to a tty-like device.");
|
||||
|
||||
static PyObject *
|
||||
bytesio_isatty(bytesio *self)
|
||||
{
|
||||
CHECK_CLOSED(self);
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(tell_doc,
|
||||
"tell() -> current file position, an integer\n");
|
||||
|
||||
static PyObject *
|
||||
bytesio_tell(bytesio *self)
|
||||
{
|
||||
CHECK_CLOSED(self);
|
||||
return PyLong_FromSsize_t(self->pos);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(read_doc,
|
||||
"read([size]) -> read at most size bytes, returned as a string.\n"
|
||||
"\n"
|
||||
"If the size argument is negative, read until EOF is reached.\n"
|
||||
"Return an empty string at EOF.");
|
||||
|
||||
static PyObject *
|
||||
bytesio_read(bytesio *self, PyObject *args)
|
||||
{
|
||||
Py_ssize_t size, n;
|
||||
char *output;
|
||||
PyObject *arg = Py_None;
|
||||
|
||||
CHECK_CLOSED(self);
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|O:read", &arg))
|
||||
return NULL;
|
||||
|
||||
if (PyNumber_Check(arg)) {
|
||||
size = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
|
||||
if (size == -1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
}
|
||||
else if (arg == Py_None) {
|
||||
/* Read until EOF is reached, by default. */
|
||||
size = -1;
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
|
||||
Py_TYPE(arg)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* adjust invalid sizes */
|
||||
n = self->string_size - self->pos;
|
||||
if (size < 0 || size > n) {
|
||||
size = n;
|
||||
if (size < 0)
|
||||
size = 0;
|
||||
}
|
||||
|
||||
assert(self->buf != NULL);
|
||||
output = self->buf + self->pos;
|
||||
self->pos += size;
|
||||
|
||||
return PyBytes_FromStringAndSize(output, size);
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(read1_doc,
|
||||
"read1(size) -> read at most size bytes, returned as a string.\n"
|
||||
"\n"
|
||||
"If the size argument is negative or omitted, read until EOF is reached.\n"
|
||||
"Return an empty string at EOF.");
|
||||
|
||||
static PyObject *
|
||||
bytesio_read1(bytesio *self, PyObject *n)
|
||||
{
|
||||
PyObject *arg, *res;
|
||||
|
||||
arg = PyTuple_Pack(1, n);
|
||||
if (arg == NULL)
|
||||
return NULL;
|
||||
res = bytesio_read(self, arg);
|
||||
Py_DECREF(arg);
|
||||
return res;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(readline_doc,
|
||||
"readline([size]) -> next line from the file, as a string.\n"
|
||||
"\n"
|
||||
"Retain newline. A non-negative size argument limits the maximum\n"
|
||||
"number of bytes to return (an incomplete line may be returned then).\n"
|
||||
"Return an empty string at EOF.\n");
|
||||
|
||||
static PyObject *
|
||||
bytesio_readline(bytesio *self, PyObject *args)
|
||||
{
|
||||
Py_ssize_t size, n;
|
||||
char *output;
|
||||
PyObject *arg = Py_None;
|
||||
|
||||
CHECK_CLOSED(self);
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|O:readline", &arg))
|
||||
return NULL;
|
||||
|
||||
if (PyNumber_Check(arg)) {
|
||||
size = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
|
||||
if (size == -1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
}
|
||||
else if (arg == Py_None) {
|
||||
/* No size limit, by default. */
|
||||
size = -1;
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
|
||||
Py_TYPE(arg)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
n = get_line(self, &output);
|
||||
|
||||
if (size >= 0 && size < n) {
|
||||
size = n - size;
|
||||
n -= size;
|
||||
self->pos -= size;
|
||||
}
|
||||
|
||||
return PyBytes_FromStringAndSize(output, n);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(readlines_doc,
|
||||
"readlines([size]) -> list of strings, each a line from the file.\n"
|
||||
"\n"
|
||||
"Call readline() repeatedly and return a list of the lines so read.\n"
|
||||
"The optional size argument, if given, is an approximate bound on the\n"
|
||||
"total number of bytes in the lines returned.\n");
|
||||
|
||||
static PyObject *
|
||||
bytesio_readlines(bytesio *self, PyObject *args)
|
||||
{
|
||||
Py_ssize_t maxsize, size, n;
|
||||
PyObject *result, *line;
|
||||
char *output;
|
||||
PyObject *arg = Py_None;
|
||||
|
||||
CHECK_CLOSED(self);
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|O:readlines", &arg))
|
||||
return NULL;
|
||||
|
||||
if (PyNumber_Check(arg)) {
|
||||
maxsize = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
|
||||
if (maxsize == -1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
}
|
||||
else if (arg == Py_None) {
|
||||
/* No size limit, by default. */
|
||||
maxsize = -1;
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
|
||||
Py_TYPE(arg)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = 0;
|
||||
result = PyList_New(0);
|
||||
if (!result)
|
||||
return NULL;
|
||||
|
||||
while ((n = get_line(self, &output)) != 0) {
|
||||
line = PyBytes_FromStringAndSize(output, n);
|
||||
if (!line)
|
||||
goto on_error;
|
||||
if (PyList_Append(result, line) == -1) {
|
||||
Py_DECREF(line);
|
||||
goto on_error;
|
||||
}
|
||||
Py_DECREF(line);
|
||||
size += n;
|
||||
if (maxsize > 0 && size >= maxsize)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
|
||||
on_error:
|
||||
Py_DECREF(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(readinto_doc,
|
||||
"readinto(b) -> int. Read up to len(b) bytes into b.\n"
|
||||
"\n"
|
||||
"Returns number of bytes read (0 for EOF), or None if the object\n"
|
||||
"is set not to block and has no data to read.");
|
||||
|
||||
static PyObject *
|
||||
bytesio_readinto(bytesio *self, PyObject *args)
|
||||
{
|
||||
Py_buffer buf;
|
||||
Py_ssize_t len, n;
|
||||
|
||||
CHECK_CLOSED(self);
|
||||
|
||||
if (!PyArg_ParseTuple(args, "w*", &buf))
|
||||
return NULL;
|
||||
|
||||
len = buf.len;
|
||||
/* adjust invalid sizes */
|
||||
n = self->string_size - self->pos;
|
||||
if (len > n) {
|
||||
len = n;
|
||||
if (len < 0)
|
||||
len = 0;
|
||||
}
|
||||
|
||||
memcpy(buf.buf, self->buf + self->pos, len);
|
||||
assert(self->pos + len < PY_SSIZE_T_MAX);
|
||||
assert(len >= 0);
|
||||
self->pos += len;
|
||||
|
||||
PyBuffer_Release(&buf);
|
||||
return PyLong_FromSsize_t(len);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(truncate_doc,
|
||||
"truncate([size]) -> int. Truncate the file to at most size bytes.\n"
|
||||
"\n"
|
||||
"Size defaults to the current file position, as returned by tell().\n"
|
||||
"The current file position is unchanged. Returns the new size.\n");
|
||||
|
||||
static PyObject *
|
||||
bytesio_truncate(bytesio *self, PyObject *args)
|
||||
{
|
||||
Py_ssize_t size;
|
||||
PyObject *arg = Py_None;
|
||||
|
||||
CHECK_CLOSED(self);
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|O:truncate", &arg))
|
||||
return NULL;
|
||||
|
||||
if (PyNumber_Check(arg)) {
|
||||
size = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
|
||||
if (size == -1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
}
|
||||
else if (arg == Py_None) {
|
||||
/* Truncate to current position if no argument is passed. */
|
||||
size = self->pos;
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
|
||||
Py_TYPE(arg)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size < 0) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"negative size value %zd", size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size < self->string_size) {
|
||||
self->string_size = size;
|
||||
if (resize_buffer(self, size) < 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return PyLong_FromSsize_t(size);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
bytesio_iternext(bytesio *self)
|
||||
{
|
||||
char *next;
|
||||
Py_ssize_t n;
|
||||
|
||||
CHECK_CLOSED(self);
|
||||
|
||||
n = get_line(self, &next);
|
||||
|
||||
if (!next || n == 0)
|
||||
return NULL;
|
||||
|
||||
return PyBytes_FromStringAndSize(next, n);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(seek_doc,
|
||||
"seek(pos[, whence]) -> int. Change stream position.\n"
|
||||
"\n"
|
||||
"Seek to byte offset pos relative to position indicated by whence:\n"
|
||||
" 0 Start of stream (the default). pos should be >= 0;\n"
|
||||
" 1 Current position - pos may be negative;\n"
|
||||
" 2 End of stream - pos usually negative.\n"
|
||||
"Returns the new absolute position.");
|
||||
|
||||
static PyObject *
|
||||
bytesio_seek(bytesio *self, PyObject *args)
|
||||
{
|
||||
PyObject *posobj;
|
||||
Py_ssize_t pos;
|
||||
int mode = 0;
|
||||
|
||||
CHECK_CLOSED(self);
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O|i:seek", &posobj, &mode))
|
||||
return NULL;
|
||||
|
||||
pos = PyNumber_AsSsize_t(posobj, PyExc_OverflowError);
|
||||
if (pos == -1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
|
||||
if (pos < 0 && mode == 0) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"negative seek value %zd", pos);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* mode 0: offset relative to beginning of the string.
|
||||
mode 1: offset relative to current position.
|
||||
mode 2: offset relative the end of the string. */
|
||||
if (mode == 1) {
|
||||
if (pos > PY_SSIZE_T_MAX - self->pos) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"new position too large");
|
||||
return NULL;
|
||||
}
|
||||
pos += self->pos;
|
||||
}
|
||||
else if (mode == 2) {
|
||||
if (pos > PY_SSIZE_T_MAX - self->string_size) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"new position too large");
|
||||
return NULL;
|
||||
}
|
||||
pos += self->string_size;
|
||||
}
|
||||
else if (mode != 0) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"invalid whence (%i, should be 0, 1 or 2)", mode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pos < 0)
|
||||
pos = 0;
|
||||
self->pos = pos;
|
||||
|
||||
return PyLong_FromSsize_t(self->pos);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(write_doc,
|
||||
"write(bytes) -> int. Write bytes to file.\n"
|
||||
"\n"
|
||||
"Return the number of bytes written.");
|
||||
|
||||
static PyObject *
|
||||
bytesio_write(bytesio *self, PyObject *obj)
|
||||
{
|
||||
Py_ssize_t n = 0;
|
||||
Py_buffer buf;
|
||||
PyObject *result = NULL;
|
||||
|
||||
CHECK_CLOSED(self);
|
||||
|
||||
if (PyObject_GetBuffer(obj, &buf, PyBUF_CONTIG_RO) < 0)
|
||||
return NULL;
|
||||
|
||||
if (buf.len != 0)
|
||||
n = write_bytes(self, buf.buf, buf.len);
|
||||
if (n >= 0)
|
||||
result = PyLong_FromSsize_t(n);
|
||||
|
||||
PyBuffer_Release(&buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(writelines_doc,
|
||||
"writelines(sequence_of_strings) -> None. Write strings to the file.\n"
|
||||
"\n"
|
||||
"Note that newlines are not added. The sequence can be any iterable\n"
|
||||
"object producing strings. This is equivalent to calling write() for\n"
|
||||
"each string.");
|
||||
|
||||
static PyObject *
|
||||
bytesio_writelines(bytesio *self, PyObject *v)
|
||||
{
|
||||
PyObject *it, *item;
|
||||
PyObject *ret;
|
||||
|
||||
CHECK_CLOSED(self);
|
||||
|
||||
it = PyObject_GetIter(v);
|
||||
if (it == NULL)
|
||||
return NULL;
|
||||
|
||||
while ((item = PyIter_Next(it)) != NULL) {
|
||||
ret = bytesio_write(self, item);
|
||||
Py_DECREF(item);
|
||||
if (ret == NULL) {
|
||||
Py_DECREF(it);
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(ret);
|
||||
}
|
||||
Py_DECREF(it);
|
||||
|
||||
/* See if PyIter_Next failed */
|
||||
if (PyErr_Occurred())
|
||||
return NULL;
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(close_doc,
|
||||
"close() -> None. Disable all I/O operations.");
|
||||
|
||||
static PyObject *
|
||||
bytesio_close(bytesio *self)
|
||||
{
|
||||
if (self->buf != NULL) {
|
||||
PyMem_Free(self->buf);
|
||||
self->buf = NULL;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/* Pickling support.
|
||||
|
||||
Note that only pickle protocol 2 and onward are supported since we use
|
||||
extended __reduce__ API of PEP 307 to make BytesIO instances picklable.
|
||||
|
||||
Providing support for protocol < 2 would require the __reduce_ex__ method
|
||||
which is notably long-winded when defined properly.
|
||||
|
||||
For BytesIO, the implementation would similar to one coded for
|
||||
object.__reduce_ex__, but slightly less general. To be more specific, we
|
||||
could call bytesio_getstate directly and avoid checking for the presence of
|
||||
a fallback __reduce__ method. However, we would still need a __newobj__
|
||||
function to use the efficient instance representation of PEP 307.
|
||||
*/
|
||||
|
||||
static PyObject *
|
||||
bytesio_getstate(bytesio *self)
|
||||
{
|
||||
PyObject *initvalue = bytesio_getvalue(self);
|
||||
PyObject *dict;
|
||||
PyObject *state;
|
||||
|
||||
if (initvalue == NULL)
|
||||
return NULL;
|
||||
if (self->dict == NULL) {
|
||||
Py_INCREF(Py_None);
|
||||
dict = Py_None;
|
||||
}
|
||||
else {
|
||||
dict = PyDict_Copy(self->dict);
|
||||
if (dict == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
state = Py_BuildValue("(OnN)", initvalue, self->pos, dict);
|
||||
Py_DECREF(initvalue);
|
||||
return state;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
bytesio_setstate(bytesio *self, PyObject *state)
|
||||
{
|
||||
PyObject *result;
|
||||
PyObject *position_obj;
|
||||
PyObject *dict;
|
||||
Py_ssize_t pos;
|
||||
|
||||
assert(state != NULL);
|
||||
|
||||
/* We allow the state tuple to be longer than 3, because we may need
|
||||
someday to extend the object's state without breaking
|
||||
backward-compatibility. */
|
||||
if (!PyTuple_Check(state) || Py_SIZE(state) < 3) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s.__setstate__ argument should be 3-tuple, got %.200s",
|
||||
Py_TYPE(self)->tp_name, Py_TYPE(state)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
/* Reset the object to its default state. This is only needed to handle
|
||||
the case of repeated calls to __setstate__. */
|
||||
self->string_size = 0;
|
||||
self->pos = 0;
|
||||
|
||||
/* Set the value of the internal buffer. If state[0] does not support the
|
||||
buffer protocol, bytesio_write will raise the appropriate TypeError. */
|
||||
result = bytesio_write(self, PyTuple_GET_ITEM(state, 0));
|
||||
if (result == NULL)
|
||||
return NULL;
|
||||
Py_DECREF(result);
|
||||
|
||||
/* Set carefully the position value. Alternatively, we could use the seek
|
||||
method instead of modifying self->pos directly to better protect the
|
||||
object internal state against errneous (or malicious) inputs. */
|
||||
position_obj = PyTuple_GET_ITEM(state, 1);
|
||||
if (!PyIndex_Check(position_obj)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"second item of state must be an integer, not %.200s",
|
||||
Py_TYPE(position_obj)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
pos = PyNumber_AsSsize_t(position_obj, PyExc_OverflowError);
|
||||
if (pos == -1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
if (pos < 0) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"position value cannot be negative");
|
||||
return NULL;
|
||||
}
|
||||
self->pos = pos;
|
||||
|
||||
/* Set the dictionary of the instance variables. */
|
||||
dict = PyTuple_GET_ITEM(state, 2);
|
||||
if (dict != Py_None) {
|
||||
if (!PyDict_Check(dict)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"third item of state should be a dict, got a %.200s",
|
||||
Py_TYPE(dict)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
if (self->dict) {
|
||||
/* Alternatively, we could replace the internal dictionary
|
||||
completely. However, it seems more practical to just update it. */
|
||||
if (PyDict_Update(self->dict, dict) < 0)
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
Py_INCREF(dict);
|
||||
self->dict = dict;
|
||||
}
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
bytesio_dealloc(bytesio *self)
|
||||
{
|
||||
/* bpo-31095: UnTrack is needed before calling any callbacks */
|
||||
_PyObject_GC_UNTRACK(self);
|
||||
if (self->buf != NULL) {
|
||||
PyMem_Free(self->buf);
|
||||
self->buf = NULL;
|
||||
}
|
||||
Py_CLEAR(self->dict);
|
||||
if (self->weakreflist != NULL)
|
||||
PyObject_ClearWeakRefs((PyObject *) self);
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
bytesio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
bytesio *self;
|
||||
|
||||
assert(type != NULL && type->tp_alloc != NULL);
|
||||
self = (bytesio *)type->tp_alloc(type, 0);
|
||||
if (self == NULL)
|
||||
return NULL;
|
||||
|
||||
/* tp_alloc initializes all the fields to zero. So we don't have to
|
||||
initialize them here. */
|
||||
|
||||
self->buf = (char *)PyMem_Malloc(0);
|
||||
if (self->buf == NULL) {
|
||||
Py_DECREF(self);
|
||||
return PyErr_NoMemory();
|
||||
}
|
||||
|
||||
return (PyObject *)self;
|
||||
}
|
||||
|
||||
static int
|
||||
bytesio_init(bytesio *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
char *kwlist[] = {"initial_bytes", NULL};
|
||||
PyObject *initvalue = NULL;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:BytesIO", kwlist,
|
||||
&initvalue))
|
||||
return -1;
|
||||
|
||||
/* In case, __init__ is called multiple times. */
|
||||
self->string_size = 0;
|
||||
self->pos = 0;
|
||||
|
||||
if (initvalue && initvalue != Py_None) {
|
||||
PyObject *res;
|
||||
res = bytesio_write(self, initvalue);
|
||||
if (res == NULL)
|
||||
return -1;
|
||||
Py_DECREF(res);
|
||||
self->pos = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
bytesio_sizeof(bytesio *self, void *unused)
|
||||
{
|
||||
Py_ssize_t res;
|
||||
|
||||
res = _PyObject_SIZE(Py_TYPE(self));
|
||||
if (self->buf)
|
||||
res += self->buf_size;
|
||||
return PyLong_FromSsize_t(res);
|
||||
}
|
||||
|
||||
static int
|
||||
bytesio_traverse(bytesio *self, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(self->dict);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bytesio_clear(bytesio *self)
|
||||
{
|
||||
Py_CLEAR(self->dict);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static PyGetSetDef bytesio_getsetlist[] = {
|
||||
{"closed", (getter)bytesio_get_closed, NULL,
|
||||
"True if the file is closed."},
|
||||
{NULL}, /* sentinel */
|
||||
};
|
||||
|
||||
static struct PyMethodDef bytesio_methods[] = {
|
||||
{"readable", (PyCFunction)return_not_closed, METH_NOARGS, readable_doc},
|
||||
{"seekable", (PyCFunction)return_not_closed, METH_NOARGS, seekable_doc},
|
||||
{"writable", (PyCFunction)return_not_closed, METH_NOARGS, writable_doc},
|
||||
{"close", (PyCFunction)bytesio_close, METH_NOARGS, close_doc},
|
||||
{"flush", (PyCFunction)bytesio_flush, METH_NOARGS, flush_doc},
|
||||
{"isatty", (PyCFunction)bytesio_isatty, METH_NOARGS, isatty_doc},
|
||||
{"tell", (PyCFunction)bytesio_tell, METH_NOARGS, tell_doc},
|
||||
{"write", (PyCFunction)bytesio_write, METH_O, write_doc},
|
||||
{"writelines", (PyCFunction)bytesio_writelines, METH_O, writelines_doc},
|
||||
{"read1", (PyCFunction)bytesio_read1, METH_O, read1_doc},
|
||||
{"readinto", (PyCFunction)bytesio_readinto, METH_VARARGS, readinto_doc},
|
||||
{"readline", (PyCFunction)bytesio_readline, METH_VARARGS, readline_doc},
|
||||
{"readlines", (PyCFunction)bytesio_readlines, METH_VARARGS, readlines_doc},
|
||||
{"read", (PyCFunction)bytesio_read, METH_VARARGS, read_doc},
|
||||
{"getvalue", (PyCFunction)bytesio_getvalue, METH_NOARGS, getval_doc},
|
||||
{"seek", (PyCFunction)bytesio_seek, METH_VARARGS, seek_doc},
|
||||
{"truncate", (PyCFunction)bytesio_truncate, METH_VARARGS, truncate_doc},
|
||||
{"__getstate__", (PyCFunction)bytesio_getstate, METH_NOARGS, NULL},
|
||||
{"__setstate__", (PyCFunction)bytesio_setstate, METH_O, NULL},
|
||||
{"__sizeof__", (PyCFunction)bytesio_sizeof, METH_NOARGS, NULL},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(bytesio_doc,
|
||||
"BytesIO([buffer]) -> object\n"
|
||||
"\n"
|
||||
"Create a buffered I/O implementation using an in-memory bytes\n"
|
||||
"buffer, ready for reading and writing.");
|
||||
|
||||
PyTypeObject PyBytesIO_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"_io.BytesIO", /*tp_name*/
|
||||
sizeof(bytesio), /*tp_basicsize*/
|
||||
0, /*tp_itemsize*/
|
||||
(destructor)bytesio_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_reserved*/
|
||||
0, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
0, /*tp_hash*/
|
||||
0, /*tp_call*/
|
||||
0, /*tp_str*/
|
||||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
|
||||
Py_TPFLAGS_HAVE_GC, /*tp_flags*/
|
||||
bytesio_doc, /*tp_doc*/
|
||||
(traverseproc)bytesio_traverse, /*tp_traverse*/
|
||||
(inquiry)bytesio_clear, /*tp_clear*/
|
||||
0, /*tp_richcompare*/
|
||||
offsetof(bytesio, weakreflist), /*tp_weaklistoffset*/
|
||||
PyObject_SelfIter, /*tp_iter*/
|
||||
(iternextfunc)bytesio_iternext, /*tp_iternext*/
|
||||
bytesio_methods, /*tp_methods*/
|
||||
0, /*tp_members*/
|
||||
bytesio_getsetlist, /*tp_getset*/
|
||||
0, /*tp_base*/
|
||||
0, /*tp_dict*/
|
||||
0, /*tp_descr_get*/
|
||||
0, /*tp_descr_set*/
|
||||
offsetof(bytesio, dict), /*tp_dictoffset*/
|
||||
(initproc)bytesio_init, /*tp_init*/
|
||||
0, /*tp_alloc*/
|
||||
bytesio_new, /*tp_new*/
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,940 @@
|
||||
/*
|
||||
An implementation of the I/O abstract base classes hierarchy
|
||||
as defined by PEP 3116 - "New I/O"
|
||||
|
||||
Classes defined here: IOBase, RawIOBase.
|
||||
|
||||
Written by Amaury Forgeot d'Arc and Antoine Pitrou
|
||||
*/
|
||||
|
||||
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include "Python.h"
|
||||
#include "structmember.h"
|
||||
#include "_iomodule.h"
|
||||
|
||||
/*
|
||||
* IOBase class, an abstract class
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
|
||||
PyObject *dict;
|
||||
PyObject *weakreflist;
|
||||
} iobase;
|
||||
|
||||
PyDoc_STRVAR(iobase_doc,
|
||||
"The abstract base class for all I/O classes, acting on streams of\n"
|
||||
"bytes. There is no public constructor.\n"
|
||||
"\n"
|
||||
"This class provides dummy implementations for many methods that\n"
|
||||
"derived classes can override selectively; the default implementations\n"
|
||||
"represent a file that cannot be read, written or seeked.\n"
|
||||
"\n"
|
||||
"Even though IOBase does not declare read, readinto, or write because\n"
|
||||
"their signatures will vary, implementations and clients should\n"
|
||||
"consider those methods part of the interface. Also, implementations\n"
|
||||
"may raise an IOError when operations they do not support are called.\n"
|
||||
"\n"
|
||||
"The basic type used for binary data read from or written to a file is\n"
|
||||
"the bytes type. Method arguments may also be bytearray or memoryview\n"
|
||||
"of arrays of bytes. In some cases, such as readinto, a writable\n"
|
||||
"object such as bytearray is required. Text I/O classes work with\n"
|
||||
"unicode data.\n"
|
||||
"\n"
|
||||
"Note that calling any method (except additional calls to close(),\n"
|
||||
"which are ignored) on a closed stream should raise a ValueError.\n"
|
||||
"\n"
|
||||
"IOBase (and its subclasses) support the iterator protocol, meaning\n"
|
||||
"that an IOBase object can be iterated over yielding the lines in a\n"
|
||||
"stream.\n"
|
||||
"\n"
|
||||
"IOBase also supports the :keyword:`with` statement. In this example,\n"
|
||||
"fp is closed after the suite of the with statement is complete:\n"
|
||||
"\n"
|
||||
"with open('spam.txt', 'r') as fp:\n"
|
||||
" fp.write('Spam and eggs!')\n");
|
||||
|
||||
/* Use this macro whenever you want to check the internal `closed` status
|
||||
of the IOBase object rather than the virtual `closed` attribute as returned
|
||||
by whatever subclass. */
|
||||
|
||||
#define IS_CLOSED(self) \
|
||||
PyObject_HasAttrString(self, "__IOBase_closed")
|
||||
|
||||
/* Internal methods */
|
||||
static PyObject *
|
||||
iobase_unsupported(const char *message)
|
||||
{
|
||||
PyErr_SetString(_PyIO_unsupported_operation, message);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Positioning */
|
||||
|
||||
PyDoc_STRVAR(iobase_seek_doc,
|
||||
"Change stream position.\n"
|
||||
"\n"
|
||||
"Change the stream position to the given byte offset. The offset is\n"
|
||||
"interpreted relative to the position indicated by whence. Values\n"
|
||||
"for whence are:\n"
|
||||
"\n"
|
||||
"* 0 -- start of stream (the default); offset should be zero or positive\n"
|
||||
"* 1 -- current stream position; offset may be negative\n"
|
||||
"* 2 -- end of stream; offset is usually negative\n"
|
||||
"\n"
|
||||
"Return the new absolute position.");
|
||||
|
||||
static PyObject *
|
||||
iobase_seek(PyObject *self, PyObject *args)
|
||||
{
|
||||
return iobase_unsupported("seek");
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(iobase_tell_doc,
|
||||
"Return current stream position.");
|
||||
|
||||
static PyObject *
|
||||
iobase_tell(PyObject *self, PyObject *args)
|
||||
{
|
||||
return PyObject_CallMethod(self, "seek", "ii", 0, 1);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(iobase_truncate_doc,
|
||||
"Truncate file to size bytes.\n"
|
||||
"\n"
|
||||
"File pointer is left unchanged. Size defaults to the current IO\n"
|
||||
"position as reported by tell(). Returns the new size.");
|
||||
|
||||
static PyObject *
|
||||
iobase_truncate(PyObject *self, PyObject *args)
|
||||
{
|
||||
return iobase_unsupported("truncate");
|
||||
}
|
||||
|
||||
/* Flush and close methods */
|
||||
|
||||
PyDoc_STRVAR(iobase_flush_doc,
|
||||
"Flush write buffers, if applicable.\n"
|
||||
"\n"
|
||||
"This is not implemented for read-only and non-blocking streams.\n");
|
||||
|
||||
static PyObject *
|
||||
iobase_flush(PyObject *self, PyObject *args)
|
||||
{
|
||||
/* XXX Should this return the number of bytes written??? */
|
||||
if (IS_CLOSED(self)) {
|
||||
PyErr_SetString(PyExc_ValueError, "I/O operation on closed file.");
|
||||
return NULL;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(iobase_close_doc,
|
||||
"Flush and close the IO object.\n"
|
||||
"\n"
|
||||
"This method has no effect if the file is already closed.\n");
|
||||
|
||||
static int
|
||||
iobase_closed(PyObject *self)
|
||||
{
|
||||
PyObject *res;
|
||||
int closed;
|
||||
/* This gets the derived attribute, which is *not* __IOBase_closed
|
||||
in most cases! */
|
||||
res = PyObject_GetAttr(self, _PyIO_str_closed);
|
||||
if (res == NULL)
|
||||
return 0;
|
||||
closed = PyObject_IsTrue(res);
|
||||
Py_DECREF(res);
|
||||
return closed;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
iobase_closed_get(PyObject *self, void *context)
|
||||
{
|
||||
return PyBool_FromLong(IS_CLOSED(self));
|
||||
}
|
||||
|
||||
PyObject *
|
||||
_PyIOBase_check_closed(PyObject *self, PyObject *args)
|
||||
{
|
||||
if (iobase_closed(self)) {
|
||||
PyErr_SetString(PyExc_ValueError, "I/O operation on closed file.");
|
||||
return NULL;
|
||||
}
|
||||
if (args == Py_True)
|
||||
return Py_None;
|
||||
else
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/* XXX: IOBase thinks it has to maintain its own internal state in
|
||||
`__IOBase_closed` and call flush() by itself, but it is redundant with
|
||||
whatever behaviour a non-trivial derived class will implement. */
|
||||
|
||||
static PyObject *
|
||||
iobase_close(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *res, *exc, *val, *tb;
|
||||
int rc;
|
||||
|
||||
if (IS_CLOSED(self))
|
||||
Py_RETURN_NONE;
|
||||
|
||||
res = PyObject_CallMethodObjArgs(self, _PyIO_str_flush, NULL);
|
||||
|
||||
PyErr_Fetch(&exc, &val, &tb);
|
||||
rc = PyObject_SetAttrString(self, "__IOBase_closed", Py_True);
|
||||
_PyErr_ReplaceException(exc, val, tb);
|
||||
if (rc < 0) {
|
||||
Py_CLEAR(res);
|
||||
}
|
||||
|
||||
if (res == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(res);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/* Finalization and garbage collection support */
|
||||
|
||||
int
|
||||
_PyIOBase_finalize(PyObject *self)
|
||||
{
|
||||
PyObject *res;
|
||||
PyObject *tp, *v, *tb;
|
||||
int closed = 1;
|
||||
int is_zombie;
|
||||
|
||||
/* If _PyIOBase_finalize() is called from a destructor, we need to
|
||||
resurrect the object as calling close() can invoke arbitrary code. */
|
||||
is_zombie = (Py_REFCNT(self) == 0);
|
||||
if (is_zombie) {
|
||||
++Py_REFCNT(self);
|
||||
}
|
||||
PyErr_Fetch(&tp, &v, &tb);
|
||||
/* If `closed` doesn't exist or can't be evaluated as bool, then the
|
||||
object is probably in an unusable state, so ignore. */
|
||||
res = PyObject_GetAttr(self, _PyIO_str_closed);
|
||||
if (res == NULL)
|
||||
PyErr_Clear();
|
||||
else {
|
||||
closed = PyObject_IsTrue(res);
|
||||
Py_DECREF(res);
|
||||
if (closed == -1)
|
||||
PyErr_Clear();
|
||||
}
|
||||
if (closed == 0) {
|
||||
res = PyObject_CallMethodObjArgs((PyObject *) self, _PyIO_str_close,
|
||||
NULL);
|
||||
/* Silencing I/O errors is bad, but printing spurious tracebacks is
|
||||
equally as bad, and potentially more frequent (because of
|
||||
shutdown issues). */
|
||||
if (res == NULL)
|
||||
PyErr_Clear();
|
||||
else
|
||||
Py_DECREF(res);
|
||||
}
|
||||
PyErr_Restore(tp, v, tb);
|
||||
if (is_zombie) {
|
||||
if (--Py_REFCNT(self) != 0) {
|
||||
/* The object lives again. The following code is taken from
|
||||
slot_tp_del in typeobject.c. */
|
||||
Py_ssize_t refcnt = Py_REFCNT(self);
|
||||
_Py_NewReference(self);
|
||||
Py_REFCNT(self) = refcnt;
|
||||
/* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so
|
||||
* we need to undo that. */
|
||||
_Py_DEC_REFTOTAL;
|
||||
/* If Py_TRACE_REFS, _Py_NewReference re-added self to the object
|
||||
* chain, so no more to do there.
|
||||
* If COUNT_ALLOCS, the original decref bumped tp_frees, and
|
||||
* _Py_NewReference bumped tp_allocs: both of those need to be
|
||||
* undone.
|
||||
*/
|
||||
#ifdef COUNT_ALLOCS
|
||||
--Py_TYPE(self)->tp_frees;
|
||||
--Py_TYPE(self)->tp_allocs;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
iobase_traverse(iobase *self, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(self->dict);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
iobase_clear(iobase *self)
|
||||
{
|
||||
if (_PyIOBase_finalize((PyObject *) self) < 0)
|
||||
return -1;
|
||||
Py_CLEAR(self->dict);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Destructor */
|
||||
|
||||
static void
|
||||
iobase_dealloc(iobase *self)
|
||||
{
|
||||
/* NOTE: since IOBaseObject has its own dict, Python-defined attributes
|
||||
are still available here for close() to use.
|
||||
However, if the derived class declares a __slots__, those slots are
|
||||
already gone.
|
||||
*/
|
||||
if (_PyIOBase_finalize((PyObject *) self) < 0) {
|
||||
/* When called from a heap type's dealloc, the type will be
|
||||
decref'ed on return (see e.g. subtype_dealloc in typeobject.c). */
|
||||
if (PyType_HasFeature(Py_TYPE(self), Py_TPFLAGS_HEAPTYPE))
|
||||
Py_INCREF(Py_TYPE(self));
|
||||
return;
|
||||
}
|
||||
_PyObject_GC_UNTRACK(self);
|
||||
if (self->weakreflist != NULL)
|
||||
PyObject_ClearWeakRefs((PyObject *) self);
|
||||
Py_CLEAR(self->dict);
|
||||
Py_TYPE(self)->tp_free((PyObject *) self);
|
||||
}
|
||||
|
||||
/* Inquiry methods */
|
||||
|
||||
PyDoc_STRVAR(iobase_seekable_doc,
|
||||
"Return whether object supports random access.\n"
|
||||
"\n"
|
||||
"If False, seek(), tell() and truncate() will raise IOError.\n"
|
||||
"This method may need to do a test seek().");
|
||||
|
||||
static PyObject *
|
||||
iobase_seekable(PyObject *self, PyObject *args)
|
||||
{
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
_PyIOBase_check_seekable(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *res = PyObject_CallMethodObjArgs(self, _PyIO_str_seekable, NULL);
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
if (res != Py_True) {
|
||||
Py_CLEAR(res);
|
||||
PyErr_SetString(PyExc_IOError, "File or stream is not seekable.");
|
||||
return NULL;
|
||||
}
|
||||
if (args == Py_True) {
|
||||
Py_DECREF(res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(iobase_readable_doc,
|
||||
"Return whether object was opened for reading.\n"
|
||||
"\n"
|
||||
"If False, read() will raise IOError.");
|
||||
|
||||
static PyObject *
|
||||
iobase_readable(PyObject *self, PyObject *args)
|
||||
{
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
/* May be called with any object */
|
||||
PyObject *
|
||||
_PyIOBase_check_readable(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *res = PyObject_CallMethodObjArgs(self, _PyIO_str_readable, NULL);
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
if (res != Py_True) {
|
||||
Py_CLEAR(res);
|
||||
PyErr_SetString(PyExc_IOError, "File or stream is not readable.");
|
||||
return NULL;
|
||||
}
|
||||
if (args == Py_True) {
|
||||
Py_DECREF(res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(iobase_writable_doc,
|
||||
"Return whether object was opened for writing.\n"
|
||||
"\n"
|
||||
"If False, read() will raise IOError.");
|
||||
|
||||
static PyObject *
|
||||
iobase_writable(PyObject *self, PyObject *args)
|
||||
{
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
/* May be called with any object */
|
||||
PyObject *
|
||||
_PyIOBase_check_writable(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *res = PyObject_CallMethodObjArgs(self, _PyIO_str_writable, NULL);
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
if (res != Py_True) {
|
||||
Py_CLEAR(res);
|
||||
PyErr_SetString(PyExc_IOError, "File or stream is not writable.");
|
||||
return NULL;
|
||||
}
|
||||
if (args == Py_True) {
|
||||
Py_DECREF(res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Context manager */
|
||||
|
||||
static PyObject *
|
||||
iobase_enter(PyObject *self, PyObject *args)
|
||||
{
|
||||
if (_PyIOBase_check_closed(self, Py_True) == NULL)
|
||||
return NULL;
|
||||
|
||||
Py_INCREF(self);
|
||||
return self;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
iobase_exit(PyObject *self, PyObject *args)
|
||||
{
|
||||
return PyObject_CallMethodObjArgs(self, _PyIO_str_close, NULL);
|
||||
}
|
||||
|
||||
/* Lower-level APIs */
|
||||
|
||||
/* XXX Should these be present even if unimplemented? */
|
||||
|
||||
PyDoc_STRVAR(iobase_fileno_doc,
|
||||
"Returns underlying file descriptor if one exists.\n"
|
||||
"\n"
|
||||
"An IOError is raised if the IO object does not use a file descriptor.\n");
|
||||
|
||||
static PyObject *
|
||||
iobase_fileno(PyObject *self, PyObject *args)
|
||||
{
|
||||
return iobase_unsupported("fileno");
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(iobase_isatty_doc,
|
||||
"Return whether this is an 'interactive' stream.\n"
|
||||
"\n"
|
||||
"Return False if it can't be determined.\n");
|
||||
|
||||
static PyObject *
|
||||
iobase_isatty(PyObject *self, PyObject *args)
|
||||
{
|
||||
if (_PyIOBase_check_closed(self, Py_True) == NULL)
|
||||
return NULL;
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
/* Readline(s) and writelines */
|
||||
|
||||
PyDoc_STRVAR(iobase_readline_doc,
|
||||
"Read and return a line from the stream.\n"
|
||||
"\n"
|
||||
"If limit is specified, at most limit bytes will be read.\n"
|
||||
"\n"
|
||||
"The line terminator is always b'\\n' for binary files; for text\n"
|
||||
"files, the newlines argument to open can be used to select the line\n"
|
||||
"terminator(s) recognized.\n");
|
||||
|
||||
static PyObject *
|
||||
iobase_readline(PyObject *self, PyObject *args)
|
||||
{
|
||||
/* For backwards compatibility, a (slowish) readline(). */
|
||||
|
||||
Py_ssize_t limit = -1;
|
||||
int has_peek = 0;
|
||||
PyObject *buffer, *result;
|
||||
Py_ssize_t old_size = -1;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|O&:readline", &_PyIO_ConvertSsize_t, &limit)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (PyObject_HasAttrString(self, "peek"))
|
||||
has_peek = 1;
|
||||
|
||||
buffer = PyByteArray_FromStringAndSize(NULL, 0);
|
||||
if (buffer == NULL)
|
||||
return NULL;
|
||||
|
||||
while (limit < 0 || Py_SIZE(buffer) < limit) {
|
||||
Py_ssize_t nreadahead = 1;
|
||||
PyObject *b;
|
||||
|
||||
if (has_peek) {
|
||||
PyObject *readahead = PyObject_CallMethod(self, "peek", "i", 1);
|
||||
if (readahead == NULL) {
|
||||
/* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals()
|
||||
when EINTR occurs so we needn't do it ourselves. */
|
||||
if (_PyIO_trap_eintr()) {
|
||||
continue;
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
if (!PyBytes_Check(readahead)) {
|
||||
PyErr_Format(PyExc_IOError,
|
||||
"peek() should have returned a bytes object, "
|
||||
"not '%.200s'", Py_TYPE(readahead)->tp_name);
|
||||
Py_DECREF(readahead);
|
||||
goto fail;
|
||||
}
|
||||
if (PyBytes_GET_SIZE(readahead) > 0) {
|
||||
Py_ssize_t n = 0;
|
||||
const char *buf = PyBytes_AS_STRING(readahead);
|
||||
if (limit >= 0) {
|
||||
do {
|
||||
if (n >= PyBytes_GET_SIZE(readahead) || n >= limit)
|
||||
break;
|
||||
if (buf[n++] == '\n')
|
||||
break;
|
||||
} while (1);
|
||||
}
|
||||
else {
|
||||
do {
|
||||
if (n >= PyBytes_GET_SIZE(readahead))
|
||||
break;
|
||||
if (buf[n++] == '\n')
|
||||
break;
|
||||
} while (1);
|
||||
}
|
||||
nreadahead = n;
|
||||
}
|
||||
Py_DECREF(readahead);
|
||||
}
|
||||
|
||||
b = PyObject_CallMethod(self, "read", "n", nreadahead);
|
||||
if (b == NULL) {
|
||||
/* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals()
|
||||
when EINTR occurs so we needn't do it ourselves. */
|
||||
if (_PyIO_trap_eintr()) {
|
||||
continue;
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
if (!PyBytes_Check(b)) {
|
||||
PyErr_Format(PyExc_IOError,
|
||||
"read() should have returned a bytes object, "
|
||||
"not '%.200s'", Py_TYPE(b)->tp_name);
|
||||
Py_DECREF(b);
|
||||
goto fail;
|
||||
}
|
||||
if (PyBytes_GET_SIZE(b) == 0) {
|
||||
Py_DECREF(b);
|
||||
break;
|
||||
}
|
||||
|
||||
old_size = PyByteArray_GET_SIZE(buffer);
|
||||
if (PyByteArray_Resize(buffer, old_size + PyBytes_GET_SIZE(b)) < 0) {
|
||||
Py_DECREF(b);
|
||||
goto fail;
|
||||
}
|
||||
memcpy(PyByteArray_AS_STRING(buffer) + old_size,
|
||||
PyBytes_AS_STRING(b), PyBytes_GET_SIZE(b));
|
||||
|
||||
Py_DECREF(b);
|
||||
|
||||
if (PyByteArray_AS_STRING(buffer)[PyByteArray_GET_SIZE(buffer) - 1] == '\n')
|
||||
break;
|
||||
}
|
||||
|
||||
result = PyBytes_FromStringAndSize(PyByteArray_AS_STRING(buffer),
|
||||
PyByteArray_GET_SIZE(buffer));
|
||||
Py_DECREF(buffer);
|
||||
return result;
|
||||
fail:
|
||||
Py_DECREF(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
iobase_iter(PyObject *self)
|
||||
{
|
||||
if (_PyIOBase_check_closed(self, Py_True) == NULL)
|
||||
return NULL;
|
||||
|
||||
Py_INCREF(self);
|
||||
return self;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
iobase_iternext(PyObject *self)
|
||||
{
|
||||
PyObject *line = PyObject_CallMethodObjArgs(self, _PyIO_str_readline, NULL);
|
||||
|
||||
if (line == NULL)
|
||||
return NULL;
|
||||
|
||||
if (PyObject_Size(line) <= 0) {
|
||||
/* Error or empty */
|
||||
Py_DECREF(line);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(iobase_readlines_doc,
|
||||
"Return a list of lines from the stream.\n"
|
||||
"\n"
|
||||
"hint can be specified to control the number of lines read: no more\n"
|
||||
"lines will be read if the total size (in bytes/characters) of all\n"
|
||||
"lines so far exceeds hint.");
|
||||
|
||||
static PyObject *
|
||||
iobase_readlines(PyObject *self, PyObject *args)
|
||||
{
|
||||
Py_ssize_t hint = -1, length = 0;
|
||||
PyObject *result, *it = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|O&:readlines", &_PyIO_ConvertSsize_t, &hint)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = PyList_New(0);
|
||||
if (result == NULL)
|
||||
return NULL;
|
||||
|
||||
if (hint <= 0) {
|
||||
/* XXX special-casing this made sense in the Python version in order
|
||||
to remove the bytecode interpretation overhead, but it could
|
||||
probably be removed here. */
|
||||
PyObject *ret = PyObject_CallMethod(result, "extend", "O", self);
|
||||
if (ret == NULL) {
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(ret);
|
||||
return result;
|
||||
}
|
||||
|
||||
it = PyObject_GetIter(self);
|
||||
if (it == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
Py_ssize_t line_length;
|
||||
PyObject *line = PyIter_Next(it);
|
||||
if (line == NULL) {
|
||||
if (PyErr_Occurred()) {
|
||||
goto error;
|
||||
}
|
||||
else
|
||||
break; /* StopIteration raised */
|
||||
}
|
||||
|
||||
if (PyList_Append(result, line) < 0) {
|
||||
Py_DECREF(line);
|
||||
goto error;
|
||||
}
|
||||
line_length = PyObject_Size(line);
|
||||
Py_DECREF(line);
|
||||
if (line_length < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (line_length > hint - length)
|
||||
break;
|
||||
length += line_length;
|
||||
}
|
||||
|
||||
Py_DECREF(it);
|
||||
return result;
|
||||
|
||||
error:
|
||||
Py_XDECREF(it);
|
||||
Py_DECREF(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
iobase_writelines(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *lines, *iter, *res;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O:writelines", &lines)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (_PyIOBase_check_closed(self, Py_True) == NULL)
|
||||
return NULL;
|
||||
|
||||
iter = PyObject_GetIter(lines);
|
||||
if (iter == NULL)
|
||||
return NULL;
|
||||
|
||||
while (1) {
|
||||
PyObject *line = PyIter_Next(iter);
|
||||
if (line == NULL) {
|
||||
if (PyErr_Occurred()) {
|
||||
Py_DECREF(iter);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
break; /* Stop Iteration */
|
||||
}
|
||||
|
||||
res = NULL;
|
||||
do {
|
||||
res = PyObject_CallMethodObjArgs(self, _PyIO_str_write, line, NULL);
|
||||
} while (res == NULL && _PyIO_trap_eintr());
|
||||
Py_DECREF(line);
|
||||
if (res == NULL) {
|
||||
Py_DECREF(iter);
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(res);
|
||||
}
|
||||
Py_DECREF(iter);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyMethodDef iobase_methods[] = {
|
||||
{"seek", iobase_seek, METH_VARARGS, iobase_seek_doc},
|
||||
{"tell", iobase_tell, METH_NOARGS, iobase_tell_doc},
|
||||
{"truncate", iobase_truncate, METH_VARARGS, iobase_truncate_doc},
|
||||
{"flush", iobase_flush, METH_NOARGS, iobase_flush_doc},
|
||||
{"close", iobase_close, METH_NOARGS, iobase_close_doc},
|
||||
|
||||
{"seekable", iobase_seekable, METH_NOARGS, iobase_seekable_doc},
|
||||
{"readable", iobase_readable, METH_NOARGS, iobase_readable_doc},
|
||||
{"writable", iobase_writable, METH_NOARGS, iobase_writable_doc},
|
||||
|
||||
{"_checkClosed", _PyIOBase_check_closed, METH_NOARGS},
|
||||
{"_checkSeekable", _PyIOBase_check_seekable, METH_NOARGS},
|
||||
{"_checkReadable", _PyIOBase_check_readable, METH_NOARGS},
|
||||
{"_checkWritable", _PyIOBase_check_writable, METH_NOARGS},
|
||||
|
||||
{"fileno", iobase_fileno, METH_NOARGS, iobase_fileno_doc},
|
||||
{"isatty", iobase_isatty, METH_NOARGS, iobase_isatty_doc},
|
||||
|
||||
{"__enter__", iobase_enter, METH_NOARGS},
|
||||
{"__exit__", iobase_exit, METH_VARARGS},
|
||||
|
||||
{"readline", iobase_readline, METH_VARARGS, iobase_readline_doc},
|
||||
{"readlines", iobase_readlines, METH_VARARGS, iobase_readlines_doc},
|
||||
{"writelines", iobase_writelines, METH_VARARGS},
|
||||
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static PyGetSetDef iobase_getset[] = {
|
||||
{"closed", (getter)iobase_closed_get, NULL, NULL},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
||||
PyTypeObject PyIOBase_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"_io._IOBase", /*tp_name*/
|
||||
sizeof(iobase), /*tp_basicsize*/
|
||||
0, /*tp_itemsize*/
|
||||
(destructor)iobase_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare */
|
||||
0, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
0, /*tp_hash */
|
||||
0, /*tp_call*/
|
||||
0, /*tp_str*/
|
||||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
|
||||
| Py_TPFLAGS_HAVE_GC, /*tp_flags*/
|
||||
iobase_doc, /* tp_doc */
|
||||
(traverseproc)iobase_traverse, /* tp_traverse */
|
||||
(inquiry)iobase_clear, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
offsetof(iobase, weakreflist), /* tp_weaklistoffset */
|
||||
iobase_iter, /* tp_iter */
|
||||
iobase_iternext, /* tp_iternext */
|
||||
iobase_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
iobase_getset, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
offsetof(iobase, dict), /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
PyType_GenericNew, /* tp_new */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* RawIOBase class, Inherits from IOBase.
|
||||
*/
|
||||
PyDoc_STRVAR(rawiobase_doc,
|
||||
"Base class for raw binary I/O.");
|
||||
|
||||
/*
|
||||
* The read() method is implemented by calling readinto(); derived classes
|
||||
* that want to support read() only need to implement readinto() as a
|
||||
* primitive operation. In general, readinto() can be more efficient than
|
||||
* read().
|
||||
*
|
||||
* (It would be tempting to also provide an implementation of readinto() in
|
||||
* terms of read(), in case the latter is a more suitable primitive operation,
|
||||
* but that would lead to nasty recursion in case a subclass doesn't implement
|
||||
* either.)
|
||||
*/
|
||||
|
||||
static PyObject *
|
||||
rawiobase_read(PyObject *self, PyObject *args)
|
||||
{
|
||||
Py_ssize_t n = -1;
|
||||
PyObject *b, *res;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|n:read", &n)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (n < 0)
|
||||
return PyObject_CallMethod(self, "readall", NULL);
|
||||
|
||||
/* TODO: allocate a bytes object directly instead and manually construct
|
||||
a writable memoryview pointing to it. */
|
||||
b = PyByteArray_FromStringAndSize(NULL, n);
|
||||
if (b == NULL)
|
||||
return NULL;
|
||||
|
||||
res = PyObject_CallMethodObjArgs(self, _PyIO_str_readinto, b, NULL);
|
||||
if (res == NULL || res == Py_None) {
|
||||
Py_DECREF(b);
|
||||
return res;
|
||||
}
|
||||
|
||||
n = PyNumber_AsSsize_t(res, PyExc_ValueError);
|
||||
Py_DECREF(res);
|
||||
if (n == -1 && PyErr_Occurred()) {
|
||||
Py_DECREF(b);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res = PyBytes_FromStringAndSize(PyByteArray_AsString(b), n);
|
||||
Py_DECREF(b);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(rawiobase_readall_doc,
|
||||
"Read until EOF, using multiple read() call.");
|
||||
|
||||
static PyObject *
|
||||
rawiobase_readall(PyObject *self, PyObject *args)
|
||||
{
|
||||
int r;
|
||||
PyObject *chunks = PyList_New(0);
|
||||
PyObject *result;
|
||||
|
||||
if (chunks == NULL)
|
||||
return NULL;
|
||||
|
||||
while (1) {
|
||||
PyObject *data = PyObject_CallMethod(self, "read",
|
||||
"i", DEFAULT_BUFFER_SIZE);
|
||||
if (!data) {
|
||||
/* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals()
|
||||
when EINTR occurs so we needn't do it ourselves. */
|
||||
if (_PyIO_trap_eintr()) {
|
||||
continue;
|
||||
}
|
||||
Py_DECREF(chunks);
|
||||
return NULL;
|
||||
}
|
||||
if (data == Py_None) {
|
||||
if (PyList_GET_SIZE(chunks) == 0) {
|
||||
Py_DECREF(chunks);
|
||||
return data;
|
||||
}
|
||||
Py_DECREF(data);
|
||||
break;
|
||||
}
|
||||
if (!PyBytes_Check(data)) {
|
||||
Py_DECREF(chunks);
|
||||
Py_DECREF(data);
|
||||
PyErr_SetString(PyExc_TypeError, "read() should return bytes");
|
||||
return NULL;
|
||||
}
|
||||
if (PyBytes_GET_SIZE(data) == 0) {
|
||||
/* EOF */
|
||||
Py_DECREF(data);
|
||||
break;
|
||||
}
|
||||
r = PyList_Append(chunks, data);
|
||||
Py_DECREF(data);
|
||||
if (r < 0) {
|
||||
Py_DECREF(chunks);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
result = _PyBytes_Join(_PyIO_empty_bytes, chunks);
|
||||
Py_DECREF(chunks);
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyMethodDef rawiobase_methods[] = {
|
||||
{"read", rawiobase_read, METH_VARARGS},
|
||||
{"readall", rawiobase_readall, METH_NOARGS, rawiobase_readall_doc},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
PyTypeObject PyRawIOBase_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"_io._RawIOBase", /*tp_name*/
|
||||
0, /*tp_basicsize*/
|
||||
0, /*tp_itemsize*/
|
||||
0, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare */
|
||||
0, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
0, /*tp_hash */
|
||||
0, /*tp_call*/
|
||||
0, /*tp_str*/
|
||||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
|
||||
rawiobase_doc, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
rawiobase_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
&PyIOBase_Type, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
0, /* tp_new */
|
||||
};
|
||||
@@ -0,0 +1,897 @@
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include "Python.h"
|
||||
#include "structmember.h"
|
||||
#include "_iomodule.h"
|
||||
|
||||
/* Implementation note: the buffer is always at least one character longer
|
||||
than the enclosed string, for proper functioning of _PyIO_find_line_ending.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
Py_UNICODE *buf;
|
||||
Py_ssize_t pos;
|
||||
Py_ssize_t string_size;
|
||||
size_t buf_size;
|
||||
|
||||
char ok; /* initialized? */
|
||||
char closed;
|
||||
char readuniversal;
|
||||
char readtranslate;
|
||||
PyObject *decoder;
|
||||
PyObject *readnl;
|
||||
PyObject *writenl;
|
||||
|
||||
PyObject *dict;
|
||||
PyObject *weakreflist;
|
||||
} stringio;
|
||||
|
||||
#define CHECK_INITIALIZED(self) \
|
||||
if (self->ok <= 0) { \
|
||||
PyErr_SetString(PyExc_ValueError, \
|
||||
"I/O operation on uninitialized object"); \
|
||||
return NULL; \
|
||||
}
|
||||
|
||||
#define CHECK_CLOSED(self) \
|
||||
if (self->closed) { \
|
||||
PyErr_SetString(PyExc_ValueError, \
|
||||
"I/O operation on closed file"); \
|
||||
return NULL; \
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(stringio_doc,
|
||||
"Text I/O implementation using an in-memory buffer.\n"
|
||||
"\n"
|
||||
"The initial_value argument sets the value of object. The newline\n"
|
||||
"argument is like the one of TextIOWrapper's constructor.");
|
||||
|
||||
|
||||
/* Internal routine for changing the size, in terms of characters, of the
|
||||
buffer of StringIO objects. The caller should ensure that the 'size'
|
||||
argument is non-negative. Returns 0 on success, -1 otherwise. */
|
||||
static int
|
||||
resize_buffer(stringio *self, size_t size)
|
||||
{
|
||||
/* Here, unsigned types are used to avoid dealing with signed integer
|
||||
overflow, which is undefined in C. */
|
||||
size_t alloc = self->buf_size;
|
||||
Py_UNICODE *new_buf = NULL;
|
||||
|
||||
assert(self->buf != NULL);
|
||||
|
||||
/* Reserve one more char for line ending detection. */
|
||||
size = size + 1;
|
||||
/* For simplicity, stay in the range of the signed type. Anyway, Python
|
||||
doesn't allow strings to be longer than this. */
|
||||
if (size > PY_SSIZE_T_MAX)
|
||||
goto overflow;
|
||||
|
||||
if (size < alloc / 2) {
|
||||
/* Major downsize; resize down to exact size. */
|
||||
alloc = size + 1;
|
||||
}
|
||||
else if (size < alloc) {
|
||||
/* Within allocated size; quick exit */
|
||||
return 0;
|
||||
}
|
||||
else if (size <= alloc * 1.125) {
|
||||
/* Moderate upsize; overallocate similar to list_resize() */
|
||||
alloc = size + (size >> 3) + (size < 9 ? 3 : 6);
|
||||
}
|
||||
else {
|
||||
/* Major upsize; resize up to exact size */
|
||||
alloc = size + 1;
|
||||
}
|
||||
|
||||
if (alloc > ((size_t)-1) / sizeof(Py_UNICODE))
|
||||
goto overflow;
|
||||
new_buf = (Py_UNICODE *)PyMem_Realloc(self->buf,
|
||||
alloc * sizeof(Py_UNICODE));
|
||||
if (new_buf == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return -1;
|
||||
}
|
||||
self->buf_size = alloc;
|
||||
self->buf = new_buf;
|
||||
|
||||
return 0;
|
||||
|
||||
overflow:
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"new buffer size too large");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Internal routine for writing a whole PyUnicode object to the buffer of a
|
||||
StringIO object. Returns 0 on success, or -1 on error. */
|
||||
static Py_ssize_t
|
||||
write_str(stringio *self, PyObject *obj)
|
||||
{
|
||||
Py_UNICODE *str;
|
||||
Py_ssize_t len;
|
||||
PyObject *decoded = NULL;
|
||||
assert(self->buf != NULL);
|
||||
assert(self->pos >= 0);
|
||||
|
||||
if (self->decoder != NULL) {
|
||||
decoded = _PyIncrementalNewlineDecoder_decode(
|
||||
self->decoder, obj, 1 /* always final */);
|
||||
}
|
||||
else {
|
||||
decoded = obj;
|
||||
Py_INCREF(decoded);
|
||||
}
|
||||
if (self->writenl) {
|
||||
PyObject *translated = PyUnicode_Replace(
|
||||
decoded, _PyIO_str_nl, self->writenl, -1);
|
||||
Py_DECREF(decoded);
|
||||
decoded = translated;
|
||||
}
|
||||
if (decoded == NULL)
|
||||
return -1;
|
||||
|
||||
assert(PyUnicode_Check(decoded));
|
||||
str = PyUnicode_AS_UNICODE(decoded);
|
||||
len = PyUnicode_GET_SIZE(decoded);
|
||||
|
||||
assert(len >= 0);
|
||||
|
||||
/* This overflow check is not strictly necessary. However, it avoids us to
|
||||
deal with funky things like comparing an unsigned and a signed
|
||||
integer. */
|
||||
if (self->pos > PY_SSIZE_T_MAX - len) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"new position too large");
|
||||
goto fail;
|
||||
}
|
||||
if (self->pos + len > self->string_size) {
|
||||
if (resize_buffer(self, self->pos + len) < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (self->pos > self->string_size) {
|
||||
/* In case of overseek, pad with null bytes the buffer region between
|
||||
the end of stream and the current position.
|
||||
|
||||
0 lo string_size hi
|
||||
| |<---used--->|<----------available----------->|
|
||||
| | <--to pad-->|<---to write---> |
|
||||
0 buf position
|
||||
|
||||
*/
|
||||
memset(self->buf + self->string_size, '\0',
|
||||
(self->pos - self->string_size) * sizeof(Py_UNICODE));
|
||||
}
|
||||
|
||||
/* Copy the data to the internal buffer, overwriting some of the
|
||||
existing data if self->pos < self->string_size. */
|
||||
memcpy(self->buf + self->pos, str, len * sizeof(Py_UNICODE));
|
||||
self->pos += len;
|
||||
|
||||
/* Set the new length of the internal string if it has changed. */
|
||||
if (self->string_size < self->pos) {
|
||||
self->string_size = self->pos;
|
||||
}
|
||||
|
||||
Py_DECREF(decoded);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
Py_XDECREF(decoded);
|
||||
return -1;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(stringio_getvalue_doc,
|
||||
"Retrieve the entire contents of the object.");
|
||||
|
||||
static PyObject *
|
||||
stringio_getvalue(stringio *self)
|
||||
{
|
||||
CHECK_INITIALIZED(self);
|
||||
CHECK_CLOSED(self);
|
||||
return PyUnicode_FromUnicode(self->buf, self->string_size);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(stringio_tell_doc,
|
||||
"Tell the current file position.");
|
||||
|
||||
static PyObject *
|
||||
stringio_tell(stringio *self)
|
||||
{
|
||||
CHECK_INITIALIZED(self);
|
||||
CHECK_CLOSED(self);
|
||||
return PyLong_FromSsize_t(self->pos);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(stringio_read_doc,
|
||||
"Read at most n characters, returned as a string.\n"
|
||||
"\n"
|
||||
"If the argument is negative or omitted, read until EOF\n"
|
||||
"is reached. Return an empty string at EOF.\n");
|
||||
|
||||
static PyObject *
|
||||
stringio_read(stringio *self, PyObject *args)
|
||||
{
|
||||
Py_ssize_t size, n;
|
||||
Py_UNICODE *output;
|
||||
PyObject *arg = Py_None;
|
||||
|
||||
CHECK_INITIALIZED(self);
|
||||
if (!PyArg_ParseTuple(args, "|O:read", &arg))
|
||||
return NULL;
|
||||
CHECK_CLOSED(self);
|
||||
|
||||
if (PyNumber_Check(arg)) {
|
||||
size = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
|
||||
if (size == -1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
}
|
||||
else if (arg == Py_None) {
|
||||
/* Read until EOF is reached, by default. */
|
||||
size = -1;
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
|
||||
Py_TYPE(arg)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* adjust invalid sizes */
|
||||
n = self->string_size - self->pos;
|
||||
if (size < 0 || size > n) {
|
||||
size = n;
|
||||
if (size < 0)
|
||||
size = 0;
|
||||
}
|
||||
|
||||
output = self->buf + self->pos;
|
||||
self->pos += size;
|
||||
return PyUnicode_FromUnicode(output, size);
|
||||
}
|
||||
|
||||
/* Internal helper, used by stringio_readline and stringio_iternext */
|
||||
static PyObject *
|
||||
_stringio_readline(stringio *self, Py_ssize_t limit)
|
||||
{
|
||||
Py_UNICODE *start, *end, old_char;
|
||||
Py_ssize_t len, consumed;
|
||||
|
||||
/* In case of overseek, return the empty string */
|
||||
if (self->pos >= self->string_size)
|
||||
return PyUnicode_FromString("");
|
||||
|
||||
start = self->buf + self->pos;
|
||||
if (limit < 0 || limit > self->string_size - self->pos)
|
||||
limit = self->string_size - self->pos;
|
||||
|
||||
end = start + limit;
|
||||
old_char = *end;
|
||||
*end = '\0';
|
||||
len = _PyIO_find_line_ending(
|
||||
self->readtranslate, self->readuniversal, self->readnl,
|
||||
start, end, &consumed);
|
||||
*end = old_char;
|
||||
/* If we haven't found any line ending, we just return everything
|
||||
(`consumed` is ignored). */
|
||||
if (len < 0)
|
||||
len = limit;
|
||||
self->pos += len;
|
||||
return PyUnicode_FromUnicode(start, len);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(stringio_readline_doc,
|
||||
"Read until newline or EOF.\n"
|
||||
"\n"
|
||||
"Returns an empty string if EOF is hit immediately.\n");
|
||||
|
||||
static PyObject *
|
||||
stringio_readline(stringio *self, PyObject *args)
|
||||
{
|
||||
PyObject *arg = Py_None;
|
||||
Py_ssize_t limit = -1;
|
||||
|
||||
CHECK_INITIALIZED(self);
|
||||
if (!PyArg_ParseTuple(args, "|O:readline", &arg))
|
||||
return NULL;
|
||||
CHECK_CLOSED(self);
|
||||
|
||||
if (PyNumber_Check(arg)) {
|
||||
limit = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
|
||||
if (limit == -1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
}
|
||||
else if (arg != Py_None) {
|
||||
PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
|
||||
Py_TYPE(arg)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
return _stringio_readline(self, limit);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
stringio_iternext(stringio *self)
|
||||
{
|
||||
PyObject *line;
|
||||
|
||||
CHECK_INITIALIZED(self);
|
||||
CHECK_CLOSED(self);
|
||||
|
||||
if (Py_TYPE(self) == &PyStringIO_Type) {
|
||||
/* Skip method call overhead for speed */
|
||||
line = _stringio_readline(self, -1);
|
||||
}
|
||||
else {
|
||||
/* XXX is subclassing StringIO really supported? */
|
||||
line = PyObject_CallMethodObjArgs((PyObject *)self,
|
||||
_PyIO_str_readline, NULL);
|
||||
if (line && !PyUnicode_Check(line)) {
|
||||
PyErr_Format(PyExc_IOError,
|
||||
"readline() should have returned an str object, "
|
||||
"not '%.200s'", Py_TYPE(line)->tp_name);
|
||||
Py_DECREF(line);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (line == NULL)
|
||||
return NULL;
|
||||
|
||||
if (PyUnicode_GET_SIZE(line) == 0) {
|
||||
/* Reached EOF */
|
||||
Py_DECREF(line);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(stringio_truncate_doc,
|
||||
"Truncate size to pos.\n"
|
||||
"\n"
|
||||
"The pos argument defaults to the current file position, as\n"
|
||||
"returned by tell(). The current file position is unchanged.\n"
|
||||
"Returns the new absolute position.\n");
|
||||
|
||||
static PyObject *
|
||||
stringio_truncate(stringio *self, PyObject *args)
|
||||
{
|
||||
Py_ssize_t size;
|
||||
PyObject *arg = Py_None;
|
||||
|
||||
CHECK_INITIALIZED(self);
|
||||
if (!PyArg_ParseTuple(args, "|O:truncate", &arg))
|
||||
return NULL;
|
||||
CHECK_CLOSED(self);
|
||||
|
||||
if (PyNumber_Check(arg)) {
|
||||
size = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
|
||||
if (size == -1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
}
|
||||
else if (arg == Py_None) {
|
||||
/* Truncate to current position if no argument is passed. */
|
||||
size = self->pos;
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
|
||||
Py_TYPE(arg)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size < 0) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"Negative size value %zd", size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size < self->string_size) {
|
||||
if (resize_buffer(self, size) < 0)
|
||||
return NULL;
|
||||
self->string_size = size;
|
||||
}
|
||||
|
||||
return PyLong_FromSsize_t(size);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(stringio_seek_doc,
|
||||
"Change stream position.\n"
|
||||
"\n"
|
||||
"Seek to character offset pos relative to position indicated by whence:\n"
|
||||
" 0 Start of stream (the default). pos should be >= 0;\n"
|
||||
" 1 Current position - pos must be 0;\n"
|
||||
" 2 End of stream - pos must be 0.\n"
|
||||
"Returns the new absolute position.\n");
|
||||
|
||||
static PyObject *
|
||||
stringio_seek(stringio *self, PyObject *args)
|
||||
{
|
||||
PyObject *posobj;
|
||||
Py_ssize_t pos;
|
||||
int mode = 0;
|
||||
|
||||
CHECK_INITIALIZED(self);
|
||||
if (!PyArg_ParseTuple(args, "O|i:seek", &posobj, &mode))
|
||||
return NULL;
|
||||
|
||||
pos = PyNumber_AsSsize_t(posobj, PyExc_OverflowError);
|
||||
if (pos == -1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
|
||||
CHECK_CLOSED(self);
|
||||
|
||||
if (mode != 0 && mode != 1 && mode != 2) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"Invalid whence (%i, should be 0, 1 or 2)", mode);
|
||||
return NULL;
|
||||
}
|
||||
else if (pos < 0 && mode == 0) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"Negative seek position %zd", pos);
|
||||
return NULL;
|
||||
}
|
||||
else if (mode != 0 && pos != 0) {
|
||||
PyErr_SetString(PyExc_IOError,
|
||||
"Can't do nonzero cur-relative seeks");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* mode 0: offset relative to beginning of the string.
|
||||
mode 1: no change to current position.
|
||||
mode 2: change position to end of file. */
|
||||
if (mode == 1) {
|
||||
pos = self->pos;
|
||||
}
|
||||
else if (mode == 2) {
|
||||
pos = self->string_size;
|
||||
}
|
||||
|
||||
self->pos = pos;
|
||||
|
||||
return PyLong_FromSsize_t(self->pos);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(stringio_write_doc,
|
||||
"Write string to file.\n"
|
||||
"\n"
|
||||
"Returns the number of characters written, which is always equal to\n"
|
||||
"the length of the string.\n");
|
||||
|
||||
static PyObject *
|
||||
stringio_write(stringio *self, PyObject *obj)
|
||||
{
|
||||
Py_ssize_t size;
|
||||
|
||||
CHECK_INITIALIZED(self);
|
||||
if (!PyUnicode_Check(obj)) {
|
||||
PyErr_Format(PyExc_TypeError, "unicode argument expected, got '%s'",
|
||||
Py_TYPE(obj)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
CHECK_CLOSED(self);
|
||||
size = PyUnicode_GET_SIZE(obj);
|
||||
|
||||
if (size > 0 && write_str(self, obj) < 0)
|
||||
return NULL;
|
||||
|
||||
return PyLong_FromSsize_t(size);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(stringio_close_doc,
|
||||
"Close the IO object. Attempting any further operation after the\n"
|
||||
"object is closed will raise a ValueError.\n"
|
||||
"\n"
|
||||
"This method has no effect if the file is already closed.\n");
|
||||
|
||||
static PyObject *
|
||||
stringio_close(stringio *self)
|
||||
{
|
||||
self->closed = 1;
|
||||
/* Free up some memory */
|
||||
if (resize_buffer(self, 0) < 0)
|
||||
return NULL;
|
||||
Py_CLEAR(self->readnl);
|
||||
Py_CLEAR(self->writenl);
|
||||
Py_CLEAR(self->decoder);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static int
|
||||
stringio_traverse(stringio *self, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(self->dict);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
stringio_clear(stringio *self)
|
||||
{
|
||||
Py_CLEAR(self->dict);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
stringio_dealloc(stringio *self)
|
||||
{
|
||||
_PyObject_GC_UNTRACK(self);
|
||||
self->ok = 0;
|
||||
if (self->buf) {
|
||||
PyMem_Free(self->buf);
|
||||
self->buf = NULL;
|
||||
}
|
||||
Py_CLEAR(self->readnl);
|
||||
Py_CLEAR(self->writenl);
|
||||
Py_CLEAR(self->decoder);
|
||||
Py_CLEAR(self->dict);
|
||||
if (self->weakreflist != NULL)
|
||||
PyObject_ClearWeakRefs((PyObject *) self);
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
stringio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
stringio *self;
|
||||
|
||||
assert(type != NULL && type->tp_alloc != NULL);
|
||||
self = (stringio *)type->tp_alloc(type, 0);
|
||||
if (self == NULL)
|
||||
return NULL;
|
||||
|
||||
/* tp_alloc initializes all the fields to zero. So we don't have to
|
||||
initialize them here. */
|
||||
|
||||
self->buf = (Py_UNICODE *)PyMem_Malloc(0);
|
||||
if (self->buf == NULL) {
|
||||
Py_DECREF(self);
|
||||
return PyErr_NoMemory();
|
||||
}
|
||||
|
||||
return (PyObject *)self;
|
||||
}
|
||||
|
||||
static int
|
||||
stringio_init(stringio *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
char *kwlist[] = {"initial_value", "newline", NULL};
|
||||
PyObject *value = NULL;
|
||||
char *newline = "\n";
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oz:__init__", kwlist,
|
||||
&value, &newline))
|
||||
return -1;
|
||||
|
||||
if (newline && newline[0] != '\0'
|
||||
&& !(newline[0] == '\n' && newline[1] == '\0')
|
||||
&& !(newline[0] == '\r' && newline[1] == '\0')
|
||||
&& !(newline[0] == '\r' && newline[1] == '\n' && newline[2] == '\0')) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"illegal newline value: %s", newline);
|
||||
return -1;
|
||||
}
|
||||
if (value && value != Py_None && !PyUnicode_Check(value)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"initial_value must be unicode or None, not %.200s",
|
||||
Py_TYPE(value)->tp_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
self->ok = 0;
|
||||
|
||||
Py_CLEAR(self->readnl);
|
||||
Py_CLEAR(self->writenl);
|
||||
Py_CLEAR(self->decoder);
|
||||
|
||||
if (newline) {
|
||||
self->readnl = PyString_FromString(newline);
|
||||
if (self->readnl == NULL)
|
||||
return -1;
|
||||
}
|
||||
self->readuniversal = (newline == NULL || newline[0] == '\0');
|
||||
self->readtranslate = (newline == NULL);
|
||||
/* If newline == "", we don't translate anything.
|
||||
If newline == "\n" or newline == None, we translate to "\n", which is
|
||||
a no-op.
|
||||
(for newline == None, TextIOWrapper translates to os.sepline, but it
|
||||
is pointless for StringIO)
|
||||
*/
|
||||
if (newline != NULL && newline[0] == '\r') {
|
||||
self->writenl = PyUnicode_FromString(newline);
|
||||
}
|
||||
|
||||
if (self->readuniversal) {
|
||||
self->decoder = PyObject_CallFunction(
|
||||
(PyObject *)&PyIncrementalNewlineDecoder_Type,
|
||||
"Oi", Py_None, (int) self->readtranslate);
|
||||
if (self->decoder == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Now everything is set up, resize buffer to size of initial value,
|
||||
and copy it */
|
||||
self->string_size = 0;
|
||||
if (value && value != Py_None) {
|
||||
Py_ssize_t len = PyUnicode_GetSize(value);
|
||||
/* This is a heuristic, for newline translation might change
|
||||
the string length. */
|
||||
if (resize_buffer(self, len) < 0)
|
||||
return -1;
|
||||
self->pos = 0;
|
||||
if (write_str(self, value) < 0)
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
if (resize_buffer(self, 0) < 0)
|
||||
return -1;
|
||||
}
|
||||
self->pos = 0;
|
||||
|
||||
self->closed = 0;
|
||||
self->ok = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Properties and pseudo-properties */
|
||||
|
||||
PyDoc_STRVAR(stringio_readable_doc,
|
||||
"readable() -> bool. Returns True if the IO object can be read.");
|
||||
|
||||
PyDoc_STRVAR(stringio_writable_doc,
|
||||
"writable() -> bool. Returns True if the IO object can be written.");
|
||||
|
||||
PyDoc_STRVAR(stringio_seekable_doc,
|
||||
"seekable() -> bool. Returns True if the IO object can be seeked.");
|
||||
|
||||
static PyObject *
|
||||
stringio_seekable(stringio *self, PyObject *args)
|
||||
{
|
||||
CHECK_INITIALIZED(self);
|
||||
CHECK_CLOSED(self);
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
stringio_readable(stringio *self, PyObject *args)
|
||||
{
|
||||
CHECK_INITIALIZED(self);
|
||||
CHECK_CLOSED(self);
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
stringio_writable(stringio *self, PyObject *args)
|
||||
{
|
||||
CHECK_INITIALIZED(self);
|
||||
CHECK_CLOSED(self);
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
|
||||
/* Pickling support.
|
||||
|
||||
The implementation of __getstate__ is similar to the one for BytesIO,
|
||||
except that we also save the newline parameter. For __setstate__ and unlike
|
||||
BytesIO, we call __init__ to restore the object's state. Doing so allows us
|
||||
to avoid decoding the complex newline state while keeping the object
|
||||
representation compact.
|
||||
|
||||
See comment in bytesio.c regarding why only pickle protocols and onward are
|
||||
supported.
|
||||
*/
|
||||
|
||||
static PyObject *
|
||||
stringio_getstate(stringio *self)
|
||||
{
|
||||
PyObject *initvalue = stringio_getvalue(self);
|
||||
PyObject *dict;
|
||||
PyObject *state;
|
||||
|
||||
if (initvalue == NULL)
|
||||
return NULL;
|
||||
if (self->dict == NULL) {
|
||||
Py_INCREF(Py_None);
|
||||
dict = Py_None;
|
||||
}
|
||||
else {
|
||||
dict = PyDict_Copy(self->dict);
|
||||
if (dict == NULL) {
|
||||
Py_DECREF(initvalue);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
state = Py_BuildValue("(OOnN)", initvalue,
|
||||
self->readnl ? self->readnl : Py_None,
|
||||
self->pos, dict);
|
||||
Py_DECREF(initvalue);
|
||||
return state;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
stringio_setstate(stringio *self, PyObject *state)
|
||||
{
|
||||
PyObject *initarg;
|
||||
PyObject *position_obj;
|
||||
PyObject *dict;
|
||||
Py_ssize_t pos;
|
||||
|
||||
assert(state != NULL);
|
||||
CHECK_CLOSED(self);
|
||||
|
||||
/* We allow the state tuple to be longer than 4, because we may need
|
||||
someday to extend the object's state without breaking
|
||||
backward-compatibility. */
|
||||
if (!PyTuple_Check(state) || Py_SIZE(state) < 4) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s.__setstate__ argument should be 4-tuple, got %.200s",
|
||||
Py_TYPE(self)->tp_name, Py_TYPE(state)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialize the object's state. */
|
||||
initarg = PyTuple_GetSlice(state, 0, 2);
|
||||
if (initarg == NULL)
|
||||
return NULL;
|
||||
if (stringio_init(self, initarg, NULL) < 0) {
|
||||
Py_DECREF(initarg);
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(initarg);
|
||||
|
||||
/* Restore the buffer state. Even if __init__ did initialize the buffer,
|
||||
we have to initialize it again since __init__ may translate the
|
||||
newlines in the initial_value string. We clearly do not want that
|
||||
because the string value in the state tuple has already been translated
|
||||
once by __init__. So we do not take any chance and replace object's
|
||||
buffer completely. */
|
||||
{
|
||||
Py_UNICODE *buf = PyUnicode_AS_UNICODE(PyTuple_GET_ITEM(state, 0));
|
||||
Py_ssize_t bufsize = PyUnicode_GET_SIZE(PyTuple_GET_ITEM(state, 0));
|
||||
if (resize_buffer(self, bufsize) < 0)
|
||||
return NULL;
|
||||
memcpy(self->buf, buf, bufsize * sizeof(Py_UNICODE));
|
||||
self->string_size = bufsize;
|
||||
}
|
||||
|
||||
/* Set carefully the position value. Alternatively, we could use the seek
|
||||
method instead of modifying self->pos directly to better protect the
|
||||
object internal state against errneous (or malicious) inputs. */
|
||||
position_obj = PyTuple_GET_ITEM(state, 2);
|
||||
if (!PyIndex_Check(position_obj)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"third item of state must be an integer, got %.200s",
|
||||
Py_TYPE(position_obj)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
pos = PyNumber_AsSsize_t(position_obj, PyExc_OverflowError);
|
||||
if (pos == -1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
if (pos < 0) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"position value cannot be negative");
|
||||
return NULL;
|
||||
}
|
||||
self->pos = pos;
|
||||
|
||||
/* Set the dictionary of the instance variables. */
|
||||
dict = PyTuple_GET_ITEM(state, 3);
|
||||
if (dict != Py_None) {
|
||||
if (!PyDict_Check(dict)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"fourth item of state should be a dict, got a %.200s",
|
||||
Py_TYPE(dict)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
if (self->dict) {
|
||||
/* Alternatively, we could replace the internal dictionary
|
||||
completely. However, it seems more practical to just update it. */
|
||||
if (PyDict_Update(self->dict, dict) < 0)
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
Py_INCREF(dict);
|
||||
self->dict = dict;
|
||||
}
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
stringio_closed(stringio *self, void *context)
|
||||
{
|
||||
CHECK_INITIALIZED(self);
|
||||
return PyBool_FromLong(self->closed);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
stringio_line_buffering(stringio *self, void *context)
|
||||
{
|
||||
CHECK_INITIALIZED(self);
|
||||
CHECK_CLOSED(self);
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
stringio_newlines(stringio *self, void *context)
|
||||
{
|
||||
CHECK_INITIALIZED(self);
|
||||
CHECK_CLOSED(self);
|
||||
if (self->decoder == NULL)
|
||||
Py_RETURN_NONE;
|
||||
return PyObject_GetAttr(self->decoder, _PyIO_str_newlines);
|
||||
}
|
||||
|
||||
static struct PyMethodDef stringio_methods[] = {
|
||||
{"close", (PyCFunction)stringio_close, METH_NOARGS, stringio_close_doc},
|
||||
{"getvalue", (PyCFunction)stringio_getvalue, METH_NOARGS, stringio_getvalue_doc},
|
||||
{"read", (PyCFunction)stringio_read, METH_VARARGS, stringio_read_doc},
|
||||
{"readline", (PyCFunction)stringio_readline, METH_VARARGS, stringio_readline_doc},
|
||||
{"tell", (PyCFunction)stringio_tell, METH_NOARGS, stringio_tell_doc},
|
||||
{"truncate", (PyCFunction)stringio_truncate, METH_VARARGS, stringio_truncate_doc},
|
||||
{"seek", (PyCFunction)stringio_seek, METH_VARARGS, stringio_seek_doc},
|
||||
{"write", (PyCFunction)stringio_write, METH_O, stringio_write_doc},
|
||||
|
||||
{"seekable", (PyCFunction)stringio_seekable, METH_NOARGS, stringio_seekable_doc},
|
||||
{"readable", (PyCFunction)stringio_readable, METH_NOARGS, stringio_readable_doc},
|
||||
{"writable", (PyCFunction)stringio_writable, METH_NOARGS, stringio_writable_doc},
|
||||
|
||||
{"__getstate__", (PyCFunction)stringio_getstate, METH_NOARGS},
|
||||
{"__setstate__", (PyCFunction)stringio_setstate, METH_O},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static PyGetSetDef stringio_getset[] = {
|
||||
{"closed", (getter)stringio_closed, NULL, NULL},
|
||||
{"newlines", (getter)stringio_newlines, NULL, NULL},
|
||||
/* (following comments straight off of the original Python wrapper:)
|
||||
XXX Cruft to support the TextIOWrapper API. This would only
|
||||
be meaningful if StringIO supported the buffer attribute.
|
||||
Hopefully, a better solution, than adding these pseudo-attributes,
|
||||
will be found.
|
||||
*/
|
||||
{"line_buffering", (getter)stringio_line_buffering, NULL, NULL},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
PyTypeObject PyStringIO_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"_io.StringIO", /*tp_name*/
|
||||
sizeof(stringio), /*tp_basicsize*/
|
||||
0, /*tp_itemsize*/
|
||||
(destructor)stringio_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_reserved*/
|
||||
0, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
0, /*tp_hash*/
|
||||
0, /*tp_call*/
|
||||
0, /*tp_str*/
|
||||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
|
||||
| Py_TPFLAGS_HAVE_GC, /*tp_flags*/
|
||||
stringio_doc, /*tp_doc*/
|
||||
(traverseproc)stringio_traverse, /*tp_traverse*/
|
||||
(inquiry)stringio_clear, /*tp_clear*/
|
||||
0, /*tp_richcompare*/
|
||||
offsetof(stringio, weakreflist), /*tp_weaklistoffset*/
|
||||
0, /*tp_iter*/
|
||||
(iternextfunc)stringio_iternext, /*tp_iternext*/
|
||||
stringio_methods, /*tp_methods*/
|
||||
0, /*tp_members*/
|
||||
stringio_getset, /*tp_getset*/
|
||||
0, /*tp_base*/
|
||||
0, /*tp_dict*/
|
||||
0, /*tp_descr_get*/
|
||||
0, /*tp_descr_set*/
|
||||
offsetof(stringio, dict), /*tp_dictoffset*/
|
||||
(initproc)stringio_init, /*tp_init*/
|
||||
0, /*tp_alloc*/
|
||||
stringio_new, /*tp_new*/
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
+2419
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,752 @@
|
||||
/***********************************************************
|
||||
Copyright (C) 1997, 2002, 2003 Martin von Loewis
|
||||
|
||||
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.
|
||||
|
||||
This software comes with no warranty. Use at your own risk.
|
||||
|
||||
******************************************************************/
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <locale.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LANGINFO_H
|
||||
#include <langinfo.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBINTL_H
|
||||
#include <libintl.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WCHAR_H
|
||||
#include <wchar.h>
|
||||
#endif
|
||||
|
||||
#if defined(MS_WINDOWS)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef RISCOS
|
||||
char *strdup(const char *);
|
||||
#endif
|
||||
|
||||
PyDoc_STRVAR(locale__doc__, "Support for POSIX locales.");
|
||||
|
||||
static PyObject *Error;
|
||||
|
||||
/* support functions for formatting floating point numbers */
|
||||
|
||||
PyDoc_STRVAR(setlocale__doc__,
|
||||
"(integer,string=None) -> string. Activates/queries locale processing.");
|
||||
|
||||
/* the grouping is terminated by either 0 or CHAR_MAX */
|
||||
static PyObject*
|
||||
copy_grouping(char* s)
|
||||
{
|
||||
int i;
|
||||
PyObject *result, *val = NULL;
|
||||
|
||||
if (s[0] == '\0') {
|
||||
/* empty string: no grouping at all */
|
||||
return PyList_New(0);
|
||||
}
|
||||
|
||||
for (i = 0; s[i] != '\0' && s[i] != CHAR_MAX; i++)
|
||||
; /* nothing */
|
||||
|
||||
result = PyList_New(i+1);
|
||||
if (!result)
|
||||
return NULL;
|
||||
|
||||
i = -1;
|
||||
do {
|
||||
i++;
|
||||
val = PyInt_FromLong(s[i]);
|
||||
if (val == NULL) {
|
||||
Py_DECREF(result);
|
||||
return NULL;
|
||||
}
|
||||
PyList_SET_ITEM(result, i, val);
|
||||
} while (s[i] != '\0' && s[i] != CHAR_MAX);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
fixup_ulcase(void)
|
||||
{
|
||||
PyObject *mods, *strop, *string, *ulo;
|
||||
unsigned char ul[256];
|
||||
int n, c;
|
||||
|
||||
/* find the string and strop modules */
|
||||
mods = PyImport_GetModuleDict();
|
||||
if (!mods)
|
||||
return;
|
||||
string = PyDict_GetItemString(mods, "string");
|
||||
if (string)
|
||||
string = PyModule_GetDict(string);
|
||||
strop=PyDict_GetItemString(mods, "strop");
|
||||
if (strop)
|
||||
strop = PyModule_GetDict(strop);
|
||||
if (!string && !strop)
|
||||
return;
|
||||
|
||||
/* create uppercase map string */
|
||||
n = 0;
|
||||
for (c = 0; c < 256; c++) {
|
||||
if (isupper(c))
|
||||
ul[n++] = c;
|
||||
}
|
||||
ulo = PyString_FromStringAndSize((const char *)ul, n);
|
||||
if (!ulo)
|
||||
return;
|
||||
if (string)
|
||||
PyDict_SetItemString(string, "uppercase", ulo);
|
||||
if (strop)
|
||||
PyDict_SetItemString(strop, "uppercase", ulo);
|
||||
Py_DECREF(ulo);
|
||||
|
||||
/* create lowercase string */
|
||||
n = 0;
|
||||
for (c = 0; c < 256; c++) {
|
||||
if (islower(c))
|
||||
ul[n++] = c;
|
||||
}
|
||||
ulo = PyString_FromStringAndSize((const char *)ul, n);
|
||||
if (!ulo)
|
||||
return;
|
||||
if (string)
|
||||
PyDict_SetItemString(string, "lowercase", ulo);
|
||||
if (strop)
|
||||
PyDict_SetItemString(strop, "lowercase", ulo);
|
||||
Py_DECREF(ulo);
|
||||
|
||||
/* create letters string */
|
||||
n = 0;
|
||||
for (c = 0; c < 256; c++) {
|
||||
if (isalpha(c))
|
||||
ul[n++] = c;
|
||||
}
|
||||
ulo = PyString_FromStringAndSize((const char *)ul, n);
|
||||
if (!ulo)
|
||||
return;
|
||||
if (string)
|
||||
PyDict_SetItemString(string, "letters", ulo);
|
||||
Py_DECREF(ulo);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
PyLocale_setlocale(PyObject* self, PyObject* args)
|
||||
{
|
||||
int category;
|
||||
char *locale = NULL, *result;
|
||||
PyObject *result_object;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i|z:setlocale", &category, &locale))
|
||||
return NULL;
|
||||
|
||||
#if defined(MS_WINDOWS)
|
||||
if (category < LC_MIN || category > LC_MAX)
|
||||
{
|
||||
PyErr_SetString(Error, "invalid locale category");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (locale) {
|
||||
/* set locale */
|
||||
result = setlocale(category, locale);
|
||||
if (!result) {
|
||||
/* operation failed, no setting was changed */
|
||||
PyErr_SetString(Error, "unsupported locale setting");
|
||||
return NULL;
|
||||
}
|
||||
result_object = PyString_FromString(result);
|
||||
if (!result_object)
|
||||
return NULL;
|
||||
/* record changes to LC_CTYPE */
|
||||
if (category == LC_CTYPE || category == LC_ALL)
|
||||
fixup_ulcase();
|
||||
/* things that got wrong up to here are ignored */
|
||||
PyErr_Clear();
|
||||
} else {
|
||||
/* get locale */
|
||||
result = setlocale(category, NULL);
|
||||
if (!result) {
|
||||
PyErr_SetString(Error, "locale query failed");
|
||||
return NULL;
|
||||
}
|
||||
result_object = PyString_FromString(result);
|
||||
}
|
||||
return result_object;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(localeconv__doc__,
|
||||
"() -> dict. Returns numeric and monetary locale-specific parameters.");
|
||||
|
||||
static PyObject*
|
||||
PyLocale_localeconv(PyObject* self)
|
||||
{
|
||||
PyObject* result;
|
||||
struct lconv *l;
|
||||
PyObject *x;
|
||||
|
||||
result = PyDict_New();
|
||||
if (!result)
|
||||
return NULL;
|
||||
|
||||
/* if LC_NUMERIC is different in the C library, use saved value */
|
||||
l = localeconv();
|
||||
|
||||
/* hopefully, the localeconv result survives the C library calls
|
||||
involved herein */
|
||||
|
||||
#define RESULT_STRING(s)\
|
||||
x = PyString_FromString(l->s);\
|
||||
if (!x) goto failed;\
|
||||
PyDict_SetItemString(result, #s, x);\
|
||||
Py_XDECREF(x)
|
||||
|
||||
#define RESULT_INT(i)\
|
||||
x = PyInt_FromLong(l->i);\
|
||||
if (!x) goto failed;\
|
||||
PyDict_SetItemString(result, #i, x);\
|
||||
Py_XDECREF(x)
|
||||
|
||||
/* Numeric information */
|
||||
RESULT_STRING(decimal_point);
|
||||
RESULT_STRING(thousands_sep);
|
||||
x = copy_grouping(l->grouping);
|
||||
if (!x)
|
||||
goto failed;
|
||||
PyDict_SetItemString(result, "grouping", x);
|
||||
Py_XDECREF(x);
|
||||
|
||||
/* Monetary information */
|
||||
RESULT_STRING(int_curr_symbol);
|
||||
RESULT_STRING(currency_symbol);
|
||||
RESULT_STRING(mon_decimal_point);
|
||||
RESULT_STRING(mon_thousands_sep);
|
||||
x = copy_grouping(l->mon_grouping);
|
||||
if (!x)
|
||||
goto failed;
|
||||
PyDict_SetItemString(result, "mon_grouping", x);
|
||||
Py_XDECREF(x);
|
||||
RESULT_STRING(positive_sign);
|
||||
RESULT_STRING(negative_sign);
|
||||
RESULT_INT(int_frac_digits);
|
||||
RESULT_INT(frac_digits);
|
||||
RESULT_INT(p_cs_precedes);
|
||||
RESULT_INT(p_sep_by_space);
|
||||
RESULT_INT(n_cs_precedes);
|
||||
RESULT_INT(n_sep_by_space);
|
||||
RESULT_INT(p_sign_posn);
|
||||
RESULT_INT(n_sign_posn);
|
||||
return result;
|
||||
|
||||
failed:
|
||||
Py_XDECREF(result);
|
||||
Py_XDECREF(x);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(strcoll__doc__,
|
||||
"string,string -> int. Compares two strings according to the locale.");
|
||||
|
||||
static PyObject*
|
||||
PyLocale_strcoll(PyObject* self, PyObject* args)
|
||||
{
|
||||
#if !defined(HAVE_WCSCOLL) || !defined(Py_USING_UNICODE)
|
||||
char *s1,*s2;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ss:strcoll", &s1, &s2))
|
||||
return NULL;
|
||||
return PyInt_FromLong(strcoll(s1, s2));
|
||||
#else
|
||||
PyObject *os1, *os2, *result = NULL;
|
||||
wchar_t *ws1 = NULL, *ws2 = NULL;
|
||||
int rel1 = 0, rel2 = 0, len1, len2;
|
||||
|
||||
if (!PyArg_UnpackTuple(args, "strcoll", 2, 2, &os1, &os2))
|
||||
return NULL;
|
||||
/* If both arguments are byte strings, use strcoll. */
|
||||
if (PyString_Check(os1) && PyString_Check(os2))
|
||||
return PyInt_FromLong(strcoll(PyString_AS_STRING(os1),
|
||||
PyString_AS_STRING(os2)));
|
||||
/* If neither argument is unicode, it's an error. */
|
||||
if (!PyUnicode_Check(os1) && !PyUnicode_Check(os2)) {
|
||||
PyErr_SetString(PyExc_ValueError, "strcoll arguments must be strings");
|
||||
}
|
||||
/* Convert the non-unicode argument to unicode. */
|
||||
if (!PyUnicode_Check(os1)) {
|
||||
os1 = PyUnicode_FromObject(os1);
|
||||
if (!os1)
|
||||
return NULL;
|
||||
rel1 = 1;
|
||||
}
|
||||
if (!PyUnicode_Check(os2)) {
|
||||
os2 = PyUnicode_FromObject(os2);
|
||||
if (!os2) {
|
||||
if (rel1) {
|
||||
Py_DECREF(os1);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
rel2 = 1;
|
||||
}
|
||||
/* Convert the unicode strings to wchar[]. */
|
||||
len1 = PyUnicode_GET_SIZE(os1) + 1;
|
||||
ws1 = PyMem_NEW(wchar_t, len1);
|
||||
if (!ws1) {
|
||||
PyErr_NoMemory();
|
||||
goto done;
|
||||
}
|
||||
if (PyUnicode_AsWideChar((PyUnicodeObject*)os1, ws1, len1) == -1)
|
||||
goto done;
|
||||
ws1[len1 - 1] = 0;
|
||||
len2 = PyUnicode_GET_SIZE(os2) + 1;
|
||||
ws2 = PyMem_NEW(wchar_t, len2);
|
||||
if (!ws2) {
|
||||
PyErr_NoMemory();
|
||||
goto done;
|
||||
}
|
||||
if (PyUnicode_AsWideChar((PyUnicodeObject*)os2, ws2, len2) == -1)
|
||||
goto done;
|
||||
ws2[len2 - 1] = 0;
|
||||
/* Collate the strings. */
|
||||
result = PyInt_FromLong(wcscoll(ws1, ws2));
|
||||
done:
|
||||
/* Deallocate everything. */
|
||||
if (ws1) PyMem_FREE(ws1);
|
||||
if (ws2) PyMem_FREE(ws2);
|
||||
if (rel1) {
|
||||
Py_DECREF(os1);
|
||||
}
|
||||
if (rel2) {
|
||||
Py_DECREF(os2);
|
||||
}
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(strxfrm__doc__,
|
||||
"string -> string. Returns a string that behaves for cmp locale-aware.");
|
||||
|
||||
static PyObject*
|
||||
PyLocale_strxfrm(PyObject* self, PyObject* args)
|
||||
{
|
||||
char *s, *buf;
|
||||
size_t n1, n2;
|
||||
PyObject *result;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s:strxfrm", &s))
|
||||
return NULL;
|
||||
|
||||
/* assume no change in size, first */
|
||||
n1 = strlen(s) + 1;
|
||||
buf = PyMem_Malloc(n1);
|
||||
if (!buf)
|
||||
return PyErr_NoMemory();
|
||||
n2 = strxfrm(buf, s, n1) + 1;
|
||||
if (n2 > n1) {
|
||||
/* more space needed */
|
||||
buf = PyMem_Realloc(buf, n2);
|
||||
if (!buf)
|
||||
return PyErr_NoMemory();
|
||||
strxfrm(buf, s, n2);
|
||||
}
|
||||
result = PyString_FromString(buf);
|
||||
PyMem_Free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined(MS_WINDOWS)
|
||||
static PyObject*
|
||||
PyLocale_getdefaultlocale(PyObject* self)
|
||||
{
|
||||
char encoding[100];
|
||||
char locale[100];
|
||||
|
||||
PyOS_snprintf(encoding, sizeof(encoding), "cp%d", GetACP());
|
||||
|
||||
if (GetLocaleInfo(LOCALE_USER_DEFAULT,
|
||||
LOCALE_SISO639LANGNAME,
|
||||
locale, sizeof(locale))) {
|
||||
Py_ssize_t i = strlen(locale);
|
||||
locale[i++] = '_';
|
||||
if (GetLocaleInfo(LOCALE_USER_DEFAULT,
|
||||
LOCALE_SISO3166CTRYNAME,
|
||||
locale+i, (int)(sizeof(locale)-i)))
|
||||
return Py_BuildValue("ss", locale, encoding);
|
||||
}
|
||||
|
||||
/* If we end up here, this windows version didn't know about
|
||||
ISO639/ISO3166 names (it's probably Windows 95). Return the
|
||||
Windows language identifier instead (a hexadecimal number) */
|
||||
|
||||
locale[0] = '0';
|
||||
locale[1] = 'x';
|
||||
if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTLANGUAGE,
|
||||
locale+2, sizeof(locale)-2)) {
|
||||
return Py_BuildValue("ss", locale, encoding);
|
||||
}
|
||||
|
||||
/* cannot determine the language code (very unlikely) */
|
||||
Py_INCREF(Py_None);
|
||||
return Py_BuildValue("Os", Py_None, encoding);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LANGINFO_H
|
||||
#define LANGINFO(X) {#X, X}
|
||||
static struct langinfo_constant{
|
||||
char* name;
|
||||
int value;
|
||||
} langinfo_constants[] =
|
||||
{
|
||||
/* These constants should exist on any langinfo implementation */
|
||||
LANGINFO(DAY_1),
|
||||
LANGINFO(DAY_2),
|
||||
LANGINFO(DAY_3),
|
||||
LANGINFO(DAY_4),
|
||||
LANGINFO(DAY_5),
|
||||
LANGINFO(DAY_6),
|
||||
LANGINFO(DAY_7),
|
||||
|
||||
LANGINFO(ABDAY_1),
|
||||
LANGINFO(ABDAY_2),
|
||||
LANGINFO(ABDAY_3),
|
||||
LANGINFO(ABDAY_4),
|
||||
LANGINFO(ABDAY_5),
|
||||
LANGINFO(ABDAY_6),
|
||||
LANGINFO(ABDAY_7),
|
||||
|
||||
LANGINFO(MON_1),
|
||||
LANGINFO(MON_2),
|
||||
LANGINFO(MON_3),
|
||||
LANGINFO(MON_4),
|
||||
LANGINFO(MON_5),
|
||||
LANGINFO(MON_6),
|
||||
LANGINFO(MON_7),
|
||||
LANGINFO(MON_8),
|
||||
LANGINFO(MON_9),
|
||||
LANGINFO(MON_10),
|
||||
LANGINFO(MON_11),
|
||||
LANGINFO(MON_12),
|
||||
|
||||
LANGINFO(ABMON_1),
|
||||
LANGINFO(ABMON_2),
|
||||
LANGINFO(ABMON_3),
|
||||
LANGINFO(ABMON_4),
|
||||
LANGINFO(ABMON_5),
|
||||
LANGINFO(ABMON_6),
|
||||
LANGINFO(ABMON_7),
|
||||
LANGINFO(ABMON_8),
|
||||
LANGINFO(ABMON_9),
|
||||
LANGINFO(ABMON_10),
|
||||
LANGINFO(ABMON_11),
|
||||
LANGINFO(ABMON_12),
|
||||
|
||||
#ifdef RADIXCHAR
|
||||
/* The following are not available with glibc 2.0 */
|
||||
LANGINFO(RADIXCHAR),
|
||||
LANGINFO(THOUSEP),
|
||||
/* YESSTR and NOSTR are deprecated in glibc, since they are
|
||||
a special case of message translation, which should be rather
|
||||
done using gettext. So we don't expose it to Python in the
|
||||
first place.
|
||||
LANGINFO(YESSTR),
|
||||
LANGINFO(NOSTR),
|
||||
*/
|
||||
LANGINFO(CRNCYSTR),
|
||||
#endif
|
||||
|
||||
LANGINFO(D_T_FMT),
|
||||
LANGINFO(D_FMT),
|
||||
LANGINFO(T_FMT),
|
||||
LANGINFO(AM_STR),
|
||||
LANGINFO(PM_STR),
|
||||
|
||||
/* The following constants are available only with XPG4, but...
|
||||
AIX 3.2. only has CODESET.
|
||||
OpenBSD doesn't have CODESET but has T_FMT_AMPM, and doesn't have
|
||||
a few of the others.
|
||||
Solution: ifdef-test them all. */
|
||||
#ifdef CODESET
|
||||
LANGINFO(CODESET),
|
||||
#endif
|
||||
#ifdef T_FMT_AMPM
|
||||
LANGINFO(T_FMT_AMPM),
|
||||
#endif
|
||||
#ifdef ERA
|
||||
LANGINFO(ERA),
|
||||
#endif
|
||||
#ifdef ERA_D_FMT
|
||||
LANGINFO(ERA_D_FMT),
|
||||
#endif
|
||||
#ifdef ERA_D_T_FMT
|
||||
LANGINFO(ERA_D_T_FMT),
|
||||
#endif
|
||||
#ifdef ERA_T_FMT
|
||||
LANGINFO(ERA_T_FMT),
|
||||
#endif
|
||||
#ifdef ALT_DIGITS
|
||||
LANGINFO(ALT_DIGITS),
|
||||
#endif
|
||||
#ifdef YESEXPR
|
||||
LANGINFO(YESEXPR),
|
||||
#endif
|
||||
#ifdef NOEXPR
|
||||
LANGINFO(NOEXPR),
|
||||
#endif
|
||||
#ifdef _DATE_FMT
|
||||
/* This is not available in all glibc versions that have CODESET. */
|
||||
LANGINFO(_DATE_FMT),
|
||||
#endif
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(nl_langinfo__doc__,
|
||||
"nl_langinfo(key) -> string\n"
|
||||
"Return the value for the locale information associated with key.");
|
||||
|
||||
static PyObject*
|
||||
PyLocale_nl_langinfo(PyObject* self, PyObject* args)
|
||||
{
|
||||
int item, i;
|
||||
if (!PyArg_ParseTuple(args, "i:nl_langinfo", &item))
|
||||
return NULL;
|
||||
/* Check whether this is a supported constant. GNU libc sometimes
|
||||
returns numeric values in the char* return value, which would
|
||||
crash PyString_FromString. */
|
||||
for (i = 0; langinfo_constants[i].name; i++)
|
||||
if (langinfo_constants[i].value == item) {
|
||||
/* Check NULL as a workaround for GNU libc's returning NULL
|
||||
instead of an empty string for nl_langinfo(ERA). */
|
||||
const char *result = nl_langinfo(item);
|
||||
return PyString_FromString(result != NULL ? result : "");
|
||||
}
|
||||
PyErr_SetString(PyExc_ValueError, "unsupported langinfo constant");
|
||||
return NULL;
|
||||
}
|
||||
#endif /* HAVE_LANGINFO_H */
|
||||
|
||||
#ifdef HAVE_LIBINTL_H
|
||||
|
||||
PyDoc_STRVAR(gettext__doc__,
|
||||
"gettext(msg) -> string\n"
|
||||
"Return translation of msg.");
|
||||
|
||||
static PyObject*
|
||||
PyIntl_gettext(PyObject* self, PyObject *args)
|
||||
{
|
||||
char *in;
|
||||
if (!PyArg_ParseTuple(args, "s", &in))
|
||||
return 0;
|
||||
return PyString_FromString(gettext(in));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(dgettext__doc__,
|
||||
"dgettext(domain, msg) -> string\n"
|
||||
"Return translation of msg in domain.");
|
||||
|
||||
static PyObject*
|
||||
PyIntl_dgettext(PyObject* self, PyObject *args)
|
||||
{
|
||||
char *domain, *in;
|
||||
if (!PyArg_ParseTuple(args, "zs", &domain, &in))
|
||||
return 0;
|
||||
return PyString_FromString(dgettext(domain, in));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(dcgettext__doc__,
|
||||
"dcgettext(domain, msg, category) -> string\n"
|
||||
"Return translation of msg in domain and category.");
|
||||
|
||||
static PyObject*
|
||||
PyIntl_dcgettext(PyObject *self, PyObject *args)
|
||||
{
|
||||
char *domain, *msgid;
|
||||
int category;
|
||||
if (!PyArg_ParseTuple(args, "zsi", &domain, &msgid, &category))
|
||||
return 0;
|
||||
return PyString_FromString(dcgettext(domain,msgid,category));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(textdomain__doc__,
|
||||
"textdomain(domain) -> string\n"
|
||||
"Set the C library's textdmain to domain, returning the new domain.");
|
||||
|
||||
static PyObject*
|
||||
PyIntl_textdomain(PyObject* self, PyObject* args)
|
||||
{
|
||||
char *domain;
|
||||
if (!PyArg_ParseTuple(args, "z", &domain))
|
||||
return 0;
|
||||
domain = textdomain(domain);
|
||||
if (!domain) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
return PyString_FromString(domain);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bindtextdomain__doc__,
|
||||
"bindtextdomain(domain, dir) -> string\n"
|
||||
"Bind the C library's domain to dir.");
|
||||
|
||||
static PyObject*
|
||||
PyIntl_bindtextdomain(PyObject* self,PyObject*args)
|
||||
{
|
||||
char *domain, *dirname;
|
||||
if (!PyArg_ParseTuple(args, "sz", &domain, &dirname))
|
||||
return 0;
|
||||
if (!strlen(domain)) {
|
||||
PyErr_SetString(Error, "domain must be a non-empty string");
|
||||
return 0;
|
||||
}
|
||||
dirname = bindtextdomain(domain, dirname);
|
||||
if (!dirname) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
return PyString_FromString(dirname);
|
||||
}
|
||||
|
||||
#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
|
||||
PyDoc_STRVAR(bind_textdomain_codeset__doc__,
|
||||
"bind_textdomain_codeset(domain, codeset) -> string\n"
|
||||
"Bind the C library's domain to codeset.");
|
||||
|
||||
static PyObject*
|
||||
PyIntl_bind_textdomain_codeset(PyObject* self,PyObject*args)
|
||||
{
|
||||
char *domain,*codeset;
|
||||
if (!PyArg_ParseTuple(args, "sz", &domain, &codeset))
|
||||
return NULL;
|
||||
codeset = bind_textdomain_codeset(domain, codeset);
|
||||
if (codeset)
|
||||
return PyString_FromString(codeset);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
static struct PyMethodDef PyLocale_Methods[] = {
|
||||
{"setlocale", (PyCFunction) PyLocale_setlocale,
|
||||
METH_VARARGS, setlocale__doc__},
|
||||
{"localeconv", (PyCFunction) PyLocale_localeconv,
|
||||
METH_NOARGS, localeconv__doc__},
|
||||
{"strcoll", (PyCFunction) PyLocale_strcoll,
|
||||
METH_VARARGS, strcoll__doc__},
|
||||
{"strxfrm", (PyCFunction) PyLocale_strxfrm,
|
||||
METH_VARARGS, strxfrm__doc__},
|
||||
#if defined(MS_WINDOWS)
|
||||
{"_getdefaultlocale", (PyCFunction) PyLocale_getdefaultlocale, METH_NOARGS},
|
||||
#endif
|
||||
#ifdef HAVE_LANGINFO_H
|
||||
{"nl_langinfo", (PyCFunction) PyLocale_nl_langinfo,
|
||||
METH_VARARGS, nl_langinfo__doc__},
|
||||
#endif
|
||||
#ifdef HAVE_LIBINTL_H
|
||||
{"gettext",(PyCFunction)PyIntl_gettext,METH_VARARGS,
|
||||
gettext__doc__},
|
||||
{"dgettext",(PyCFunction)PyIntl_dgettext,METH_VARARGS,
|
||||
dgettext__doc__},
|
||||
{"dcgettext",(PyCFunction)PyIntl_dcgettext,METH_VARARGS,
|
||||
dcgettext__doc__},
|
||||
{"textdomain",(PyCFunction)PyIntl_textdomain,METH_VARARGS,
|
||||
textdomain__doc__},
|
||||
{"bindtextdomain",(PyCFunction)PyIntl_bindtextdomain,METH_VARARGS,
|
||||
bindtextdomain__doc__},
|
||||
#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
|
||||
{"bind_textdomain_codeset",(PyCFunction)PyIntl_bind_textdomain_codeset,
|
||||
METH_VARARGS, bind_textdomain_codeset__doc__},
|
||||
#endif
|
||||
#endif
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC
|
||||
init_locale(void)
|
||||
{
|
||||
PyObject *m, *d, *x;
|
||||
#ifdef HAVE_LANGINFO_H
|
||||
int i;
|
||||
#endif
|
||||
|
||||
m = Py_InitModule("_locale", PyLocale_Methods);
|
||||
if (m == NULL)
|
||||
return;
|
||||
|
||||
d = PyModule_GetDict(m);
|
||||
|
||||
x = PyInt_FromLong(LC_CTYPE);
|
||||
PyDict_SetItemString(d, "LC_CTYPE", x);
|
||||
Py_XDECREF(x);
|
||||
|
||||
x = PyInt_FromLong(LC_TIME);
|
||||
PyDict_SetItemString(d, "LC_TIME", x);
|
||||
Py_XDECREF(x);
|
||||
|
||||
x = PyInt_FromLong(LC_COLLATE);
|
||||
PyDict_SetItemString(d, "LC_COLLATE", x);
|
||||
Py_XDECREF(x);
|
||||
|
||||
x = PyInt_FromLong(LC_MONETARY);
|
||||
PyDict_SetItemString(d, "LC_MONETARY", x);
|
||||
Py_XDECREF(x);
|
||||
|
||||
#ifdef LC_MESSAGES
|
||||
x = PyInt_FromLong(LC_MESSAGES);
|
||||
PyDict_SetItemString(d, "LC_MESSAGES", x);
|
||||
Py_XDECREF(x);
|
||||
#endif /* LC_MESSAGES */
|
||||
|
||||
x = PyInt_FromLong(LC_NUMERIC);
|
||||
PyDict_SetItemString(d, "LC_NUMERIC", x);
|
||||
Py_XDECREF(x);
|
||||
|
||||
x = PyInt_FromLong(LC_ALL);
|
||||
PyDict_SetItemString(d, "LC_ALL", x);
|
||||
Py_XDECREF(x);
|
||||
|
||||
x = PyInt_FromLong(CHAR_MAX);
|
||||
PyDict_SetItemString(d, "CHAR_MAX", x);
|
||||
Py_XDECREF(x);
|
||||
|
||||
Error = PyErr_NewException("locale.Error", NULL, NULL);
|
||||
PyDict_SetItemString(d, "Error", Error);
|
||||
|
||||
x = PyString_FromString(locale__doc__);
|
||||
PyDict_SetItemString(d, "__doc__", x);
|
||||
Py_XDECREF(x);
|
||||
|
||||
#ifdef HAVE_LANGINFO_H
|
||||
for (i = 0; langinfo_constants[i].name; i++) {
|
||||
PyModule_AddIntConstant(m, langinfo_constants[i].name,
|
||||
langinfo_constants[i].value);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
Local variables:
|
||||
c-basic-offset: 4
|
||||
indent-tabs-mode: nil
|
||||
End:
|
||||
*/
|
||||
@@ -0,0 +1,891 @@
|
||||
#include "Python.h"
|
||||
#include "compile.h"
|
||||
#include "frameobject.h"
|
||||
#include "structseq.h"
|
||||
#include "rotatingtree.h"
|
||||
|
||||
#if !defined(HAVE_LONG_LONG)
|
||||
#error "This module requires long longs!"
|
||||
#endif
|
||||
|
||||
/*** Selection of a high-precision timer ***/
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
static PY_LONG_LONG
|
||||
hpTimer(void)
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
QueryPerformanceCounter(&li);
|
||||
return li.QuadPart;
|
||||
}
|
||||
|
||||
static double
|
||||
hpTimerUnit(void)
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
if (QueryPerformanceFrequency(&li))
|
||||
return 1.0 / li.QuadPart;
|
||||
else
|
||||
return 0.000001; /* unlikely */
|
||||
}
|
||||
|
||||
#else /* !MS_WINDOWS */
|
||||
|
||||
#ifndef HAVE_GETTIMEOFDAY
|
||||
#error "This module requires gettimeofday() on non-Windows platforms!"
|
||||
#endif
|
||||
|
||||
#if (defined(PYOS_OS2) && defined(PYCC_GCC))
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <sys/resource.h>
|
||||
#include <sys/times.h>
|
||||
#endif
|
||||
|
||||
static PY_LONG_LONG
|
||||
hpTimer(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
PY_LONG_LONG ret;
|
||||
#ifdef GETTIMEOFDAY_NO_TZ
|
||||
gettimeofday(&tv);
|
||||
#else
|
||||
gettimeofday(&tv, (struct timezone *)NULL);
|
||||
#endif
|
||||
ret = tv.tv_sec;
|
||||
ret = ret * 1000000 + tv.tv_usec;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static double
|
||||
hpTimerUnit(void)
|
||||
{
|
||||
return 0.000001;
|
||||
}
|
||||
|
||||
#endif /* MS_WINDOWS */
|
||||
|
||||
/************************************************************/
|
||||
/* Written by Brett Rosen and Ted Czotter */
|
||||
|
||||
struct _ProfilerEntry;
|
||||
|
||||
/* represents a function called from another function */
|
||||
typedef struct _ProfilerSubEntry {
|
||||
rotating_node_t header;
|
||||
PY_LONG_LONG tt;
|
||||
PY_LONG_LONG it;
|
||||
long callcount;
|
||||
long recursivecallcount;
|
||||
long recursionLevel;
|
||||
} ProfilerSubEntry;
|
||||
|
||||
/* represents a function or user defined block */
|
||||
typedef struct _ProfilerEntry {
|
||||
rotating_node_t header;
|
||||
PyObject *userObj; /* PyCodeObject, or a descriptive str for builtins */
|
||||
PY_LONG_LONG tt; /* total time in this entry */
|
||||
PY_LONG_LONG it; /* inline time in this entry (not in subcalls) */
|
||||
long callcount; /* how many times this was called */
|
||||
long recursivecallcount; /* how many times called recursively */
|
||||
long recursionLevel;
|
||||
rotating_node_t *calls;
|
||||
} ProfilerEntry;
|
||||
|
||||
typedef struct _ProfilerContext {
|
||||
PY_LONG_LONG t0;
|
||||
PY_LONG_LONG subt;
|
||||
struct _ProfilerContext *previous;
|
||||
ProfilerEntry *ctxEntry;
|
||||
} ProfilerContext;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
rotating_node_t *profilerEntries;
|
||||
ProfilerContext *currentProfilerContext;
|
||||
ProfilerContext *freelistProfilerContext;
|
||||
int flags;
|
||||
PyObject *externalTimer;
|
||||
double externalTimerUnit;
|
||||
} ProfilerObject;
|
||||
|
||||
#define POF_ENABLED 0x001
|
||||
#define POF_SUBCALLS 0x002
|
||||
#define POF_BUILTINS 0x004
|
||||
#define POF_NOMEMORY 0x100
|
||||
|
||||
staticforward PyTypeObject PyProfiler_Type;
|
||||
|
||||
#define PyProfiler_Check(op) PyObject_TypeCheck(op, &PyProfiler_Type)
|
||||
#define PyProfiler_CheckExact(op) (Py_TYPE(op) == &PyProfiler_Type)
|
||||
|
||||
/*** External Timers ***/
|
||||
|
||||
#define DOUBLE_TIMER_PRECISION 4294967296.0
|
||||
static PyObject *empty_tuple;
|
||||
|
||||
static PY_LONG_LONG CallExternalTimer(ProfilerObject *pObj)
|
||||
{
|
||||
PY_LONG_LONG result;
|
||||
PyObject *o = PyObject_Call(pObj->externalTimer, empty_tuple, NULL);
|
||||
if (o == NULL) {
|
||||
PyErr_WriteUnraisable(pObj->externalTimer);
|
||||
return 0;
|
||||
}
|
||||
if (pObj->externalTimerUnit > 0.0) {
|
||||
/* interpret the result as an integer that will be scaled
|
||||
in profiler_getstats() */
|
||||
result = PyLong_AsLongLong(o);
|
||||
}
|
||||
else {
|
||||
/* interpret the result as a double measured in seconds.
|
||||
As the profiler works with PY_LONG_LONG internally
|
||||
we convert it to a large integer */
|
||||
double val = PyFloat_AsDouble(o);
|
||||
/* error handling delayed to the code below */
|
||||
result = (PY_LONG_LONG) (val * DOUBLE_TIMER_PRECISION);
|
||||
}
|
||||
Py_DECREF(o);
|
||||
if (PyErr_Occurred()) {
|
||||
PyErr_WriteUnraisable(pObj->externalTimer);
|
||||
return 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#define CALL_TIMER(pObj) ((pObj)->externalTimer ? \
|
||||
CallExternalTimer(pObj) : \
|
||||
hpTimer())
|
||||
|
||||
/*** ProfilerObject ***/
|
||||
|
||||
static PyObject *
|
||||
normalizeUserObj(PyObject *obj)
|
||||
{
|
||||
PyCFunctionObject *fn;
|
||||
if (!PyCFunction_Check(obj)) {
|
||||
Py_INCREF(obj);
|
||||
return obj;
|
||||
}
|
||||
/* Replace built-in function objects with a descriptive string
|
||||
because of built-in methods -- keeping a reference to
|
||||
__self__ is probably not a good idea. */
|
||||
fn = (PyCFunctionObject *)obj;
|
||||
|
||||
if (fn->m_self == NULL) {
|
||||
/* built-in function: look up the module name */
|
||||
PyObject *mod = fn->m_module;
|
||||
char *modname;
|
||||
if (mod && PyString_Check(mod)) {
|
||||
modname = PyString_AS_STRING(mod);
|
||||
}
|
||||
else if (mod && PyModule_Check(mod)) {
|
||||
modname = PyModule_GetName(mod);
|
||||
if (modname == NULL) {
|
||||
PyErr_Clear();
|
||||
modname = "__builtin__";
|
||||
}
|
||||
}
|
||||
else {
|
||||
modname = "__builtin__";
|
||||
}
|
||||
if (strcmp(modname, "__builtin__") != 0)
|
||||
return PyString_FromFormat("<%s.%s>",
|
||||
modname,
|
||||
fn->m_ml->ml_name);
|
||||
else
|
||||
return PyString_FromFormat("<%s>",
|
||||
fn->m_ml->ml_name);
|
||||
}
|
||||
else {
|
||||
/* built-in method: try to return
|
||||
repr(getattr(type(__self__), __name__))
|
||||
*/
|
||||
PyObject *self = fn->m_self;
|
||||
PyObject *name = PyString_FromString(fn->m_ml->ml_name);
|
||||
if (name != NULL) {
|
||||
PyObject *mo = _PyType_Lookup(Py_TYPE(self), name);
|
||||
Py_XINCREF(mo);
|
||||
Py_DECREF(name);
|
||||
if (mo != NULL) {
|
||||
PyObject *res = PyObject_Repr(mo);
|
||||
Py_DECREF(mo);
|
||||
if (res != NULL)
|
||||
return res;
|
||||
}
|
||||
}
|
||||
PyErr_Clear();
|
||||
return PyString_FromFormat("<built-in method %s>",
|
||||
fn->m_ml->ml_name);
|
||||
}
|
||||
}
|
||||
|
||||
static ProfilerEntry*
|
||||
newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj)
|
||||
{
|
||||
ProfilerEntry *self;
|
||||
self = (ProfilerEntry*) malloc(sizeof(ProfilerEntry));
|
||||
if (self == NULL) {
|
||||
pObj->flags |= POF_NOMEMORY;
|
||||
return NULL;
|
||||
}
|
||||
userObj = normalizeUserObj(userObj);
|
||||
if (userObj == NULL) {
|
||||
PyErr_Clear();
|
||||
free(self);
|
||||
pObj->flags |= POF_NOMEMORY;
|
||||
return NULL;
|
||||
}
|
||||
self->header.key = key;
|
||||
self->userObj = userObj;
|
||||
self->tt = 0;
|
||||
self->it = 0;
|
||||
self->callcount = 0;
|
||||
self->recursivecallcount = 0;
|
||||
self->recursionLevel = 0;
|
||||
self->calls = EMPTY_ROTATING_TREE;
|
||||
RotatingTree_Add(&pObj->profilerEntries, &self->header);
|
||||
return self;
|
||||
}
|
||||
|
||||
static ProfilerEntry*
|
||||
getEntry(ProfilerObject *pObj, void *key)
|
||||
{
|
||||
return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key);
|
||||
}
|
||||
|
||||
static ProfilerSubEntry *
|
||||
getSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
|
||||
{
|
||||
return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls,
|
||||
(void *)entry);
|
||||
}
|
||||
|
||||
static ProfilerSubEntry *
|
||||
newSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
|
||||
{
|
||||
ProfilerSubEntry *self;
|
||||
self = (ProfilerSubEntry*) malloc(sizeof(ProfilerSubEntry));
|
||||
if (self == NULL) {
|
||||
pObj->flags |= POF_NOMEMORY;
|
||||
return NULL;
|
||||
}
|
||||
self->header.key = (void *)entry;
|
||||
self->tt = 0;
|
||||
self->it = 0;
|
||||
self->callcount = 0;
|
||||
self->recursivecallcount = 0;
|
||||
self->recursionLevel = 0;
|
||||
RotatingTree_Add(&caller->calls, &self->header);
|
||||
return self;
|
||||
}
|
||||
|
||||
static int freeSubEntry(rotating_node_t *header, void *arg)
|
||||
{
|
||||
ProfilerSubEntry *subentry = (ProfilerSubEntry*) header;
|
||||
free(subentry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int freeEntry(rotating_node_t *header, void *arg)
|
||||
{
|
||||
ProfilerEntry *entry = (ProfilerEntry*) header;
|
||||
RotatingTree_Enum(entry->calls, freeSubEntry, NULL);
|
||||
Py_DECREF(entry->userObj);
|
||||
free(entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clearEntries(ProfilerObject *pObj)
|
||||
{
|
||||
RotatingTree_Enum(pObj->profilerEntries, freeEntry, NULL);
|
||||
pObj->profilerEntries = EMPTY_ROTATING_TREE;
|
||||
/* release the memory hold by the ProfilerContexts */
|
||||
if (pObj->currentProfilerContext) {
|
||||
free(pObj->currentProfilerContext);
|
||||
pObj->currentProfilerContext = NULL;
|
||||
}
|
||||
while (pObj->freelistProfilerContext) {
|
||||
ProfilerContext *c = pObj->freelistProfilerContext;
|
||||
pObj->freelistProfilerContext = c->previous;
|
||||
free(c);
|
||||
}
|
||||
pObj->freelistProfilerContext = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
|
||||
{
|
||||
self->ctxEntry = entry;
|
||||
self->subt = 0;
|
||||
self->previous = pObj->currentProfilerContext;
|
||||
pObj->currentProfilerContext = self;
|
||||
++entry->recursionLevel;
|
||||
if ((pObj->flags & POF_SUBCALLS) && self->previous) {
|
||||
/* find or create an entry for me in my caller's entry */
|
||||
ProfilerEntry *caller = self->previous->ctxEntry;
|
||||
ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
|
||||
if (subentry == NULL)
|
||||
subentry = newSubEntry(pObj, caller, entry);
|
||||
if (subentry)
|
||||
++subentry->recursionLevel;
|
||||
}
|
||||
self->t0 = CALL_TIMER(pObj);
|
||||
}
|
||||
|
||||
static void
|
||||
Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
|
||||
{
|
||||
PY_LONG_LONG tt = CALL_TIMER(pObj) - self->t0;
|
||||
PY_LONG_LONG it = tt - self->subt;
|
||||
if (self->previous)
|
||||
self->previous->subt += tt;
|
||||
pObj->currentProfilerContext = self->previous;
|
||||
if (--entry->recursionLevel == 0)
|
||||
entry->tt += tt;
|
||||
else
|
||||
++entry->recursivecallcount;
|
||||
entry->it += it;
|
||||
entry->callcount++;
|
||||
if ((pObj->flags & POF_SUBCALLS) && self->previous) {
|
||||
/* find or create an entry for me in my caller's entry */
|
||||
ProfilerEntry *caller = self->previous->ctxEntry;
|
||||
ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
|
||||
if (subentry) {
|
||||
if (--subentry->recursionLevel == 0)
|
||||
subentry->tt += tt;
|
||||
else
|
||||
++subentry->recursivecallcount;
|
||||
subentry->it += it;
|
||||
++subentry->callcount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ptrace_enter_call(PyObject *self, void *key, PyObject *userObj)
|
||||
{
|
||||
/* entering a call to the function identified by 'key'
|
||||
(which can be a PyCodeObject or a PyMethodDef pointer) */
|
||||
ProfilerObject *pObj = (ProfilerObject*)self;
|
||||
ProfilerEntry *profEntry;
|
||||
ProfilerContext *pContext;
|
||||
|
||||
/* In the case of entering a generator expression frame via a
|
||||
* throw (gen_send_ex(.., 1)), we may already have an
|
||||
* Exception set here. We must not mess around with this
|
||||
* exception, and some of the code under here assumes that
|
||||
* PyErr_* is its own to mess around with, so we have to
|
||||
* save and restore any current exception. */
|
||||
PyObject *last_type, *last_value, *last_tb;
|
||||
PyErr_Fetch(&last_type, &last_value, &last_tb);
|
||||
|
||||
profEntry = getEntry(pObj, key);
|
||||
if (profEntry == NULL) {
|
||||
profEntry = newProfilerEntry(pObj, key, userObj);
|
||||
if (profEntry == NULL)
|
||||
goto restorePyerr;
|
||||
}
|
||||
/* grab a ProfilerContext out of the free list */
|
||||
pContext = pObj->freelistProfilerContext;
|
||||
if (pContext) {
|
||||
pObj->freelistProfilerContext = pContext->previous;
|
||||
}
|
||||
else {
|
||||
/* free list exhausted, allocate a new one */
|
||||
pContext = (ProfilerContext*)
|
||||
malloc(sizeof(ProfilerContext));
|
||||
if (pContext == NULL) {
|
||||
pObj->flags |= POF_NOMEMORY;
|
||||
goto restorePyerr;
|
||||
}
|
||||
}
|
||||
initContext(pObj, pContext, profEntry);
|
||||
|
||||
restorePyerr:
|
||||
PyErr_Restore(last_type, last_value, last_tb);
|
||||
}
|
||||
|
||||
static void
|
||||
ptrace_leave_call(PyObject *self, void *key)
|
||||
{
|
||||
/* leaving a call to the function identified by 'key' */
|
||||
ProfilerObject *pObj = (ProfilerObject*)self;
|
||||
ProfilerEntry *profEntry;
|
||||
ProfilerContext *pContext;
|
||||
|
||||
pContext = pObj->currentProfilerContext;
|
||||
if (pContext == NULL)
|
||||
return;
|
||||
profEntry = getEntry(pObj, key);
|
||||
if (profEntry) {
|
||||
Stop(pObj, pContext, profEntry);
|
||||
}
|
||||
else {
|
||||
pObj->currentProfilerContext = pContext->previous;
|
||||
}
|
||||
/* put pContext into the free list */
|
||||
pContext->previous = pObj->freelistProfilerContext;
|
||||
pObj->freelistProfilerContext = pContext;
|
||||
}
|
||||
|
||||
static int
|
||||
profiler_callback(PyObject *self, PyFrameObject *frame, int what,
|
||||
PyObject *arg)
|
||||
{
|
||||
switch (what) {
|
||||
|
||||
/* the 'frame' of a called function is about to start its execution */
|
||||
case PyTrace_CALL:
|
||||
ptrace_enter_call(self, (void *)frame->f_code,
|
||||
(PyObject *)frame->f_code);
|
||||
break;
|
||||
|
||||
/* the 'frame' of a called function is about to finish
|
||||
(either normally or with an exception) */
|
||||
case PyTrace_RETURN:
|
||||
ptrace_leave_call(self, (void *)frame->f_code);
|
||||
break;
|
||||
|
||||
/* case PyTrace_EXCEPTION:
|
||||
If the exception results in the function exiting, a
|
||||
PyTrace_RETURN event will be generated, so we don't need to
|
||||
handle it. */
|
||||
|
||||
#ifdef PyTrace_C_CALL /* not defined in Python <= 2.3 */
|
||||
/* the Python function 'frame' is issuing a call to the built-in
|
||||
function 'arg' */
|
||||
case PyTrace_C_CALL:
|
||||
if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
|
||||
&& PyCFunction_Check(arg)) {
|
||||
ptrace_enter_call(self,
|
||||
((PyCFunctionObject *)arg)->m_ml,
|
||||
arg);
|
||||
}
|
||||
break;
|
||||
|
||||
/* the call to the built-in function 'arg' is returning into its
|
||||
caller 'frame' */
|
||||
case PyTrace_C_RETURN: /* ...normally */
|
||||
case PyTrace_C_EXCEPTION: /* ...with an exception set */
|
||||
if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
|
||||
&& PyCFunction_Check(arg)) {
|
||||
ptrace_leave_call(self,
|
||||
((PyCFunctionObject *)arg)->m_ml);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
pending_exception(ProfilerObject *pObj)
|
||||
{
|
||||
if (pObj->flags & POF_NOMEMORY) {
|
||||
pObj->flags -= POF_NOMEMORY;
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"memory was exhausted while profiling");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/************************************************************/
|
||||
|
||||
static PyStructSequence_Field profiler_entry_fields[] = {
|
||||
{"code", "code object or built-in function name"},
|
||||
{"callcount", "how many times this was called"},
|
||||
{"reccallcount", "how many times called recursively"},
|
||||
{"totaltime", "total time in this entry"},
|
||||
{"inlinetime", "inline time in this entry (not in subcalls)"},
|
||||
{"calls", "details of the calls"},
|
||||
{0}
|
||||
};
|
||||
|
||||
static PyStructSequence_Field profiler_subentry_fields[] = {
|
||||
{"code", "called code object or built-in function name"},
|
||||
{"callcount", "how many times this is called"},
|
||||
{"reccallcount", "how many times this is called recursively"},
|
||||
{"totaltime", "total time spent in this call"},
|
||||
{"inlinetime", "inline time (not in further subcalls)"},
|
||||
{0}
|
||||
};
|
||||
|
||||
static PyStructSequence_Desc profiler_entry_desc = {
|
||||
"_lsprof.profiler_entry", /* name */
|
||||
NULL, /* doc */
|
||||
profiler_entry_fields,
|
||||
6
|
||||
};
|
||||
|
||||
static PyStructSequence_Desc profiler_subentry_desc = {
|
||||
"_lsprof.profiler_subentry", /* name */
|
||||
NULL, /* doc */
|
||||
profiler_subentry_fields,
|
||||
5
|
||||
};
|
||||
|
||||
static int initialized;
|
||||
static PyTypeObject StatsEntryType;
|
||||
static PyTypeObject StatsSubEntryType;
|
||||
|
||||
|
||||
typedef struct {
|
||||
PyObject *list;
|
||||
PyObject *sublist;
|
||||
double factor;
|
||||
} statscollector_t;
|
||||
|
||||
static int statsForSubEntry(rotating_node_t *node, void *arg)
|
||||
{
|
||||
ProfilerSubEntry *sentry = (ProfilerSubEntry*) node;
|
||||
statscollector_t *collect = (statscollector_t*) arg;
|
||||
ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
|
||||
int err;
|
||||
PyObject *sinfo;
|
||||
sinfo = PyObject_CallFunction((PyObject*) &StatsSubEntryType,
|
||||
"((Olldd))",
|
||||
entry->userObj,
|
||||
sentry->callcount,
|
||||
sentry->recursivecallcount,
|
||||
collect->factor * sentry->tt,
|
||||
collect->factor * sentry->it);
|
||||
if (sinfo == NULL)
|
||||
return -1;
|
||||
err = PyList_Append(collect->sublist, sinfo);
|
||||
Py_DECREF(sinfo);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int statsForEntry(rotating_node_t *node, void *arg)
|
||||
{
|
||||
ProfilerEntry *entry = (ProfilerEntry*) node;
|
||||
statscollector_t *collect = (statscollector_t*) arg;
|
||||
PyObject *info;
|
||||
int err;
|
||||
if (entry->callcount == 0)
|
||||
return 0; /* skip */
|
||||
|
||||
if (entry->calls != EMPTY_ROTATING_TREE) {
|
||||
collect->sublist = PyList_New(0);
|
||||
if (collect->sublist == NULL)
|
||||
return -1;
|
||||
if (RotatingTree_Enum(entry->calls,
|
||||
statsForSubEntry, collect) != 0) {
|
||||
Py_DECREF(collect->sublist);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Py_INCREF(Py_None);
|
||||
collect->sublist = Py_None;
|
||||
}
|
||||
|
||||
info = PyObject_CallFunction((PyObject*) &StatsEntryType,
|
||||
"((OllddO))",
|
||||
entry->userObj,
|
||||
entry->callcount,
|
||||
entry->recursivecallcount,
|
||||
collect->factor * entry->tt,
|
||||
collect->factor * entry->it,
|
||||
collect->sublist);
|
||||
Py_DECREF(collect->sublist);
|
||||
if (info == NULL)
|
||||
return -1;
|
||||
err = PyList_Append(collect->list, info);
|
||||
Py_DECREF(info);
|
||||
return err;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(getstats_doc, "\
|
||||
getstats() -> list of profiler_entry objects\n\
|
||||
\n\
|
||||
Return all information collected by the profiler.\n\
|
||||
Each profiler_entry is a tuple-like object with the\n\
|
||||
following attributes:\n\
|
||||
\n\
|
||||
code code object\n\
|
||||
callcount how many times this was called\n\
|
||||
reccallcount how many times called recursively\n\
|
||||
totaltime total time in this entry\n\
|
||||
inlinetime inline time in this entry (not in subcalls)\n\
|
||||
calls details of the calls\n\
|
||||
\n\
|
||||
The calls attribute is either None or a list of\n\
|
||||
profiler_subentry objects:\n\
|
||||
\n\
|
||||
code called code object\n\
|
||||
callcount how many times this is called\n\
|
||||
reccallcount how many times this is called recursively\n\
|
||||
totaltime total time spent in this call\n\
|
||||
inlinetime inline time (not in further subcalls)\n\
|
||||
");
|
||||
|
||||
static PyObject*
|
||||
profiler_getstats(ProfilerObject *pObj, PyObject* noarg)
|
||||
{
|
||||
statscollector_t collect;
|
||||
if (pending_exception(pObj))
|
||||
return NULL;
|
||||
if (!pObj->externalTimer)
|
||||
collect.factor = hpTimerUnit();
|
||||
else if (pObj->externalTimerUnit > 0.0)
|
||||
collect.factor = pObj->externalTimerUnit;
|
||||
else
|
||||
collect.factor = 1.0 / DOUBLE_TIMER_PRECISION;
|
||||
collect.list = PyList_New(0);
|
||||
if (collect.list == NULL)
|
||||
return NULL;
|
||||
if (RotatingTree_Enum(pObj->profilerEntries, statsForEntry, &collect)
|
||||
!= 0) {
|
||||
Py_DECREF(collect.list);
|
||||
return NULL;
|
||||
}
|
||||
return collect.list;
|
||||
}
|
||||
|
||||
static int
|
||||
setSubcalls(ProfilerObject *pObj, int nvalue)
|
||||
{
|
||||
if (nvalue == 0)
|
||||
pObj->flags &= ~POF_SUBCALLS;
|
||||
else if (nvalue > 0)
|
||||
pObj->flags |= POF_SUBCALLS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
setBuiltins(ProfilerObject *pObj, int nvalue)
|
||||
{
|
||||
if (nvalue == 0)
|
||||
pObj->flags &= ~POF_BUILTINS;
|
||||
else if (nvalue > 0) {
|
||||
#ifndef PyTrace_C_CALL
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"builtins=True requires Python >= 2.4");
|
||||
return -1;
|
||||
#else
|
||||
pObj->flags |= POF_BUILTINS;
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(enable_doc, "\
|
||||
enable(subcalls=True, builtins=True)\n\
|
||||
\n\
|
||||
Start collecting profiling information.\n\
|
||||
If 'subcalls' is True, also records for each function\n\
|
||||
statistics separated according to its current caller.\n\
|
||||
If 'builtins' is True, records the time spent in\n\
|
||||
built-in functions separately from their caller.\n\
|
||||
");
|
||||
|
||||
static PyObject*
|
||||
profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
int subcalls = -1;
|
||||
int builtins = -1;
|
||||
static char *kwlist[] = {"subcalls", "builtins", 0};
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable",
|
||||
kwlist, &subcalls, &builtins))
|
||||
return NULL;
|
||||
if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0)
|
||||
return NULL;
|
||||
PyEval_SetProfile(profiler_callback, (PyObject*)self);
|
||||
self->flags |= POF_ENABLED;
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static void
|
||||
flush_unmatched(ProfilerObject *pObj)
|
||||
{
|
||||
while (pObj->currentProfilerContext) {
|
||||
ProfilerContext *pContext = pObj->currentProfilerContext;
|
||||
ProfilerEntry *profEntry= pContext->ctxEntry;
|
||||
if (profEntry)
|
||||
Stop(pObj, pContext, profEntry);
|
||||
else
|
||||
pObj->currentProfilerContext = pContext->previous;
|
||||
if (pContext)
|
||||
free(pContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(disable_doc, "\
|
||||
disable()\n\
|
||||
\n\
|
||||
Stop collecting profiling information.\n\
|
||||
");
|
||||
|
||||
static PyObject*
|
||||
profiler_disable(ProfilerObject *self, PyObject* noarg)
|
||||
{
|
||||
self->flags &= ~POF_ENABLED;
|
||||
PyEval_SetProfile(NULL, NULL);
|
||||
flush_unmatched(self);
|
||||
if (pending_exception(self))
|
||||
return NULL;
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(clear_doc, "\
|
||||
clear()\n\
|
||||
\n\
|
||||
Clear all profiling information collected so far.\n\
|
||||
");
|
||||
|
||||
static PyObject*
|
||||
profiler_clear(ProfilerObject *pObj, PyObject* noarg)
|
||||
{
|
||||
clearEntries(pObj);
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static void
|
||||
profiler_dealloc(ProfilerObject *op)
|
||||
{
|
||||
if (op->flags & POF_ENABLED)
|
||||
PyEval_SetProfile(NULL, NULL);
|
||||
flush_unmatched(op);
|
||||
clearEntries(op);
|
||||
Py_XDECREF(op->externalTimer);
|
||||
Py_TYPE(op)->tp_free(op);
|
||||
}
|
||||
|
||||
static int
|
||||
profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw)
|
||||
{
|
||||
PyObject *o;
|
||||
PyObject *timer = NULL;
|
||||
double timeunit = 0.0;
|
||||
int subcalls = 1;
|
||||
#ifdef PyTrace_C_CALL
|
||||
int builtins = 1;
|
||||
#else
|
||||
int builtins = 0;
|
||||
#endif
|
||||
static char *kwlist[] = {"timer", "timeunit",
|
||||
"subcalls", "builtins", 0};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist,
|
||||
&timer, &timeunit,
|
||||
&subcalls, &builtins))
|
||||
return -1;
|
||||
|
||||
if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0)
|
||||
return -1;
|
||||
o = pObj->externalTimer;
|
||||
pObj->externalTimer = timer;
|
||||
Py_XINCREF(timer);
|
||||
Py_XDECREF(o);
|
||||
pObj->externalTimerUnit = timeunit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyMethodDef profiler_methods[] = {
|
||||
{"getstats", (PyCFunction)profiler_getstats,
|
||||
METH_NOARGS, getstats_doc},
|
||||
{"enable", (PyCFunction)profiler_enable,
|
||||
METH_VARARGS | METH_KEYWORDS, enable_doc},
|
||||
{"disable", (PyCFunction)profiler_disable,
|
||||
METH_NOARGS, disable_doc},
|
||||
{"clear", (PyCFunction)profiler_clear,
|
||||
METH_NOARGS, clear_doc},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(profiler_doc, "\
|
||||
Profiler(timer=None, timeunit=None, subcalls=True, builtins=True)\n\
|
||||
\n\
|
||||
Builds a profiler object using the specified timer function.\n\
|
||||
The default timer is a fast built-in one based on real time.\n\
|
||||
For custom timer functions returning integers, timeunit can\n\
|
||||
be a float specifying a scale (i.e. how long each integer unit\n\
|
||||
is, in seconds).\n\
|
||||
");
|
||||
|
||||
statichere PyTypeObject PyProfiler_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"_lsprof.Profiler", /* tp_name */
|
||||
sizeof(ProfilerObject), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
(destructor)profiler_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
0, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
profiler_doc, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
profiler_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
(initproc)profiler_init, /* tp_init */
|
||||
PyType_GenericAlloc, /* tp_alloc */
|
||||
PyType_GenericNew, /* tp_new */
|
||||
PyObject_Del, /* tp_free */
|
||||
};
|
||||
|
||||
static PyMethodDef moduleMethods[] = {
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC
|
||||
init_lsprof(void)
|
||||
{
|
||||
PyObject *module, *d;
|
||||
module = Py_InitModule3("_lsprof", moduleMethods, "Fast profiler");
|
||||
if (module == NULL)
|
||||
return;
|
||||
d = PyModule_GetDict(module);
|
||||
if (PyType_Ready(&PyProfiler_Type) < 0)
|
||||
return;
|
||||
PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type);
|
||||
|
||||
if (!initialized) {
|
||||
PyStructSequence_InitType(&StatsEntryType,
|
||||
&profiler_entry_desc);
|
||||
PyStructSequence_InitType(&StatsSubEntryType,
|
||||
&profiler_subentry_desc);
|
||||
}
|
||||
Py_INCREF((PyObject*) &StatsEntryType);
|
||||
Py_INCREF((PyObject*) &StatsSubEntryType);
|
||||
PyModule_AddObject(module, "profiler_entry",
|
||||
(PyObject*) &StatsEntryType);
|
||||
PyModule_AddObject(module, "profiler_subentry",
|
||||
(PyObject*) &StatsSubEntryType);
|
||||
empty_tuple = PyTuple_New(0);
|
||||
initialized = 1;
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
/* Definitions of some C99 math library functions, for those platforms
|
||||
that don't implement these functions already. */
|
||||
|
||||
#include "Python.h"
|
||||
#include <float.h>
|
||||
#include "_math.h"
|
||||
|
||||
/* The following copyright notice applies to the original
|
||||
implementations of acosh, asinh and atanh. */
|
||||
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
static const double ln2 = 6.93147180559945286227E-01;
|
||||
static const double two_pow_m28 = 3.7252902984619141E-09; /* 2**-28 */
|
||||
static const double two_pow_p28 = 268435456.0; /* 2**28 */
|
||||
|
||||
/* acosh(x)
|
||||
* Method :
|
||||
* Based on
|
||||
* acosh(x) = log [ x + sqrt(x*x-1) ]
|
||||
* we have
|
||||
* acosh(x) := log(x)+ln2, if x is large; else
|
||||
* acosh(x) := log(2x-1/(sqrt(x*x-1)+x)) if x>2; else
|
||||
* acosh(x) := log1p(t+sqrt(2.0*t+t*t)); where t=x-1.
|
||||
*
|
||||
* Special cases:
|
||||
* acosh(x) is NaN with signal if x<1.
|
||||
* acosh(NaN) is NaN without signal.
|
||||
*/
|
||||
|
||||
double
|
||||
_Py_acosh(double x)
|
||||
{
|
||||
if (Py_IS_NAN(x)) {
|
||||
return x+x;
|
||||
}
|
||||
if (x < 1.) { /* x < 1; return a signaling NaN */
|
||||
errno = EDOM;
|
||||
#ifdef Py_NAN
|
||||
return Py_NAN;
|
||||
#else
|
||||
return (x-x)/(x-x);
|
||||
#endif
|
||||
}
|
||||
else if (x >= two_pow_p28) { /* x > 2**28 */
|
||||
if (Py_IS_INFINITY(x)) {
|
||||
return x+x;
|
||||
}
|
||||
else {
|
||||
return log(x)+ln2; /* acosh(huge)=log(2x) */
|
||||
}
|
||||
}
|
||||
else if (x == 1.) {
|
||||
return 0.0; /* acosh(1) = 0 */
|
||||
}
|
||||
else if (x > 2.) { /* 2 < x < 2**28 */
|
||||
double t = x*x;
|
||||
return log(2.0*x - 1.0 / (x + sqrt(t - 1.0)));
|
||||
}
|
||||
else { /* 1 < x <= 2 */
|
||||
double t = x - 1.0;
|
||||
return m_log1p(t + sqrt(2.0*t + t*t));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* asinh(x)
|
||||
* Method :
|
||||
* Based on
|
||||
* asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ]
|
||||
* we have
|
||||
* asinh(x) := x if 1+x*x=1,
|
||||
* := sign(x)*(log(x)+ln2)) for large |x|, else
|
||||
* := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else
|
||||
* := sign(x)*log1p(|x| + x^2/(1 + sqrt(1+x^2)))
|
||||
*/
|
||||
|
||||
double
|
||||
_Py_asinh(double x)
|
||||
{
|
||||
double w;
|
||||
double absx = fabs(x);
|
||||
|
||||
if (Py_IS_NAN(x) || Py_IS_INFINITY(x)) {
|
||||
return x+x;
|
||||
}
|
||||
if (absx < two_pow_m28) { /* |x| < 2**-28 */
|
||||
return x; /* return x inexact except 0 */
|
||||
}
|
||||
if (absx > two_pow_p28) { /* |x| > 2**28 */
|
||||
w = log(absx)+ln2;
|
||||
}
|
||||
else if (absx > 2.0) { /* 2 < |x| < 2**28 */
|
||||
w = log(2.0*absx + 1.0 / (sqrt(x*x + 1.0) + absx));
|
||||
}
|
||||
else { /* 2**-28 <= |x| < 2= */
|
||||
double t = x*x;
|
||||
w = m_log1p(absx + t / (1.0 + sqrt(1.0 + t)));
|
||||
}
|
||||
return copysign(w, x);
|
||||
|
||||
}
|
||||
|
||||
/* atanh(x)
|
||||
* Method :
|
||||
* 1.Reduced x to positive by atanh(-x) = -atanh(x)
|
||||
* 2.For x>=0.5
|
||||
* 1 2x x
|
||||
* atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * -------)
|
||||
* 2 1 - x 1 - x
|
||||
*
|
||||
* For x<0.5
|
||||
* atanh(x) = 0.5*log1p(2x+2x*x/(1-x))
|
||||
*
|
||||
* Special cases:
|
||||
* atanh(x) is NaN if |x| >= 1 with signal;
|
||||
* atanh(NaN) is that NaN with no signal;
|
||||
*
|
||||
*/
|
||||
|
||||
double
|
||||
_Py_atanh(double x)
|
||||
{
|
||||
double absx;
|
||||
double t;
|
||||
|
||||
if (Py_IS_NAN(x)) {
|
||||
return x+x;
|
||||
}
|
||||
absx = fabs(x);
|
||||
if (absx >= 1.) { /* |x| >= 1 */
|
||||
errno = EDOM;
|
||||
#ifdef Py_NAN
|
||||
return Py_NAN;
|
||||
#else
|
||||
return x/0.0;
|
||||
#endif
|
||||
}
|
||||
if (absx < two_pow_m28) { /* |x| < 2**-28 */
|
||||
return x;
|
||||
}
|
||||
if (absx < 0.5) { /* |x| < 0.5 */
|
||||
t = absx+absx;
|
||||
t = 0.5 * m_log1p(t + t*absx / (1.0 - absx));
|
||||
}
|
||||
else { /* 0.5 <= |x| <= 1.0 */
|
||||
t = 0.5 * m_log1p((absx + absx) / (1.0 - absx));
|
||||
}
|
||||
return copysign(t, x);
|
||||
}
|
||||
|
||||
/* Mathematically, expm1(x) = exp(x) - 1. The expm1 function is designed
|
||||
to avoid the significant loss of precision that arises from direct
|
||||
evaluation of the expression exp(x) - 1, for x near 0. */
|
||||
|
||||
double
|
||||
_Py_expm1(double x)
|
||||
{
|
||||
/* For abs(x) >= log(2), it's safe to evaluate exp(x) - 1 directly; this
|
||||
also works fine for infinities and nans.
|
||||
|
||||
For smaller x, we can use a method due to Kahan that achieves close to
|
||||
full accuracy.
|
||||
*/
|
||||
|
||||
if (fabs(x) < 0.7) {
|
||||
double u;
|
||||
u = exp(x);
|
||||
if (u == 1.0)
|
||||
return x;
|
||||
else
|
||||
return (u - 1.0) * x / log(u);
|
||||
}
|
||||
else
|
||||
return exp(x) - 1.0;
|
||||
}
|
||||
|
||||
/* log1p(x) = log(1+x). The log1p function is designed to avoid the
|
||||
significant loss of precision that arises from direct evaluation when x is
|
||||
small. */
|
||||
|
||||
#ifdef HAVE_LOG1P
|
||||
|
||||
double
|
||||
_Py_log1p(double x)
|
||||
{
|
||||
/* Some platforms supply a log1p function but don't respect the sign of
|
||||
zero: log1p(-0.0) gives 0.0 instead of the correct result of -0.0.
|
||||
|
||||
To save fiddling with configure tests and platform checks, we handle the
|
||||
special case of zero input directly on all platforms.
|
||||
*/
|
||||
if (x == 0.0) {
|
||||
return x;
|
||||
}
|
||||
else {
|
||||
return log1p(x);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
double
|
||||
_Py_log1p(double x)
|
||||
{
|
||||
/* For x small, we use the following approach. Let y be the nearest float
|
||||
to 1+x, then
|
||||
|
||||
1+x = y * (1 - (y-1-x)/y)
|
||||
|
||||
so log(1+x) = log(y) + log(1-(y-1-x)/y). Since (y-1-x)/y is tiny, the
|
||||
second term is well approximated by (y-1-x)/y. If abs(x) >=
|
||||
DBL_EPSILON/2 or the rounding-mode is some form of round-to-nearest
|
||||
then y-1-x will be exactly representable, and is computed exactly by
|
||||
(y-1)-x.
|
||||
|
||||
If abs(x) < DBL_EPSILON/2 and the rounding mode is not known to be
|
||||
round-to-nearest then this method is slightly dangerous: 1+x could be
|
||||
rounded up to 1+DBL_EPSILON instead of down to 1, and in that case
|
||||
y-1-x will not be exactly representable any more and the result can be
|
||||
off by many ulps. But this is easily fixed: for a floating-point
|
||||
number |x| < DBL_EPSILON/2., the closest floating-point number to
|
||||
log(1+x) is exactly x.
|
||||
*/
|
||||
|
||||
double y;
|
||||
if (fabs(x) < DBL_EPSILON/2.) {
|
||||
return x;
|
||||
}
|
||||
else if (-0.5 <= x && x <= 1.) {
|
||||
/* WARNING: it's possible than an overeager compiler
|
||||
will incorrectly optimize the following two lines
|
||||
to the equivalent of "return log(1.+x)". If this
|
||||
happens, then results from log1p will be inaccurate
|
||||
for small x. */
|
||||
y = 1.+x;
|
||||
return log(y)-((y-1.)-x)/y;
|
||||
}
|
||||
else {
|
||||
/* NaNs and infinities should end up here */
|
||||
return log(1.+x);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* ifdef HAVE_LOG1P */
|
||||
@@ -0,0 +1,41 @@
|
||||
double _Py_acosh(double x);
|
||||
double _Py_asinh(double x);
|
||||
double _Py_atanh(double x);
|
||||
double _Py_expm1(double x);
|
||||
double _Py_log1p(double x);
|
||||
|
||||
#ifdef HAVE_ACOSH
|
||||
#define m_acosh acosh
|
||||
#else
|
||||
/* if the system doesn't have acosh, use the substitute
|
||||
function defined in Modules/_math.c. */
|
||||
#define m_acosh _Py_acosh
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ASINH
|
||||
#define m_asinh asinh
|
||||
#else
|
||||
/* if the system doesn't have asinh, use the substitute
|
||||
function defined in Modules/_math.c. */
|
||||
#define m_asinh _Py_asinh
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ATANH
|
||||
#define m_atanh atanh
|
||||
#else
|
||||
/* if the system doesn't have atanh, use the substitute
|
||||
function defined in Modules/_math.c. */
|
||||
#define m_atanh _Py_atanh
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_EXPM1
|
||||
#define m_expm1 expm1
|
||||
#else
|
||||
/* if the system doesn't have expm1, use the substitute
|
||||
function defined in Modules/_math.c. */
|
||||
#define m_expm1 _Py_expm1
|
||||
#endif
|
||||
|
||||
/* Use the substitute from _math.c on all platforms:
|
||||
it includes workarounds for buggy handling of zeros. */
|
||||
#define m_log1p _Py_log1p
|
||||
@@ -0,0 +1,519 @@
|
||||
/*
|
||||
* Definition of a `Connection` type.
|
||||
* Used by `socket_connection.c` and `pipe_connection.c`.
|
||||
*
|
||||
* connection.h
|
||||
*
|
||||
* Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
|
||||
*/
|
||||
|
||||
#ifndef CONNECTION_H
|
||||
#define CONNECTION_H
|
||||
|
||||
/*
|
||||
* Read/write flags
|
||||
*/
|
||||
|
||||
#define READABLE 1
|
||||
#define WRITABLE 2
|
||||
|
||||
#define CHECK_READABLE(self) \
|
||||
if (!(self->flags & READABLE)) { \
|
||||
PyErr_SetString(PyExc_IOError, "connection is write-only"); \
|
||||
return NULL; \
|
||||
}
|
||||
|
||||
#define CHECK_WRITABLE(self) \
|
||||
if (!(self->flags & WRITABLE)) { \
|
||||
PyErr_SetString(PyExc_IOError, "connection is read-only"); \
|
||||
return NULL; \
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocation and deallocation
|
||||
*/
|
||||
|
||||
static PyObject *
|
||||
connection_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
ConnectionObject *self;
|
||||
HANDLE handle;
|
||||
BOOL readable = TRUE, writable = TRUE;
|
||||
|
||||
static char *kwlist[] = {"handle", "readable", "writable", NULL};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, F_HANDLE "|ii", kwlist,
|
||||
&handle, &readable, &writable))
|
||||
return NULL;
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE || (Py_ssize_t)handle < 0) {
|
||||
PyErr_Format(PyExc_IOError, "invalid handle %zd",
|
||||
(Py_ssize_t)handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!readable && !writable) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"either readable or writable must be true");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self = PyObject_New(ConnectionObject, type);
|
||||
if (self == NULL)
|
||||
return NULL;
|
||||
|
||||
self->weakreflist = NULL;
|
||||
self->handle = handle;
|
||||
self->flags = 0;
|
||||
|
||||
if (readable)
|
||||
self->flags |= READABLE;
|
||||
if (writable)
|
||||
self->flags |= WRITABLE;
|
||||
assert(self->flags >= 1 && self->flags <= 3);
|
||||
|
||||
return (PyObject*)self;
|
||||
}
|
||||
|
||||
static void
|
||||
connection_dealloc(ConnectionObject* self)
|
||||
{
|
||||
if (self->weakreflist != NULL)
|
||||
PyObject_ClearWeakRefs((PyObject*)self);
|
||||
|
||||
if (self->handle != INVALID_HANDLE_VALUE) {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
CLOSE(self->handle);
|
||||
Py_END_ALLOW_THREADS
|
||||
}
|
||||
PyObject_Del(self);
|
||||
}
|
||||
|
||||
/*
|
||||
* Functions for transferring buffers
|
||||
*/
|
||||
|
||||
static PyObject *
|
||||
connection_sendbytes(ConnectionObject *self, PyObject *args)
|
||||
{
|
||||
char *buffer;
|
||||
Py_ssize_t length, offset=0, size=PY_SSIZE_T_MIN;
|
||||
int res;
|
||||
|
||||
if (!PyArg_ParseTuple(args, F_RBUFFER "#|" F_PY_SSIZE_T F_PY_SSIZE_T,
|
||||
&buffer, &length, &offset, &size))
|
||||
return NULL;
|
||||
|
||||
CHECK_WRITABLE(self);
|
||||
|
||||
if (offset < 0) {
|
||||
PyErr_SetString(PyExc_ValueError, "offset is negative");
|
||||
return NULL;
|
||||
}
|
||||
if (length < offset) {
|
||||
PyErr_SetString(PyExc_ValueError, "buffer length < offset");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size == PY_SSIZE_T_MIN) {
|
||||
size = length - offset;
|
||||
} else {
|
||||
if (size < 0) {
|
||||
PyErr_SetString(PyExc_ValueError, "size is negative");
|
||||
return NULL;
|
||||
}
|
||||
if (offset + size > length) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"buffer length < offset + size");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
res = conn_send_string(self, buffer + offset, size);
|
||||
|
||||
if (res < 0) {
|
||||
if (PyErr_Occurred())
|
||||
return NULL;
|
||||
else
|
||||
return mp_SetError(PyExc_IOError, res);
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
connection_recvbytes(ConnectionObject *self, PyObject *args)
|
||||
{
|
||||
char *freeme = NULL;
|
||||
Py_ssize_t res, maxlength = PY_SSIZE_T_MAX;
|
||||
PyObject *result = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|" F_PY_SSIZE_T, &maxlength))
|
||||
return NULL;
|
||||
|
||||
CHECK_READABLE(self);
|
||||
|
||||
if (maxlength < 0) {
|
||||
PyErr_SetString(PyExc_ValueError, "maxlength < 0");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res = conn_recv_string(self, self->buffer, CONNECTION_BUFFER_SIZE,
|
||||
&freeme, maxlength);
|
||||
|
||||
if (res < 0) {
|
||||
if (res == MP_BAD_MESSAGE_LENGTH) {
|
||||
if ((self->flags & WRITABLE) == 0) {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
CLOSE(self->handle);
|
||||
Py_END_ALLOW_THREADS
|
||||
self->handle = INVALID_HANDLE_VALUE;
|
||||
} else {
|
||||
self->flags = WRITABLE;
|
||||
}
|
||||
}
|
||||
mp_SetError(PyExc_IOError, res);
|
||||
} else {
|
||||
if (freeme == NULL) {
|
||||
result = PyString_FromStringAndSize(self->buffer, res);
|
||||
} else {
|
||||
result = PyString_FromStringAndSize(freeme, res);
|
||||
PyMem_Free(freeme);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
connection_recvbytes_into(ConnectionObject *self, PyObject *args)
|
||||
{
|
||||
char *freeme = NULL, *buffer = NULL;
|
||||
Py_ssize_t res, length, offset = 0;
|
||||
PyObject *result = NULL;
|
||||
Py_buffer pbuf;
|
||||
|
||||
CHECK_READABLE(self);
|
||||
|
||||
if (!PyArg_ParseTuple(args, "w*|" F_PY_SSIZE_T,
|
||||
&pbuf, &offset))
|
||||
return NULL;
|
||||
|
||||
buffer = pbuf.buf;
|
||||
length = pbuf.len;
|
||||
|
||||
if (offset < 0) {
|
||||
PyErr_SetString(PyExc_ValueError, "negative offset");
|
||||
goto _error;
|
||||
}
|
||||
|
||||
if (offset > length) {
|
||||
PyErr_SetString(PyExc_ValueError, "offset too large");
|
||||
goto _error;
|
||||
}
|
||||
|
||||
res = conn_recv_string(self, buffer+offset, length-offset,
|
||||
&freeme, PY_SSIZE_T_MAX);
|
||||
|
||||
if (res < 0) {
|
||||
if (res == MP_BAD_MESSAGE_LENGTH) {
|
||||
if ((self->flags & WRITABLE) == 0) {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
CLOSE(self->handle);
|
||||
Py_END_ALLOW_THREADS
|
||||
self->handle = INVALID_HANDLE_VALUE;
|
||||
} else {
|
||||
self->flags = WRITABLE;
|
||||
}
|
||||
}
|
||||
mp_SetError(PyExc_IOError, res);
|
||||
} else {
|
||||
if (freeme == NULL) {
|
||||
result = PyInt_FromSsize_t(res);
|
||||
} else {
|
||||
result = PyObject_CallFunction(BufferTooShort,
|
||||
F_RBUFFER "#",
|
||||
freeme, res);
|
||||
PyMem_Free(freeme);
|
||||
if (result) {
|
||||
PyErr_SetObject(BufferTooShort, result);
|
||||
Py_DECREF(result);
|
||||
}
|
||||
goto _error;
|
||||
}
|
||||
}
|
||||
|
||||
_cleanup:
|
||||
PyBuffer_Release(&pbuf);
|
||||
return result;
|
||||
|
||||
_error:
|
||||
result = NULL;
|
||||
goto _cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Functions for transferring objects
|
||||
*/
|
||||
|
||||
static PyObject *
|
||||
connection_send_obj(ConnectionObject *self, PyObject *obj)
|
||||
{
|
||||
char *buffer;
|
||||
int res;
|
||||
Py_ssize_t length;
|
||||
PyObject *pickled_string = NULL;
|
||||
|
||||
CHECK_WRITABLE(self);
|
||||
|
||||
pickled_string = PyObject_CallFunctionObjArgs(pickle_dumps, obj,
|
||||
pickle_protocol, NULL);
|
||||
if (!pickled_string)
|
||||
goto failure;
|
||||
|
||||
if (PyString_AsStringAndSize(pickled_string, &buffer, &length) < 0)
|
||||
goto failure;
|
||||
|
||||
res = conn_send_string(self, buffer, (int)length);
|
||||
|
||||
if (res < 0) {
|
||||
mp_SetError(PyExc_IOError, res);
|
||||
goto failure;
|
||||
}
|
||||
|
||||
Py_XDECREF(pickled_string);
|
||||
Py_RETURN_NONE;
|
||||
|
||||
failure:
|
||||
Py_XDECREF(pickled_string);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
connection_recv_obj(ConnectionObject *self)
|
||||
{
|
||||
char *freeme = NULL;
|
||||
Py_ssize_t res;
|
||||
PyObject *temp = NULL, *result = NULL;
|
||||
|
||||
CHECK_READABLE(self);
|
||||
|
||||
res = conn_recv_string(self, self->buffer, CONNECTION_BUFFER_SIZE,
|
||||
&freeme, PY_SSIZE_T_MAX);
|
||||
|
||||
if (res < 0) {
|
||||
if (res == MP_BAD_MESSAGE_LENGTH) {
|
||||
if ((self->flags & WRITABLE) == 0) {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
CLOSE(self->handle);
|
||||
Py_END_ALLOW_THREADS
|
||||
self->handle = INVALID_HANDLE_VALUE;
|
||||
} else {
|
||||
self->flags = WRITABLE;
|
||||
}
|
||||
}
|
||||
mp_SetError(PyExc_IOError, res);
|
||||
} else {
|
||||
if (freeme == NULL) {
|
||||
temp = PyString_FromStringAndSize(self->buffer, res);
|
||||
} else {
|
||||
temp = PyString_FromStringAndSize(freeme, res);
|
||||
PyMem_Free(freeme);
|
||||
}
|
||||
}
|
||||
|
||||
if (temp)
|
||||
result = PyObject_CallFunctionObjArgs(pickle_loads,
|
||||
temp, NULL);
|
||||
Py_XDECREF(temp);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Other functions
|
||||
*/
|
||||
|
||||
static PyObject *
|
||||
connection_poll(ConnectionObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *timeout_obj = NULL;
|
||||
double timeout = 0.0;
|
||||
int res;
|
||||
|
||||
CHECK_READABLE(self);
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|O", &timeout_obj))
|
||||
return NULL;
|
||||
|
||||
if (timeout_obj == NULL) {
|
||||
timeout = 0.0;
|
||||
} else if (timeout_obj == Py_None) {
|
||||
timeout = -1.0; /* block forever */
|
||||
} else {
|
||||
timeout = PyFloat_AsDouble(timeout_obj);
|
||||
if (PyErr_Occurred())
|
||||
return NULL;
|
||||
if (timeout < 0.0)
|
||||
timeout = 0.0;
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = conn_poll(self, timeout, _save);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
switch (res) {
|
||||
case TRUE:
|
||||
Py_RETURN_TRUE;
|
||||
case FALSE:
|
||||
Py_RETURN_FALSE;
|
||||
default:
|
||||
return mp_SetError(PyExc_IOError, res);
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
connection_fileno(ConnectionObject* self)
|
||||
{
|
||||
if (self->handle == INVALID_HANDLE_VALUE) {
|
||||
PyErr_SetString(PyExc_IOError, "handle is invalid");
|
||||
return NULL;
|
||||
}
|
||||
return PyInt_FromLong((long)self->handle);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
connection_close(ConnectionObject *self)
|
||||
{
|
||||
if (self->handle != INVALID_HANDLE_VALUE) {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
CLOSE(self->handle);
|
||||
Py_END_ALLOW_THREADS
|
||||
self->handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
connection_repr(ConnectionObject *self)
|
||||
{
|
||||
static char *conn_type[] = {"read-only", "write-only", "read-write"};
|
||||
|
||||
assert(self->flags >= 1 && self->flags <= 3);
|
||||
return FROM_FORMAT("<%s %s, handle %zd>",
|
||||
conn_type[self->flags - 1],
|
||||
CONNECTION_NAME, (Py_ssize_t)self->handle);
|
||||
}
|
||||
|
||||
/*
|
||||
* Getters and setters
|
||||
*/
|
||||
|
||||
static PyObject *
|
||||
connection_closed(ConnectionObject *self, void *closure)
|
||||
{
|
||||
return PyBool_FromLong((long)(self->handle == INVALID_HANDLE_VALUE));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
connection_readable(ConnectionObject *self, void *closure)
|
||||
{
|
||||
return PyBool_FromLong((long)(self->flags & READABLE));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
connection_writable(ConnectionObject *self, void *closure)
|
||||
{
|
||||
return PyBool_FromLong((long)(self->flags & WRITABLE));
|
||||
}
|
||||
|
||||
/*
|
||||
* Tables
|
||||
*/
|
||||
|
||||
static PyMethodDef connection_methods[] = {
|
||||
{"send_bytes", (PyCFunction)connection_sendbytes, METH_VARARGS,
|
||||
"send the byte data from a readable buffer-like object"},
|
||||
{"recv_bytes", (PyCFunction)connection_recvbytes, METH_VARARGS,
|
||||
"receive byte data as a string"},
|
||||
{"recv_bytes_into",(PyCFunction)connection_recvbytes_into,METH_VARARGS,
|
||||
"receive byte data into a writeable buffer-like object\n"
|
||||
"returns the number of bytes read"},
|
||||
|
||||
{"send", (PyCFunction)connection_send_obj, METH_O,
|
||||
"send a (picklable) object"},
|
||||
{"recv", (PyCFunction)connection_recv_obj, METH_NOARGS,
|
||||
"receive a (picklable) object"},
|
||||
|
||||
{"poll", (PyCFunction)connection_poll, METH_VARARGS,
|
||||
"whether there is any input available to be read"},
|
||||
{"fileno", (PyCFunction)connection_fileno, METH_NOARGS,
|
||||
"file descriptor or handle of the connection"},
|
||||
{"close", (PyCFunction)connection_close, METH_NOARGS,
|
||||
"close the connection"},
|
||||
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyGetSetDef connection_getset[] = {
|
||||
{"closed", (getter)connection_closed, NULL,
|
||||
"True if the connection is closed", NULL},
|
||||
{"readable", (getter)connection_readable, NULL,
|
||||
"True if the connection is readable", NULL},
|
||||
{"writable", (getter)connection_writable, NULL,
|
||||
"True if the connection is writable", NULL},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
/*
|
||||
* Connection type
|
||||
*/
|
||||
|
||||
PyDoc_STRVAR(connection_doc,
|
||||
"Connection type whose constructor signature is\n\n"
|
||||
" Connection(handle, readable=True, writable=True).\n\n"
|
||||
"The constructor does *not* duplicate the handle.");
|
||||
|
||||
PyTypeObject CONNECTION_TYPE = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
/* tp_name */ "_multiprocessing." CONNECTION_NAME,
|
||||
/* tp_basicsize */ sizeof(ConnectionObject),
|
||||
/* tp_itemsize */ 0,
|
||||
/* tp_dealloc */ (destructor)connection_dealloc,
|
||||
/* tp_print */ 0,
|
||||
/* tp_getattr */ 0,
|
||||
/* tp_setattr */ 0,
|
||||
/* tp_compare */ 0,
|
||||
/* tp_repr */ (reprfunc)connection_repr,
|
||||
/* tp_as_number */ 0,
|
||||
/* tp_as_sequence */ 0,
|
||||
/* tp_as_mapping */ 0,
|
||||
/* tp_hash */ 0,
|
||||
/* tp_call */ 0,
|
||||
/* tp_str */ 0,
|
||||
/* tp_getattro */ 0,
|
||||
/* tp_setattro */ 0,
|
||||
/* tp_as_buffer */ 0,
|
||||
/* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
|
||||
Py_TPFLAGS_HAVE_WEAKREFS,
|
||||
/* tp_doc */ connection_doc,
|
||||
/* tp_traverse */ 0,
|
||||
/* tp_clear */ 0,
|
||||
/* tp_richcompare */ 0,
|
||||
/* tp_weaklistoffset */ offsetof(ConnectionObject, weakreflist),
|
||||
/* tp_iter */ 0,
|
||||
/* tp_iternext */ 0,
|
||||
/* tp_methods */ connection_methods,
|
||||
/* tp_members */ 0,
|
||||
/* tp_getset */ connection_getset,
|
||||
/* tp_base */ 0,
|
||||
/* tp_dict */ 0,
|
||||
/* tp_descr_get */ 0,
|
||||
/* tp_descr_set */ 0,
|
||||
/* tp_dictoffset */ 0,
|
||||
/* tp_init */ 0,
|
||||
/* tp_alloc */ 0,
|
||||
/* tp_new */ connection_new,
|
||||
};
|
||||
|
||||
#endif /* CONNECTION_H */
|
||||
+352
@@ -0,0 +1,352 @@
|
||||
/*
|
||||
* Extension module used by multiprocessing package
|
||||
*
|
||||
* multiprocessing.c
|
||||
*
|
||||
* Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
|
||||
*/
|
||||
|
||||
#include "multiprocessing.h"
|
||||
|
||||
#if (defined(CMSG_LEN) && defined(SCM_RIGHTS))
|
||||
#define HAVE_FD_TRANSFER 1
|
||||
#else
|
||||
#define HAVE_FD_TRANSFER 0
|
||||
#endif
|
||||
|
||||
PyObject *create_win32_namespace(void);
|
||||
|
||||
PyObject *pickle_dumps, *pickle_loads, *pickle_protocol;
|
||||
PyObject *ProcessError, *BufferTooShort;
|
||||
|
||||
/*
|
||||
* Function which raises exceptions based on error codes
|
||||
*/
|
||||
|
||||
PyObject *
|
||||
mp_SetError(PyObject *Type, int num)
|
||||
{
|
||||
switch (num) {
|
||||
#ifdef MS_WINDOWS
|
||||
case MP_STANDARD_ERROR:
|
||||
if (Type == NULL)
|
||||
Type = PyExc_WindowsError;
|
||||
PyErr_SetExcFromWindowsErr(Type, 0);
|
||||
break;
|
||||
case MP_SOCKET_ERROR:
|
||||
if (Type == NULL)
|
||||
Type = PyExc_WindowsError;
|
||||
PyErr_SetExcFromWindowsErr(Type, WSAGetLastError());
|
||||
break;
|
||||
#else /* !MS_WINDOWS */
|
||||
case MP_STANDARD_ERROR:
|
||||
case MP_SOCKET_ERROR:
|
||||
if (Type == NULL)
|
||||
Type = PyExc_OSError;
|
||||
PyErr_SetFromErrno(Type);
|
||||
break;
|
||||
#endif /* !MS_WINDOWS */
|
||||
case MP_MEMORY_ERROR:
|
||||
PyErr_NoMemory();
|
||||
break;
|
||||
case MP_END_OF_FILE:
|
||||
PyErr_SetNone(PyExc_EOFError);
|
||||
break;
|
||||
case MP_EARLY_END_OF_FILE:
|
||||
PyErr_SetString(PyExc_IOError,
|
||||
"got end of file during message");
|
||||
break;
|
||||
case MP_BAD_MESSAGE_LENGTH:
|
||||
PyErr_SetString(PyExc_IOError, "bad message length");
|
||||
break;
|
||||
case MP_EXCEPTION_HAS_BEEN_SET:
|
||||
break;
|
||||
default:
|
||||
PyErr_Format(PyExc_RuntimeError,
|
||||
"unknown error number %d", num);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Windows only
|
||||
*/
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
|
||||
/* On Windows we set an event to signal Ctrl-C; compare with timemodule.c */
|
||||
|
||||
HANDLE sigint_event = NULL;
|
||||
|
||||
static BOOL WINAPI
|
||||
ProcessingCtrlHandler(DWORD dwCtrlType)
|
||||
{
|
||||
SetEvent(sigint_event);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unix only
|
||||
*/
|
||||
|
||||
#else /* !MS_WINDOWS */
|
||||
|
||||
#if HAVE_FD_TRANSFER
|
||||
|
||||
/* Functions for transferring file descriptors between processes.
|
||||
Reimplements some of the functionality of the fdcred
|
||||
module at http://www.mca-ltd.com/resources/fdcred_1.tgz. */
|
||||
/* Based in http://resin.csoft.net/cgi-bin/man.cgi?section=3&topic=CMSG_DATA */
|
||||
|
||||
static PyObject *
|
||||
multiprocessing_sendfd(PyObject *self, PyObject *args)
|
||||
{
|
||||
int conn, fd, res;
|
||||
struct iovec dummy_iov;
|
||||
char dummy_char;
|
||||
struct msghdr msg;
|
||||
struct cmsghdr *cmsg;
|
||||
union {
|
||||
struct cmsghdr hdr;
|
||||
unsigned char buf[CMSG_SPACE(sizeof(int))];
|
||||
} cmsgbuf;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ii", &conn, &fd))
|
||||
return NULL;
|
||||
|
||||
dummy_iov.iov_base = &dummy_char;
|
||||
dummy_iov.iov_len = 1;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_control = &cmsgbuf.buf;
|
||||
msg.msg_controllen = sizeof(cmsgbuf.buf);
|
||||
msg.msg_iov = &dummy_iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
* (int *) CMSG_DATA(cmsg) = fd;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = sendmsg(conn, &msg, 0);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (res < 0)
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
multiprocessing_recvfd(PyObject *self, PyObject *args)
|
||||
{
|
||||
int conn, fd, res;
|
||||
char dummy_char;
|
||||
struct iovec dummy_iov;
|
||||
struct msghdr msg = {0};
|
||||
struct cmsghdr *cmsg;
|
||||
union {
|
||||
struct cmsghdr hdr;
|
||||
unsigned char buf[CMSG_SPACE(sizeof(int))];
|
||||
} cmsgbuf;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i", &conn))
|
||||
return NULL;
|
||||
|
||||
dummy_iov.iov_base = &dummy_char;
|
||||
dummy_iov.iov_len = 1;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_control = &cmsgbuf.buf;
|
||||
msg.msg_controllen = sizeof(cmsgbuf.buf);
|
||||
msg.msg_iov = &dummy_iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = CMSG_SPACE(sizeof(int));
|
||||
msg.msg_controllen = cmsg->cmsg_len;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = recvmsg(conn, &msg, 0);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (res < 0)
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
|
||||
if (msg.msg_controllen < CMSG_LEN(sizeof(int)) ||
|
||||
(cmsg = CMSG_FIRSTHDR(&msg)) == NULL ||
|
||||
cmsg->cmsg_level != SOL_SOCKET ||
|
||||
cmsg->cmsg_type != SCM_RIGHTS ||
|
||||
cmsg->cmsg_len < CMSG_LEN(sizeof(int))) {
|
||||
/* If at least one control message is present, there should be
|
||||
no room for any further data in the buffer. */
|
||||
PyErr_SetString(PyExc_RuntimeError, "No file descriptor received");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fd = * (int *) CMSG_DATA(cmsg);
|
||||
return Py_BuildValue("i", fd);
|
||||
}
|
||||
|
||||
#endif /* HAVE_FD_TRANSFER */
|
||||
|
||||
#endif /* !MS_WINDOWS */
|
||||
|
||||
|
||||
/*
|
||||
* All platforms
|
||||
*/
|
||||
|
||||
static PyObject*
|
||||
multiprocessing_address_of_buffer(PyObject *self, PyObject *obj)
|
||||
{
|
||||
void *buffer;
|
||||
Py_ssize_t buffer_len;
|
||||
|
||||
if (PyObject_AsWriteBuffer(obj, &buffer, &buffer_len) < 0)
|
||||
return NULL;
|
||||
|
||||
return Py_BuildValue("N" F_PY_SSIZE_T,
|
||||
PyLong_FromVoidPtr(buffer), buffer_len);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Function table
|
||||
*/
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
{"address_of_buffer", multiprocessing_address_of_buffer, METH_O,
|
||||
"address_of_buffer(obj) -> int\n"
|
||||
"Return address of obj assuming obj supports buffer inteface"},
|
||||
#if HAVE_FD_TRANSFER
|
||||
{"sendfd", multiprocessing_sendfd, METH_VARARGS,
|
||||
"sendfd(sockfd, fd) -> None\n"
|
||||
"Send file descriptor given by fd over the unix domain socket\n"
|
||||
"whose file decriptor is sockfd"},
|
||||
{"recvfd", multiprocessing_recvfd, METH_VARARGS,
|
||||
"recvfd(sockfd) -> fd\n"
|
||||
"Receive a file descriptor over a unix domain socket\n"
|
||||
"whose file decriptor is sockfd"},
|
||||
#endif
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Initialize
|
||||
*/
|
||||
|
||||
PyMODINIT_FUNC
|
||||
init_multiprocessing(void)
|
||||
{
|
||||
PyObject *module, *temp, *value;
|
||||
|
||||
/* Initialize module */
|
||||
module = Py_InitModule("_multiprocessing", module_methods);
|
||||
if (!module)
|
||||
return;
|
||||
|
||||
/* Get copy of objects from pickle */
|
||||
temp = PyImport_ImportModule(PICKLE_MODULE);
|
||||
if (!temp)
|
||||
return;
|
||||
pickle_dumps = PyObject_GetAttrString(temp, "dumps");
|
||||
pickle_loads = PyObject_GetAttrString(temp, "loads");
|
||||
pickle_protocol = PyObject_GetAttrString(temp, "HIGHEST_PROTOCOL");
|
||||
Py_XDECREF(temp);
|
||||
|
||||
/* Get copy of BufferTooShort */
|
||||
temp = PyImport_ImportModule("multiprocessing");
|
||||
if (!temp)
|
||||
return;
|
||||
BufferTooShort = PyObject_GetAttrString(temp, "BufferTooShort");
|
||||
Py_XDECREF(temp);
|
||||
|
||||
/* Add connection type to module */
|
||||
if (PyType_Ready(&ConnectionType) < 0)
|
||||
return;
|
||||
Py_INCREF(&ConnectionType);
|
||||
PyModule_AddObject(module, "Connection", (PyObject*)&ConnectionType);
|
||||
|
||||
#if defined(MS_WINDOWS) || \
|
||||
(defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED))
|
||||
/* Add SemLock type to module */
|
||||
if (PyType_Ready(&SemLockType) < 0)
|
||||
return;
|
||||
Py_INCREF(&SemLockType);
|
||||
{
|
||||
PyObject *py_sem_value_max;
|
||||
/* Some systems define SEM_VALUE_MAX as an unsigned value that
|
||||
* causes it to be negative when used as an int (NetBSD). */
|
||||
if ((int)(SEM_VALUE_MAX) < 0)
|
||||
py_sem_value_max = PyLong_FromLong(INT_MAX);
|
||||
else
|
||||
py_sem_value_max = PyLong_FromLong(SEM_VALUE_MAX);
|
||||
if (py_sem_value_max == NULL)
|
||||
return;
|
||||
PyDict_SetItemString(SemLockType.tp_dict, "SEM_VALUE_MAX",
|
||||
py_sem_value_max);
|
||||
}
|
||||
PyModule_AddObject(module, "SemLock", (PyObject*)&SemLockType);
|
||||
#endif
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
/* Add PipeConnection to module */
|
||||
if (PyType_Ready(&PipeConnectionType) < 0)
|
||||
return;
|
||||
Py_INCREF(&PipeConnectionType);
|
||||
PyModule_AddObject(module, "PipeConnection",
|
||||
(PyObject*)&PipeConnectionType);
|
||||
|
||||
/* Initialize win32 class and add to multiprocessing */
|
||||
temp = create_win32_namespace();
|
||||
if (!temp)
|
||||
return;
|
||||
PyModule_AddObject(module, "win32", temp);
|
||||
|
||||
/* Initialize the event handle used to signal Ctrl-C */
|
||||
sigint_event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
if (!sigint_event) {
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
return;
|
||||
}
|
||||
if (!SetConsoleCtrlHandler(ProcessingCtrlHandler, TRUE)) {
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Add configuration macros */
|
||||
temp = PyDict_New();
|
||||
if (!temp)
|
||||
return;
|
||||
#define ADD_FLAG(name) \
|
||||
value = Py_BuildValue("i", name); \
|
||||
if (value == NULL) { Py_DECREF(temp); return; } \
|
||||
if (PyDict_SetItemString(temp, #name, value) < 0) { \
|
||||
Py_DECREF(temp); Py_DECREF(value); return; } \
|
||||
Py_DECREF(value)
|
||||
|
||||
#if defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED)
|
||||
ADD_FLAG(HAVE_SEM_OPEN);
|
||||
#endif
|
||||
#ifdef HAVE_SEM_TIMEDWAIT
|
||||
ADD_FLAG(HAVE_SEM_TIMEDWAIT);
|
||||
#endif
|
||||
#ifdef HAVE_FD_TRANSFER
|
||||
ADD_FLAG(HAVE_FD_TRANSFER);
|
||||
#endif
|
||||
#ifdef HAVE_BROKEN_SEM_GETVALUE
|
||||
ADD_FLAG(HAVE_BROKEN_SEM_GETVALUE);
|
||||
#endif
|
||||
#ifdef HAVE_BROKEN_SEM_UNLINK
|
||||
ADD_FLAG(HAVE_BROKEN_SEM_UNLINK);
|
||||
#endif
|
||||
if (PyModule_AddObject(module, "flags", temp) < 0)
|
||||
return;
|
||||
}
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
#ifndef MULTIPROCESSING_H
|
||||
#define MULTIPROCESSING_H
|
||||
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
|
||||
#ifdef __sun
|
||||
/* The control message API is only available on Solaris
|
||||
if XPG 4.2 or later is requested. */
|
||||
#define _XOPEN_SOURCE 500
|
||||
#endif
|
||||
|
||||
#include "Python.h"
|
||||
#include "structmember.h"
|
||||
#include "pythread.h"
|
||||
|
||||
/*
|
||||
* Platform includes and definitions
|
||||
*/
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# include <winsock2.h>
|
||||
# include <process.h> /* getpid() */
|
||||
# ifdef Py_DEBUG
|
||||
# include <crtdbg.h>
|
||||
# endif
|
||||
# define SEM_HANDLE HANDLE
|
||||
# define SEM_VALUE_MAX LONG_MAX
|
||||
#else
|
||||
# include <fcntl.h> /* O_CREAT and O_EXCL */
|
||||
# include <netinet/in.h>
|
||||
# include <sys/socket.h>
|
||||
# include <sys/uio.h>
|
||||
# include <arpa/inet.h> /* htonl() and ntohl() */
|
||||
# if defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED)
|
||||
# include <semaphore.h>
|
||||
typedef sem_t *SEM_HANDLE;
|
||||
# endif
|
||||
# define HANDLE int
|
||||
# define SOCKET int
|
||||
# define BOOL int
|
||||
# define UINT32 uint32_t
|
||||
# define INT32 int32_t
|
||||
# define TRUE 1
|
||||
# define FALSE 0
|
||||
# define INVALID_HANDLE_VALUE (-1)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Issue 3110 - Solaris does not define SEM_VALUE_MAX
|
||||
*/
|
||||
#ifndef SEM_VALUE_MAX
|
||||
#if defined(HAVE_SYSCONF) && defined(_SC_SEM_VALUE_MAX)
|
||||
# define SEM_VALUE_MAX sysconf(_SC_SEM_VALUE_MAX)
|
||||
#elif defined(_SEM_VALUE_MAX)
|
||||
# define SEM_VALUE_MAX _SEM_VALUE_MAX
|
||||
#elif defined(_POSIX_SEM_VALUE_MAX)
|
||||
# define SEM_VALUE_MAX _POSIX_SEM_VALUE_MAX
|
||||
#else
|
||||
# define SEM_VALUE_MAX INT_MAX
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Make sure Py_ssize_t available
|
||||
*/
|
||||
|
||||
#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
|
||||
typedef int Py_ssize_t;
|
||||
# define PY_SSIZE_T_MAX INT_MAX
|
||||
# define PY_SSIZE_T_MIN INT_MIN
|
||||
# define F_PY_SSIZE_T "i"
|
||||
# define PyInt_FromSsize_t(n) PyInt_FromLong((long)n)
|
||||
#else
|
||||
# define F_PY_SSIZE_T "n"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Format codes
|
||||
*/
|
||||
|
||||
#if SIZEOF_VOID_P == SIZEOF_LONG
|
||||
# define F_POINTER "k"
|
||||
# define T_POINTER T_ULONG
|
||||
#elif defined(HAVE_LONG_LONG) && (SIZEOF_VOID_P == SIZEOF_LONG_LONG)
|
||||
# define F_POINTER "K"
|
||||
# define T_POINTER T_ULONGLONG
|
||||
#else
|
||||
# error "can't find format code for unsigned integer of same size as void*"
|
||||
#endif
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
# define F_HANDLE F_POINTER
|
||||
# define T_HANDLE T_POINTER
|
||||
# define F_SEM_HANDLE F_HANDLE
|
||||
# define T_SEM_HANDLE T_HANDLE
|
||||
# define F_DWORD "k"
|
||||
# define T_DWORD T_ULONG
|
||||
#else
|
||||
# define F_HANDLE "i"
|
||||
# define T_HANDLE T_INT
|
||||
# define F_SEM_HANDLE F_POINTER
|
||||
# define T_SEM_HANDLE T_POINTER
|
||||
#endif
|
||||
|
||||
#if PY_VERSION_HEX >= 0x03000000
|
||||
# define F_RBUFFER "y"
|
||||
#else
|
||||
# define F_RBUFFER "s"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Error codes which can be returned by functions called without GIL
|
||||
*/
|
||||
|
||||
#define MP_SUCCESS (0)
|
||||
#define MP_STANDARD_ERROR (-1)
|
||||
#define MP_MEMORY_ERROR (-1001)
|
||||
#define MP_END_OF_FILE (-1002)
|
||||
#define MP_EARLY_END_OF_FILE (-1003)
|
||||
#define MP_BAD_MESSAGE_LENGTH (-1004)
|
||||
#define MP_SOCKET_ERROR (-1005)
|
||||
#define MP_EXCEPTION_HAS_BEEN_SET (-1006)
|
||||
|
||||
PyObject *mp_SetError(PyObject *Type, int num);
|
||||
|
||||
/*
|
||||
* Externs - not all will really exist on all platforms
|
||||
*/
|
||||
|
||||
extern PyObject *pickle_dumps;
|
||||
extern PyObject *pickle_loads;
|
||||
extern PyObject *pickle_protocol;
|
||||
extern PyObject *BufferTooShort;
|
||||
extern PyTypeObject SemLockType;
|
||||
extern PyTypeObject ConnectionType;
|
||||
extern PyTypeObject PipeConnectionType;
|
||||
extern HANDLE sigint_event;
|
||||
|
||||
/*
|
||||
* Py3k compatibility
|
||||
*/
|
||||
|
||||
#if PY_VERSION_HEX >= 0x03000000
|
||||
# define PICKLE_MODULE "pickle"
|
||||
# define FROM_FORMAT PyUnicode_FromFormat
|
||||
# define PyInt_FromLong PyLong_FromLong
|
||||
# define PyInt_FromSsize_t PyLong_FromSsize_t
|
||||
#else
|
||||
# define PICKLE_MODULE "cPickle"
|
||||
# define FROM_FORMAT PyString_FromFormat
|
||||
#endif
|
||||
|
||||
#ifndef PyVarObject_HEAD_INIT
|
||||
# define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size,
|
||||
#endif
|
||||
|
||||
#ifndef Py_TPFLAGS_HAVE_WEAKREFS
|
||||
# define Py_TPFLAGS_HAVE_WEAKREFS 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Connection definition
|
||||
*/
|
||||
|
||||
#define CONNECTION_BUFFER_SIZE 1024
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
HANDLE handle;
|
||||
int flags;
|
||||
PyObject *weakreflist;
|
||||
char buffer[CONNECTION_BUFFER_SIZE];
|
||||
} ConnectionObject;
|
||||
|
||||
/*
|
||||
* Miscellaneous
|
||||
*/
|
||||
|
||||
#define MAX_MESSAGE_LENGTH 0x7fffffff
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(x, y) ((x) < (y) ? x : y)
|
||||
# define MAX(x, y) ((x) > (y) ? x : y)
|
||||
#endif
|
||||
|
||||
#endif /* MULTIPROCESSING_H */
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* A type which wraps a pipe handle in message oriented mode
|
||||
*
|
||||
* pipe_connection.c
|
||||
*
|
||||
* Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
|
||||
*/
|
||||
|
||||
#include "multiprocessing.h"
|
||||
|
||||
#define CLOSE(h) CloseHandle(h)
|
||||
|
||||
/*
|
||||
* Send string to the pipe; assumes in message oriented mode
|
||||
*/
|
||||
|
||||
static Py_ssize_t
|
||||
conn_send_string(ConnectionObject *conn, char *string, size_t length)
|
||||
{
|
||||
DWORD amount_written;
|
||||
BOOL ret;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
ret = WriteFile(conn->handle, string, length, &amount_written, NULL);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (ret == 0 && GetLastError() == ERROR_NO_SYSTEM_RESOURCES) {
|
||||
PyErr_Format(PyExc_ValueError, "Cannnot send %" PY_FORMAT_SIZE_T "d bytes over connection", length);
|
||||
return MP_STANDARD_ERROR;
|
||||
}
|
||||
|
||||
return ret ? MP_SUCCESS : MP_STANDARD_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempts to read into buffer, or if buffer too small into *newbuffer.
|
||||
*
|
||||
* Returns number of bytes read. Assumes in message oriented mode.
|
||||
*/
|
||||
|
||||
static Py_ssize_t
|
||||
conn_recv_string(ConnectionObject *conn, char *buffer,
|
||||
size_t buflength, char **newbuffer, size_t maxlength)
|
||||
{
|
||||
DWORD left, length, full_length, err;
|
||||
BOOL ret;
|
||||
*newbuffer = NULL;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
ret = ReadFile(conn->handle, buffer, MIN(buflength, maxlength),
|
||||
&length, NULL);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (ret)
|
||||
return length;
|
||||
|
||||
err = GetLastError();
|
||||
if (err != ERROR_MORE_DATA) {
|
||||
if (err == ERROR_BROKEN_PIPE)
|
||||
return MP_END_OF_FILE;
|
||||
return MP_STANDARD_ERROR;
|
||||
}
|
||||
|
||||
if (!PeekNamedPipe(conn->handle, NULL, 0, NULL, NULL, &left))
|
||||
return MP_STANDARD_ERROR;
|
||||
|
||||
full_length = length + left;
|
||||
if (full_length > maxlength)
|
||||
return MP_BAD_MESSAGE_LENGTH;
|
||||
|
||||
*newbuffer = PyMem_Malloc(full_length);
|
||||
if (*newbuffer == NULL)
|
||||
return MP_MEMORY_ERROR;
|
||||
|
||||
memcpy(*newbuffer, buffer, length);
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
ret = ReadFile(conn->handle, *newbuffer+length, left, &length, NULL);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (ret) {
|
||||
assert(length == left);
|
||||
return full_length;
|
||||
} else {
|
||||
PyMem_Free(*newbuffer);
|
||||
return MP_STANDARD_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether any data is available for reading
|
||||
*/
|
||||
|
||||
static int
|
||||
conn_poll(ConnectionObject *conn, double timeout, PyThreadState *_save)
|
||||
{
|
||||
DWORD bytes, deadline, delay;
|
||||
int difference, res;
|
||||
BOOL block = FALSE;
|
||||
|
||||
if (!PeekNamedPipe(conn->handle, NULL, 0, NULL, &bytes, NULL))
|
||||
return MP_STANDARD_ERROR;
|
||||
|
||||
if (timeout == 0.0)
|
||||
return bytes > 0;
|
||||
|
||||
if (timeout < 0.0)
|
||||
block = TRUE;
|
||||
else
|
||||
/* XXX does not check for overflow */
|
||||
deadline = GetTickCount() + (DWORD)(1000 * timeout + 0.5);
|
||||
|
||||
Sleep(0);
|
||||
|
||||
for (delay = 1 ; ; delay += 1) {
|
||||
if (!PeekNamedPipe(conn->handle, NULL, 0, NULL, &bytes, NULL))
|
||||
return MP_STANDARD_ERROR;
|
||||
else if (bytes > 0)
|
||||
return TRUE;
|
||||
|
||||
if (!block) {
|
||||
difference = deadline - GetTickCount();
|
||||
if (difference < 0)
|
||||
return FALSE;
|
||||
if ((int)delay > difference)
|
||||
delay = difference;
|
||||
}
|
||||
|
||||
if (delay > 20)
|
||||
delay = 20;
|
||||
|
||||
Sleep(delay);
|
||||
|
||||
/* check for signals */
|
||||
Py_BLOCK_THREADS
|
||||
res = PyErr_CheckSignals();
|
||||
Py_UNBLOCK_THREADS
|
||||
|
||||
if (res)
|
||||
return MP_EXCEPTION_HAS_BEEN_SET;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* "connection.h" defines the PipeConnection type using the definitions above
|
||||
*/
|
||||
|
||||
#define CONNECTION_NAME "PipeConnection"
|
||||
#define CONNECTION_TYPE PipeConnectionType
|
||||
|
||||
#include "connection.h"
|
||||
@@ -0,0 +1,640 @@
|
||||
/*
|
||||
* A type which wraps a semaphore
|
||||
*
|
||||
* semaphore.c
|
||||
*
|
||||
* Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
|
||||
*/
|
||||
|
||||
#include "multiprocessing.h"
|
||||
|
||||
enum { RECURSIVE_MUTEX, SEMAPHORE };
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
SEM_HANDLE handle;
|
||||
long last_tid;
|
||||
int count;
|
||||
int maxvalue;
|
||||
int kind;
|
||||
} SemLockObject;
|
||||
|
||||
#define ISMINE(o) (o->count > 0 && PyThread_get_thread_ident() == o->last_tid)
|
||||
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
|
||||
/*
|
||||
* Windows definitions
|
||||
*/
|
||||
|
||||
#define SEM_FAILED NULL
|
||||
|
||||
#define SEM_CLEAR_ERROR() SetLastError(0)
|
||||
#define SEM_GET_LAST_ERROR() GetLastError()
|
||||
#define SEM_CREATE(name, val, max) CreateSemaphore(NULL, val, max, NULL)
|
||||
#define SEM_CLOSE(sem) (CloseHandle(sem) ? 0 : -1)
|
||||
#define SEM_GETVALUE(sem, pval) _GetSemaphoreValue(sem, pval)
|
||||
#define SEM_UNLINK(name) 0
|
||||
|
||||
static int
|
||||
_GetSemaphoreValue(HANDLE handle, long *value)
|
||||
{
|
||||
long previous;
|
||||
|
||||
switch (WaitForSingleObject(handle, 0)) {
|
||||
case WAIT_OBJECT_0:
|
||||
if (!ReleaseSemaphore(handle, 1, &previous))
|
||||
return MP_STANDARD_ERROR;
|
||||
*value = previous + 1;
|
||||
return 0;
|
||||
case WAIT_TIMEOUT:
|
||||
*value = 0;
|
||||
return 0;
|
||||
default:
|
||||
return MP_STANDARD_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
semlock_acquire(SemLockObject *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
int blocking = 1;
|
||||
double timeout;
|
||||
PyObject *timeout_obj = Py_None;
|
||||
DWORD res, full_msecs, msecs, start, ticks;
|
||||
|
||||
static char *kwlist[] = {"block", "timeout", NULL};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist,
|
||||
&blocking, &timeout_obj))
|
||||
return NULL;
|
||||
|
||||
/* calculate timeout */
|
||||
if (!blocking) {
|
||||
full_msecs = 0;
|
||||
} else if (timeout_obj == Py_None) {
|
||||
full_msecs = INFINITE;
|
||||
} else {
|
||||
timeout = PyFloat_AsDouble(timeout_obj);
|
||||
if (PyErr_Occurred())
|
||||
return NULL;
|
||||
timeout *= 1000.0; /* convert to millisecs */
|
||||
if (timeout < 0.0) {
|
||||
timeout = 0.0;
|
||||
} else if (timeout >= 0.5 * INFINITE) { /* 25 days */
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"timeout is too large");
|
||||
return NULL;
|
||||
}
|
||||
full_msecs = (DWORD)(timeout + 0.5);
|
||||
}
|
||||
|
||||
/* check whether we already own the lock */
|
||||
if (self->kind == RECURSIVE_MUTEX && ISMINE(self)) {
|
||||
++self->count;
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
|
||||
/* check whether we can acquire without blocking */
|
||||
if (WaitForSingleObject(self->handle, 0) == WAIT_OBJECT_0) {
|
||||
self->last_tid = GetCurrentThreadId();
|
||||
++self->count;
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
|
||||
msecs = full_msecs;
|
||||
start = GetTickCount();
|
||||
|
||||
for ( ; ; ) {
|
||||
HANDLE handles[2] = {self->handle, sigint_event};
|
||||
|
||||
/* do the wait */
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
ResetEvent(sigint_event);
|
||||
res = WaitForMultipleObjects(2, handles, FALSE, msecs);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
/* handle result */
|
||||
if (res != WAIT_OBJECT_0 + 1)
|
||||
break;
|
||||
|
||||
/* got SIGINT so give signal handler a chance to run */
|
||||
Sleep(1);
|
||||
|
||||
/* if this is main thread let KeyboardInterrupt be raised */
|
||||
if (PyErr_CheckSignals())
|
||||
return NULL;
|
||||
|
||||
/* recalculate timeout */
|
||||
if (msecs != INFINITE) {
|
||||
ticks = GetTickCount();
|
||||
if ((DWORD)(ticks - start) >= full_msecs)
|
||||
Py_RETURN_FALSE;
|
||||
msecs = full_msecs - (ticks - start);
|
||||
}
|
||||
}
|
||||
|
||||
/* handle result */
|
||||
switch (res) {
|
||||
case WAIT_TIMEOUT:
|
||||
Py_RETURN_FALSE;
|
||||
case WAIT_OBJECT_0:
|
||||
self->last_tid = GetCurrentThreadId();
|
||||
++self->count;
|
||||
Py_RETURN_TRUE;
|
||||
case WAIT_FAILED:
|
||||
return PyErr_SetFromWindowsErr(0);
|
||||
default:
|
||||
PyErr_Format(PyExc_RuntimeError, "WaitForSingleObject() or "
|
||||
"WaitForMultipleObjects() gave unrecognized "
|
||||
"value %d", res);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
semlock_release(SemLockObject *self, PyObject *args)
|
||||
{
|
||||
if (self->kind == RECURSIVE_MUTEX) {
|
||||
if (!ISMINE(self)) {
|
||||
PyErr_SetString(PyExc_AssertionError, "attempt to "
|
||||
"release recursive lock not owned "
|
||||
"by thread");
|
||||
return NULL;
|
||||
}
|
||||
if (self->count > 1) {
|
||||
--self->count;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
assert(self->count == 1);
|
||||
}
|
||||
|
||||
if (!ReleaseSemaphore(self->handle, 1, NULL)) {
|
||||
if (GetLastError() == ERROR_TOO_MANY_POSTS) {
|
||||
PyErr_SetString(PyExc_ValueError, "semaphore or lock "
|
||||
"released too many times");
|
||||
return NULL;
|
||||
} else {
|
||||
return PyErr_SetFromWindowsErr(0);
|
||||
}
|
||||
}
|
||||
|
||||
--self->count;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
#else /* !MS_WINDOWS */
|
||||
|
||||
/*
|
||||
* Unix definitions
|
||||
*/
|
||||
|
||||
#define SEM_CLEAR_ERROR()
|
||||
#define SEM_GET_LAST_ERROR() 0
|
||||
#define SEM_CREATE(name, val, max) sem_open(name, O_CREAT | O_EXCL, 0600, val)
|
||||
#define SEM_CLOSE(sem) sem_close(sem)
|
||||
#define SEM_GETVALUE(sem, pval) sem_getvalue(sem, pval)
|
||||
#define SEM_UNLINK(name) sem_unlink(name)
|
||||
|
||||
/* OS X 10.4 defines SEM_FAILED as -1 instead of (sem_t *)-1; this gives
|
||||
compiler warnings, and (potentially) undefined behaviour. */
|
||||
#ifdef __APPLE__
|
||||
# undef SEM_FAILED
|
||||
# define SEM_FAILED ((sem_t *)-1)
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SEM_UNLINK
|
||||
# define sem_unlink(name) 0
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SEM_TIMEDWAIT
|
||||
# define sem_timedwait(sem,deadline) sem_timedwait_save(sem,deadline,_save)
|
||||
|
||||
int
|
||||
sem_timedwait_save(sem_t *sem, struct timespec *deadline, PyThreadState *_save)
|
||||
{
|
||||
int res;
|
||||
unsigned long delay, difference;
|
||||
struct timeval now, tvdeadline, tvdelay;
|
||||
|
||||
errno = 0;
|
||||
tvdeadline.tv_sec = deadline->tv_sec;
|
||||
tvdeadline.tv_usec = deadline->tv_nsec / 1000;
|
||||
|
||||
for (delay = 0 ; ; delay += 1000) {
|
||||
/* poll */
|
||||
if (sem_trywait(sem) == 0)
|
||||
return 0;
|
||||
else if (errno != EAGAIN)
|
||||
return MP_STANDARD_ERROR;
|
||||
|
||||
/* get current time */
|
||||
if (gettimeofday(&now, NULL) < 0)
|
||||
return MP_STANDARD_ERROR;
|
||||
|
||||
/* check for timeout */
|
||||
if (tvdeadline.tv_sec < now.tv_sec ||
|
||||
(tvdeadline.tv_sec == now.tv_sec &&
|
||||
tvdeadline.tv_usec <= now.tv_usec)) {
|
||||
errno = ETIMEDOUT;
|
||||
return MP_STANDARD_ERROR;
|
||||
}
|
||||
|
||||
/* calculate how much time is left */
|
||||
difference = (tvdeadline.tv_sec - now.tv_sec) * 1000000 +
|
||||
(tvdeadline.tv_usec - now.tv_usec);
|
||||
|
||||
/* check delay not too long -- maximum is 20 msecs */
|
||||
if (delay > 20000)
|
||||
delay = 20000;
|
||||
if (delay > difference)
|
||||
delay = difference;
|
||||
|
||||
/* sleep */
|
||||
tvdelay.tv_sec = delay / 1000000;
|
||||
tvdelay.tv_usec = delay % 1000000;
|
||||
if (select(0, NULL, NULL, NULL, &tvdelay) < 0)
|
||||
return MP_STANDARD_ERROR;
|
||||
|
||||
/* check for signals */
|
||||
Py_BLOCK_THREADS
|
||||
res = PyErr_CheckSignals();
|
||||
Py_UNBLOCK_THREADS
|
||||
|
||||
if (res) {
|
||||
errno = EINTR;
|
||||
return MP_EXCEPTION_HAS_BEEN_SET;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !HAVE_SEM_TIMEDWAIT */
|
||||
|
||||
static PyObject *
|
||||
semlock_acquire(SemLockObject *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
int blocking = 1, res;
|
||||
double timeout;
|
||||
PyObject *timeout_obj = Py_None;
|
||||
struct timespec deadline = {0};
|
||||
struct timeval now;
|
||||
long sec, nsec;
|
||||
|
||||
static char *kwlist[] = {"block", "timeout", NULL};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist,
|
||||
&blocking, &timeout_obj))
|
||||
return NULL;
|
||||
|
||||
if (self->kind == RECURSIVE_MUTEX && ISMINE(self)) {
|
||||
++self->count;
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
|
||||
if (timeout_obj != Py_None) {
|
||||
timeout = PyFloat_AsDouble(timeout_obj);
|
||||
if (PyErr_Occurred())
|
||||
return NULL;
|
||||
if (timeout < 0.0)
|
||||
timeout = 0.0;
|
||||
|
||||
if (gettimeofday(&now, NULL) < 0) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
sec = (long) timeout;
|
||||
nsec = (long) (1e9 * (timeout - sec) + 0.5);
|
||||
deadline.tv_sec = now.tv_sec + sec;
|
||||
deadline.tv_nsec = now.tv_usec * 1000 + nsec;
|
||||
deadline.tv_sec += (deadline.tv_nsec / 1000000000);
|
||||
deadline.tv_nsec %= 1000000000;
|
||||
}
|
||||
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
if (blocking && timeout_obj == Py_None)
|
||||
res = sem_wait(self->handle);
|
||||
else if (!blocking)
|
||||
res = sem_trywait(self->handle);
|
||||
else
|
||||
res = sem_timedwait(self->handle, &deadline);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (res == MP_EXCEPTION_HAS_BEEN_SET)
|
||||
break;
|
||||
} while (res < 0 && errno == EINTR && !PyErr_CheckSignals());
|
||||
|
||||
if (res < 0) {
|
||||
if (errno == EAGAIN || errno == ETIMEDOUT)
|
||||
Py_RETURN_FALSE;
|
||||
else if (errno == EINTR)
|
||||
return NULL;
|
||||
else
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
}
|
||||
|
||||
++self->count;
|
||||
self->last_tid = PyThread_get_thread_ident();
|
||||
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
semlock_release(SemLockObject *self, PyObject *args)
|
||||
{
|
||||
if (self->kind == RECURSIVE_MUTEX) {
|
||||
if (!ISMINE(self)) {
|
||||
PyErr_SetString(PyExc_AssertionError, "attempt to "
|
||||
"release recursive lock not owned "
|
||||
"by thread");
|
||||
return NULL;
|
||||
}
|
||||
if (self->count > 1) {
|
||||
--self->count;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
assert(self->count == 1);
|
||||
} else {
|
||||
#ifdef HAVE_BROKEN_SEM_GETVALUE
|
||||
/* We will only check properly the maxvalue == 1 case */
|
||||
if (self->maxvalue == 1) {
|
||||
/* make sure that already locked */
|
||||
if (sem_trywait(self->handle) < 0) {
|
||||
if (errno != EAGAIN) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
/* it is already locked as expected */
|
||||
} else {
|
||||
/* it was not locked so undo wait and raise */
|
||||
if (sem_post(self->handle) < 0) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
PyErr_SetString(PyExc_ValueError, "semaphore "
|
||||
"or lock released too many "
|
||||
"times");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#else
|
||||
int sval;
|
||||
|
||||
/* This check is not an absolute guarantee that the semaphore
|
||||
does not rise above maxvalue. */
|
||||
if (sem_getvalue(self->handle, &sval) < 0) {
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
} else if (sval >= self->maxvalue) {
|
||||
PyErr_SetString(PyExc_ValueError, "semaphore or lock "
|
||||
"released too many times");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (sem_post(self->handle) < 0)
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
|
||||
--self->count;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
#endif /* !MS_WINDOWS */
|
||||
|
||||
/*
|
||||
* All platforms
|
||||
*/
|
||||
|
||||
static PyObject *
|
||||
newsemlockobject(PyTypeObject *type, SEM_HANDLE handle, int kind, int maxvalue)
|
||||
{
|
||||
SemLockObject *self;
|
||||
|
||||
self = PyObject_New(SemLockObject, type);
|
||||
if (!self)
|
||||
return NULL;
|
||||
self->handle = handle;
|
||||
self->kind = kind;
|
||||
self->count = 0;
|
||||
self->last_tid = 0;
|
||||
self->maxvalue = maxvalue;
|
||||
return (PyObject*)self;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
semlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
char buffer[256];
|
||||
SEM_HANDLE handle = SEM_FAILED;
|
||||
int kind, maxvalue, value;
|
||||
PyObject *result;
|
||||
static char *kwlist[] = {"kind", "value", "maxvalue", NULL};
|
||||
int try = 0;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "iii", kwlist,
|
||||
&kind, &value, &maxvalue))
|
||||
return NULL;
|
||||
|
||||
if (kind != RECURSIVE_MUTEX && kind != SEMAPHORE) {
|
||||
PyErr_SetString(PyExc_ValueError, "unrecognized kind");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create a semaphore with a unique name. The bytes returned by
|
||||
* _PyOS_URandom() are treated as unsigned long to ensure that the filename
|
||||
* is valid (no special characters). */
|
||||
do {
|
||||
unsigned long suffix;
|
||||
_PyOS_URandom((char *)&suffix, sizeof(suffix));
|
||||
PyOS_snprintf(buffer, sizeof(buffer), "/mp%ld-%lu", (long)getpid(),
|
||||
suffix);
|
||||
SEM_CLEAR_ERROR();
|
||||
handle = SEM_CREATE(buffer, value, maxvalue);
|
||||
} while ((handle == SEM_FAILED) && (errno == EEXIST) && (++try < 100));
|
||||
|
||||
/* On Windows we should fail if GetLastError()==ERROR_ALREADY_EXISTS */
|
||||
if (handle == SEM_FAILED || SEM_GET_LAST_ERROR() != 0)
|
||||
goto failure;
|
||||
|
||||
if (SEM_UNLINK(buffer) < 0)
|
||||
goto failure;
|
||||
|
||||
result = newsemlockobject(type, handle, kind, maxvalue);
|
||||
if (!result)
|
||||
goto failure;
|
||||
|
||||
return result;
|
||||
|
||||
failure:
|
||||
if (handle != SEM_FAILED)
|
||||
SEM_CLOSE(handle);
|
||||
mp_SetError(NULL, MP_STANDARD_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
semlock_rebuild(PyTypeObject *type, PyObject *args)
|
||||
{
|
||||
SEM_HANDLE handle;
|
||||
int kind, maxvalue;
|
||||
|
||||
if (!PyArg_ParseTuple(args, F_SEM_HANDLE "ii",
|
||||
&handle, &kind, &maxvalue))
|
||||
return NULL;
|
||||
|
||||
return newsemlockobject(type, handle, kind, maxvalue);
|
||||
}
|
||||
|
||||
static void
|
||||
semlock_dealloc(SemLockObject* self)
|
||||
{
|
||||
if (self->handle != SEM_FAILED)
|
||||
SEM_CLOSE(self->handle);
|
||||
PyObject_Del(self);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
semlock_count(SemLockObject *self)
|
||||
{
|
||||
return PyInt_FromLong((long)self->count);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
semlock_ismine(SemLockObject *self)
|
||||
{
|
||||
/* only makes sense for a lock */
|
||||
return PyBool_FromLong(ISMINE(self));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
semlock_getvalue(SemLockObject *self)
|
||||
{
|
||||
#ifdef HAVE_BROKEN_SEM_GETVALUE
|
||||
PyErr_SetNone(PyExc_NotImplementedError);
|
||||
return NULL;
|
||||
#else
|
||||
int sval;
|
||||
if (SEM_GETVALUE(self->handle, &sval) < 0)
|
||||
return mp_SetError(NULL, MP_STANDARD_ERROR);
|
||||
/* some posix implementations use negative numbers to indicate
|
||||
the number of waiting threads */
|
||||
if (sval < 0)
|
||||
sval = 0;
|
||||
return PyInt_FromLong((long)sval);
|
||||
#endif
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
semlock_iszero(SemLockObject *self)
|
||||
{
|
||||
#ifdef HAVE_BROKEN_SEM_GETVALUE
|
||||
if (sem_trywait(self->handle) < 0) {
|
||||
if (errno == EAGAIN)
|
||||
Py_RETURN_TRUE;
|
||||
return mp_SetError(NULL, MP_STANDARD_ERROR);
|
||||
} else {
|
||||
if (sem_post(self->handle) < 0)
|
||||
return mp_SetError(NULL, MP_STANDARD_ERROR);
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
#else
|
||||
int sval;
|
||||
if (SEM_GETVALUE(self->handle, &sval) < 0)
|
||||
return mp_SetError(NULL, MP_STANDARD_ERROR);
|
||||
return PyBool_FromLong((long)sval == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
semlock_afterfork(SemLockObject *self)
|
||||
{
|
||||
self->count = 0;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Semaphore methods
|
||||
*/
|
||||
|
||||
static PyMethodDef semlock_methods[] = {
|
||||
{"acquire", (PyCFunction)semlock_acquire, METH_VARARGS | METH_KEYWORDS,
|
||||
"acquire the semaphore/lock"},
|
||||
{"release", (PyCFunction)semlock_release, METH_NOARGS,
|
||||
"release the semaphore/lock"},
|
||||
{"__enter__", (PyCFunction)semlock_acquire, METH_VARARGS | METH_KEYWORDS,
|
||||
"enter the semaphore/lock"},
|
||||
{"__exit__", (PyCFunction)semlock_release, METH_VARARGS,
|
||||
"exit the semaphore/lock"},
|
||||
{"_count", (PyCFunction)semlock_count, METH_NOARGS,
|
||||
"num of `acquire()`s minus num of `release()`s for this process"},
|
||||
{"_is_mine", (PyCFunction)semlock_ismine, METH_NOARGS,
|
||||
"whether the lock is owned by this thread"},
|
||||
{"_get_value", (PyCFunction)semlock_getvalue, METH_NOARGS,
|
||||
"get the value of the semaphore"},
|
||||
{"_is_zero", (PyCFunction)semlock_iszero, METH_NOARGS,
|
||||
"returns whether semaphore has value zero"},
|
||||
{"_rebuild", (PyCFunction)semlock_rebuild, METH_VARARGS | METH_CLASS,
|
||||
""},
|
||||
{"_after_fork", (PyCFunction)semlock_afterfork, METH_NOARGS,
|
||||
"rezero the net acquisition count after fork()"},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
/*
|
||||
* Member table
|
||||
*/
|
||||
|
||||
static PyMemberDef semlock_members[] = {
|
||||
{"handle", T_SEM_HANDLE, offsetof(SemLockObject, handle), READONLY,
|
||||
""},
|
||||
{"kind", T_INT, offsetof(SemLockObject, kind), READONLY,
|
||||
""},
|
||||
{"maxvalue", T_INT, offsetof(SemLockObject, maxvalue), READONLY,
|
||||
""},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
/*
|
||||
* Semaphore type
|
||||
*/
|
||||
|
||||
PyTypeObject SemLockType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
/* tp_name */ "_multiprocessing.SemLock",
|
||||
/* tp_basicsize */ sizeof(SemLockObject),
|
||||
/* tp_itemsize */ 0,
|
||||
/* tp_dealloc */ (destructor)semlock_dealloc,
|
||||
/* tp_print */ 0,
|
||||
/* tp_getattr */ 0,
|
||||
/* tp_setattr */ 0,
|
||||
/* tp_compare */ 0,
|
||||
/* tp_repr */ 0,
|
||||
/* tp_as_number */ 0,
|
||||
/* tp_as_sequence */ 0,
|
||||
/* tp_as_mapping */ 0,
|
||||
/* tp_hash */ 0,
|
||||
/* tp_call */ 0,
|
||||
/* tp_str */ 0,
|
||||
/* tp_getattro */ 0,
|
||||
/* tp_setattro */ 0,
|
||||
/* tp_as_buffer */ 0,
|
||||
/* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
/* tp_doc */ "Semaphore/Mutex type",
|
||||
/* tp_traverse */ 0,
|
||||
/* tp_clear */ 0,
|
||||
/* tp_richcompare */ 0,
|
||||
/* tp_weaklistoffset */ 0,
|
||||
/* tp_iter */ 0,
|
||||
/* tp_iternext */ 0,
|
||||
/* tp_methods */ semlock_methods,
|
||||
/* tp_members */ semlock_members,
|
||||
/* tp_getset */ 0,
|
||||
/* tp_base */ 0,
|
||||
/* tp_dict */ 0,
|
||||
/* tp_descr_get */ 0,
|
||||
/* tp_descr_set */ 0,
|
||||
/* tp_dictoffset */ 0,
|
||||
/* tp_init */ 0,
|
||||
/* tp_alloc */ 0,
|
||||
/* tp_new */ semlock_new,
|
||||
};
|
||||
+277
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
* A type which wraps a socket
|
||||
*
|
||||
* socket_connection.c
|
||||
*
|
||||
* Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
|
||||
*/
|
||||
|
||||
#include "multiprocessing.h"
|
||||
|
||||
#if defined(HAVE_POLL) && !defined(HAVE_BROKEN_POLL)
|
||||
# include "poll.h"
|
||||
#endif
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
# define WRITE(h, buffer, length) send((SOCKET)h, buffer, length, 0)
|
||||
# define READ(h, buffer, length) recv((SOCKET)h, buffer, length, 0)
|
||||
# define CLOSE(h) closesocket((SOCKET)h)
|
||||
#else
|
||||
# define WRITE(h, buffer, length) write(h, buffer, length)
|
||||
# define READ(h, buffer, length) read(h, buffer, length)
|
||||
# define CLOSE(h) close(h)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Wrapper for PyErr_CheckSignals() which can be called without the GIL
|
||||
*/
|
||||
|
||||
static int
|
||||
check_signals(void)
|
||||
{
|
||||
PyGILState_STATE state;
|
||||
int res;
|
||||
state = PyGILState_Ensure();
|
||||
res = PyErr_CheckSignals();
|
||||
PyGILState_Release(state);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send string to file descriptor
|
||||
*/
|
||||
|
||||
static Py_ssize_t
|
||||
_conn_sendall(HANDLE h, char *string, size_t length)
|
||||
{
|
||||
char *p = string;
|
||||
Py_ssize_t res;
|
||||
|
||||
while (length > 0) {
|
||||
res = WRITE(h, p, length);
|
||||
if (res < 0) {
|
||||
if (errno == EINTR) {
|
||||
if (check_signals() < 0)
|
||||
return MP_EXCEPTION_HAS_BEEN_SET;
|
||||
continue;
|
||||
}
|
||||
return MP_SOCKET_ERROR;
|
||||
}
|
||||
length -= res;
|
||||
p += res;
|
||||
}
|
||||
|
||||
return MP_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive string of exact length from file descriptor
|
||||
*/
|
||||
|
||||
static Py_ssize_t
|
||||
_conn_recvall(HANDLE h, char *buffer, size_t length)
|
||||
{
|
||||
size_t remaining = length;
|
||||
Py_ssize_t temp;
|
||||
char *p = buffer;
|
||||
|
||||
while (remaining > 0) {
|
||||
temp = READ(h, p, remaining);
|
||||
if (temp < 0) {
|
||||
if (errno == EINTR) {
|
||||
if (check_signals() < 0)
|
||||
return MP_EXCEPTION_HAS_BEEN_SET;
|
||||
continue;
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
else if (temp == 0) {
|
||||
return remaining == length ? MP_END_OF_FILE : MP_EARLY_END_OF_FILE;
|
||||
}
|
||||
remaining -= temp;
|
||||
p += temp;
|
||||
}
|
||||
|
||||
return MP_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a string prepended by the string length in network byte order
|
||||
*/
|
||||
|
||||
static Py_ssize_t
|
||||
conn_send_string(ConnectionObject *conn, char *string, size_t length)
|
||||
{
|
||||
Py_ssize_t res;
|
||||
/* The "header" of the message is a 32 bit unsigned number (in
|
||||
network order) which specifies the length of the "body". If
|
||||
the message is shorter than about 16kb then it is quicker to
|
||||
combine the "header" and the "body" of the message and send
|
||||
them at once. */
|
||||
if (length < (16*1024)) {
|
||||
char *message;
|
||||
|
||||
message = PyMem_Malloc(length+4);
|
||||
if (message == NULL)
|
||||
return MP_MEMORY_ERROR;
|
||||
|
||||
*(UINT32*)message = htonl((UINT32)length);
|
||||
memcpy(message+4, string, length);
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = _conn_sendall(conn->handle, message, length+4);
|
||||
Py_END_ALLOW_THREADS
|
||||
PyMem_Free(message);
|
||||
} else {
|
||||
UINT32 lenbuff;
|
||||
|
||||
if (length > MAX_MESSAGE_LENGTH)
|
||||
return MP_BAD_MESSAGE_LENGTH;
|
||||
|
||||
lenbuff = htonl((UINT32)length);
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = _conn_sendall(conn->handle, (char*)&lenbuff, 4) ||
|
||||
_conn_sendall(conn->handle, string, length);
|
||||
Py_END_ALLOW_THREADS
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempts to read into buffer, or failing that into *newbuffer
|
||||
*
|
||||
* Returns number of bytes read.
|
||||
*/
|
||||
|
||||
static Py_ssize_t
|
||||
conn_recv_string(ConnectionObject *conn, char *buffer,
|
||||
size_t buflength, char **newbuffer, size_t maxlength)
|
||||
{
|
||||
Py_ssize_t res;
|
||||
UINT32 ulength;
|
||||
|
||||
*newbuffer = NULL;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = _conn_recvall(conn->handle, (char*)&ulength, 4);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
ulength = ntohl(ulength);
|
||||
if (ulength > maxlength)
|
||||
return MP_BAD_MESSAGE_LENGTH;
|
||||
|
||||
if (ulength > buflength) {
|
||||
*newbuffer = buffer = PyMem_Malloc((size_t)ulength);
|
||||
if (buffer == NULL)
|
||||
return MP_MEMORY_ERROR;
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = _conn_recvall(conn->handle, buffer, (size_t)ulength);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (res >= 0) {
|
||||
res = (Py_ssize_t)ulength;
|
||||
} else if (*newbuffer != NULL) {
|
||||
PyMem_Free(*newbuffer);
|
||||
*newbuffer = NULL;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether any data is available for reading -- neg timeout blocks
|
||||
*/
|
||||
|
||||
static int
|
||||
conn_poll(ConnectionObject *conn, double timeout, PyThreadState *_save)
|
||||
{
|
||||
#if defined(HAVE_POLL) && !defined(HAVE_BROKEN_POLL)
|
||||
int res;
|
||||
struct pollfd p;
|
||||
|
||||
p.fd = (int)conn->handle;
|
||||
p.events = POLLIN | POLLPRI;
|
||||
p.revents = 0;
|
||||
|
||||
if (timeout < 0) {
|
||||
do {
|
||||
res = poll(&p, 1, -1);
|
||||
} while (res < 0 && errno == EINTR);
|
||||
} else {
|
||||
res = poll(&p, 1, (int)(timeout * 1000 + 0.5));
|
||||
if (res < 0 && errno == EINTR) {
|
||||
/* We were interrupted by a signal. Just indicate a
|
||||
timeout even though we are early. */
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (res < 0) {
|
||||
return MP_SOCKET_ERROR;
|
||||
} else if (p.revents & (POLLNVAL|POLLERR)) {
|
||||
Py_BLOCK_THREADS
|
||||
PyErr_SetString(PyExc_IOError, "poll() gave POLLNVAL or POLLERR");
|
||||
Py_UNBLOCK_THREADS
|
||||
return MP_EXCEPTION_HAS_BEEN_SET;
|
||||
} else if (p.revents != 0) {
|
||||
return TRUE;
|
||||
} else {
|
||||
assert(res == 0);
|
||||
return FALSE;
|
||||
}
|
||||
#else
|
||||
int res;
|
||||
fd_set rfds;
|
||||
|
||||
/*
|
||||
* Verify the handle, issue 3321. Not required for windows.
|
||||
*/
|
||||
#ifndef MS_WINDOWS
|
||||
if (((int)conn->handle) < 0 || ((int)conn->handle) >= FD_SETSIZE) {
|
||||
Py_BLOCK_THREADS
|
||||
PyErr_SetString(PyExc_IOError, "handle out of range in select()");
|
||||
Py_UNBLOCK_THREADS
|
||||
return MP_EXCEPTION_HAS_BEEN_SET;
|
||||
}
|
||||
#endif
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET((SOCKET)conn->handle, &rfds);
|
||||
|
||||
if (timeout < 0.0) {
|
||||
do {
|
||||
res = select((int)conn->handle+1, &rfds, NULL, NULL, NULL);
|
||||
} while (res < 0 && errno == EINTR);
|
||||
} else {
|
||||
struct timeval tv;
|
||||
tv.tv_sec = (long)timeout;
|
||||
tv.tv_usec = (long)((timeout - tv.tv_sec) * 1e6 + 0.5);
|
||||
res = select((int)conn->handle+1, &rfds, NULL, NULL, &tv);
|
||||
if (res < 0 && errno == EINTR) {
|
||||
/* We were interrupted by a signal. Just indicate a
|
||||
timeout even though we are early. */
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (res < 0) {
|
||||
return MP_SOCKET_ERROR;
|
||||
} else if (FD_ISSET(conn->handle, &rfds)) {
|
||||
return TRUE;
|
||||
} else {
|
||||
assert(res == 0);
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* "connection.h" defines the Connection type using defs above
|
||||
*/
|
||||
|
||||
#define CONNECTION_NAME "Connection"
|
||||
#define CONNECTION_TYPE ConnectionType
|
||||
|
||||
#include "connection.h"
|
||||
+267
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Win32 functions used by multiprocessing package
|
||||
*
|
||||
* win32_functions.c
|
||||
*
|
||||
* Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
|
||||
*/
|
||||
|
||||
#include "multiprocessing.h"
|
||||
|
||||
|
||||
#define WIN32_FUNCTION(func) \
|
||||
{#func, (PyCFunction)win32_ ## func, METH_VARARGS | METH_STATIC, ""}
|
||||
|
||||
#define WIN32_CONSTANT(fmt, con) \
|
||||
PyDict_SetItemString(Win32Type.tp_dict, #con, Py_BuildValue(fmt, con))
|
||||
|
||||
|
||||
static PyObject *
|
||||
win32_CloseHandle(PyObject *self, PyObject *args)
|
||||
{
|
||||
HANDLE hObject;
|
||||
BOOL success;
|
||||
|
||||
if (!PyArg_ParseTuple(args, F_HANDLE, &hObject))
|
||||
return NULL;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
success = CloseHandle(hObject);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (!success)
|
||||
return PyErr_SetFromWindowsErr(0);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
win32_ConnectNamedPipe(PyObject *self, PyObject *args)
|
||||
{
|
||||
HANDLE hNamedPipe;
|
||||
LPOVERLAPPED lpOverlapped;
|
||||
BOOL success;
|
||||
|
||||
if (!PyArg_ParseTuple(args, F_HANDLE F_POINTER,
|
||||
&hNamedPipe, &lpOverlapped))
|
||||
return NULL;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
success = ConnectNamedPipe(hNamedPipe, lpOverlapped);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (!success)
|
||||
return PyErr_SetFromWindowsErr(0);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
win32_CreateFile(PyObject *self, PyObject *args)
|
||||
{
|
||||
LPCTSTR lpFileName;
|
||||
DWORD dwDesiredAccess;
|
||||
DWORD dwShareMode;
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes;
|
||||
DWORD dwCreationDisposition;
|
||||
DWORD dwFlagsAndAttributes;
|
||||
HANDLE hTemplateFile;
|
||||
HANDLE handle;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s" F_DWORD F_DWORD F_POINTER
|
||||
F_DWORD F_DWORD F_HANDLE,
|
||||
&lpFileName, &dwDesiredAccess, &dwShareMode,
|
||||
&lpSecurityAttributes, &dwCreationDisposition,
|
||||
&dwFlagsAndAttributes, &hTemplateFile))
|
||||
return NULL;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
handle = CreateFile(lpFileName, dwDesiredAccess,
|
||||
dwShareMode, lpSecurityAttributes,
|
||||
dwCreationDisposition,
|
||||
dwFlagsAndAttributes, hTemplateFile);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return PyErr_SetFromWindowsErr(0);
|
||||
|
||||
return Py_BuildValue(F_HANDLE, handle);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
win32_CreateNamedPipe(PyObject *self, PyObject *args)
|
||||
{
|
||||
LPCTSTR lpName;
|
||||
DWORD dwOpenMode;
|
||||
DWORD dwPipeMode;
|
||||
DWORD nMaxInstances;
|
||||
DWORD nOutBufferSize;
|
||||
DWORD nInBufferSize;
|
||||
DWORD nDefaultTimeOut;
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes;
|
||||
HANDLE handle;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s" F_DWORD F_DWORD F_DWORD
|
||||
F_DWORD F_DWORD F_DWORD F_POINTER,
|
||||
&lpName, &dwOpenMode, &dwPipeMode,
|
||||
&nMaxInstances, &nOutBufferSize,
|
||||
&nInBufferSize, &nDefaultTimeOut,
|
||||
&lpSecurityAttributes))
|
||||
return NULL;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
handle = CreateNamedPipe(lpName, dwOpenMode, dwPipeMode,
|
||||
nMaxInstances, nOutBufferSize,
|
||||
nInBufferSize, nDefaultTimeOut,
|
||||
lpSecurityAttributes);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return PyErr_SetFromWindowsErr(0);
|
||||
|
||||
return Py_BuildValue(F_HANDLE, handle);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
win32_ExitProcess(PyObject *self, PyObject *args)
|
||||
{
|
||||
UINT uExitCode;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "I", &uExitCode))
|
||||
return NULL;
|
||||
|
||||
#if defined(Py_DEBUG)
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOALIGNMENTFAULTEXCEPT|SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX);
|
||||
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
|
||||
#endif
|
||||
|
||||
|
||||
ExitProcess(uExitCode);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
win32_GetLastError(PyObject *self, PyObject *args)
|
||||
{
|
||||
return Py_BuildValue(F_DWORD, GetLastError());
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
win32_OpenProcess(PyObject *self, PyObject *args)
|
||||
{
|
||||
DWORD dwDesiredAccess;
|
||||
BOOL bInheritHandle;
|
||||
DWORD dwProcessId;
|
||||
HANDLE handle;
|
||||
|
||||
if (!PyArg_ParseTuple(args, F_DWORD "i" F_DWORD,
|
||||
&dwDesiredAccess, &bInheritHandle, &dwProcessId))
|
||||
return NULL;
|
||||
|
||||
handle = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
|
||||
if (handle == NULL)
|
||||
return PyErr_SetFromWindowsErr(0);
|
||||
|
||||
return Py_BuildValue(F_HANDLE, handle);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
win32_SetNamedPipeHandleState(PyObject *self, PyObject *args)
|
||||
{
|
||||
HANDLE hNamedPipe;
|
||||
PyObject *oArgs[3];
|
||||
DWORD dwArgs[3], *pArgs[3] = {NULL, NULL, NULL};
|
||||
int i;
|
||||
|
||||
if (!PyArg_ParseTuple(args, F_HANDLE "OOO",
|
||||
&hNamedPipe, &oArgs[0], &oArgs[1], &oArgs[2]))
|
||||
return NULL;
|
||||
|
||||
PyErr_Clear();
|
||||
|
||||
for (i = 0 ; i < 3 ; i++) {
|
||||
if (oArgs[i] != Py_None) {
|
||||
dwArgs[i] = PyInt_AsUnsignedLongMask(oArgs[i]);
|
||||
if (PyErr_Occurred())
|
||||
return NULL;
|
||||
pArgs[i] = &dwArgs[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (!SetNamedPipeHandleState(hNamedPipe, pArgs[0], pArgs[1], pArgs[2]))
|
||||
return PyErr_SetFromWindowsErr(0);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
win32_WaitNamedPipe(PyObject *self, PyObject *args)
|
||||
{
|
||||
LPCTSTR lpNamedPipeName;
|
||||
DWORD nTimeOut;
|
||||
BOOL success;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s" F_DWORD, &lpNamedPipeName, &nTimeOut))
|
||||
return NULL;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
success = WaitNamedPipe(lpNamedPipeName, nTimeOut);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (!success)
|
||||
return PyErr_SetFromWindowsErr(0);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyMethodDef win32_methods[] = {
|
||||
WIN32_FUNCTION(CloseHandle),
|
||||
WIN32_FUNCTION(GetLastError),
|
||||
WIN32_FUNCTION(OpenProcess),
|
||||
WIN32_FUNCTION(ExitProcess),
|
||||
WIN32_FUNCTION(ConnectNamedPipe),
|
||||
WIN32_FUNCTION(CreateFile),
|
||||
WIN32_FUNCTION(CreateNamedPipe),
|
||||
WIN32_FUNCTION(SetNamedPipeHandleState),
|
||||
WIN32_FUNCTION(WaitNamedPipe),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
||||
PyTypeObject Win32Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
};
|
||||
|
||||
|
||||
PyObject *
|
||||
create_win32_namespace(void)
|
||||
{
|
||||
Win32Type.tp_name = "_multiprocessing.win32";
|
||||
Win32Type.tp_methods = win32_methods;
|
||||
if (PyType_Ready(&Win32Type) < 0)
|
||||
return NULL;
|
||||
Py_INCREF(&Win32Type);
|
||||
|
||||
WIN32_CONSTANT(F_DWORD, ERROR_ALREADY_EXISTS);
|
||||
WIN32_CONSTANT(F_DWORD, ERROR_NO_DATA);
|
||||
WIN32_CONSTANT(F_DWORD, ERROR_PIPE_BUSY);
|
||||
WIN32_CONSTANT(F_DWORD, ERROR_PIPE_CONNECTED);
|
||||
WIN32_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT);
|
||||
WIN32_CONSTANT(F_DWORD, GENERIC_READ);
|
||||
WIN32_CONSTANT(F_DWORD, GENERIC_WRITE);
|
||||
WIN32_CONSTANT(F_DWORD, INFINITE);
|
||||
WIN32_CONSTANT(F_DWORD, NMPWAIT_WAIT_FOREVER);
|
||||
WIN32_CONSTANT(F_DWORD, OPEN_EXISTING);
|
||||
WIN32_CONSTANT(F_DWORD, PIPE_ACCESS_DUPLEX);
|
||||
WIN32_CONSTANT(F_DWORD, PIPE_ACCESS_INBOUND);
|
||||
WIN32_CONSTANT(F_DWORD, PIPE_READMODE_MESSAGE);
|
||||
WIN32_CONSTANT(F_DWORD, PIPE_TYPE_MESSAGE);
|
||||
WIN32_CONSTANT(F_DWORD, PIPE_UNLIMITED_INSTANCES);
|
||||
WIN32_CONSTANT(F_DWORD, PIPE_WAIT);
|
||||
WIN32_CONSTANT(F_DWORD, PROCESS_ALL_ACCESS);
|
||||
|
||||
WIN32_CONSTANT("i", NULL);
|
||||
|
||||
return (PyObject*)&Win32Type;
|
||||
}
|
||||
@@ -0,0 +1,608 @@
|
||||
/* Random objects */
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
The code in this module was based on a download from:
|
||||
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html
|
||||
|
||||
It was modified in 2002 by Raymond Hettinger as follows:
|
||||
|
||||
* the principal computational lines untouched.
|
||||
|
||||
* renamed genrand_res53() to random_random() and wrapped
|
||||
in python calling/return code.
|
||||
|
||||
* genrand_int32() and the helper functions, init_genrand()
|
||||
and init_by_array(), were declared static, wrapped in
|
||||
Python calling/return code. also, their global data
|
||||
references were replaced with structure references.
|
||||
|
||||
* unused functions from the original were deleted.
|
||||
new, original C python code was added to implement the
|
||||
Random() interface.
|
||||
|
||||
The following are the verbatim comments from the original code:
|
||||
|
||||
A C-program for MT19937, with initialization improved 2002/1/26.
|
||||
Coded by Takuji Nishimura and Makoto Matsumoto.
|
||||
|
||||
Before using, initialize the state by using init_genrand(seed)
|
||||
or init_by_array(init_key, key_length).
|
||||
|
||||
Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. 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.
|
||||
|
||||
3. The names of its contributors may not 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 COPYRIGHT OWNER 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.
|
||||
|
||||
|
||||
Any feedback is very welcome.
|
||||
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
|
||||
email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
|
||||
*/
|
||||
|
||||
/* ---------------------------------------------------------------*/
|
||||
|
||||
#include "Python.h"
|
||||
#include <time.h> /* for seeding to current time */
|
||||
|
||||
/* Period parameters -- These are all magic. Don't change. */
|
||||
#define N 624
|
||||
#define M 397
|
||||
#define MATRIX_A 0x9908b0dfUL /* constant vector a */
|
||||
#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
|
||||
#define LOWER_MASK 0x7fffffffUL /* least significant r bits */
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
unsigned long state[N];
|
||||
int index;
|
||||
} RandomObject;
|
||||
|
||||
static PyTypeObject Random_Type;
|
||||
|
||||
#define RandomObject_Check(v) (Py_TYPE(v) == &Random_Type)
|
||||
|
||||
|
||||
/* Random methods */
|
||||
|
||||
|
||||
/* generates a random number on [0,0xffffffff]-interval */
|
||||
static unsigned long
|
||||
genrand_int32(RandomObject *self)
|
||||
{
|
||||
unsigned long y;
|
||||
static unsigned long mag01[2]={0x0UL, MATRIX_A};
|
||||
/* mag01[x] = x * MATRIX_A for x=0,1 */
|
||||
unsigned long *mt;
|
||||
|
||||
mt = self->state;
|
||||
if (self->index >= N) { /* generate N words at one time */
|
||||
int kk;
|
||||
|
||||
for (kk=0;kk<N-M;kk++) {
|
||||
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
|
||||
mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
}
|
||||
for (;kk<N-1;kk++) {
|
||||
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
|
||||
mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
}
|
||||
y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
|
||||
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
|
||||
self->index = 0;
|
||||
}
|
||||
|
||||
y = mt[self->index++];
|
||||
y ^= (y >> 11);
|
||||
y ^= (y << 7) & 0x9d2c5680UL;
|
||||
y ^= (y << 15) & 0xefc60000UL;
|
||||
y ^= (y >> 18);
|
||||
return y;
|
||||
}
|
||||
|
||||
/* random_random is the function named genrand_res53 in the original code;
|
||||
* generates a random number on [0,1) with 53-bit resolution; note that
|
||||
* 9007199254740992 == 2**53; I assume they're spelling "/2**53" as
|
||||
* multiply-by-reciprocal in the (likely vain) hope that the compiler will
|
||||
* optimize the division away at compile-time. 67108864 is 2**26. In
|
||||
* effect, a contains 27 random bits shifted left 26, and b fills in the
|
||||
* lower 26 bits of the 53-bit numerator.
|
||||
* The orginal code credited Isaku Wada for this algorithm, 2002/01/09.
|
||||
*/
|
||||
static PyObject *
|
||||
random_random(RandomObject *self)
|
||||
{
|
||||
unsigned long a=genrand_int32(self)>>5, b=genrand_int32(self)>>6;
|
||||
return PyFloat_FromDouble((a*67108864.0+b)*(1.0/9007199254740992.0));
|
||||
}
|
||||
|
||||
/* initializes mt[N] with a seed */
|
||||
static void
|
||||
init_genrand(RandomObject *self, unsigned long s)
|
||||
{
|
||||
int mti;
|
||||
unsigned long *mt;
|
||||
|
||||
mt = self->state;
|
||||
mt[0]= s & 0xffffffffUL;
|
||||
for (mti=1; mti<N; mti++) {
|
||||
mt[mti] =
|
||||
(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
|
||||
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
|
||||
/* In the previous versions, MSBs of the seed affect */
|
||||
/* only MSBs of the array mt[]. */
|
||||
/* 2002/01/09 modified by Makoto Matsumoto */
|
||||
mt[mti] &= 0xffffffffUL;
|
||||
/* for >32 bit machines */
|
||||
}
|
||||
self->index = mti;
|
||||
return;
|
||||
}
|
||||
|
||||
/* initialize by an array with array-length */
|
||||
/* init_key is the array for initializing keys */
|
||||
/* key_length is its length */
|
||||
static PyObject *
|
||||
init_by_array(RandomObject *self, unsigned long init_key[], unsigned long key_length)
|
||||
{
|
||||
unsigned int i, j, k; /* was signed in the original code. RDH 12/16/2002 */
|
||||
unsigned long *mt;
|
||||
|
||||
mt = self->state;
|
||||
init_genrand(self, 19650218UL);
|
||||
i=1; j=0;
|
||||
k = (N>key_length ? N : key_length);
|
||||
for (; k; k--) {
|
||||
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))
|
||||
+ init_key[j] + j; /* non linear */
|
||||
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
|
||||
i++; j++;
|
||||
if (i>=N) { mt[0] = mt[N-1]; i=1; }
|
||||
if (j>=key_length) j=0;
|
||||
}
|
||||
for (k=N-1; k; k--) {
|
||||
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))
|
||||
- i; /* non linear */
|
||||
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
|
||||
i++;
|
||||
if (i>=N) { mt[0] = mt[N-1]; i=1; }
|
||||
}
|
||||
|
||||
mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
/*
|
||||
* The rest is Python-specific code, neither part of, nor derived from, the
|
||||
* Twister download.
|
||||
*/
|
||||
|
||||
static PyObject *
|
||||
random_seed(RandomObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *result = NULL; /* guilty until proved innocent */
|
||||
PyObject *masklower = NULL;
|
||||
PyObject *thirtytwo = NULL;
|
||||
PyObject *n = NULL;
|
||||
unsigned long *key = NULL;
|
||||
unsigned long keymax; /* # of allocated slots in key */
|
||||
unsigned long keyused; /* # of used slots in key */
|
||||
int err;
|
||||
|
||||
PyObject *arg = NULL;
|
||||
|
||||
if (!PyArg_UnpackTuple(args, "seed", 0, 1, &arg))
|
||||
return NULL;
|
||||
|
||||
if (arg == NULL || arg == Py_None) {
|
||||
time_t now;
|
||||
|
||||
time(&now);
|
||||
init_genrand(self, (unsigned long)now);
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
/* If the arg is an int or long, use its absolute value; else use
|
||||
* the absolute value of its hash code.
|
||||
* Calling int.__abs__() or long.__abs__() prevents calling arg.__abs__(),
|
||||
* which might return an invalid value. See issue #31478.
|
||||
*/
|
||||
if (PyInt_Check(arg)) {
|
||||
n = PyInt_Type.tp_as_number->nb_absolute(arg);
|
||||
}
|
||||
else if (PyLong_Check(arg)) {
|
||||
n = PyLong_Type.tp_as_number->nb_absolute(arg);
|
||||
}
|
||||
else {
|
||||
long hash = PyObject_Hash(arg);
|
||||
if (hash == -1)
|
||||
goto Done;
|
||||
n = PyLong_FromUnsignedLong((unsigned long)hash);
|
||||
}
|
||||
if (n == NULL)
|
||||
goto Done;
|
||||
|
||||
/* Now split n into 32-bit chunks, from the right. Each piece is
|
||||
* stored into key, which has a capacity of keymax chunks, of which
|
||||
* keyused are filled. Alas, the repeated shifting makes this a
|
||||
* quadratic-time algorithm; we'd really like to use
|
||||
* _PyLong_AsByteArray here, but then we'd have to break into the
|
||||
* long representation to figure out how big an array was needed
|
||||
* in advance.
|
||||
*/
|
||||
keymax = 8; /* arbitrary; grows later if needed */
|
||||
keyused = 0;
|
||||
key = (unsigned long *)PyMem_Malloc(keymax * sizeof(*key));
|
||||
if (key == NULL)
|
||||
goto Done;
|
||||
|
||||
masklower = PyLong_FromUnsignedLong(0xffffffffU);
|
||||
if (masklower == NULL)
|
||||
goto Done;
|
||||
thirtytwo = PyInt_FromLong(32L);
|
||||
if (thirtytwo == NULL)
|
||||
goto Done;
|
||||
while ((err=PyObject_IsTrue(n))) {
|
||||
PyObject *newn;
|
||||
PyObject *pychunk;
|
||||
unsigned long chunk;
|
||||
|
||||
if (err == -1)
|
||||
goto Done;
|
||||
pychunk = PyNumber_And(n, masklower);
|
||||
if (pychunk == NULL)
|
||||
goto Done;
|
||||
chunk = PyLong_AsUnsignedLong(pychunk);
|
||||
Py_DECREF(pychunk);
|
||||
if (chunk == (unsigned long)-1 && PyErr_Occurred())
|
||||
goto Done;
|
||||
newn = PyNumber_Rshift(n, thirtytwo);
|
||||
if (newn == NULL)
|
||||
goto Done;
|
||||
Py_DECREF(n);
|
||||
n = newn;
|
||||
if (keyused >= keymax) {
|
||||
unsigned long bigger = keymax << 1;
|
||||
if ((bigger >> 1) != keymax) {
|
||||
PyErr_NoMemory();
|
||||
goto Done;
|
||||
}
|
||||
key = (unsigned long *)PyMem_Realloc(key,
|
||||
bigger * sizeof(*key));
|
||||
if (key == NULL)
|
||||
goto Done;
|
||||
keymax = bigger;
|
||||
}
|
||||
assert(keyused < keymax);
|
||||
key[keyused++] = chunk;
|
||||
}
|
||||
|
||||
if (keyused == 0)
|
||||
key[keyused++] = 0UL;
|
||||
result = init_by_array(self, key, keyused);
|
||||
Done:
|
||||
Py_XDECREF(masklower);
|
||||
Py_XDECREF(thirtytwo);
|
||||
Py_XDECREF(n);
|
||||
PyMem_Free(key);
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
random_getstate(RandomObject *self)
|
||||
{
|
||||
PyObject *state;
|
||||
PyObject *element;
|
||||
int i;
|
||||
|
||||
state = PyTuple_New(N+1);
|
||||
if (state == NULL)
|
||||
return NULL;
|
||||
for (i=0; i<N ; i++) {
|
||||
element = PyLong_FromUnsignedLong(self->state[i]);
|
||||
if (element == NULL)
|
||||
goto Fail;
|
||||
PyTuple_SET_ITEM(state, i, element);
|
||||
}
|
||||
element = PyLong_FromLong((long)(self->index));
|
||||
if (element == NULL)
|
||||
goto Fail;
|
||||
PyTuple_SET_ITEM(state, i, element);
|
||||
return state;
|
||||
|
||||
Fail:
|
||||
Py_DECREF(state);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
random_setstate(RandomObject *self, PyObject *state)
|
||||
{
|
||||
int i;
|
||||
unsigned long element;
|
||||
long index;
|
||||
unsigned long new_state[N];
|
||||
|
||||
if (!PyTuple_Check(state)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"state vector must be a tuple");
|
||||
return NULL;
|
||||
}
|
||||
if (PyTuple_Size(state) != N+1) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"state vector is the wrong size");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i=0; i<N ; i++) {
|
||||
element = PyLong_AsUnsignedLong(PyTuple_GET_ITEM(state, i));
|
||||
if (element == (unsigned long)-1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
new_state[i] = element & 0xffffffffUL; /* Make sure we get sane state */
|
||||
}
|
||||
|
||||
index = PyLong_AsLong(PyTuple_GET_ITEM(state, i));
|
||||
if (index == -1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
if (index < 0 || index > N) {
|
||||
PyErr_SetString(PyExc_ValueError, "invalid state");
|
||||
return NULL;
|
||||
}
|
||||
self->index = (int)index;
|
||||
for (i = 0; i < N; i++)
|
||||
self->state[i] = new_state[i];
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
/*
|
||||
Jumpahead should be a fast way advance the generator n-steps ahead, but
|
||||
lacking a formula for that, the next best is to use n and the existing
|
||||
state to create a new state far away from the original.
|
||||
|
||||
The generator uses constant spaced additive feedback, so shuffling the
|
||||
state elements ought to produce a state which would not be encountered
|
||||
(in the near term) by calls to random(). Shuffling is normally
|
||||
implemented by swapping the ith element with another element ranging
|
||||
from 0 to i inclusive. That allows the element to have the possibility
|
||||
of not being moved. Since the goal is to produce a new, different
|
||||
state, the swap element is ranged from 0 to i-1 inclusive. This assures
|
||||
that each element gets moved at least once.
|
||||
|
||||
To make sure that consecutive calls to jumpahead(n) produce different
|
||||
states (even in the rare case of involutory shuffles), i+1 is added to
|
||||
each element at position i. Successive calls are then guaranteed to
|
||||
have changing (growing) values as well as shuffled positions.
|
||||
|
||||
Finally, the self->index value is set to N so that the generator itself
|
||||
kicks in on the next call to random(). This assures that all results
|
||||
have been through the generator and do not just reflect alterations to
|
||||
the underlying state.
|
||||
*/
|
||||
|
||||
static PyObject *
|
||||
random_jumpahead(RandomObject *self, PyObject *n)
|
||||
{
|
||||
long i, j;
|
||||
PyObject *iobj;
|
||||
PyObject *remobj;
|
||||
unsigned long *mt, tmp, nonzero;
|
||||
|
||||
if (!_PyAnyInt_Check(n)) {
|
||||
PyErr_Format(PyExc_TypeError, "jumpahead requires an "
|
||||
"integer, not '%s'",
|
||||
Py_TYPE(n)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mt = self->state;
|
||||
for (i = N-1; i > 1; i--) {
|
||||
iobj = PyInt_FromLong(i);
|
||||
if (iobj == NULL)
|
||||
return NULL;
|
||||
remobj = PyNumber_Remainder(n, iobj);
|
||||
Py_DECREF(iobj);
|
||||
if (remobj == NULL)
|
||||
return NULL;
|
||||
j = PyInt_AsLong(remobj);
|
||||
Py_DECREF(remobj);
|
||||
if (j == -1L && PyErr_Occurred())
|
||||
return NULL;
|
||||
tmp = mt[i];
|
||||
mt[i] = mt[j];
|
||||
mt[j] = tmp;
|
||||
}
|
||||
|
||||
nonzero = 0;
|
||||
for (i = 1; i < N; i++) {
|
||||
mt[i] += i+1;
|
||||
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
|
||||
nonzero |= mt[i];
|
||||
}
|
||||
|
||||
/* Ensure the state is nonzero: in the unlikely event that mt[1] through
|
||||
mt[N-1] are all zero, set the MSB of mt[0] (see issue #14591). In the
|
||||
normal case, we fall back to the pre-issue 14591 behaviour for mt[0]. */
|
||||
if (nonzero) {
|
||||
mt[0] += 1;
|
||||
mt[0] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
|
||||
}
|
||||
else {
|
||||
mt[0] = 0x80000000UL;
|
||||
}
|
||||
|
||||
self->index = N;
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
random_getrandbits(RandomObject *self, PyObject *args)
|
||||
{
|
||||
int k, i, bytes;
|
||||
unsigned long r;
|
||||
unsigned char *bytearray;
|
||||
PyObject *result;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i:getrandbits", &k))
|
||||
return NULL;
|
||||
|
||||
if (k <= 0) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"number of bits must be greater than zero");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bytes = ((k - 1) / 32 + 1) * 4;
|
||||
bytearray = (unsigned char *)PyMem_Malloc(bytes);
|
||||
if (bytearray == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Fill-out whole words, byte-by-byte to avoid endianness issues */
|
||||
for (i=0 ; i<bytes ; i+=4, k-=32) {
|
||||
r = genrand_int32(self);
|
||||
if (k < 32)
|
||||
r >>= (32 - k);
|
||||
bytearray[i+0] = (unsigned char)r;
|
||||
bytearray[i+1] = (unsigned char)(r >> 8);
|
||||
bytearray[i+2] = (unsigned char)(r >> 16);
|
||||
bytearray[i+3] = (unsigned char)(r >> 24);
|
||||
}
|
||||
|
||||
/* little endian order to match bytearray assignment order */
|
||||
result = _PyLong_FromByteArray(bytearray, bytes, 1, 0);
|
||||
PyMem_Free(bytearray);
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
random_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
RandomObject *self;
|
||||
PyObject *tmp;
|
||||
|
||||
if (type == &Random_Type && !_PyArg_NoKeywords("Random()", kwds))
|
||||
return NULL;
|
||||
|
||||
self = (RandomObject *)type->tp_alloc(type, 0);
|
||||
if (self == NULL)
|
||||
return NULL;
|
||||
tmp = random_seed(self, args);
|
||||
if (tmp == NULL) {
|
||||
Py_DECREF(self);
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(tmp);
|
||||
return (PyObject *)self;
|
||||
}
|
||||
|
||||
static PyMethodDef random_methods[] = {
|
||||
{"random", (PyCFunction)random_random, METH_NOARGS,
|
||||
PyDoc_STR("random() -> x in the interval [0, 1).")},
|
||||
{"seed", (PyCFunction)random_seed, METH_VARARGS,
|
||||
PyDoc_STR("seed([n]) -> None. Defaults to current time.")},
|
||||
{"getstate", (PyCFunction)random_getstate, METH_NOARGS,
|
||||
PyDoc_STR("getstate() -> tuple containing the current state.")},
|
||||
{"setstate", (PyCFunction)random_setstate, METH_O,
|
||||
PyDoc_STR("setstate(state) -> None. Restores generator state.")},
|
||||
{"jumpahead", (PyCFunction)random_jumpahead, METH_O,
|
||||
PyDoc_STR("jumpahead(int) -> None. Create new state from "
|
||||
"existing state and integer.")},
|
||||
{"getrandbits", (PyCFunction)random_getrandbits, METH_VARARGS,
|
||||
PyDoc_STR("getrandbits(k) -> x. Generates a long int with "
|
||||
"k random bits.")},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(random_doc,
|
||||
"Random() -> create a random number generator with its own internal state.");
|
||||
|
||||
static PyTypeObject Random_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"_random.Random", /*tp_name*/
|
||||
sizeof(RandomObject), /*tp_basicsize*/
|
||||
0, /*tp_itemsize*/
|
||||
/* methods */
|
||||
0, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
0, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
0, /*tp_hash*/
|
||||
0, /*tp_call*/
|
||||
0, /*tp_str*/
|
||||
PyObject_GenericGetAttr, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
|
||||
random_doc, /*tp_doc*/
|
||||
0, /*tp_traverse*/
|
||||
0, /*tp_clear*/
|
||||
0, /*tp_richcompare*/
|
||||
0, /*tp_weaklistoffset*/
|
||||
0, /*tp_iter*/
|
||||
0, /*tp_iternext*/
|
||||
random_methods, /*tp_methods*/
|
||||
0, /*tp_members*/
|
||||
0, /*tp_getset*/
|
||||
0, /*tp_base*/
|
||||
0, /*tp_dict*/
|
||||
0, /*tp_descr_get*/
|
||||
0, /*tp_descr_set*/
|
||||
0, /*tp_dictoffset*/
|
||||
0, /*tp_init*/
|
||||
0, /*tp_alloc*/
|
||||
random_new, /*tp_new*/
|
||||
_PyObject_Del, /*tp_free*/
|
||||
0, /*tp_is_gc*/
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(module_doc,
|
||||
"Module implements the Mersenne Twister random number generator.");
|
||||
|
||||
PyMODINIT_FUNC
|
||||
init_random(void)
|
||||
{
|
||||
PyObject *m;
|
||||
|
||||
if (PyType_Ready(&Random_Type) < 0)
|
||||
return;
|
||||
m = Py_InitModule3("_random", NULL, module_doc);
|
||||
if (m == NULL)
|
||||
return;
|
||||
Py_INCREF(&Random_Type);
|
||||
PyModule_AddObject(m, "Random", (PyObject *)&Random_Type);
|
||||
}
|
||||
+4072
File diff suppressed because it is too large
Load Diff
+4534
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+2099
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+3712
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,151 @@
|
||||
#include "Python.h"
|
||||
|
||||
|
||||
#define GET_WEAKREFS_LISTPTR(o) \
|
||||
((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o))
|
||||
|
||||
|
||||
static int
|
||||
is_dead_weakref(PyObject *value)
|
||||
{
|
||||
if (!PyWeakref_Check(value)) {
|
||||
PyErr_SetString(PyExc_TypeError, "not a weakref");
|
||||
return -1;
|
||||
}
|
||||
return PyWeakref_GET_OBJECT(value) == Py_None;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(remove_dead_weakref__doc__,
|
||||
"_remove_dead_weakref(dict, key) -- atomically remove key from dict\n"
|
||||
"if it points to a dead weakref.");
|
||||
|
||||
static PyObject *
|
||||
remove_dead_weakref(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *dct, *key;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O!O:_remove_dead_weakref",
|
||||
&PyDict_Type, &dct, &key)) {
|
||||
return NULL;
|
||||
}
|
||||
if (_PyDict_DelItemIf(dct, key, is_dead_weakref) < 0) {
|
||||
if (PyErr_ExceptionMatches(PyExc_KeyError))
|
||||
/* This function is meant to allow safe weak-value dicts
|
||||
with GC in another thread (see issue #28427), so it's
|
||||
ok if the key doesn't exist anymore.
|
||||
*/
|
||||
PyErr_Clear();
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(weakref_getweakrefcount__doc__,
|
||||
"getweakrefcount(object) -- return the number of weak references\n"
|
||||
"to 'object'.");
|
||||
|
||||
static PyObject *
|
||||
weakref_getweakrefcount(PyObject *self, PyObject *object)
|
||||
{
|
||||
PyObject *result = NULL;
|
||||
|
||||
if (PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))) {
|
||||
PyWeakReference **list = GET_WEAKREFS_LISTPTR(object);
|
||||
|
||||
result = PyInt_FromSsize_t(_PyWeakref_GetWeakrefCount(*list));
|
||||
}
|
||||
else
|
||||
result = PyInt_FromLong(0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(weakref_getweakrefs__doc__,
|
||||
"getweakrefs(object) -- return a list of all weak reference objects\n"
|
||||
"that point to 'object'.");
|
||||
|
||||
static PyObject *
|
||||
weakref_getweakrefs(PyObject *self, PyObject *object)
|
||||
{
|
||||
PyObject *result = NULL;
|
||||
|
||||
if (PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))) {
|
||||
PyWeakReference **list = GET_WEAKREFS_LISTPTR(object);
|
||||
Py_ssize_t count = _PyWeakref_GetWeakrefCount(*list);
|
||||
|
||||
result = PyList_New(count);
|
||||
if (result != NULL) {
|
||||
PyWeakReference *current = *list;
|
||||
Py_ssize_t i;
|
||||
for (i = 0; i < count; ++i) {
|
||||
PyList_SET_ITEM(result, i, (PyObject *) current);
|
||||
Py_INCREF(current);
|
||||
current = current->wr_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = PyList_New(0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(weakref_proxy__doc__,
|
||||
"proxy(object[, callback]) -- create a proxy object that weakly\n"
|
||||
"references 'object'. 'callback', if given, is called with a\n"
|
||||
"reference to the proxy when 'object' is about to be finalized.");
|
||||
|
||||
static PyObject *
|
||||
weakref_proxy(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *object;
|
||||
PyObject *callback = NULL;
|
||||
PyObject *result = NULL;
|
||||
|
||||
if (PyArg_UnpackTuple(args, "proxy", 1, 2, &object, &callback)) {
|
||||
result = PyWeakref_NewProxy(object, callback);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef
|
||||
weakref_functions[] = {
|
||||
{"getweakrefcount", weakref_getweakrefcount, METH_O,
|
||||
weakref_getweakrefcount__doc__},
|
||||
{"getweakrefs", weakref_getweakrefs, METH_O,
|
||||
weakref_getweakrefs__doc__},
|
||||
{"proxy", weakref_proxy, METH_VARARGS,
|
||||
weakref_proxy__doc__},
|
||||
{"_remove_dead_weakref", remove_dead_weakref, METH_VARARGS,
|
||||
remove_dead_weakref__doc__},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
||||
PyMODINIT_FUNC
|
||||
init_weakref(void)
|
||||
{
|
||||
PyObject *m;
|
||||
|
||||
m = Py_InitModule3("_weakref", weakref_functions,
|
||||
"Weak-reference support module.");
|
||||
if (m != NULL) {
|
||||
Py_INCREF(&_PyWeakref_RefType);
|
||||
PyModule_AddObject(m, "ref",
|
||||
(PyObject *) &_PyWeakref_RefType);
|
||||
Py_INCREF(&_PyWeakref_RefType);
|
||||
PyModule_AddObject(m, "ReferenceType",
|
||||
(PyObject *) &_PyWeakref_RefType);
|
||||
Py_INCREF(&_PyWeakref_ProxyType);
|
||||
PyModule_AddObject(m, "ProxyType",
|
||||
(PyObject *) &_PyWeakref_ProxyType);
|
||||
Py_INCREF(&_PyWeakref_CallableProxyType);
|
||||
PyModule_AddObject(m, "CallableProxyType",
|
||||
(PyObject *) &_PyWeakref_CallableProxyType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. Neither the name of the project 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 PROJECT 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 PROJECT 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.
|
||||
*/
|
||||
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
|
||||
/*
|
||||
* Error return codes from getaddrinfo()
|
||||
*/
|
||||
#ifdef EAI_ADDRFAMILY
|
||||
/* If this is defined, there is a conflicting implementation
|
||||
in the C library, which can't be used for some reason.
|
||||
Make sure it won't interfere with this emulation. */
|
||||
|
||||
#undef EAI_ADDRFAMILY
|
||||
#undef EAI_AGAIN
|
||||
#undef EAI_BADFLAGS
|
||||
#undef EAI_FAIL
|
||||
#undef EAI_FAMILY
|
||||
#undef EAI_MEMORY
|
||||
#undef EAI_NODATA
|
||||
#undef EAI_NONAME
|
||||
#undef EAI_SERVICE
|
||||
#undef EAI_SOCKTYPE
|
||||
#undef EAI_SYSTEM
|
||||
#undef EAI_BADHINTS
|
||||
#undef EAI_PROTOCOL
|
||||
#undef EAI_MAX
|
||||
#undef getaddrinfo
|
||||
#define getaddrinfo fake_getaddrinfo
|
||||
#endif /* EAI_ADDRFAMILY */
|
||||
|
||||
#define EAI_ADDRFAMILY 1 /* address family for hostname not supported */
|
||||
#define EAI_AGAIN 2 /* temporary failure in name resolution */
|
||||
#define EAI_BADFLAGS 3 /* invalid value for ai_flags */
|
||||
#define EAI_FAIL 4 /* non-recoverable failure in name resolution */
|
||||
#define EAI_FAMILY 5 /* ai_family not supported */
|
||||
#define EAI_MEMORY 6 /* memory allocation failure */
|
||||
#define EAI_NODATA 7 /* no address associated with hostname */
|
||||
#define EAI_NONAME 8 /* hostname nor servname provided, or not known */
|
||||
#define EAI_SERVICE 9 /* servname not supported for ai_socktype */
|
||||
#define EAI_SOCKTYPE 10 /* ai_socktype not supported */
|
||||
#define EAI_SYSTEM 11 /* system error returned in errno */
|
||||
#define EAI_BADHINTS 12
|
||||
#define EAI_PROTOCOL 13
|
||||
#define EAI_MAX 14
|
||||
|
||||
/*
|
||||
* Flag values for getaddrinfo()
|
||||
*/
|
||||
#ifdef AI_PASSIVE
|
||||
#undef AI_PASSIVE
|
||||
#undef AI_CANONNAME
|
||||
#undef AI_NUMERICHOST
|
||||
#undef AI_MASK
|
||||
#undef AI_ALL
|
||||
#undef AI_V4MAPPED_CFG
|
||||
#undef AI_ADDRCONFIG
|
||||
#undef AI_V4MAPPED
|
||||
#undef AI_DEFAULT
|
||||
#endif /* AI_PASSIVE */
|
||||
|
||||
#define AI_PASSIVE 0x00000001 /* get address to use bind() */
|
||||
#define AI_CANONNAME 0x00000002 /* fill ai_canonname */
|
||||
#define AI_NUMERICHOST 0x00000004 /* prevent name resolution */
|
||||
/* valid flags for addrinfo */
|
||||
#define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST)
|
||||
|
||||
#define AI_ALL 0x00000100 /* IPv6 and IPv4-mapped (with AI_V4MAPPED) */
|
||||
#define AI_V4MAPPED_CFG 0x00000200 /* accept IPv4-mapped if kernel supports */
|
||||
#define AI_ADDRCONFIG 0x00000400 /* only if any address is assigned */
|
||||
#define AI_V4MAPPED 0x00000800 /* accept IPv4-mapped IPv6 address */
|
||||
/* special recommended flags for getipnodebyname */
|
||||
#define AI_DEFAULT (AI_V4MAPPED_CFG | AI_ADDRCONFIG)
|
||||
|
||||
#endif /* !HAVE_GETADDRINFO */
|
||||
|
||||
#ifndef HAVE_GETNAMEINFO
|
||||
|
||||
/*
|
||||
* Constants for getnameinfo()
|
||||
*/
|
||||
#ifndef NI_MAXHOST
|
||||
#define NI_MAXHOST 1025
|
||||
#define NI_MAXSERV 32
|
||||
#endif /* !NI_MAXHOST */
|
||||
|
||||
/*
|
||||
* Flag values for getnameinfo()
|
||||
*/
|
||||
#ifndef NI_NOFQDN
|
||||
#define NI_NOFQDN 0x00000001
|
||||
#define NI_NUMERICHOST 0x00000002
|
||||
#define NI_NAMEREQD 0x00000004
|
||||
#define NI_NUMERICSERV 0x00000008
|
||||
#define NI_DGRAM 0x00000010
|
||||
#endif /* !NI_NOFQDN */
|
||||
|
||||
#endif /* !HAVE_GETNAMEINFO */
|
||||
|
||||
#ifndef HAVE_ADDRINFO
|
||||
struct addrinfo {
|
||||
int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
|
||||
int ai_family; /* PF_xxx */
|
||||
int ai_socktype; /* SOCK_xxx */
|
||||
int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
|
||||
size_t ai_addrlen; /* length of ai_addr */
|
||||
char *ai_canonname; /* canonical name for hostname */
|
||||
struct sockaddr *ai_addr; /* binary address */
|
||||
struct addrinfo *ai_next; /* next structure in linked list */
|
||||
};
|
||||
#endif /* !HAVE_ADDRINFO */
|
||||
|
||||
#ifndef HAVE_SOCKADDR_STORAGE
|
||||
/*
|
||||
* RFC 2553: protocol-independent placeholder for socket addresses
|
||||
*/
|
||||
#define _SS_MAXSIZE 128
|
||||
#ifdef HAVE_LONG_LONG
|
||||
#define _SS_ALIGNSIZE (sizeof(PY_LONG_LONG))
|
||||
#else
|
||||
#define _SS_ALIGNSIZE (sizeof(double))
|
||||
#endif /* HAVE_LONG_LONG */
|
||||
#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof(u_char) * 2)
|
||||
#define _SS_PAD2SIZE (_SS_MAXSIZE - sizeof(u_char) * 2 - \
|
||||
_SS_PAD1SIZE - _SS_ALIGNSIZE)
|
||||
|
||||
struct sockaddr_storage {
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
unsigned char ss_len; /* address length */
|
||||
unsigned char ss_family; /* address family */
|
||||
#else
|
||||
unsigned short ss_family; /* address family */
|
||||
#endif /* HAVE_SOCKADDR_SA_LEN */
|
||||
char __ss_pad1[_SS_PAD1SIZE];
|
||||
#ifdef HAVE_LONG_LONG
|
||||
PY_LONG_LONG __ss_align; /* force desired structure storage alignment */
|
||||
#else
|
||||
double __ss_align; /* force desired structure storage alignment */
|
||||
#endif /* HAVE_LONG_LONG */
|
||||
char __ss_pad2[_SS_PAD2SIZE];
|
||||
};
|
||||
#endif /* !HAVE_SOCKADDR_STORAGE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
extern void freehostent Py_PROTO((struct hostent *));
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
+3232
File diff suppressed because it is too large
Load Diff
+73
@@ -0,0 +1,73 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Truly fake ar, using a directory to store object files.
|
||||
#
|
||||
# Donn Cave, donn@oz.net
|
||||
|
||||
usage='Usage: ar-fake cr libpython.dir obj.o ...
|
||||
ar-fake d libpython.dir obj.o ...
|
||||
ar-fake so libpython.dir libpython.so'
|
||||
|
||||
case $# in
|
||||
0|1|2)
|
||||
echo "$usage" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
command=$1
|
||||
library=$2
|
||||
shift 2
|
||||
|
||||
case $command in
|
||||
cr)
|
||||
if test -d $library
|
||||
then :
|
||||
else
|
||||
mkdir $library
|
||||
fi
|
||||
if cp -p $* $library
|
||||
then
|
||||
# To force directory modify date, create or delete a file.
|
||||
if test -e $library/.tch
|
||||
then rm $library/.tch
|
||||
else echo tch > $library/.tch
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
;;
|
||||
d)
|
||||
if test -d $library
|
||||
then
|
||||
cd $library
|
||||
rm -f $*
|
||||
fi
|
||||
;;
|
||||
so)
|
||||
case $BE_HOST_CPU in
|
||||
ppc)
|
||||
# In case your libpython.a refers to any exotic libraries,
|
||||
# mwld needs to know that here. The following hack makes
|
||||
# a couple of assumptions about Modules/Makefile. If it
|
||||
# doesn't work, you may as well add the necessary libraries
|
||||
# here explicitly instead.
|
||||
extralibs=$(
|
||||
(cd Modules; make -f Makefile -n link) |
|
||||
sed -n 's/.*\.so \(.*\) -o python.*/\1/p'
|
||||
)
|
||||
mwld -xms -export pragma -nodup -o $1 $library/* $extralibs
|
||||
;;
|
||||
x86)
|
||||
ld -shared -soname $(basename $1) -o $1 $library/*
|
||||
;;
|
||||
esac
|
||||
status=$?
|
||||
cd $(dirname $1)
|
||||
ln -sf $PWD lib
|
||||
exit $status
|
||||
;;
|
||||
*)
|
||||
echo "$usage" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
File diff suppressed because it is too large
Load Diff
+1687
File diff suppressed because it is too large
Load Diff
+1525
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,315 @@
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 1999-2001, Digital Creations, Fredericksburg, VA, USA
|
||||
and Andrew Kuchling. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
o Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions, and the disclaimer that follows.
|
||||
|
||||
o 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.
|
||||
|
||||
o Neither the name of Digital Creations 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 DIGITAL CREATIONS 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 DIGITAL
|
||||
CREATIONS 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.
|
||||
------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
/*
|
||||
* Handwritten code to wrap version 3.x of the Berkeley DB library,
|
||||
* written to replace a SWIG-generated file. It has since been updated
|
||||
* to compile with Berkeley DB versions 3.2 through 4.2.
|
||||
*
|
||||
* This module was started by Andrew Kuchling to remove the dependency
|
||||
* on SWIG in a package by Gregory P. Smith who based his work on a
|
||||
* similar package by Robin Dunn <robin@alldunn.com> which wrapped
|
||||
* Berkeley DB 2.7.x.
|
||||
*
|
||||
* Development of this module then returned full circle back to Robin Dunn
|
||||
* who worked on behalf of Digital Creations to complete the wrapping of
|
||||
* the DB 3.x API and to build a solid unit test suite. Robin has
|
||||
* since gone onto other projects (wxPython).
|
||||
*
|
||||
* Gregory P. Smith <greg@krypto.org> is once again the maintainer.
|
||||
*
|
||||
* Use the pybsddb-users@lists.sf.net mailing list for all questions.
|
||||
* Things can change faster than the header of this file is updated. This
|
||||
* file is shared with the PyBSDDB project at SourceForge:
|
||||
*
|
||||
* http://pybsddb.sf.net
|
||||
*
|
||||
* This file should remain backward compatible with Python 2.1, but see PEP
|
||||
* 291 for the most current backward compatibility requirements:
|
||||
*
|
||||
* http://www.python.org/peps/pep-0291.html
|
||||
*
|
||||
* This module contains 7 types:
|
||||
*
|
||||
* DB (Database)
|
||||
* DBCursor (Database Cursor)
|
||||
* DBEnv (database environment)
|
||||
* DBTxn (An explicit database transaction)
|
||||
* DBLock (A lock handle)
|
||||
* DBSequence (Sequence)
|
||||
* DBSite (Site)
|
||||
*
|
||||
* New datatypes:
|
||||
*
|
||||
* DBLogCursor (Log Cursor)
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Portions of this module, associated unit tests and build scripts are the
|
||||
* result of a contract with The Written Word (http://thewrittenword.com/)
|
||||
* Many thanks go out to them for causing me to raise the bar on quality and
|
||||
* functionality, resulting in a better bsddb3 package for all of us to use.
|
||||
*
|
||||
* --Robin
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Work to split it up into a separate header and to add a C API was
|
||||
* contributed by Duncan Grisby <duncan@tideway.com>. See here:
|
||||
* http://sourceforge.net/tracker/index.php?func=detail&aid=1551895&group_id=13900&atid=313900
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
#ifndef _BSDDB_H_
|
||||
#define _BSDDB_H_
|
||||
|
||||
#include <db.h>
|
||||
|
||||
|
||||
/* 40 = 4.0, 33 = 3.3; this will break if the minor revision is > 9 */
|
||||
#define DBVER (DB_VERSION_MAJOR * 10 + DB_VERSION_MINOR)
|
||||
#if DB_VERSION_MINOR > 9
|
||||
#error "eek! DBVER can't handle minor versions > 9"
|
||||
#endif
|
||||
|
||||
#define PY_BSDDB_VERSION "5.3.0"
|
||||
|
||||
/* Python object definitions */
|
||||
|
||||
struct behaviourFlags {
|
||||
/* What is the default behaviour when DB->get or DBCursor->get returns a
|
||||
DB_NOTFOUND || DB_KEYEMPTY error? Return None or raise an exception? */
|
||||
unsigned int getReturnsNone : 1;
|
||||
/* What is the default behaviour for DBCursor.set* methods when DBCursor->get
|
||||
* returns a DB_NOTFOUND || DB_KEYEMPTY error? Return None or raise? */
|
||||
unsigned int cursorSetReturnsNone : 1;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct DBObject; /* Forward declaration */
|
||||
struct DBCursorObject; /* Forward declaration */
|
||||
struct DBLogCursorObject; /* Forward declaration */
|
||||
struct DBTxnObject; /* Forward declaration */
|
||||
struct DBSequenceObject; /* Forward declaration */
|
||||
#if (DBVER >= 52)
|
||||
struct DBSiteObject; /* Forward declaration */
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
DB_ENV* db_env;
|
||||
u_int32_t flags; /* saved flags from open() */
|
||||
int closed;
|
||||
struct behaviourFlags moduleFlags;
|
||||
PyObject* event_notifyCallback;
|
||||
struct DBObject *children_dbs;
|
||||
struct DBTxnObject *children_txns;
|
||||
struct DBLogCursorObject *children_logcursors;
|
||||
#if (DBVER >= 52)
|
||||
struct DBSiteObject *children_sites;
|
||||
#endif
|
||||
PyObject *private_obj;
|
||||
PyObject *rep_transport;
|
||||
PyObject *in_weakreflist; /* List of weak references */
|
||||
} DBEnvObject;
|
||||
|
||||
typedef struct DBObject {
|
||||
PyObject_HEAD
|
||||
DB* db;
|
||||
DBEnvObject* myenvobj; /* PyObject containing the DB_ENV */
|
||||
u_int32_t flags; /* saved flags from open() */
|
||||
u_int32_t setflags; /* saved flags from set_flags() */
|
||||
struct behaviourFlags moduleFlags;
|
||||
struct DBTxnObject *txn;
|
||||
struct DBCursorObject *children_cursors;
|
||||
struct DBSequenceObject *children_sequences;
|
||||
struct DBObject **sibling_prev_p;
|
||||
struct DBObject *sibling_next;
|
||||
struct DBObject **sibling_prev_p_txn;
|
||||
struct DBObject *sibling_next_txn;
|
||||
PyObject* associateCallback;
|
||||
PyObject* btCompareCallback;
|
||||
PyObject* dupCompareCallback;
|
||||
int primaryDBType;
|
||||
PyObject *private_obj;
|
||||
PyObject *in_weakreflist; /* List of weak references */
|
||||
} DBObject;
|
||||
|
||||
|
||||
typedef struct DBCursorObject {
|
||||
PyObject_HEAD
|
||||
DBC* dbc;
|
||||
struct DBCursorObject **sibling_prev_p;
|
||||
struct DBCursorObject *sibling_next;
|
||||
struct DBCursorObject **sibling_prev_p_txn;
|
||||
struct DBCursorObject *sibling_next_txn;
|
||||
DBObject* mydb;
|
||||
struct DBTxnObject *txn;
|
||||
PyObject *in_weakreflist; /* List of weak references */
|
||||
} DBCursorObject;
|
||||
|
||||
|
||||
typedef struct DBTxnObject {
|
||||
PyObject_HEAD
|
||||
DB_TXN* txn;
|
||||
DBEnvObject* env;
|
||||
int flag_prepare;
|
||||
struct DBTxnObject *parent_txn;
|
||||
struct DBTxnObject **sibling_prev_p;
|
||||
struct DBTxnObject *sibling_next;
|
||||
struct DBTxnObject *children_txns;
|
||||
struct DBObject *children_dbs;
|
||||
struct DBSequenceObject *children_sequences;
|
||||
struct DBCursorObject *children_cursors;
|
||||
PyObject *in_weakreflist; /* List of weak references */
|
||||
} DBTxnObject;
|
||||
|
||||
|
||||
typedef struct DBLogCursorObject {
|
||||
PyObject_HEAD
|
||||
DB_LOGC* logc;
|
||||
DBEnvObject* env;
|
||||
struct DBLogCursorObject **sibling_prev_p;
|
||||
struct DBLogCursorObject *sibling_next;
|
||||
PyObject *in_weakreflist; /* List of weak references */
|
||||
} DBLogCursorObject;
|
||||
|
||||
#if (DBVER >= 52)
|
||||
typedef struct DBSiteObject {
|
||||
PyObject_HEAD
|
||||
DB_SITE *site;
|
||||
DBEnvObject *env;
|
||||
struct DBSiteObject **sibling_prev_p;
|
||||
struct DBSiteObject *sibling_next;
|
||||
PyObject *in_weakreflist; /* List of weak references */
|
||||
} DBSiteObject;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
DB_LOCK lock;
|
||||
int lock_initialized; /* Signal if we actually have a lock */
|
||||
PyObject *in_weakreflist; /* List of weak references */
|
||||
} DBLockObject;
|
||||
|
||||
|
||||
typedef struct DBSequenceObject {
|
||||
PyObject_HEAD
|
||||
DB_SEQUENCE* sequence;
|
||||
DBObject* mydb;
|
||||
struct DBTxnObject *txn;
|
||||
struct DBSequenceObject **sibling_prev_p;
|
||||
struct DBSequenceObject *sibling_next;
|
||||
struct DBSequenceObject **sibling_prev_p_txn;
|
||||
struct DBSequenceObject *sibling_next_txn;
|
||||
PyObject *in_weakreflist; /* List of weak references */
|
||||
} DBSequenceObject;
|
||||
|
||||
|
||||
/* API structure for use by C code */
|
||||
|
||||
/* To access the structure from an external module, use code like the
|
||||
following (error checking missed out for clarity):
|
||||
|
||||
// If you are using Python before 2.7:
|
||||
BSDDB_api* bsddb_api;
|
||||
PyObject* mod;
|
||||
PyObject* cobj;
|
||||
|
||||
mod = PyImport_ImportModule("bsddb._bsddb");
|
||||
// Use "bsddb3._pybsddb" if you're using the standalone pybsddb add-on.
|
||||
cobj = PyObject_GetAttrString(mod, "api");
|
||||
api = (BSDDB_api*)PyCObject_AsVoidPtr(cobj);
|
||||
Py_DECREF(cobj);
|
||||
Py_DECREF(mod);
|
||||
|
||||
|
||||
// If you are using Python 2.7 or up: (except Python 3.0, unsupported)
|
||||
BSDDB_api* bsddb_api;
|
||||
|
||||
// Use "bsddb3._pybsddb.api" if you're using
|
||||
// the standalone pybsddb add-on.
|
||||
bsddb_api = (void **)PyCapsule_Import("bsddb._bsddb.api", 1);
|
||||
|
||||
|
||||
Check "api_version" number before trying to use the API.
|
||||
|
||||
The structure's members must not be changed.
|
||||
*/
|
||||
|
||||
#define PYBSDDB_API_VERSION 1
|
||||
typedef struct {
|
||||
unsigned int api_version;
|
||||
/* Type objects */
|
||||
PyTypeObject* db_type;
|
||||
PyTypeObject* dbcursor_type;
|
||||
PyTypeObject* dblogcursor_type;
|
||||
PyTypeObject* dbenv_type;
|
||||
PyTypeObject* dbtxn_type;
|
||||
PyTypeObject* dblock_type;
|
||||
PyTypeObject* dbsequence_type;
|
||||
|
||||
/* Functions */
|
||||
int (*makeDBError)(int err);
|
||||
} BSDDB_api;
|
||||
|
||||
|
||||
#ifndef COMPILING_BSDDB_C
|
||||
|
||||
/* If not inside _bsddb.c, define type check macros that use the api
|
||||
structure. The calling code must have a value named bsddb_api
|
||||
pointing to the api structure.
|
||||
*/
|
||||
|
||||
#define DBObject_Check(v) ((v)->ob_type == bsddb_api->db_type)
|
||||
#define DBCursorObject_Check(v) ((v)->ob_type == bsddb_api->dbcursor_type)
|
||||
#define DBEnvObject_Check(v) ((v)->ob_type == bsddb_api->dbenv_type)
|
||||
#define DBTxnObject_Check(v) ((v)->ob_type == bsddb_api->dbtxn_type)
|
||||
#define DBLockObject_Check(v) ((v)->ob_type == bsddb_api->dblock_type)
|
||||
#define DBSequenceObject_Check(v) \
|
||||
((bsddb_api->dbsequence_type) && \
|
||||
((v)->ob_type == bsddb_api->dbsequence_type))
|
||||
|
||||
#endif /* COMPILING_BSDDB_C */
|
||||
|
||||
|
||||
#endif /* _BSDDB_H_ */
|
||||
@@ -0,0 +1,864 @@
|
||||
/* Berkeley DB interface.
|
||||
Author: Michael McLay
|
||||
Hacked: Guido van Rossum
|
||||
Btree and Recno additions plus sequence methods: David Ely
|
||||
Hacked by Gustavo Niemeyer <niemeyer@conectiva.com> fixing recno
|
||||
support.
|
||||
|
||||
XXX To do:
|
||||
- provide a way to access the various hash functions
|
||||
- support more open flags
|
||||
|
||||
The windows port of the Berkeley DB code is hard to find on the web:
|
||||
www.nightmare.com/software.html
|
||||
*/
|
||||
|
||||
#include "Python.h"
|
||||
#ifdef WITH_THREAD
|
||||
#include "pythread.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_DB_185_H
|
||||
#include <db_185.h>
|
||||
#else
|
||||
#include <db.h>
|
||||
#endif
|
||||
/* Please don't include internal header files of the Berkeley db package
|
||||
(it messes up the info required in the Setup file) */
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
DB *di_bsddb;
|
||||
int di_size; /* -1 means recompute */
|
||||
int di_type;
|
||||
#ifdef WITH_THREAD
|
||||
PyThread_type_lock di_lock;
|
||||
#endif
|
||||
} bsddbobject;
|
||||
|
||||
static PyTypeObject Bsddbtype;
|
||||
|
||||
#define is_bsddbobject(v) ((v)->ob_type == &Bsddbtype)
|
||||
#define check_bsddbobject_open(v, r) if ((v)->di_bsddb == NULL) \
|
||||
{ PyErr_SetString(BsddbError, \
|
||||
"BSDDB object has already been closed"); \
|
||||
return r; }
|
||||
|
||||
static PyObject *BsddbError;
|
||||
|
||||
static PyObject *
|
||||
newdbhashobject(char *file, int flags, int mode,
|
||||
int bsize, int ffactor, int nelem, int cachesize,
|
||||
int hash, int lorder)
|
||||
{
|
||||
bsddbobject *dp;
|
||||
HASHINFO info;
|
||||
|
||||
if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL)
|
||||
return NULL;
|
||||
|
||||
info.bsize = bsize;
|
||||
info.ffactor = ffactor;
|
||||
info.nelem = nelem;
|
||||
info.cachesize = cachesize;
|
||||
info.hash = NULL; /* XXX should derive from hash argument */
|
||||
info.lorder = lorder;
|
||||
|
||||
#ifdef O_BINARY
|
||||
flags |= O_BINARY;
|
||||
#endif
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
dp->di_bsddb = dbopen(file, flags, mode, DB_HASH, &info);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (dp->di_bsddb == NULL) {
|
||||
PyErr_SetFromErrno(BsddbError);
|
||||
#ifdef WITH_THREAD
|
||||
dp->di_lock = NULL;
|
||||
#endif
|
||||
Py_DECREF(dp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dp->di_size = -1;
|
||||
dp->di_type = DB_HASH;
|
||||
|
||||
#ifdef WITH_THREAD
|
||||
dp->di_lock = PyThread_allocate_lock();
|
||||
if (dp->di_lock == NULL) {
|
||||
PyErr_SetString(BsddbError, "can't allocate lock");
|
||||
Py_DECREF(dp);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return (PyObject *)dp;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
newdbbtobject(char *file, int flags, int mode,
|
||||
int btflags, int cachesize, int maxkeypage,
|
||||
int minkeypage, int psize, int lorder)
|
||||
{
|
||||
bsddbobject *dp;
|
||||
BTREEINFO info;
|
||||
|
||||
if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL)
|
||||
return NULL;
|
||||
|
||||
info.flags = btflags;
|
||||
info.cachesize = cachesize;
|
||||
info.maxkeypage = maxkeypage;
|
||||
info.minkeypage = minkeypage;
|
||||
info.psize = psize;
|
||||
info.lorder = lorder;
|
||||
info.compare = 0; /* Use default comparison functions, for now..*/
|
||||
info.prefix = 0;
|
||||
|
||||
#ifdef O_BINARY
|
||||
flags |= O_BINARY;
|
||||
#endif
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
dp->di_bsddb = dbopen(file, flags, mode, DB_BTREE, &info);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (dp->di_bsddb == NULL) {
|
||||
PyErr_SetFromErrno(BsddbError);
|
||||
#ifdef WITH_THREAD
|
||||
dp->di_lock = NULL;
|
||||
#endif
|
||||
Py_DECREF(dp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dp->di_size = -1;
|
||||
dp->di_type = DB_BTREE;
|
||||
|
||||
#ifdef WITH_THREAD
|
||||
dp->di_lock = PyThread_allocate_lock();
|
||||
if (dp->di_lock == NULL) {
|
||||
PyErr_SetString(BsddbError, "can't allocate lock");
|
||||
Py_DECREF(dp);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return (PyObject *)dp;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
newdbrnobject(char *file, int flags, int mode,
|
||||
int rnflags, int cachesize, int psize, int lorder,
|
||||
size_t reclen, u_char bval, char *bfname)
|
||||
{
|
||||
bsddbobject *dp;
|
||||
RECNOINFO info;
|
||||
int fd;
|
||||
|
||||
if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL)
|
||||
return NULL;
|
||||
|
||||
info.flags = rnflags;
|
||||
info.cachesize = cachesize;
|
||||
info.psize = psize;
|
||||
info.lorder = lorder;
|
||||
info.reclen = reclen;
|
||||
info.bval = bval;
|
||||
info.bfname = bfname;
|
||||
|
||||
#ifdef O_BINARY
|
||||
flags |= O_BINARY;
|
||||
#endif
|
||||
/* This is a hack to avoid a dbopen() bug that happens when
|
||||
* it fails. */
|
||||
fd = open(file, flags);
|
||||
if (fd == -1) {
|
||||
dp->di_bsddb = NULL;
|
||||
}
|
||||
else {
|
||||
close(fd);
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
dp->di_bsddb = dbopen(file, flags, mode, DB_RECNO, &info);
|
||||
Py_END_ALLOW_THREADS
|
||||
}
|
||||
if (dp->di_bsddb == NULL) {
|
||||
PyErr_SetFromErrno(BsddbError);
|
||||
#ifdef WITH_THREAD
|
||||
dp->di_lock = NULL;
|
||||
#endif
|
||||
Py_DECREF(dp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dp->di_size = -1;
|
||||
dp->di_type = DB_RECNO;
|
||||
|
||||
#ifdef WITH_THREAD
|
||||
dp->di_lock = PyThread_allocate_lock();
|
||||
if (dp->di_lock == NULL) {
|
||||
PyErr_SetString(BsddbError, "can't allocate lock");
|
||||
Py_DECREF(dp);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return (PyObject *)dp;
|
||||
}
|
||||
|
||||
static void
|
||||
bsddb_dealloc(bsddbobject *dp)
|
||||
{
|
||||
#ifdef WITH_THREAD
|
||||
if (dp->di_lock) {
|
||||
PyThread_acquire_lock(dp->di_lock, 0);
|
||||
PyThread_release_lock(dp->di_lock);
|
||||
PyThread_free_lock(dp->di_lock);
|
||||
dp->di_lock = NULL;
|
||||
}
|
||||
#endif
|
||||
if (dp->di_bsddb != NULL) {
|
||||
int status;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
status = (dp->di_bsddb->close)(dp->di_bsddb);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (status != 0)
|
||||
fprintf(stderr,
|
||||
"Python bsddb: close errno %d in dealloc\n",
|
||||
errno);
|
||||
}
|
||||
PyObject_Del(dp);
|
||||
}
|
||||
|
||||
#ifdef WITH_THREAD
|
||||
#define BSDDB_BGN_SAVE(_dp) \
|
||||
Py_BEGIN_ALLOW_THREADS PyThread_acquire_lock(_dp->di_lock,1);
|
||||
#define BSDDB_END_SAVE(_dp) \
|
||||
PyThread_release_lock(_dp->di_lock); Py_END_ALLOW_THREADS
|
||||
#else
|
||||
#define BSDDB_BGN_SAVE(_dp) Py_BEGIN_ALLOW_THREADS
|
||||
#define BSDDB_END_SAVE(_dp) Py_END_ALLOW_THREADS
|
||||
#endif
|
||||
|
||||
static Py_ssize_t
|
||||
bsddb_length(bsddbobject *dp)
|
||||
{
|
||||
check_bsddbobject_open(dp, -1);
|
||||
if (dp->di_size < 0) {
|
||||
DBT krec, drec;
|
||||
int status;
|
||||
int size = 0;
|
||||
BSDDB_BGN_SAVE(dp)
|
||||
for (status = (dp->di_bsddb->seq)(dp->di_bsddb,
|
||||
&krec, &drec,R_FIRST);
|
||||
status == 0;
|
||||
status = (dp->di_bsddb->seq)(dp->di_bsddb,
|
||||
&krec, &drec, R_NEXT))
|
||||
size++;
|
||||
BSDDB_END_SAVE(dp)
|
||||
if (status < 0) {
|
||||
PyErr_SetFromErrno(BsddbError);
|
||||
return -1;
|
||||
}
|
||||
dp->di_size = size;
|
||||
}
|
||||
return dp->di_size;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
bsddb_subscript(bsddbobject *dp, PyObject *key)
|
||||
{
|
||||
int status;
|
||||
DBT krec, drec;
|
||||
char *data = NULL;
|
||||
char buf[4096];
|
||||
int size;
|
||||
PyObject *result;
|
||||
recno_t recno;
|
||||
|
||||
if (dp->di_type == DB_RECNO) {
|
||||
if (!PyArg_Parse(key, "i", &recno)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"key type must be integer");
|
||||
return NULL;
|
||||
}
|
||||
krec.data = &recno;
|
||||
krec.size = sizeof(recno);
|
||||
}
|
||||
else {
|
||||
if (!PyArg_Parse(key, "s#", &data, &size)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"key type must be string");
|
||||
return NULL;
|
||||
}
|
||||
krec.data = data;
|
||||
krec.size = size;
|
||||
}
|
||||
check_bsddbobject_open(dp, NULL);
|
||||
|
||||
BSDDB_BGN_SAVE(dp)
|
||||
status = (dp->di_bsddb->get)(dp->di_bsddb, &krec, &drec, 0);
|
||||
if (status == 0) {
|
||||
if (drec.size > sizeof(buf)) data = malloc(drec.size);
|
||||
else data = buf;
|
||||
if (data!=NULL) memcpy(data,drec.data,drec.size);
|
||||
}
|
||||
BSDDB_END_SAVE(dp)
|
||||
if (data==NULL) return PyErr_NoMemory();
|
||||
if (status != 0) {
|
||||
if (status < 0)
|
||||
PyErr_SetFromErrno(BsddbError);
|
||||
else
|
||||
PyErr_SetObject(PyExc_KeyError, key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = PyString_FromStringAndSize(data, (int)drec.size);
|
||||
if (data != buf) free(data);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
bsddb_ass_sub(bsddbobject *dp, PyObject *key, PyObject *value)
|
||||
{
|
||||
int status;
|
||||
DBT krec, drec;
|
||||
char *data;
|
||||
int size;
|
||||
recno_t recno;
|
||||
|
||||
if (dp->di_type == DB_RECNO) {
|
||||
if (!PyArg_Parse(key, "i", &recno)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"bsddb key type must be integer");
|
||||
return -1;
|
||||
}
|
||||
krec.data = &recno;
|
||||
krec.size = sizeof(recno);
|
||||
}
|
||||
else {
|
||||
if (!PyArg_Parse(key, "s#", &data, &size)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"bsddb key type must be string");
|
||||
return -1;
|
||||
}
|
||||
krec.data = data;
|
||||
krec.size = size;
|
||||
}
|
||||
check_bsddbobject_open(dp, -1);
|
||||
dp->di_size = -1;
|
||||
if (value == NULL) {
|
||||
BSDDB_BGN_SAVE(dp)
|
||||
status = (dp->di_bsddb->del)(dp->di_bsddb, &krec, 0);
|
||||
BSDDB_END_SAVE(dp)
|
||||
}
|
||||
else {
|
||||
if (!PyArg_Parse(value, "s#", &data, &size)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"bsddb value type must be string");
|
||||
return -1;
|
||||
}
|
||||
drec.data = data;
|
||||
drec.size = size;
|
||||
BSDDB_BGN_SAVE(dp)
|
||||
status = (dp->di_bsddb->put)(dp->di_bsddb, &krec, &drec, 0);
|
||||
BSDDB_END_SAVE(dp)
|
||||
}
|
||||
if (status != 0) {
|
||||
if (status < 0)
|
||||
PyErr_SetFromErrno(BsddbError);
|
||||
else
|
||||
PyErr_SetObject(PyExc_KeyError, key);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyMappingMethods bsddb_as_mapping = {
|
||||
(lenfunc)bsddb_length, /*mp_length*/
|
||||
(binaryfunc)bsddb_subscript, /*mp_subscript*/
|
||||
(objobjargproc)bsddb_ass_sub, /*mp_ass_subscript*/
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
bsddb_close(bsddbobject *dp)
|
||||
{
|
||||
if (dp->di_bsddb != NULL) {
|
||||
int status;
|
||||
BSDDB_BGN_SAVE(dp)
|
||||
status = (dp->di_bsddb->close)(dp->di_bsddb);
|
||||
BSDDB_END_SAVE(dp)
|
||||
if (status != 0) {
|
||||
dp->di_bsddb = NULL;
|
||||
PyErr_SetFromErrno(BsddbError);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
dp->di_bsddb = NULL;
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
bsddb_keys(bsddbobject *dp)
|
||||
{
|
||||
PyObject *list, *item=NULL;
|
||||
DBT krec, drec;
|
||||
char *data=NULL,buf[4096];
|
||||
int status;
|
||||
int err;
|
||||
|
||||
check_bsddbobject_open(dp, NULL);
|
||||
list = PyList_New(0);
|
||||
if (list == NULL)
|
||||
return NULL;
|
||||
BSDDB_BGN_SAVE(dp)
|
||||
status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec, R_FIRST);
|
||||
if (status == 0) {
|
||||
if (krec.size > sizeof(buf)) data = malloc(krec.size);
|
||||
else data = buf;
|
||||
if (data != NULL) memcpy(data,krec.data,krec.size);
|
||||
}
|
||||
BSDDB_END_SAVE(dp)
|
||||
if (status == 0 && data==NULL) return PyErr_NoMemory();
|
||||
while (status == 0) {
|
||||
if (dp->di_type == DB_RECNO)
|
||||
item = PyInt_FromLong(*((int*)data));
|
||||
else
|
||||
item = PyString_FromStringAndSize(data,
|
||||
(int)krec.size);
|
||||
if (data != buf) free(data);
|
||||
if (item == NULL) {
|
||||
Py_DECREF(list);
|
||||
return NULL;
|
||||
}
|
||||
err = PyList_Append(list, item);
|
||||
Py_DECREF(item);
|
||||
if (err != 0) {
|
||||
Py_DECREF(list);
|
||||
return NULL;
|
||||
}
|
||||
BSDDB_BGN_SAVE(dp)
|
||||
status = (dp->di_bsddb->seq)
|
||||
(dp->di_bsddb, &krec, &drec, R_NEXT);
|
||||
if (status == 0) {
|
||||
if (krec.size > sizeof(buf))
|
||||
data = malloc(krec.size);
|
||||
else data = buf;
|
||||
if (data != NULL)
|
||||
memcpy(data,krec.data,krec.size);
|
||||
}
|
||||
BSDDB_END_SAVE(dp)
|
||||
if (data == NULL) return PyErr_NoMemory();
|
||||
}
|
||||
if (status < 0) {
|
||||
PyErr_SetFromErrno(BsddbError);
|
||||
Py_DECREF(list);
|
||||
return NULL;
|
||||
}
|
||||
if (dp->di_size < 0)
|
||||
dp->di_size = PyList_Size(list); /* We just did the work */
|
||||
return list;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
bsddb_has_key(bsddbobject *dp, PyObject *args)
|
||||
{
|
||||
DBT krec, drec;
|
||||
int status;
|
||||
char *data;
|
||||
int size;
|
||||
recno_t recno;
|
||||
|
||||
if (dp->di_type == DB_RECNO) {
|
||||
if (!PyArg_ParseTuple(args, "i;key type must be integer",
|
||||
&recno)) {
|
||||
return NULL;
|
||||
}
|
||||
krec.data = &recno;
|
||||
krec.size = sizeof(recno);
|
||||
}
|
||||
else {
|
||||
if (!PyArg_ParseTuple(args, "s#;key type must be string",
|
||||
&data, &size)) {
|
||||
return NULL;
|
||||
}
|
||||
krec.data = data;
|
||||
krec.size = size;
|
||||
}
|
||||
check_bsddbobject_open(dp, NULL);
|
||||
|
||||
BSDDB_BGN_SAVE(dp)
|
||||
status = (dp->di_bsddb->get)(dp->di_bsddb, &krec, &drec, 0);
|
||||
BSDDB_END_SAVE(dp)
|
||||
if (status < 0) {
|
||||
PyErr_SetFromErrno(BsddbError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return PyInt_FromLong(status == 0);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
bsddb_set_location(bsddbobject *dp, PyObject *key)
|
||||
{
|
||||
int status;
|
||||
DBT krec, drec;
|
||||
char *data = NULL;
|
||||
char buf[4096];
|
||||
int size;
|
||||
PyObject *result;
|
||||
recno_t recno;
|
||||
|
||||
if (dp->di_type == DB_RECNO) {
|
||||
if (!PyArg_ParseTuple(key, "i;key type must be integer",
|
||||
&recno)) {
|
||||
return NULL;
|
||||
}
|
||||
krec.data = &recno;
|
||||
krec.size = sizeof(recno);
|
||||
}
|
||||
else {
|
||||
if (!PyArg_ParseTuple(key, "s#;key type must be string",
|
||||
&data, &size)) {
|
||||
return NULL;
|
||||
}
|
||||
krec.data = data;
|
||||
krec.size = size;
|
||||
}
|
||||
check_bsddbobject_open(dp, NULL);
|
||||
|
||||
BSDDB_BGN_SAVE(dp)
|
||||
status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec, R_CURSOR);
|
||||
if (status == 0) {
|
||||
if (drec.size > sizeof(buf)) data = malloc(drec.size);
|
||||
else data = buf;
|
||||
if (data!=NULL) memcpy(data,drec.data,drec.size);
|
||||
}
|
||||
BSDDB_END_SAVE(dp)
|
||||
if (data==NULL) return PyErr_NoMemory();
|
||||
if (status != 0) {
|
||||
if (status < 0)
|
||||
PyErr_SetFromErrno(BsddbError);
|
||||
else
|
||||
PyErr_SetObject(PyExc_KeyError, key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dp->di_type == DB_RECNO)
|
||||
result = Py_BuildValue("is#", *((int*)krec.data),
|
||||
data, drec.size);
|
||||
else
|
||||
result = Py_BuildValue("s#s#", krec.data, krec.size,
|
||||
data, drec.size);
|
||||
if (data != buf) free(data);
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
bsddb_seq(bsddbobject *dp, int sequence_request)
|
||||
{
|
||||
int status;
|
||||
DBT krec, drec;
|
||||
char *kdata=NULL,kbuf[4096];
|
||||
char *ddata=NULL,dbuf[4096];
|
||||
PyObject *result;
|
||||
|
||||
check_bsddbobject_open(dp, NULL);
|
||||
krec.data = 0;
|
||||
krec.size = 0;
|
||||
|
||||
BSDDB_BGN_SAVE(dp)
|
||||
status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec,
|
||||
&drec, sequence_request);
|
||||
if (status == 0) {
|
||||
if (krec.size > sizeof(kbuf)) kdata = malloc(krec.size);
|
||||
else kdata = kbuf;
|
||||
if (kdata != NULL) memcpy(kdata,krec.data,krec.size);
|
||||
if (drec.size > sizeof(dbuf)) ddata = malloc(drec.size);
|
||||
else ddata = dbuf;
|
||||
if (ddata != NULL) memcpy(ddata,drec.data,drec.size);
|
||||
}
|
||||
BSDDB_END_SAVE(dp)
|
||||
if (status == 0) {
|
||||
if ((kdata == NULL) || (ddata == NULL))
|
||||
return PyErr_NoMemory();
|
||||
}
|
||||
else {
|
||||
/* (status != 0) */
|
||||
if (status < 0)
|
||||
PyErr_SetFromErrno(BsddbError);
|
||||
else
|
||||
PyErr_SetString(PyExc_KeyError, "no key/data pairs");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dp->di_type == DB_RECNO)
|
||||
result = Py_BuildValue("is#", *((int*)kdata),
|
||||
ddata, drec.size);
|
||||
else
|
||||
result = Py_BuildValue("s#s#", kdata, krec.size,
|
||||
ddata, drec.size);
|
||||
if (kdata != kbuf) free(kdata);
|
||||
if (ddata != dbuf) free(ddata);
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
bsddb_next(bsddbobject *dp)
|
||||
{
|
||||
return bsddb_seq(dp, R_NEXT);
|
||||
}
|
||||
static PyObject *
|
||||
bsddb_previous(bsddbobject *dp)
|
||||
{
|
||||
return bsddb_seq(dp, R_PREV);
|
||||
}
|
||||
static PyObject *
|
||||
bsddb_first(bsddbobject *dp)
|
||||
{
|
||||
return bsddb_seq(dp, R_FIRST);
|
||||
}
|
||||
static PyObject *
|
||||
bsddb_last(bsddbobject *dp)
|
||||
{
|
||||
return bsddb_seq(dp, R_LAST);
|
||||
}
|
||||
static PyObject *
|
||||
bsddb_sync(bsddbobject *dp)
|
||||
{
|
||||
int status;
|
||||
|
||||
check_bsddbobject_open(dp, NULL);
|
||||
BSDDB_BGN_SAVE(dp)
|
||||
status = (dp->di_bsddb->sync)(dp->di_bsddb, 0);
|
||||
BSDDB_END_SAVE(dp)
|
||||
if (status != 0) {
|
||||
PyErr_SetFromErrno(BsddbError);
|
||||
return NULL;
|
||||
}
|
||||
return PyInt_FromLong(0);
|
||||
}
|
||||
static PyMethodDef bsddb_methods[] = {
|
||||
{"close", (PyCFunction)bsddb_close, METH_NOARGS},
|
||||
{"keys", (PyCFunction)bsddb_keys, METH_NOARGS},
|
||||
{"has_key", (PyCFunction)bsddb_has_key, METH_VARARGS},
|
||||
{"set_location", (PyCFunction)bsddb_set_location, METH_VARARGS},
|
||||
{"next", (PyCFunction)bsddb_next, METH_NOARGS},
|
||||
{"previous", (PyCFunction)bsddb_previous, METH_NOARGS},
|
||||
{"first", (PyCFunction)bsddb_first, METH_NOARGS},
|
||||
{"last", (PyCFunction)bsddb_last, METH_NOARGS},
|
||||
{"sync", (PyCFunction)bsddb_sync, METH_NOARGS},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
bsddb_getattr(PyObject *dp, char *name)
|
||||
{
|
||||
return Py_FindMethod(bsddb_methods, dp, name);
|
||||
}
|
||||
|
||||
static PyTypeObject Bsddbtype = {
|
||||
PyObject_HEAD_INIT(NULL)
|
||||
0,
|
||||
"bsddb.bsddb",
|
||||
sizeof(bsddbobject),
|
||||
0,
|
||||
(destructor)bsddb_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
(getattrfunc)bsddb_getattr, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
0, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
&bsddb_as_mapping, /*tp_as_mapping*/
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
bsdhashopen(PyObject *self, PyObject *args)
|
||||
{
|
||||
char *file;
|
||||
char *flag = NULL;
|
||||
int flags = O_RDONLY;
|
||||
int mode = 0666;
|
||||
int bsize = 0;
|
||||
int ffactor = 0;
|
||||
int nelem = 0;
|
||||
int cachesize = 0;
|
||||
int hash = 0; /* XXX currently ignored */
|
||||
int lorder = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "z|siiiiiii:hashopen",
|
||||
&file, &flag, &mode,
|
||||
&bsize, &ffactor, &nelem, &cachesize,
|
||||
&hash, &lorder))
|
||||
return NULL;
|
||||
if (flag != NULL) {
|
||||
/* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
|
||||
if (flag[0] == 'r')
|
||||
flags = O_RDONLY;
|
||||
else if (flag[0] == 'w')
|
||||
flags = O_RDWR;
|
||||
else if (flag[0] == 'c')
|
||||
flags = O_RDWR|O_CREAT;
|
||||
else if (flag[0] == 'n')
|
||||
flags = O_RDWR|O_CREAT|O_TRUNC;
|
||||
else {
|
||||
PyErr_SetString(BsddbError,
|
||||
"Flag should begin with 'r', 'w', 'c' or 'n'");
|
||||
return NULL;
|
||||
}
|
||||
if (flag[1] == 'l') {
|
||||
#if defined(O_EXLOCK) && defined(O_SHLOCK)
|
||||
if (flag[0] == 'r')
|
||||
flags |= O_SHLOCK;
|
||||
else
|
||||
flags |= O_EXLOCK;
|
||||
#else
|
||||
PyErr_SetString(BsddbError,
|
||||
"locking not supported on this platform");
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return newdbhashobject(file, flags, mode,
|
||||
bsize, ffactor, nelem, cachesize, hash, lorder);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
bsdbtopen(PyObject *self, PyObject *args)
|
||||
{
|
||||
char *file;
|
||||
char *flag = NULL;
|
||||
int flags = O_RDONLY;
|
||||
int mode = 0666;
|
||||
int cachesize = 0;
|
||||
int maxkeypage = 0;
|
||||
int minkeypage = 0;
|
||||
int btflags = 0;
|
||||
unsigned int psize = 0;
|
||||
int lorder = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "z|siiiiiii:btopen",
|
||||
&file, &flag, &mode,
|
||||
&btflags, &cachesize, &maxkeypage, &minkeypage,
|
||||
&psize, &lorder))
|
||||
return NULL;
|
||||
if (flag != NULL) {
|
||||
/* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
|
||||
if (flag[0] == 'r')
|
||||
flags = O_RDONLY;
|
||||
else if (flag[0] == 'w')
|
||||
flags = O_RDWR;
|
||||
else if (flag[0] == 'c')
|
||||
flags = O_RDWR|O_CREAT;
|
||||
else if (flag[0] == 'n')
|
||||
flags = O_RDWR|O_CREAT|O_TRUNC;
|
||||
else {
|
||||
PyErr_SetString(BsddbError,
|
||||
"Flag should begin with 'r', 'w', 'c' or 'n'");
|
||||
return NULL;
|
||||
}
|
||||
if (flag[1] == 'l') {
|
||||
#if defined(O_EXLOCK) && defined(O_SHLOCK)
|
||||
if (flag[0] == 'r')
|
||||
flags |= O_SHLOCK;
|
||||
else
|
||||
flags |= O_EXLOCK;
|
||||
#else
|
||||
PyErr_SetString(BsddbError,
|
||||
"locking not supported on this platform");
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return newdbbtobject(file, flags, mode,
|
||||
btflags, cachesize, maxkeypage, minkeypage,
|
||||
psize, lorder);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
bsdrnopen(PyObject *self, PyObject *args)
|
||||
{
|
||||
char *file;
|
||||
char *flag = NULL;
|
||||
int flags = O_RDONLY;
|
||||
int mode = 0666;
|
||||
int cachesize = 0;
|
||||
int rnflags = 0;
|
||||
unsigned int psize = 0;
|
||||
int lorder = 0;
|
||||
size_t reclen = 0;
|
||||
char *bval = "";
|
||||
char *bfname = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "z|siiiiiiss:rnopen",
|
||||
&file, &flag, &mode,
|
||||
&rnflags, &cachesize, &psize, &lorder,
|
||||
&reclen, &bval, &bfname))
|
||||
return NULL;
|
||||
|
||||
if (flag != NULL) {
|
||||
/* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
|
||||
if (flag[0] == 'r')
|
||||
flags = O_RDONLY;
|
||||
else if (flag[0] == 'w')
|
||||
flags = O_RDWR;
|
||||
else if (flag[0] == 'c')
|
||||
flags = O_RDWR|O_CREAT;
|
||||
else if (flag[0] == 'n')
|
||||
flags = O_RDWR|O_CREAT|O_TRUNC;
|
||||
else {
|
||||
PyErr_SetString(BsddbError,
|
||||
"Flag should begin with 'r', 'w', 'c' or 'n'");
|
||||
return NULL;
|
||||
}
|
||||
if (flag[1] == 'l') {
|
||||
#if defined(O_EXLOCK) && defined(O_SHLOCK)
|
||||
if (flag[0] == 'r')
|
||||
flags |= O_SHLOCK;
|
||||
else
|
||||
flags |= O_EXLOCK;
|
||||
#else
|
||||
PyErr_SetString(BsddbError,
|
||||
"locking not supported on this platform");
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
else if (flag[1] != '\0') {
|
||||
PyErr_SetString(BsddbError,
|
||||
"Flag char 2 should be 'l' or absent");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return newdbrnobject(file, flags, mode, rnflags, cachesize,
|
||||
psize, lorder, reclen, bval[0], bfname);
|
||||
}
|
||||
|
||||
static PyMethodDef bsddbmodule_methods[] = {
|
||||
{"hashopen", (PyCFunction)bsdhashopen, METH_VARARGS},
|
||||
{"btopen", (PyCFunction)bsdbtopen, METH_VARARGS},
|
||||
{"rnopen", (PyCFunction)bsdrnopen, METH_VARARGS},
|
||||
/* strictly for use by dbhhash!!! */
|
||||
{"open", (PyCFunction)bsdhashopen, METH_VARARGS},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC
|
||||
initbsddb185(void) {
|
||||
PyObject *m, *d;
|
||||
|
||||
if (PyErr_WarnPy3k("the bsddb185 module has been removed in "
|
||||
"Python 3.0", 2) < 0)
|
||||
return;
|
||||
|
||||
Bsddbtype.ob_type = &PyType_Type;
|
||||
m = Py_InitModule("bsddb185", bsddbmodule_methods);
|
||||
if (m == NULL)
|
||||
return;
|
||||
d = PyModule_GetDict(m);
|
||||
BsddbError = PyErr_NewException("bsddb.error", NULL, NULL);
|
||||
if (BsddbError != NULL)
|
||||
PyDict_SetItemString(d, "error", BsddbError);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+6074
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,779 @@
|
||||
|
||||
#include "Python.h"
|
||||
#include "import.h"
|
||||
#include "cStringIO.h"
|
||||
#include "structmember.h"
|
||||
|
||||
PyDoc_STRVAR(cStringIO_module_documentation,
|
||||
"A simple fast partial StringIO replacement.\n"
|
||||
"\n"
|
||||
"This module provides a simple useful replacement for\n"
|
||||
"the StringIO module that is written in C. It does not provide the\n"
|
||||
"full generality of StringIO, but it provides enough for most\n"
|
||||
"applications and is especially useful in conjunction with the\n"
|
||||
"pickle module.\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
"\n"
|
||||
" from cStringIO import StringIO\n"
|
||||
"\n"
|
||||
" an_output_stream=StringIO()\n"
|
||||
" an_output_stream.write(some_stuff)\n"
|
||||
" ...\n"
|
||||
" value=an_output_stream.getvalue()\n"
|
||||
"\n"
|
||||
" an_input_stream=StringIO(a_string)\n"
|
||||
" spam=an_input_stream.readline()\n"
|
||||
" spam=an_input_stream.read(5)\n"
|
||||
" an_input_stream.seek(0) # OK, start over\n"
|
||||
" spam=an_input_stream.read() # and read it all\n"
|
||||
" \n"
|
||||
"If someone else wants to provide a more complete implementation,\n"
|
||||
"go for it. :-) \n"
|
||||
"\n"
|
||||
"cStringIO.c,v 1.29 1999/06/15 14:10:27 jim Exp\n");
|
||||
|
||||
/* Declaration for file-like objects that manage data as strings
|
||||
|
||||
The IOobject type should be though of as a common base type for
|
||||
Iobjects, which provide input (read-only) StringIO objects and
|
||||
Oobjects, which provide read-write objects. Most of the methods
|
||||
depend only on common data.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
char *buf;
|
||||
Py_ssize_t pos, string_size;
|
||||
} IOobject;
|
||||
|
||||
#define IOOOBJECT(O) ((IOobject*)(O))
|
||||
|
||||
/* Declarations for objects of type StringO */
|
||||
|
||||
typedef struct { /* Subtype of IOobject */
|
||||
PyObject_HEAD
|
||||
char *buf;
|
||||
Py_ssize_t pos, string_size;
|
||||
|
||||
Py_ssize_t buf_size;
|
||||
int softspace;
|
||||
} Oobject;
|
||||
|
||||
/* Declarations for objects of type StringI */
|
||||
|
||||
typedef struct { /* Subtype of IOobject */
|
||||
PyObject_HEAD
|
||||
char *buf;
|
||||
Py_ssize_t pos, string_size;
|
||||
Py_buffer pbuf;
|
||||
} Iobject;
|
||||
|
||||
/* IOobject (common) methods */
|
||||
|
||||
PyDoc_STRVAR(IO_flush__doc__, "flush(): does nothing.");
|
||||
|
||||
static int
|
||||
IO__opencheck(IOobject *self) {
|
||||
if (!self->buf) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"I/O operation on closed file");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
IO_get_closed(IOobject *self, void *closure)
|
||||
{
|
||||
PyObject *result = Py_False;
|
||||
|
||||
if (self->buf == NULL)
|
||||
result = Py_True;
|
||||
Py_INCREF(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyGetSetDef file_getsetlist[] = {
|
||||
{"closed", (getter)IO_get_closed, NULL, "True if the file is closed"},
|
||||
{0},
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
IO_flush(IOobject *self, PyObject *unused) {
|
||||
|
||||
if (!IO__opencheck(self)) return NULL;
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(IO_getval__doc__,
|
||||
"getvalue([use_pos]) -- Get the string value."
|
||||
"\n"
|
||||
"If use_pos is specified and is a true value, then the string returned\n"
|
||||
"will include only the text up to the current file position.\n");
|
||||
|
||||
static PyObject *
|
||||
IO_cgetval(PyObject *self) {
|
||||
if (!IO__opencheck(IOOOBJECT(self))) return NULL;
|
||||
assert(IOOOBJECT(self)->pos >= 0);
|
||||
return PyString_FromStringAndSize(((IOobject*)self)->buf,
|
||||
((IOobject*)self)->pos);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
IO_getval(IOobject *self, PyObject *args) {
|
||||
PyObject *use_pos=Py_None;
|
||||
int b;
|
||||
Py_ssize_t s;
|
||||
|
||||
if (!IO__opencheck(self)) return NULL;
|
||||
if (!PyArg_UnpackTuple(args,"getval", 0, 1,&use_pos)) return NULL;
|
||||
|
||||
b = PyObject_IsTrue(use_pos);
|
||||
if (b < 0)
|
||||
return NULL;
|
||||
if (b) {
|
||||
s=self->pos;
|
||||
if (s > self->string_size) s=self->string_size;
|
||||
}
|
||||
else
|
||||
s=self->string_size;
|
||||
assert(self->pos >= 0);
|
||||
return PyString_FromStringAndSize(self->buf, s);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(IO_isatty__doc__, "isatty(): always returns 0");
|
||||
|
||||
static PyObject *
|
||||
IO_isatty(IOobject *self, PyObject *unused) {
|
||||
if (!IO__opencheck(self)) return NULL;
|
||||
Py_INCREF(Py_False);
|
||||
return Py_False;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(IO_read__doc__,
|
||||
"read([s]) -- Read s characters, or the rest of the string");
|
||||
|
||||
static int
|
||||
IO_cread(PyObject *self, char **output, Py_ssize_t n) {
|
||||
Py_ssize_t l;
|
||||
|
||||
if (!IO__opencheck(IOOOBJECT(self))) return -1;
|
||||
assert(IOOOBJECT(self)->pos >= 0);
|
||||
assert(IOOOBJECT(self)->string_size >= 0);
|
||||
l = ((IOobject*)self)->string_size - ((IOobject*)self)->pos;
|
||||
if (n < 0 || n > l) {
|
||||
n = l;
|
||||
if (n < 0) n=0;
|
||||
}
|
||||
if (n > INT_MAX) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"length too large");
|
||||
return -1;
|
||||
}
|
||||
|
||||
*output=((IOobject*)self)->buf + ((IOobject*)self)->pos;
|
||||
((IOobject*)self)->pos += n;
|
||||
return (int)n;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
IO_read(IOobject *self, PyObject *args) {
|
||||
Py_ssize_t n = -1;
|
||||
char *output = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|n:read", &n)) return NULL;
|
||||
|
||||
if ( (n=IO_cread((PyObject*)self,&output,n)) < 0) return NULL;
|
||||
|
||||
return PyString_FromStringAndSize(output, n);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(IO_readline__doc__, "readline() -- Read one line");
|
||||
|
||||
static int
|
||||
IO_creadline(PyObject *self, char **output) {
|
||||
char *n, *start, *end;
|
||||
Py_ssize_t len;
|
||||
|
||||
if (!IO__opencheck(IOOOBJECT(self))) return -1;
|
||||
|
||||
n = start = ((IOobject*)self)->buf + ((IOobject*)self)->pos;
|
||||
end = ((IOobject*)self)->buf + ((IOobject*)self)->string_size;
|
||||
while (n < end && *n != '\n')
|
||||
n++;
|
||||
|
||||
if (n < end) n++;
|
||||
|
||||
len = n - start;
|
||||
if (len > INT_MAX)
|
||||
len = INT_MAX;
|
||||
|
||||
*output=start;
|
||||
|
||||
assert(IOOOBJECT(self)->pos <= PY_SSIZE_T_MAX - len);
|
||||
assert(IOOOBJECT(self)->pos >= 0);
|
||||
assert(IOOOBJECT(self)->string_size >= 0);
|
||||
|
||||
((IOobject*)self)->pos += len;
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
IO_readline(IOobject *self, PyObject *args) {
|
||||
int n, m=-1;
|
||||
char *output;
|
||||
|
||||
if (args)
|
||||
if (!PyArg_ParseTuple(args, "|i:readline", &m)) return NULL;
|
||||
|
||||
if( (n=IO_creadline((PyObject*)self,&output)) < 0) return NULL;
|
||||
if (m >= 0 && m < n) {
|
||||
m = n - m;
|
||||
n -= m;
|
||||
self->pos -= m;
|
||||
}
|
||||
assert(IOOOBJECT(self)->pos >= 0);
|
||||
return PyString_FromStringAndSize(output, n);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(IO_readlines__doc__, "readlines() -- Read all lines");
|
||||
|
||||
static PyObject *
|
||||
IO_readlines(IOobject *self, PyObject *args) {
|
||||
int n;
|
||||
char *output;
|
||||
PyObject *result, *line;
|
||||
Py_ssize_t hint = 0, length = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|n:readlines", &hint)) return NULL;
|
||||
|
||||
result = PyList_New(0);
|
||||
if (!result)
|
||||
return NULL;
|
||||
|
||||
while (1){
|
||||
if ( (n = IO_creadline((PyObject*)self,&output)) < 0)
|
||||
goto err;
|
||||
if (n == 0)
|
||||
break;
|
||||
line = PyString_FromStringAndSize (output, n);
|
||||
if (!line)
|
||||
goto err;
|
||||
if (PyList_Append (result, line) == -1) {
|
||||
Py_DECREF (line);
|
||||
goto err;
|
||||
}
|
||||
Py_DECREF (line);
|
||||
length += n;
|
||||
if (hint > 0 && length >= hint)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
err:
|
||||
Py_DECREF(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(IO_reset__doc__,
|
||||
"reset() -- Reset the file position to the beginning");
|
||||
|
||||
static PyObject *
|
||||
IO_reset(IOobject *self, PyObject *unused) {
|
||||
|
||||
if (!IO__opencheck(self)) return NULL;
|
||||
|
||||
self->pos = 0;
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(IO_tell__doc__, "tell() -- get the current position.");
|
||||
|
||||
static PyObject *
|
||||
IO_tell(IOobject *self, PyObject *unused) {
|
||||
|
||||
if (!IO__opencheck(self)) return NULL;
|
||||
|
||||
assert(self->pos >= 0);
|
||||
return PyInt_FromSsize_t(self->pos);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(IO_truncate__doc__,
|
||||
"truncate(): truncate the file at the current position.");
|
||||
|
||||
static PyObject *
|
||||
IO_truncate(IOobject *self, PyObject *args) {
|
||||
Py_ssize_t pos = -1;
|
||||
|
||||
if (!IO__opencheck(self)) return NULL;
|
||||
if (!PyArg_ParseTuple(args, "|n:truncate", &pos)) return NULL;
|
||||
|
||||
if (PyTuple_Size(args) == 0) {
|
||||
/* No argument passed, truncate to current position */
|
||||
pos = self->pos;
|
||||
}
|
||||
|
||||
if (pos < 0) {
|
||||
errno = EINVAL;
|
||||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (self->string_size > pos) self->string_size = pos;
|
||||
self->pos = self->string_size;
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
IO_iternext(Iobject *self)
|
||||
{
|
||||
PyObject *next;
|
||||
next = IO_readline((IOobject *)self, NULL);
|
||||
if (!next)
|
||||
return NULL;
|
||||
if (!PyString_GET_SIZE(next)) {
|
||||
Py_DECREF(next);
|
||||
PyErr_SetNone(PyExc_StopIteration);
|
||||
return NULL;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Read-write object methods */
|
||||
|
||||
PyDoc_STRVAR(IO_seek__doc__,
|
||||
"seek(position) -- set the current position\n"
|
||||
"seek(position, mode) -- mode 0: absolute; 1: relative; 2: relative to EOF");
|
||||
|
||||
static PyObject *
|
||||
IO_seek(Iobject *self, PyObject *args) {
|
||||
Py_ssize_t position;
|
||||
int mode = 0;
|
||||
|
||||
if (!IO__opencheck(IOOOBJECT(self))) return NULL;
|
||||
if (!PyArg_ParseTuple(args, "n|i:seek", &position, &mode))
|
||||
return NULL;
|
||||
|
||||
if (mode == 2) {
|
||||
position += self->string_size;
|
||||
}
|
||||
else if (mode == 1) {
|
||||
position += self->pos;
|
||||
}
|
||||
|
||||
if (position < 0) position=0;
|
||||
|
||||
self->pos=position;
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(O_write__doc__,
|
||||
"write(s) -- Write a string to the file"
|
||||
"\n\nNote (hack:) writing None resets the buffer");
|
||||
|
||||
|
||||
static int
|
||||
O_cwrite(PyObject *self, const char *c, Py_ssize_t len) {
|
||||
Py_ssize_t newpos;
|
||||
Oobject *oself;
|
||||
char *newbuf;
|
||||
|
||||
if (!IO__opencheck(IOOOBJECT(self))) return -1;
|
||||
oself = (Oobject *)self;
|
||||
|
||||
if (len > INT_MAX) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"length too large");
|
||||
return -1;
|
||||
}
|
||||
assert(len >= 0);
|
||||
if (oself->pos >= PY_SSIZE_T_MAX - len) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"new position too large");
|
||||
return -1;
|
||||
}
|
||||
newpos = oself->pos + len;
|
||||
if (newpos >= oself->buf_size) {
|
||||
size_t newsize = oself->buf_size;
|
||||
newsize *= 2;
|
||||
if (newsize <= (size_t)newpos || newsize > PY_SSIZE_T_MAX) {
|
||||
assert(newpos < PY_SSIZE_T_MAX - 1);
|
||||
newsize = newpos + 1;
|
||||
}
|
||||
newbuf = (char*)realloc(oself->buf, newsize);
|
||||
if (!newbuf) {
|
||||
PyErr_SetString(PyExc_MemoryError,"out of memory");
|
||||
return -1;
|
||||
}
|
||||
oself->buf_size = (Py_ssize_t)newsize;
|
||||
oself->buf = newbuf;
|
||||
}
|
||||
|
||||
if (oself->string_size < oself->pos) {
|
||||
/* In case of overseek, pad with null bytes the buffer region between
|
||||
the end of stream and the current position.
|
||||
|
||||
0 lo string_size hi
|
||||
| |<---used--->|<----------available----------->|
|
||||
| | <--to pad-->|<---to write---> |
|
||||
0 buf position
|
||||
*/
|
||||
memset(oself->buf + oself->string_size, '\0',
|
||||
(oself->pos - oself->string_size) * sizeof(char));
|
||||
}
|
||||
|
||||
memcpy(oself->buf + oself->pos, c, len);
|
||||
|
||||
oself->pos = newpos;
|
||||
|
||||
if (oself->string_size < oself->pos) {
|
||||
oself->string_size = oself->pos;
|
||||
}
|
||||
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
O_write(Oobject *self, PyObject *args) {
|
||||
Py_buffer buf;
|
||||
int result;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s*:write", &buf)) return NULL;
|
||||
|
||||
result = O_cwrite((PyObject*)self, buf.buf, buf.len);
|
||||
PyBuffer_Release(&buf);
|
||||
if (result < 0) return NULL;
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(O_close__doc__, "close(): explicitly release resources held.");
|
||||
|
||||
static PyObject *
|
||||
O_close(Oobject *self, PyObject *unused) {
|
||||
if (self->buf != NULL) free(self->buf);
|
||||
self->buf = NULL;
|
||||
|
||||
self->pos = self->string_size = self->buf_size = 0;
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(O_writelines__doc__,
|
||||
"writelines(sequence_of_strings) -> None. Write the strings to the file.\n"
|
||||
"\n"
|
||||
"Note that newlines are not added. The sequence can be any iterable object\n"
|
||||
"producing strings. This is equivalent to calling write() for each string.");
|
||||
static PyObject *
|
||||
O_writelines(Oobject *self, PyObject *args) {
|
||||
PyObject *it, *s;
|
||||
|
||||
it = PyObject_GetIter(args);
|
||||
if (it == NULL)
|
||||
return NULL;
|
||||
while ((s = PyIter_Next(it)) != NULL) {
|
||||
Py_ssize_t n;
|
||||
char *c;
|
||||
if (PyString_AsStringAndSize(s, &c, &n) == -1) {
|
||||
Py_DECREF(it);
|
||||
Py_DECREF(s);
|
||||
return NULL;
|
||||
}
|
||||
if (O_cwrite((PyObject *)self, c, n) == -1) {
|
||||
Py_DECREF(it);
|
||||
Py_DECREF(s);
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(s);
|
||||
}
|
||||
|
||||
Py_DECREF(it);
|
||||
|
||||
/* See if PyIter_Next failed */
|
||||
if (PyErr_Occurred())
|
||||
return NULL;
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
static struct PyMethodDef O_methods[] = {
|
||||
/* Common methods: */
|
||||
{"flush", (PyCFunction)IO_flush, METH_NOARGS, IO_flush__doc__},
|
||||
{"getvalue", (PyCFunction)IO_getval, METH_VARARGS, IO_getval__doc__},
|
||||
{"isatty", (PyCFunction)IO_isatty, METH_NOARGS, IO_isatty__doc__},
|
||||
{"read", (PyCFunction)IO_read, METH_VARARGS, IO_read__doc__},
|
||||
{"readline", (PyCFunction)IO_readline, METH_VARARGS, IO_readline__doc__},
|
||||
{"readlines", (PyCFunction)IO_readlines,METH_VARARGS, IO_readlines__doc__},
|
||||
{"reset", (PyCFunction)IO_reset, METH_NOARGS, IO_reset__doc__},
|
||||
{"seek", (PyCFunction)IO_seek, METH_VARARGS, IO_seek__doc__},
|
||||
{"tell", (PyCFunction)IO_tell, METH_NOARGS, IO_tell__doc__},
|
||||
{"truncate", (PyCFunction)IO_truncate, METH_VARARGS, IO_truncate__doc__},
|
||||
|
||||
/* Read-write StringIO specific methods: */
|
||||
{"close", (PyCFunction)O_close, METH_NOARGS, O_close__doc__},
|
||||
{"write", (PyCFunction)O_write, METH_VARARGS, O_write__doc__},
|
||||
{"writelines", (PyCFunction)O_writelines, METH_O, O_writelines__doc__},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static PyMemberDef O_memberlist[] = {
|
||||
{"softspace", T_INT, offsetof(Oobject, softspace), 0,
|
||||
"flag indicating that a space needs to be printed; used by print"},
|
||||
/* getattr(f, "closed") is implemented without this table */
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static void
|
||||
O_dealloc(Oobject *self) {
|
||||
if (self->buf != NULL)
|
||||
free(self->buf);
|
||||
PyObject_Del(self);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Otype__doc__, "Simple type for output to strings.");
|
||||
|
||||
static PyTypeObject Otype = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"cStringIO.StringO", /*tp_name*/
|
||||
sizeof(Oobject), /*tp_basicsize*/
|
||||
0, /*tp_itemsize*/
|
||||
/* methods */
|
||||
(destructor)O_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
0, /*tp_getattr */
|
||||
0, /*tp_setattr */
|
||||
0, /*tp_compare*/
|
||||
0, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
0, /*tp_hash*/
|
||||
0 , /*tp_call*/
|
||||
0, /*tp_str*/
|
||||
0, /*tp_getattro */
|
||||
0, /*tp_setattro */
|
||||
0, /*tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
||||
Otype__doc__, /*tp_doc */
|
||||
0, /*tp_traverse */
|
||||
0, /*tp_clear */
|
||||
0, /*tp_richcompare */
|
||||
0, /*tp_weaklistoffset */
|
||||
PyObject_SelfIter, /*tp_iter */
|
||||
(iternextfunc)IO_iternext, /*tp_iternext */
|
||||
O_methods, /*tp_methods */
|
||||
O_memberlist, /*tp_members */
|
||||
file_getsetlist, /*tp_getset */
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
newOobject(int size) {
|
||||
Oobject *self;
|
||||
|
||||
self = PyObject_New(Oobject, &Otype);
|
||||
if (self == NULL)
|
||||
return NULL;
|
||||
self->pos=0;
|
||||
self->string_size = 0;
|
||||
self->softspace = 0;
|
||||
|
||||
self->buf = (char *)malloc(size);
|
||||
if (!self->buf) {
|
||||
PyErr_SetString(PyExc_MemoryError,"out of memory");
|
||||
self->buf_size = 0;
|
||||
Py_DECREF(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->buf_size=size;
|
||||
return (PyObject*)self;
|
||||
}
|
||||
|
||||
/* End of code for StringO objects */
|
||||
/* -------------------------------------------------------- */
|
||||
|
||||
static PyObject *
|
||||
I_close(Iobject *self, PyObject *unused) {
|
||||
PyBuffer_Release(&self->pbuf);
|
||||
self->buf = NULL;
|
||||
|
||||
self->pos = self->string_size = 0;
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static struct PyMethodDef I_methods[] = {
|
||||
/* Common methods: */
|
||||
{"flush", (PyCFunction)IO_flush, METH_NOARGS, IO_flush__doc__},
|
||||
{"getvalue", (PyCFunction)IO_getval, METH_VARARGS, IO_getval__doc__},
|
||||
{"isatty", (PyCFunction)IO_isatty, METH_NOARGS, IO_isatty__doc__},
|
||||
{"read", (PyCFunction)IO_read, METH_VARARGS, IO_read__doc__},
|
||||
{"readline", (PyCFunction)IO_readline, METH_VARARGS, IO_readline__doc__},
|
||||
{"readlines", (PyCFunction)IO_readlines,METH_VARARGS, IO_readlines__doc__},
|
||||
{"reset", (PyCFunction)IO_reset, METH_NOARGS, IO_reset__doc__},
|
||||
{"seek", (PyCFunction)IO_seek, METH_VARARGS, IO_seek__doc__},
|
||||
{"tell", (PyCFunction)IO_tell, METH_NOARGS, IO_tell__doc__},
|
||||
{"truncate", (PyCFunction)IO_truncate, METH_VARARGS, IO_truncate__doc__},
|
||||
|
||||
/* Read-only StringIO specific methods: */
|
||||
{"close", (PyCFunction)I_close, METH_NOARGS, O_close__doc__},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static void
|
||||
I_dealloc(Iobject *self) {
|
||||
PyBuffer_Release(&self->pbuf);
|
||||
PyObject_Del(self);
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(Itype__doc__,
|
||||
"Simple type for treating strings as input file streams");
|
||||
|
||||
static PyTypeObject Itype = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"cStringIO.StringI", /*tp_name*/
|
||||
sizeof(Iobject), /*tp_basicsize*/
|
||||
0, /*tp_itemsize*/
|
||||
/* methods */
|
||||
(destructor)I_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
0, /* tp_getattr */
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
0, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
0, /*tp_hash*/
|
||||
0, /*tp_call*/
|
||||
0, /*tp_str*/
|
||||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
Itype__doc__, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
PyObject_SelfIter, /* tp_iter */
|
||||
(iternextfunc)IO_iternext, /* tp_iternext */
|
||||
I_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
file_getsetlist, /* tp_getset */
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
newIobject(PyObject *s) {
|
||||
Iobject *self;
|
||||
Py_buffer buf;
|
||||
PyObject *args;
|
||||
int result;
|
||||
|
||||
args = Py_BuildValue("(O)", s);
|
||||
if (args == NULL)
|
||||
return NULL;
|
||||
result = PyArg_ParseTuple(args, "s*:StringIO", &buf);
|
||||
Py_DECREF(args);
|
||||
if (!result)
|
||||
return NULL;
|
||||
|
||||
self = PyObject_New(Iobject, &Itype);
|
||||
if (!self) {
|
||||
PyBuffer_Release(&buf);
|
||||
return NULL;
|
||||
}
|
||||
self->buf=buf.buf;
|
||||
self->string_size=buf.len;
|
||||
self->pbuf=buf;
|
||||
self->pos=0;
|
||||
|
||||
return (PyObject*)self;
|
||||
}
|
||||
|
||||
/* End of code for StringI objects */
|
||||
/* -------------------------------------------------------- */
|
||||
|
||||
|
||||
PyDoc_STRVAR(IO_StringIO__doc__,
|
||||
"StringIO([s]) -- Return a StringIO-like stream for reading or writing");
|
||||
|
||||
static PyObject *
|
||||
IO_StringIO(PyObject *self, PyObject *args) {
|
||||
PyObject *s=0;
|
||||
|
||||
if (!PyArg_UnpackTuple(args, "StringIO", 0, 1, &s)) return NULL;
|
||||
|
||||
if (s) return newIobject(s);
|
||||
return newOobject(128);
|
||||
}
|
||||
|
||||
/* List of methods defined in the module */
|
||||
|
||||
static struct PyMethodDef IO_methods[] = {
|
||||
{"StringIO", (PyCFunction)IO_StringIO,
|
||||
METH_VARARGS, IO_StringIO__doc__},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
|
||||
/* Initialization function for the module (*must* be called initcStringIO) */
|
||||
|
||||
static struct PycStringIO_CAPI CAPI = {
|
||||
IO_cread,
|
||||
IO_creadline,
|
||||
O_cwrite,
|
||||
IO_cgetval,
|
||||
newOobject,
|
||||
newIobject,
|
||||
&Itype,
|
||||
&Otype,
|
||||
};
|
||||
|
||||
#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
|
||||
#define PyMODINIT_FUNC void
|
||||
#endif
|
||||
PyMODINIT_FUNC
|
||||
initcStringIO(void) {
|
||||
PyObject *m, *d, *v;
|
||||
|
||||
|
||||
/* Create the module and add the functions */
|
||||
m = Py_InitModule4("cStringIO", IO_methods,
|
||||
cStringIO_module_documentation,
|
||||
(PyObject*)NULL,PYTHON_API_VERSION);
|
||||
if (m == NULL) return;
|
||||
|
||||
/* Add some symbolic constants to the module */
|
||||
d = PyModule_GetDict(m);
|
||||
|
||||
/* Export C API */
|
||||
Py_TYPE(&Itype)=&PyType_Type;
|
||||
Py_TYPE(&Otype)=&PyType_Type;
|
||||
if (PyType_Ready(&Otype) < 0) return;
|
||||
if (PyType_Ready(&Itype) < 0) return;
|
||||
v = PyCapsule_New(&CAPI, PycStringIO_CAPSULE_NAME, NULL);
|
||||
PyDict_SetItemString(d,"cStringIO_CAPI", v);
|
||||
Py_XDECREF(v);
|
||||
|
||||
/* Export Types */
|
||||
PyDict_SetItemString(d,"InputType", (PyObject*)&Itype);
|
||||
PyDict_SetItemString(d,"OutputType", (PyObject*)&Otype);
|
||||
|
||||
/* Maybe make certain warnings go away */
|
||||
if (0) PycString_IMPORT;
|
||||
}
|
||||
@@ -0,0 +1,792 @@
|
||||
/* CD module -- interface to Mark Callow's and Roger Chickering's */
|
||||
/* CD Audio Library (CD). */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <cdaudio.h>
|
||||
#include "Python.h"
|
||||
|
||||
#define NCALLBACKS 8
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
CDPLAYER *ob_cdplayer;
|
||||
} cdplayerobject;
|
||||
|
||||
static PyObject *CdError; /* exception cd.error */
|
||||
|
||||
static PyObject *
|
||||
CD_allowremoval(cdplayerobject *self, PyObject *args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ":allowremoval"))
|
||||
return NULL;
|
||||
|
||||
CDallowremoval(self->ob_cdplayer);
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_preventremoval(cdplayerobject *self, PyObject *args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ":preventremoval"))
|
||||
return NULL;
|
||||
|
||||
CDpreventremoval(self->ob_cdplayer);
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_bestreadsize(cdplayerobject *self, PyObject *args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ":bestreadsize"))
|
||||
return NULL;
|
||||
|
||||
return PyInt_FromLong((long) CDbestreadsize(self->ob_cdplayer));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_close(cdplayerobject *self, PyObject *args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ":close"))
|
||||
return NULL;
|
||||
|
||||
if (!CDclose(self->ob_cdplayer)) {
|
||||
PyErr_SetFromErrno(CdError); /* XXX - ??? */
|
||||
return NULL;
|
||||
}
|
||||
self->ob_cdplayer = NULL;
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_eject(cdplayerobject *self, PyObject *args)
|
||||
{
|
||||
CDSTATUS status;
|
||||
|
||||
if (!PyArg_ParseTuple(args, ":eject"))
|
||||
return NULL;
|
||||
|
||||
if (!CDeject(self->ob_cdplayer)) {
|
||||
if (CDgetstatus(self->ob_cdplayer, &status) &&
|
||||
status.state == CD_NODISC)
|
||||
PyErr_SetString(CdError, "no disc in player");
|
||||
else
|
||||
PyErr_SetString(CdError, "eject failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_getstatus(cdplayerobject *self, PyObject *args)
|
||||
{
|
||||
CDSTATUS status;
|
||||
|
||||
if (!PyArg_ParseTuple(args, ":getstatus"))
|
||||
return NULL;
|
||||
|
||||
if (!CDgetstatus(self->ob_cdplayer, &status)) {
|
||||
PyErr_SetFromErrno(CdError); /* XXX - ??? */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return Py_BuildValue("(ii(iii)(iii)(iii)iiii)", status.state,
|
||||
status.track, status.min, status.sec, status.frame,
|
||||
status.abs_min, status.abs_sec, status.abs_frame,
|
||||
status.total_min, status.total_sec, status.total_frame,
|
||||
status.first, status.last, status.scsi_audio,
|
||||
status.cur_block);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_gettrackinfo(cdplayerobject *self, PyObject *args)
|
||||
{
|
||||
int track;
|
||||
CDTRACKINFO info;
|
||||
CDSTATUS status;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i:gettrackinfo", &track))
|
||||
return NULL;
|
||||
|
||||
if (!CDgettrackinfo(self->ob_cdplayer, track, &info)) {
|
||||
if (CDgetstatus(self->ob_cdplayer, &status) &&
|
||||
status.state == CD_NODISC)
|
||||
PyErr_SetString(CdError, "no disc in player");
|
||||
else
|
||||
PyErr_SetString(CdError, "gettrackinfo failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return Py_BuildValue("((iii)(iii))",
|
||||
info.start_min, info.start_sec, info.start_frame,
|
||||
info.total_min, info.total_sec, info.total_frame);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_msftoblock(cdplayerobject *self, PyObject *args)
|
||||
{
|
||||
int min, sec, frame;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "iii:msftoblock", &min, &sec, &frame))
|
||||
return NULL;
|
||||
|
||||
return PyInt_FromLong((long) CDmsftoblock(self->ob_cdplayer,
|
||||
min, sec, frame));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_play(cdplayerobject *self, PyObject *args)
|
||||
{
|
||||
int start, play;
|
||||
CDSTATUS status;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ii:play", &start, &play))
|
||||
return NULL;
|
||||
|
||||
if (!CDplay(self->ob_cdplayer, start, play)) {
|
||||
if (CDgetstatus(self->ob_cdplayer, &status) &&
|
||||
status.state == CD_NODISC)
|
||||
PyErr_SetString(CdError, "no disc in player");
|
||||
else
|
||||
PyErr_SetString(CdError, "play failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_playabs(cdplayerobject *self, PyObject *args)
|
||||
{
|
||||
int min, sec, frame, play;
|
||||
CDSTATUS status;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "iiii:playabs", &min, &sec, &frame, &play))
|
||||
return NULL;
|
||||
|
||||
if (!CDplayabs(self->ob_cdplayer, min, sec, frame, play)) {
|
||||
if (CDgetstatus(self->ob_cdplayer, &status) &&
|
||||
status.state == CD_NODISC)
|
||||
PyErr_SetString(CdError, "no disc in player");
|
||||
else
|
||||
PyErr_SetString(CdError, "playabs failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_playtrack(cdplayerobject *self, PyObject *args)
|
||||
{
|
||||
int start, play;
|
||||
CDSTATUS status;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ii:playtrack", &start, &play))
|
||||
return NULL;
|
||||
|
||||
if (!CDplaytrack(self->ob_cdplayer, start, play)) {
|
||||
if (CDgetstatus(self->ob_cdplayer, &status) &&
|
||||
status.state == CD_NODISC)
|
||||
PyErr_SetString(CdError, "no disc in player");
|
||||
else
|
||||
PyErr_SetString(CdError, "playtrack failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_playtrackabs(cdplayerobject *self, PyObject *args)
|
||||
{
|
||||
int track, min, sec, frame, play;
|
||||
CDSTATUS status;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "iiiii:playtrackabs", &track, &min, &sec,
|
||||
&frame, &play))
|
||||
return NULL;
|
||||
|
||||
if (!CDplaytrackabs(self->ob_cdplayer, track, min, sec, frame, play)) {
|
||||
if (CDgetstatus(self->ob_cdplayer, &status) &&
|
||||
status.state == CD_NODISC)
|
||||
PyErr_SetString(CdError, "no disc in player");
|
||||
else
|
||||
PyErr_SetString(CdError, "playtrackabs failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_readda(cdplayerobject *self, PyObject *args)
|
||||
{
|
||||
int numframes, n;
|
||||
PyObject *result;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i:readda", &numframes))
|
||||
return NULL;
|
||||
|
||||
result = PyString_FromStringAndSize(NULL, numframes * sizeof(CDFRAME));
|
||||
if (result == NULL)
|
||||
return NULL;
|
||||
|
||||
n = CDreadda(self->ob_cdplayer,
|
||||
(CDFRAME *) PyString_AsString(result), numframes);
|
||||
if (n == -1) {
|
||||
Py_DECREF(result);
|
||||
PyErr_SetFromErrno(CdError);
|
||||
return NULL;
|
||||
}
|
||||
if (n < numframes)
|
||||
_PyString_Resize(&result, n * sizeof(CDFRAME));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_seek(cdplayerobject *self, PyObject *args)
|
||||
{
|
||||
int min, sec, frame;
|
||||
long PyTryBlock;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "iii:seek", &min, &sec, &frame))
|
||||
return NULL;
|
||||
|
||||
PyTryBlock = CDseek(self->ob_cdplayer, min, sec, frame);
|
||||
if (PyTryBlock == -1) {
|
||||
PyErr_SetFromErrno(CdError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return PyInt_FromLong(PyTryBlock);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_seektrack(cdplayerobject *self, PyObject *args)
|
||||
{
|
||||
int track;
|
||||
long PyTryBlock;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i:seektrack", &track))
|
||||
return NULL;
|
||||
|
||||
PyTryBlock = CDseektrack(self->ob_cdplayer, track);
|
||||
if (PyTryBlock == -1) {
|
||||
PyErr_SetFromErrno(CdError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return PyInt_FromLong(PyTryBlock);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_seekblock(cdplayerobject *self, PyObject *args)
|
||||
{
|
||||
unsigned long PyTryBlock;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "l:seekblock", &PyTryBlock))
|
||||
return NULL;
|
||||
|
||||
PyTryBlock = CDseekblock(self->ob_cdplayer, PyTryBlock);
|
||||
if (PyTryBlock == (unsigned long) -1) {
|
||||
PyErr_SetFromErrno(CdError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return PyInt_FromLong(PyTryBlock);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_stop(cdplayerobject *self, PyObject *args)
|
||||
{
|
||||
CDSTATUS status;
|
||||
|
||||
if (!PyArg_ParseTuple(args, ":stop"))
|
||||
return NULL;
|
||||
|
||||
if (!CDstop(self->ob_cdplayer)) {
|
||||
if (CDgetstatus(self->ob_cdplayer, &status) &&
|
||||
status.state == CD_NODISC)
|
||||
PyErr_SetString(CdError, "no disc in player");
|
||||
else
|
||||
PyErr_SetString(CdError, "stop failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_togglepause(cdplayerobject *self, PyObject *args)
|
||||
{
|
||||
CDSTATUS status;
|
||||
|
||||
if (!PyArg_ParseTuple(args, ":togglepause"))
|
||||
return NULL;
|
||||
|
||||
if (!CDtogglepause(self->ob_cdplayer)) {
|
||||
if (CDgetstatus(self->ob_cdplayer, &status) &&
|
||||
status.state == CD_NODISC)
|
||||
PyErr_SetString(CdError, "no disc in player");
|
||||
else
|
||||
PyErr_SetString(CdError, "togglepause failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyMethodDef cdplayer_methods[] = {
|
||||
{"allowremoval", (PyCFunction)CD_allowremoval, METH_VARARGS},
|
||||
{"bestreadsize", (PyCFunction)CD_bestreadsize, METH_VARARGS},
|
||||
{"close", (PyCFunction)CD_close, METH_VARARGS},
|
||||
{"eject", (PyCFunction)CD_eject, METH_VARARGS},
|
||||
{"getstatus", (PyCFunction)CD_getstatus, METH_VARARGS},
|
||||
{"gettrackinfo", (PyCFunction)CD_gettrackinfo, METH_VARARGS},
|
||||
{"msftoblock", (PyCFunction)CD_msftoblock, METH_VARARGS},
|
||||
{"play", (PyCFunction)CD_play, METH_VARARGS},
|
||||
{"playabs", (PyCFunction)CD_playabs, METH_VARARGS},
|
||||
{"playtrack", (PyCFunction)CD_playtrack, METH_VARARGS},
|
||||
{"playtrackabs", (PyCFunction)CD_playtrackabs, METH_VARARGS},
|
||||
{"preventremoval", (PyCFunction)CD_preventremoval, METH_VARARGS},
|
||||
{"readda", (PyCFunction)CD_readda, METH_VARARGS},
|
||||
{"seek", (PyCFunction)CD_seek, METH_VARARGS},
|
||||
{"seekblock", (PyCFunction)CD_seekblock, METH_VARARGS},
|
||||
{"seektrack", (PyCFunction)CD_seektrack, METH_VARARGS},
|
||||
{"stop", (PyCFunction)CD_stop, METH_VARARGS},
|
||||
{"togglepause", (PyCFunction)CD_togglepause, METH_VARARGS},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static void
|
||||
cdplayer_dealloc(cdplayerobject *self)
|
||||
{
|
||||
if (self->ob_cdplayer != NULL)
|
||||
CDclose(self->ob_cdplayer);
|
||||
PyObject_Del(self);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cdplayer_getattr(cdplayerobject *self, char *name)
|
||||
{
|
||||
if (self->ob_cdplayer == NULL) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "no player active");
|
||||
return NULL;
|
||||
}
|
||||
return Py_FindMethod(cdplayer_methods, (PyObject *)self, name);
|
||||
}
|
||||
|
||||
PyTypeObject CdPlayertype = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0, /*ob_size*/
|
||||
"cd.cdplayer", /*tp_name*/
|
||||
sizeof(cdplayerobject), /*tp_size*/
|
||||
0, /*tp_itemsize*/
|
||||
/* methods */
|
||||
(destructor)cdplayer_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
(getattrfunc)cdplayer_getattr, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
0, /*tp_repr*/
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
newcdplayerobject(CDPLAYER *cdp)
|
||||
{
|
||||
cdplayerobject *p;
|
||||
|
||||
p = PyObject_New(cdplayerobject, &CdPlayertype);
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
p->ob_cdplayer = cdp;
|
||||
return (PyObject *) p;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_open(PyObject *self, PyObject *args)
|
||||
{
|
||||
char *dev, *direction;
|
||||
CDPLAYER *cdp;
|
||||
|
||||
/*
|
||||
* Variable number of args.
|
||||
* First defaults to "None", second defaults to "r".
|
||||
*/
|
||||
dev = NULL;
|
||||
direction = "r";
|
||||
if (!PyArg_ParseTuple(args, "|zs:open", &dev, &direction))
|
||||
return NULL;
|
||||
|
||||
cdp = CDopen(dev, direction);
|
||||
if (cdp == NULL) {
|
||||
PyErr_SetFromErrno(CdError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return newcdplayerobject(cdp);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
CDPARSER *ob_cdparser;
|
||||
struct {
|
||||
PyObject *ob_cdcallback;
|
||||
PyObject *ob_cdcallbackarg;
|
||||
} ob_cdcallbacks[NCALLBACKS];
|
||||
} cdparserobject;
|
||||
|
||||
static void
|
||||
CD_callback(void *arg, CDDATATYPES type, void *data)
|
||||
{
|
||||
PyObject *result, *args, *v = NULL;
|
||||
char *p;
|
||||
int i;
|
||||
cdparserobject *self;
|
||||
|
||||
self = (cdparserobject *) arg;
|
||||
args = PyTuple_New(3);
|
||||
if (args == NULL)
|
||||
return;
|
||||
Py_INCREF(self->ob_cdcallbacks[type].ob_cdcallbackarg);
|
||||
PyTuple_SetItem(args, 0, self->ob_cdcallbacks[type].ob_cdcallbackarg);
|
||||
PyTuple_SetItem(args, 1, PyInt_FromLong((long) type));
|
||||
switch (type) {
|
||||
case cd_audio:
|
||||
v = PyString_FromStringAndSize(data, CDDA_DATASIZE);
|
||||
break;
|
||||
case cd_pnum:
|
||||
case cd_index:
|
||||
v = PyInt_FromLong(((CDPROGNUM *) data)->value);
|
||||
break;
|
||||
case cd_ptime:
|
||||
case cd_atime:
|
||||
#define ptr ((struct cdtimecode *) data)
|
||||
v = Py_BuildValue("(iii)",
|
||||
ptr->mhi * 10 + ptr->mlo,
|
||||
ptr->shi * 10 + ptr->slo,
|
||||
ptr->fhi * 10 + ptr->flo);
|
||||
#undef ptr
|
||||
break;
|
||||
case cd_catalog:
|
||||
v = PyString_FromStringAndSize(NULL, 13);
|
||||
p = PyString_AsString(v);
|
||||
for (i = 0; i < 13; i++)
|
||||
*p++ = ((char *) data)[i] + '0';
|
||||
break;
|
||||
case cd_ident:
|
||||
#define ptr ((struct cdident *) data)
|
||||
v = PyString_FromStringAndSize(NULL, 12);
|
||||
p = PyString_AsString(v);
|
||||
CDsbtoa(p, ptr->country, 2);
|
||||
p += 2;
|
||||
CDsbtoa(p, ptr->owner, 3);
|
||||
p += 3;
|
||||
*p++ = ptr->year[0] + '0';
|
||||
*p++ = ptr->year[1] + '0';
|
||||
*p++ = ptr->serial[0] + '0';
|
||||
*p++ = ptr->serial[1] + '0';
|
||||
*p++ = ptr->serial[2] + '0';
|
||||
*p++ = ptr->serial[3] + '0';
|
||||
*p++ = ptr->serial[4] + '0';
|
||||
#undef ptr
|
||||
break;
|
||||
case cd_control:
|
||||
v = PyInt_FromLong((long) *((unchar *) data));
|
||||
break;
|
||||
}
|
||||
PyTuple_SetItem(args, 2, v);
|
||||
if (PyErr_Occurred()) {
|
||||
Py_DECREF(args);
|
||||
return;
|
||||
}
|
||||
|
||||
result = PyEval_CallObject(self->ob_cdcallbacks[type].ob_cdcallback,
|
||||
args);
|
||||
Py_DECREF(args);
|
||||
Py_XDECREF(result);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_deleteparser(cdparserobject *self, PyObject *args)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!PyArg_ParseTuple(args, ":deleteparser"))
|
||||
return NULL;
|
||||
|
||||
CDdeleteparser(self->ob_cdparser);
|
||||
self->ob_cdparser = NULL;
|
||||
|
||||
/* no sense in keeping the callbacks, so remove them */
|
||||
for (i = 0; i < NCALLBACKS; i++) {
|
||||
Py_CLEAR(self->ob_cdcallbacks[i].ob_cdcallback);
|
||||
Py_CLEAR(self->ob_cdcallbacks[i].ob_cdcallbackarg);
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_parseframe(cdparserobject *self, PyObject *args)
|
||||
{
|
||||
char *cdfp;
|
||||
int length;
|
||||
CDFRAME *p;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s#:parseframe", &cdfp, &length))
|
||||
return NULL;
|
||||
|
||||
if (length % sizeof(CDFRAME) != 0) {
|
||||
PyErr_SetString(PyExc_TypeError, "bad length");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = (CDFRAME *) cdfp;
|
||||
while (length > 0) {
|
||||
CDparseframe(self->ob_cdparser, p);
|
||||
length -= sizeof(CDFRAME);
|
||||
p++;
|
||||
if (PyErr_Occurred())
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_removecallback(cdparserobject *self, PyObject *args)
|
||||
{
|
||||
int type;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i:removecallback", &type))
|
||||
return NULL;
|
||||
|
||||
if (type < 0 || type >= NCALLBACKS) {
|
||||
PyErr_SetString(PyExc_TypeError, "bad type");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CDremovecallback(self->ob_cdparser, (CDDATATYPES) type);
|
||||
|
||||
Py_CLEAR(self->ob_cdcallbacks[type].ob_cdcallback);
|
||||
|
||||
Py_CLEAR(self->ob_cdcallbacks[type].ob_cdcallbackarg);
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_resetparser(cdparserobject *self, PyObject *args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ":resetparser"))
|
||||
return NULL;
|
||||
|
||||
CDresetparser(self->ob_cdparser);
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_addcallback(cdparserobject *self, PyObject *args)
|
||||
{
|
||||
int type;
|
||||
PyObject *func, *funcarg;
|
||||
|
||||
/* XXX - more work here */
|
||||
if (!PyArg_ParseTuple(args, "iOO:addcallback", &type, &func, &funcarg))
|
||||
return NULL;
|
||||
|
||||
if (type < 0 || type >= NCALLBACKS) {
|
||||
PyErr_SetString(PyExc_TypeError, "argument out of range");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef CDsetcallback
|
||||
CDaddcallback(self->ob_cdparser, (CDDATATYPES) type, CD_callback,
|
||||
(void *) self);
|
||||
#else
|
||||
CDsetcallback(self->ob_cdparser, (CDDATATYPES) type, CD_callback,
|
||||
(void *) self);
|
||||
#endif
|
||||
Py_INCREF(func);
|
||||
Py_XSETREF(self->ob_cdcallbacks[type].ob_cdcallback, func);
|
||||
Py_INCREF(funcarg);
|
||||
Py_XSETREF(self->ob_cdcallbacks[type].ob_cdcallbackarg, funcarg);
|
||||
|
||||
/*
|
||||
if (type == cd_audio) {
|
||||
sigfpe_[_UNDERFL].repls = _ZERO;
|
||||
handle_sigfpes(_ON, _EN_UNDERFL, NULL,
|
||||
_ABORT_ON_ERROR, NULL);
|
||||
}
|
||||
*/
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyMethodDef cdparser_methods[] = {
|
||||
{"addcallback", (PyCFunction)CD_addcallback, METH_VARARGS},
|
||||
{"deleteparser", (PyCFunction)CD_deleteparser, METH_VARARGS},
|
||||
{"parseframe", (PyCFunction)CD_parseframe, METH_VARARGS},
|
||||
{"removecallback", (PyCFunction)CD_removecallback, METH_VARARGS},
|
||||
{"resetparser", (PyCFunction)CD_resetparser, METH_VARARGS},
|
||||
/* backward compatibility */
|
||||
{"setcallback", (PyCFunction)CD_addcallback, METH_VARARGS},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static void
|
||||
cdparser_dealloc(cdparserobject *self)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NCALLBACKS; i++) {
|
||||
Py_CLEAR(self->ob_cdcallbacks[i].ob_cdcallback);
|
||||
Py_CLEAR(self->ob_cdcallbacks[i].ob_cdcallbackarg);
|
||||
}
|
||||
CDdeleteparser(self->ob_cdparser);
|
||||
PyObject_Del(self);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cdparser_getattr(cdparserobject *self, char *name)
|
||||
{
|
||||
if (self->ob_cdparser == NULL) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "no parser active");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return Py_FindMethod(cdparser_methods, (PyObject *)self, name);
|
||||
}
|
||||
|
||||
PyTypeObject CdParsertype = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0, /*ob_size*/
|
||||
"cd.cdparser", /*tp_name*/
|
||||
sizeof(cdparserobject), /*tp_size*/
|
||||
0, /*tp_itemsize*/
|
||||
/* methods */
|
||||
(destructor)cdparser_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
(getattrfunc)cdparser_getattr, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
0, /*tp_repr*/
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
newcdparserobject(CDPARSER *cdp)
|
||||
{
|
||||
cdparserobject *p;
|
||||
int i;
|
||||
|
||||
p = PyObject_New(cdparserobject, &CdParsertype);
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
p->ob_cdparser = cdp;
|
||||
for (i = 0; i < NCALLBACKS; i++) {
|
||||
p->ob_cdcallbacks[i].ob_cdcallback = NULL;
|
||||
p->ob_cdcallbacks[i].ob_cdcallbackarg = NULL;
|
||||
}
|
||||
return (PyObject *) p;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_createparser(PyObject *self, PyObject *args)
|
||||
{
|
||||
CDPARSER *cdp;
|
||||
|
||||
if (!PyArg_ParseTuple(args, ":createparser"))
|
||||
return NULL;
|
||||
cdp = CDcreateparser();
|
||||
if (cdp == NULL) {
|
||||
PyErr_SetString(CdError, "createparser failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return newcdparserobject(cdp);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CD_msftoframe(PyObject *self, PyObject *args)
|
||||
{
|
||||
int min, sec, frame;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "iii:msftoframe", &min, &sec, &frame))
|
||||
return NULL;
|
||||
|
||||
return PyInt_FromLong((long) CDmsftoframe(min, sec, frame));
|
||||
}
|
||||
|
||||
static PyMethodDef CD_methods[] = {
|
||||
{"open", (PyCFunction)CD_open, METH_VARARGS},
|
||||
{"createparser", (PyCFunction)CD_createparser, METH_VARARGS},
|
||||
{"msftoframe", (PyCFunction)CD_msftoframe, METH_VARARGS},
|
||||
{NULL, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
void
|
||||
initcd(void)
|
||||
{
|
||||
PyObject *m, *d;
|
||||
|
||||
if (PyErr_WarnPy3k("the cd module has been removed in "
|
||||
"Python 3.0", 2) < 0)
|
||||
return;
|
||||
|
||||
m = Py_InitModule("cd", CD_methods);
|
||||
if (m == NULL)
|
||||
return;
|
||||
d = PyModule_GetDict(m);
|
||||
|
||||
CdError = PyErr_NewException("cd.error", NULL, NULL);
|
||||
PyDict_SetItemString(d, "error", CdError);
|
||||
|
||||
/* Identifiers for the different types of callbacks from the parser */
|
||||
PyDict_SetItemString(d, "audio", PyInt_FromLong((long) cd_audio));
|
||||
PyDict_SetItemString(d, "pnum", PyInt_FromLong((long) cd_pnum));
|
||||
PyDict_SetItemString(d, "index", PyInt_FromLong((long) cd_index));
|
||||
PyDict_SetItemString(d, "ptime", PyInt_FromLong((long) cd_ptime));
|
||||
PyDict_SetItemString(d, "atime", PyInt_FromLong((long) cd_atime));
|
||||
PyDict_SetItemString(d, "catalog", PyInt_FromLong((long) cd_catalog));
|
||||
PyDict_SetItemString(d, "ident", PyInt_FromLong((long) cd_ident));
|
||||
PyDict_SetItemString(d, "control", PyInt_FromLong((long) cd_control));
|
||||
|
||||
/* Block size information for digital audio data */
|
||||
PyDict_SetItemString(d, "DATASIZE",
|
||||
PyInt_FromLong((long) CDDA_DATASIZE));
|
||||
PyDict_SetItemString(d, "BLOCKSIZE",
|
||||
PyInt_FromLong((long) CDDA_BLOCKSIZE));
|
||||
|
||||
/* Possible states for the cd player */
|
||||
PyDict_SetItemString(d, "ERROR", PyInt_FromLong((long) CD_ERROR));
|
||||
PyDict_SetItemString(d, "NODISC", PyInt_FromLong((long) CD_NODISC));
|
||||
PyDict_SetItemString(d, "READY", PyInt_FromLong((long) CD_READY));
|
||||
PyDict_SetItemString(d, "PLAYING", PyInt_FromLong((long) CD_PLAYING));
|
||||
PyDict_SetItemString(d, "PAUSED", PyInt_FromLong((long) CD_PAUSED));
|
||||
PyDict_SetItemString(d, "STILL", PyInt_FromLong((long) CD_STILL));
|
||||
#ifdef CD_CDROM /* only newer versions of the library */
|
||||
PyDict_SetItemString(d, "CDROM", PyInt_FromLong((long) CD_CDROM));
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,523 @@
|
||||
########################################################################
|
||||
# Copyright (c) 2000, BeOpen.com.
|
||||
# Copyright (c) 1995-2000, Corporation for National Research Initiatives.
|
||||
# Copyright (c) 1990-1995, Stichting Mathematisch Centrum.
|
||||
# All rights reserved.
|
||||
#
|
||||
# See the file "Misc/COPYRIGHT" for information on usage and
|
||||
# redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
########################################################################
|
||||
|
||||
# Python script to parse cstubs file for gl and generate C stubs.
|
||||
# usage: python cgen.py <cstubs >glmodule.c
|
||||
#
|
||||
# NOTE: You must first make a python binary without the "GL" option
|
||||
# before you can run this, when building Python for the first time.
|
||||
# See comments in the Makefile.
|
||||
#
|
||||
# XXX BUG return arrays generate wrong code
|
||||
# XXX need to change error returns into gotos to free mallocked arrays
|
||||
from warnings import warnpy3k
|
||||
warnpy3k("the cgen module has been removed in Python 3.0", stacklevel=2)
|
||||
del warnpy3k
|
||||
|
||||
|
||||
import string
|
||||
import sys
|
||||
|
||||
|
||||
# Function to print to stderr
|
||||
#
|
||||
def err(*args):
|
||||
savestdout = sys.stdout
|
||||
try:
|
||||
sys.stdout = sys.stderr
|
||||
for i in args:
|
||||
print i,
|
||||
print
|
||||
finally:
|
||||
sys.stdout = savestdout
|
||||
|
||||
|
||||
# The set of digits that form a number
|
||||
#
|
||||
digits = '0123456789'
|
||||
|
||||
|
||||
# Function to extract a string of digits from the front of the string.
|
||||
# Returns the leading string of digits and the remaining string.
|
||||
# If no number is found, returns '' and the original string.
|
||||
#
|
||||
def getnum(s):
|
||||
n = ''
|
||||
while s and s[0] in digits:
|
||||
n = n + s[0]
|
||||
s = s[1:]
|
||||
return n, s
|
||||
|
||||
|
||||
# Function to check if a string is a number
|
||||
#
|
||||
def isnum(s):
|
||||
if not s: return False
|
||||
for c in s:
|
||||
if not c in digits: return False
|
||||
return True
|
||||
|
||||
|
||||
# Allowed function return types
|
||||
#
|
||||
return_types = ['void', 'short', 'long']
|
||||
|
||||
|
||||
# Allowed function argument types
|
||||
#
|
||||
arg_types = ['char', 'string', 'short', 'u_short', 'float', 'long', 'double']
|
||||
|
||||
|
||||
# Need to classify arguments as follows
|
||||
# simple input variable
|
||||
# simple output variable
|
||||
# input array
|
||||
# output array
|
||||
# input giving size of some array
|
||||
#
|
||||
# Array dimensions can be specified as follows
|
||||
# constant
|
||||
# argN
|
||||
# constant * argN
|
||||
# retval
|
||||
# constant * retval
|
||||
#
|
||||
# The dimensions given as constants * something are really
|
||||
# arrays of points where points are 2- 3- or 4-tuples
|
||||
#
|
||||
# We have to consider three lists:
|
||||
# python input arguments
|
||||
# C stub arguments (in & out)
|
||||
# python output arguments (really return values)
|
||||
#
|
||||
# There is a mapping from python input arguments to the input arguments
|
||||
# of the C stub, and a further mapping from C stub arguments to the
|
||||
# python return values
|
||||
|
||||
|
||||
# Exception raised by checkarg() and generate()
|
||||
#
|
||||
arg_error = 'bad arg'
|
||||
|
||||
|
||||
# Function to check one argument.
|
||||
# Arguments: the type and the arg "name" (really mode plus subscript).
|
||||
# Raises arg_error if something's wrong.
|
||||
# Return type, mode, factor, rest of subscript; factor and rest may be empty.
|
||||
#
|
||||
def checkarg(type, arg):
|
||||
#
|
||||
# Turn "char *x" into "string x".
|
||||
#
|
||||
if type == 'char' and arg[0] == '*':
|
||||
type = 'string'
|
||||
arg = arg[1:]
|
||||
#
|
||||
# Check that the type is supported.
|
||||
#
|
||||
if type not in arg_types:
|
||||
raise arg_error, ('bad type', type)
|
||||
if type[:2] == 'u_':
|
||||
type = 'unsigned ' + type[2:]
|
||||
#
|
||||
# Split it in the mode (first character) and the rest.
|
||||
#
|
||||
mode, rest = arg[:1], arg[1:]
|
||||
#
|
||||
# The mode must be 's' for send (= input) or 'r' for return argument.
|
||||
#
|
||||
if mode not in ('r', 's'):
|
||||
raise arg_error, ('bad arg mode', mode)
|
||||
#
|
||||
# Is it a simple argument: if so, we are done.
|
||||
#
|
||||
if not rest:
|
||||
return type, mode, '', ''
|
||||
#
|
||||
# Not a simple argument; must be an array.
|
||||
# The 'rest' must be a subscript enclosed in [ and ].
|
||||
# The subscript must be one of the following forms,
|
||||
# otherwise we don't handle it (where N is a number):
|
||||
# N
|
||||
# argN
|
||||
# retval
|
||||
# N*argN
|
||||
# N*retval
|
||||
#
|
||||
if rest[:1] <> '[' or rest[-1:] <> ']':
|
||||
raise arg_error, ('subscript expected', rest)
|
||||
sub = rest[1:-1]
|
||||
#
|
||||
# Is there a leading number?
|
||||
#
|
||||
num, sub = getnum(sub)
|
||||
if num:
|
||||
# There is a leading number
|
||||
if not sub:
|
||||
# The subscript is just a number
|
||||
return type, mode, num, ''
|
||||
if sub[:1] == '*':
|
||||
# There is a factor prefix
|
||||
sub = sub[1:]
|
||||
else:
|
||||
raise arg_error, ('\'*\' expected', sub)
|
||||
if sub == 'retval':
|
||||
# size is retval -- must be a reply argument
|
||||
if mode <> 'r':
|
||||
raise arg_error, ('non-r mode with [retval]', mode)
|
||||
elif not isnum(sub) and (sub[:3] <> 'arg' or not isnum(sub[3:])):
|
||||
raise arg_error, ('bad subscript', sub)
|
||||
#
|
||||
return type, mode, num, sub
|
||||
|
||||
|
||||
# List of functions for which we have generated stubs
|
||||
#
|
||||
functions = []
|
||||
|
||||
|
||||
# Generate the stub for the given function, using the database of argument
|
||||
# information build by successive calls to checkarg()
|
||||
#
|
||||
def generate(type, func, database):
|
||||
#
|
||||
# Check that we can handle this case:
|
||||
# no variable size reply arrays yet
|
||||
#
|
||||
n_in_args = 0
|
||||
n_out_args = 0
|
||||
#
|
||||
for a_type, a_mode, a_factor, a_sub in database:
|
||||
if a_mode == 's':
|
||||
n_in_args = n_in_args + 1
|
||||
elif a_mode == 'r':
|
||||
n_out_args = n_out_args + 1
|
||||
else:
|
||||
# Can't happen
|
||||
raise arg_error, ('bad a_mode', a_mode)
|
||||
if (a_mode == 'r' and a_sub) or a_sub == 'retval':
|
||||
err('Function', func, 'too complicated:',
|
||||
a_type, a_mode, a_factor, a_sub)
|
||||
print '/* XXX Too complicated to generate code for */'
|
||||
return
|
||||
#
|
||||
functions.append(func)
|
||||
#
|
||||
# Stub header
|
||||
#
|
||||
print
|
||||
print 'static PyObject *'
|
||||
print 'gl_' + func + '(self, args)'
|
||||
print '\tPyObject *self;'
|
||||
print '\tPyObject *args;'
|
||||
print '{'
|
||||
#
|
||||
# Declare return value if any
|
||||
#
|
||||
if type <> 'void':
|
||||
print '\t' + type, 'retval;'
|
||||
#
|
||||
# Declare arguments
|
||||
#
|
||||
for i in range(len(database)):
|
||||
a_type, a_mode, a_factor, a_sub = database[i]
|
||||
print '\t' + a_type,
|
||||
brac = ket = ''
|
||||
if a_sub and not isnum(a_sub):
|
||||
if a_factor:
|
||||
brac = '('
|
||||
ket = ')'
|
||||
print brac + '*',
|
||||
print 'arg' + repr(i+1) + ket,
|
||||
if a_sub and isnum(a_sub):
|
||||
print '[', a_sub, ']',
|
||||
if a_factor:
|
||||
print '[', a_factor, ']',
|
||||
print ';'
|
||||
#
|
||||
# Find input arguments derived from array sizes
|
||||
#
|
||||
for i in range(len(database)):
|
||||
a_type, a_mode, a_factor, a_sub = database[i]
|
||||
if a_mode == 's' and a_sub[:3] == 'arg' and isnum(a_sub[3:]):
|
||||
# Sending a variable-length array
|
||||
n = eval(a_sub[3:])
|
||||
if 1 <= n <= len(database):
|
||||
b_type, b_mode, b_factor, b_sub = database[n-1]
|
||||
if b_mode == 's':
|
||||
database[n-1] = b_type, 'i', a_factor, repr(i)
|
||||
n_in_args = n_in_args - 1
|
||||
#
|
||||
# Assign argument positions in the Python argument list
|
||||
#
|
||||
in_pos = []
|
||||
i_in = 0
|
||||
for i in range(len(database)):
|
||||
a_type, a_mode, a_factor, a_sub = database[i]
|
||||
if a_mode == 's':
|
||||
in_pos.append(i_in)
|
||||
i_in = i_in + 1
|
||||
else:
|
||||
in_pos.append(-1)
|
||||
#
|
||||
# Get input arguments
|
||||
#
|
||||
for i in range(len(database)):
|
||||
a_type, a_mode, a_factor, a_sub = database[i]
|
||||
if a_type[:9] == 'unsigned ':
|
||||
xtype = a_type[9:]
|
||||
else:
|
||||
xtype = a_type
|
||||
if a_mode == 'i':
|
||||
#
|
||||
# Implicit argument;
|
||||
# a_factor is divisor if present,
|
||||
# a_sub indicates which arg (`database index`)
|
||||
#
|
||||
j = eval(a_sub)
|
||||
print '\tif',
|
||||
print '(!geti' + xtype + 'arraysize(args,',
|
||||
print repr(n_in_args) + ',',
|
||||
print repr(in_pos[j]) + ',',
|
||||
if xtype <> a_type:
|
||||
print '('+xtype+' *)',
|
||||
print '&arg' + repr(i+1) + '))'
|
||||
print '\t\treturn NULL;'
|
||||
if a_factor:
|
||||
print '\targ' + repr(i+1),
|
||||
print '= arg' + repr(i+1),
|
||||
print '/', a_factor + ';'
|
||||
elif a_mode == 's':
|
||||
if a_sub and not isnum(a_sub):
|
||||
# Allocate memory for varsize array
|
||||
print '\tif ((arg' + repr(i+1), '=',
|
||||
if a_factor:
|
||||
print '('+a_type+'(*)['+a_factor+'])',
|
||||
print 'PyMem_NEW(' + a_type, ',',
|
||||
if a_factor:
|
||||
print a_factor, '*',
|
||||
print a_sub, ')) == NULL)'
|
||||
print '\t\treturn PyErr_NoMemory();'
|
||||
print '\tif',
|
||||
if a_factor or a_sub: # Get a fixed-size array array
|
||||
print '(!geti' + xtype + 'array(args,',
|
||||
print repr(n_in_args) + ',',
|
||||
print repr(in_pos[i]) + ',',
|
||||
if a_factor: print a_factor,
|
||||
if a_factor and a_sub: print '*',
|
||||
if a_sub: print a_sub,
|
||||
print ',',
|
||||
if (a_sub and a_factor) or xtype <> a_type:
|
||||
print '('+xtype+' *)',
|
||||
print 'arg' + repr(i+1) + '))'
|
||||
else: # Get a simple variable
|
||||
print '(!geti' + xtype + 'arg(args,',
|
||||
print repr(n_in_args) + ',',
|
||||
print repr(in_pos[i]) + ',',
|
||||
if xtype <> a_type:
|
||||
print '('+xtype+' *)',
|
||||
print '&arg' + repr(i+1) + '))'
|
||||
print '\t\treturn NULL;'
|
||||
#
|
||||
# Begin of function call
|
||||
#
|
||||
if type <> 'void':
|
||||
print '\tretval =', func + '(',
|
||||
else:
|
||||
print '\t' + func + '(',
|
||||
#
|
||||
# Argument list
|
||||
#
|
||||
for i in range(len(database)):
|
||||
if i > 0: print ',',
|
||||
a_type, a_mode, a_factor, a_sub = database[i]
|
||||
if a_mode == 'r' and not a_factor:
|
||||
print '&',
|
||||
print 'arg' + repr(i+1),
|
||||
#
|
||||
# End of function call
|
||||
#
|
||||
print ');'
|
||||
#
|
||||
# Free varsize arrays
|
||||
#
|
||||
for i in range(len(database)):
|
||||
a_type, a_mode, a_factor, a_sub = database[i]
|
||||
if a_mode == 's' and a_sub and not isnum(a_sub):
|
||||
print '\tPyMem_DEL(arg' + repr(i+1) + ');'
|
||||
#
|
||||
# Return
|
||||
#
|
||||
if n_out_args:
|
||||
#
|
||||
# Multiple return values -- construct a tuple
|
||||
#
|
||||
if type <> 'void':
|
||||
n_out_args = n_out_args + 1
|
||||
if n_out_args == 1:
|
||||
for i in range(len(database)):
|
||||
a_type, a_mode, a_factor, a_sub = database[i]
|
||||
if a_mode == 'r':
|
||||
break
|
||||
else:
|
||||
raise arg_error, 'expected r arg not found'
|
||||
print '\treturn',
|
||||
print mkobject(a_type, 'arg' + repr(i+1)) + ';'
|
||||
else:
|
||||
print '\t{ PyObject *v = PyTuple_New(',
|
||||
print n_out_args, ');'
|
||||
print '\t if (v == NULL) return NULL;'
|
||||
i_out = 0
|
||||
if type <> 'void':
|
||||
print '\t PyTuple_SetItem(v,',
|
||||
print repr(i_out) + ',',
|
||||
print mkobject(type, 'retval') + ');'
|
||||
i_out = i_out + 1
|
||||
for i in range(len(database)):
|
||||
a_type, a_mode, a_factor, a_sub = database[i]
|
||||
if a_mode == 'r':
|
||||
print '\t PyTuple_SetItem(v,',
|
||||
print repr(i_out) + ',',
|
||||
s = mkobject(a_type, 'arg' + repr(i+1))
|
||||
print s + ');'
|
||||
i_out = i_out + 1
|
||||
print '\t return v;'
|
||||
print '\t}'
|
||||
else:
|
||||
#
|
||||
# Simple function return
|
||||
# Return None or return value
|
||||
#
|
||||
if type == 'void':
|
||||
print '\tPy_INCREF(Py_None);'
|
||||
print '\treturn Py_None;'
|
||||
else:
|
||||
print '\treturn', mkobject(type, 'retval') + ';'
|
||||
#
|
||||
# Stub body closing brace
|
||||
#
|
||||
print '}'
|
||||
|
||||
|
||||
# Subroutine to return a function call to mknew<type>object(<arg>)
|
||||
#
|
||||
def mkobject(type, arg):
|
||||
if type[:9] == 'unsigned ':
|
||||
type = type[9:]
|
||||
return 'mknew' + type + 'object((' + type + ') ' + arg + ')'
|
||||
return 'mknew' + type + 'object(' + arg + ')'
|
||||
|
||||
|
||||
defined_archs = []
|
||||
|
||||
# usage: cgen [ -Dmach ... ] [ file ]
|
||||
for arg in sys.argv[1:]:
|
||||
if arg[:2] == '-D':
|
||||
defined_archs.append(arg[2:])
|
||||
else:
|
||||
# Open optional file argument
|
||||
sys.stdin = open(arg, 'r')
|
||||
|
||||
|
||||
# Input line number
|
||||
lno = 0
|
||||
|
||||
|
||||
# Input is divided in two parts, separated by a line containing '%%'.
|
||||
# <part1> -- literally copied to stdout
|
||||
# <part2> -- stub definitions
|
||||
|
||||
# Variable indicating the current input part.
|
||||
#
|
||||
part = 1
|
||||
|
||||
# Main loop over the input
|
||||
#
|
||||
while 1:
|
||||
try:
|
||||
line = raw_input()
|
||||
except EOFError:
|
||||
break
|
||||
#
|
||||
lno = lno+1
|
||||
words = string.split(line)
|
||||
#
|
||||
if part == 1:
|
||||
#
|
||||
# In part 1, copy everything literally
|
||||
# except look for a line of just '%%'
|
||||
#
|
||||
if words == ['%%']:
|
||||
part = part + 1
|
||||
else:
|
||||
#
|
||||
# Look for names of manually written
|
||||
# stubs: a single percent followed by the name
|
||||
# of the function in Python.
|
||||
# The stub name is derived by prefixing 'gl_'.
|
||||
#
|
||||
if words and words[0][0] == '%':
|
||||
func = words[0][1:]
|
||||
if (not func) and words[1:]:
|
||||
func = words[1]
|
||||
if func:
|
||||
functions.append(func)
|
||||
else:
|
||||
print line
|
||||
continue
|
||||
if not words:
|
||||
continue # skip empty line
|
||||
elif words[0] == 'if':
|
||||
# if XXX rest
|
||||
# if !XXX rest
|
||||
if words[1][0] == '!':
|
||||
if words[1][1:] in defined_archs:
|
||||
continue
|
||||
elif words[1] not in defined_archs:
|
||||
continue
|
||||
words = words[2:]
|
||||
if words[0] == '#include':
|
||||
print line
|
||||
elif words[0][:1] == '#':
|
||||
pass # ignore comment
|
||||
elif words[0] not in return_types:
|
||||
err('Line', lno, ': bad return type :', words[0])
|
||||
elif len(words) < 2:
|
||||
err('Line', lno, ': no funcname :', line)
|
||||
else:
|
||||
if len(words) % 2 <> 0:
|
||||
err('Line', lno, ': odd argument list :', words[2:])
|
||||
else:
|
||||
database = []
|
||||
try:
|
||||
for i in range(2, len(words), 2):
|
||||
x = checkarg(words[i], words[i+1])
|
||||
database.append(x)
|
||||
print
|
||||
print '/*',
|
||||
for w in words: print w,
|
||||
print '*/'
|
||||
generate(words[0], words[1], database)
|
||||
except arg_error, msg:
|
||||
err('Line', lno, ':', msg)
|
||||
|
||||
|
||||
print
|
||||
print 'static struct PyMethodDef gl_methods[] = {'
|
||||
for func in functions:
|
||||
print '\t{"' + func + '", gl_' + func + '},'
|
||||
print '\t{NULL, NULL} /* Sentinel */'
|
||||
print '};'
|
||||
print
|
||||
print 'void'
|
||||
print 'initgl()'
|
||||
print '{'
|
||||
print '\t(void) Py_InitModule("gl", gl_methods);'
|
||||
print '}'
|
||||
@@ -0,0 +1,310 @@
|
||||
|
||||
/* Functions used by cgen output */
|
||||
|
||||
#include "Python.h"
|
||||
#include "cgensupport.h"
|
||||
|
||||
|
||||
/* Functions to extract arguments.
|
||||
These needs to know the total number of arguments supplied,
|
||||
since the argument list is a tuple only of there is more than
|
||||
one argument. */
|
||||
|
||||
int
|
||||
PyArg_GetObject(register PyObject *args, int nargs, int i, PyObject **p_arg)
|
||||
{
|
||||
if (nargs != 1) {
|
||||
if (args == NULL || !PyTuple_Check(args) ||
|
||||
nargs != PyTuple_Size(args) ||
|
||||
i < 0 || i >= nargs) {
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
else {
|
||||
args = PyTuple_GetItem(args, i);
|
||||
}
|
||||
}
|
||||
if (args == NULL) {
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
*p_arg = args;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
PyArg_GetLong(register PyObject *args, int nargs, int i, long *p_arg)
|
||||
{
|
||||
if (nargs != 1) {
|
||||
if (args == NULL || !PyTuple_Check(args) ||
|
||||
nargs != PyTuple_Size(args) ||
|
||||
i < 0 || i >= nargs) {
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
args = PyTuple_GetItem(args, i);
|
||||
}
|
||||
if (args == NULL || !PyInt_Check(args)) {
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
*p_arg = PyInt_AsLong(args);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
PyArg_GetShort(register PyObject *args, int nargs, int i, short *p_arg)
|
||||
{
|
||||
long x;
|
||||
if (!PyArg_GetLong(args, nargs, i, &x))
|
||||
return 0;
|
||||
*p_arg = (short) x;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
extractdouble(register PyObject *v, double *p_arg)
|
||||
{
|
||||
if (v == NULL) {
|
||||
/* Fall through to error return at end of function */
|
||||
}
|
||||
else if (PyFloat_Check(v)) {
|
||||
*p_arg = PyFloat_AS_DOUBLE((PyFloatObject *)v);
|
||||
return 1;
|
||||
}
|
||||
else if (PyInt_Check(v)) {
|
||||
*p_arg = PyInt_AS_LONG((PyIntObject *)v);
|
||||
return 1;
|
||||
}
|
||||
else if (PyLong_Check(v)) {
|
||||
*p_arg = PyLong_AsDouble(v);
|
||||
return 1;
|
||||
}
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
|
||||
static int
|
||||
extractfloat(register PyObject *v, float *p_arg)
|
||||
{
|
||||
if (v == NULL) {
|
||||
/* Fall through to error return at end of function */
|
||||
}
|
||||
else if (PyFloat_Check(v)) {
|
||||
*p_arg = (float) PyFloat_AS_DOUBLE((PyFloatObject *)v);
|
||||
return 1;
|
||||
}
|
||||
else if (PyInt_Check(v)) {
|
||||
*p_arg = (float) PyInt_AS_LONG((PyIntObject *)v);
|
||||
return 1;
|
||||
}
|
||||
else if (PyLong_Check(v)) {
|
||||
*p_arg = (float) PyLong_AsDouble(v);
|
||||
return 1;
|
||||
}
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
|
||||
int
|
||||
PyArg_GetFloat(register PyObject *args, int nargs, int i, float *p_arg)
|
||||
{
|
||||
PyObject *v;
|
||||
float x;
|
||||
if (!PyArg_GetObject(args, nargs, i, &v))
|
||||
return 0;
|
||||
if (!extractfloat(v, &x))
|
||||
return 0;
|
||||
*p_arg = x;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
PyArg_GetString(PyObject *args, int nargs, int i, string *p_arg)
|
||||
{
|
||||
PyObject *v;
|
||||
if (!PyArg_GetObject(args, nargs, i, &v))
|
||||
return 0;
|
||||
if (!PyString_Check(v)) {
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
*p_arg = PyString_AsString(v);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
PyArg_GetChar(PyObject *args, int nargs, int i, char *p_arg)
|
||||
{
|
||||
string x;
|
||||
if (!PyArg_GetString(args, nargs, i, &x))
|
||||
return 0;
|
||||
if (x[0] == '\0' || x[1] != '\0') {
|
||||
/* Not exactly one char */
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
*p_arg = x[0];
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
PyArg_GetLongArraySize(PyObject *args, int nargs, int i, long *p_arg)
|
||||
{
|
||||
PyObject *v;
|
||||
if (!PyArg_GetObject(args, nargs, i, &v))
|
||||
return 0;
|
||||
if (PyTuple_Check(v)) {
|
||||
*p_arg = PyTuple_Size(v);
|
||||
return 1;
|
||||
}
|
||||
if (PyList_Check(v)) {
|
||||
*p_arg = PyList_Size(v);
|
||||
return 1;
|
||||
}
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
|
||||
int
|
||||
PyArg_GetShortArraySize(PyObject *args, int nargs, int i, short *p_arg)
|
||||
{
|
||||
long x;
|
||||
if (!PyArg_GetLongArraySize(args, nargs, i, &x))
|
||||
return 0;
|
||||
*p_arg = (short) x;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* XXX The following four are too similar. Should share more code. */
|
||||
|
||||
int
|
||||
PyArg_GetLongArray(PyObject *args, int nargs, int i, int n, long *p_arg)
|
||||
{
|
||||
PyObject *v, *w;
|
||||
if (!PyArg_GetObject(args, nargs, i, &v))
|
||||
return 0;
|
||||
if (PyTuple_Check(v)) {
|
||||
if (PyTuple_Size(v) != n) {
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
w = PyTuple_GetItem(v, i);
|
||||
if (!PyInt_Check(w)) {
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
p_arg[i] = PyInt_AsLong(w);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else if (PyList_Check(v)) {
|
||||
if (PyList_Size(v) != n) {
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
w = PyList_GetItem(v, i);
|
||||
if (!PyInt_Check(w)) {
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
p_arg[i] = PyInt_AsLong(w);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
PyArg_GetShortArray(PyObject *args, int nargs, int i, int n, short *p_arg)
|
||||
{
|
||||
PyObject *v, *w;
|
||||
if (!PyArg_GetObject(args, nargs, i, &v))
|
||||
return 0;
|
||||
if (PyTuple_Check(v)) {
|
||||
if (PyTuple_Size(v) != n) {
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
w = PyTuple_GetItem(v, i);
|
||||
if (!PyInt_Check(w)) {
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
p_arg[i] = (short) PyInt_AsLong(w);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else if (PyList_Check(v)) {
|
||||
if (PyList_Size(v) != n) {
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
w = PyList_GetItem(v, i);
|
||||
if (!PyInt_Check(w)) {
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
p_arg[i] = (short) PyInt_AsLong(w);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
PyArg_GetDoubleArray(PyObject *args, int nargs, int i, int n, double *p_arg)
|
||||
{
|
||||
PyObject *v, *w;
|
||||
if (!PyArg_GetObject(args, nargs, i, &v))
|
||||
return 0;
|
||||
if (PyTuple_Check(v)) {
|
||||
if (PyTuple_Size(v) != n) {
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
w = PyTuple_GetItem(v, i);
|
||||
if (!extractdouble(w, &p_arg[i]))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else if (PyList_Check(v)) {
|
||||
if (PyList_Size(v) != n) {
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
w = PyList_GetItem(v, i);
|
||||
if (!extractdouble(w, &p_arg[i]))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
PyArg_GetFloatArray(PyObject *args, int nargs, int i, int n, float *p_arg)
|
||||
{
|
||||
PyObject *v, *w;
|
||||
if (!PyArg_GetObject(args, nargs, i, &v))
|
||||
return 0;
|
||||
if (PyTuple_Check(v)) {
|
||||
if (PyTuple_Size(v) != n) {
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
w = PyTuple_GetItem(v, i);
|
||||
if (!extractfloat(w, &p_arg[i]))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else if (PyList_Check(v)) {
|
||||
if (PyList_Size(v) != n) {
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
w = PyList_GetItem(v, i);
|
||||
if (!extractfloat(w, &p_arg[i]))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return PyErr_BadArgument();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#ifndef Py_CGENSUPPORT_H
|
||||
#define Py_CGENSUPPORT_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* Definitions used by cgen output */
|
||||
|
||||
/* XXX This file is obsolete. It is *only* used by glmodule.c. */
|
||||
|
||||
typedef char *string;
|
||||
|
||||
#define mknewlongobject(x) PyInt_FromLong(x)
|
||||
#define mknewshortobject(x) PyInt_FromLong((long)x)
|
||||
#define mknewfloatobject(x) PyFloat_FromDouble(x)
|
||||
#define mknewcharobject(ch) Py_BuildValue("c", ch)
|
||||
|
||||
#define getichararg PyArg_GetChar
|
||||
#define getidoublearray PyArg_GetDoubleArray
|
||||
#define getifloatarg PyArg_GetFloat
|
||||
#define getifloatarray PyArg_GetFloatArray
|
||||
#define getilongarg PyArg_GetLong
|
||||
#define getilongarray PyArg_GetLongArray
|
||||
#define getilongarraysize PyArg_GetLongArraySize
|
||||
#define getiobjectarg PyArg_GetObject
|
||||
#define getishortarg PyArg_GetShort
|
||||
#define getishortarray PyArg_GetShortArray
|
||||
#define getishortarraysize PyArg_GetShortArraySize
|
||||
#define getistringarg PyArg_GetString
|
||||
|
||||
extern int PyArg_GetObject(PyObject *args, int nargs,
|
||||
int i, PyObject **p_a);
|
||||
extern int PyArg_GetLong(PyObject *args, int nargs,
|
||||
int i, long *p_a);
|
||||
extern int PyArg_GetShort(PyObject *args, int nargs,
|
||||
int i, short *p_a);
|
||||
extern int PyArg_GetFloat(PyObject *args, int nargs,
|
||||
int i, float *p_a);
|
||||
extern int PyArg_GetString(PyObject *args, int nargs,
|
||||
int i, string *p_a);
|
||||
extern int PyArg_GetChar(PyObject *args, int nargs,
|
||||
int i, char *p_a);
|
||||
extern int PyArg_GetLongArray(PyObject *args, int nargs,
|
||||
int i, int n, long *p_a);
|
||||
extern int PyArg_GetShortArray(PyObject *args, int nargs,
|
||||
int i, int n, short *p_a);
|
||||
extern int PyArg_GetDoubleArray(PyObject *args, int nargs,
|
||||
int i, int n, double *p_a);
|
||||
extern int PyArg_GetFloatArray(PyObject *args, int nargs,
|
||||
int i, int n, float *p_a);
|
||||
extern int PyArg_GetLongArraySize(PyObject *args, int nargs,
|
||||
int i, long *p_a);
|
||||
extern int PyArg_GetShortArraySize(PyObject *args, int nargs,
|
||||
int i, short *p_a);
|
||||
extern int PyArg_GetDoubleArraySize(PyObject *args, int nargs,
|
||||
int i, double *p_a);
|
||||
extern int PyArg_GetFloatArraySize(PyObject *args, int nargs,
|
||||
int i, float *p_a);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* !Py_CGENSUPPORT_H */
|
||||
@@ -0,0 +1,79 @@
|
||||
To generate or modify mapping headers
|
||||
-------------------------------------
|
||||
Mapping headers are imported from CJKCodecs as pre-generated form.
|
||||
If you need to tweak or add something on it, please look at tools/
|
||||
subdirectory of CJKCodecs' distribution.
|
||||
|
||||
|
||||
|
||||
Notes on implmentation characteristics of each codecs
|
||||
-----------------------------------------------------
|
||||
|
||||
1) Big5 codec
|
||||
|
||||
The big5 codec maps the following characters as cp950 does rather
|
||||
than conforming Unicode.org's that maps to 0xFFFD.
|
||||
|
||||
BIG5 Unicode Description
|
||||
|
||||
0xA15A 0x2574 SPACING UNDERSCORE
|
||||
0xA1C3 0xFFE3 SPACING HEAVY OVERSCORE
|
||||
0xA1C5 0x02CD SPACING HEAVY UNDERSCORE
|
||||
0xA1FE 0xFF0F LT DIAG UP RIGHT TO LOW LEFT
|
||||
0xA240 0xFF3C LT DIAG UP LEFT TO LOW RIGHT
|
||||
0xA2CC 0x5341 HANGZHOU NUMERAL TEN
|
||||
0xA2CE 0x5345 HANGZHOU NUMERAL THIRTY
|
||||
|
||||
Because unicode 0x5341, 0x5345, 0xFF0F, 0xFF3C is mapped to another
|
||||
big5 codes already, a roundtrip compatibility is not guaranteed for
|
||||
them.
|
||||
|
||||
|
||||
2) cp932 codec
|
||||
|
||||
To conform to Windows's real mapping, cp932 codec maps the following
|
||||
codepoints in addition of the official cp932 mapping.
|
||||
|
||||
CP932 Unicode Description
|
||||
|
||||
0x80 0x80 UNDEFINED
|
||||
0xA0 0xF8F0 UNDEFINED
|
||||
0xFD 0xF8F1 UNDEFINED
|
||||
0xFE 0xF8F2 UNDEFINED
|
||||
0xFF 0xF8F3 UNDEFINED
|
||||
|
||||
|
||||
3) euc-jisx0213 codec
|
||||
|
||||
The euc-jisx0213 codec maps JIS X 0213 Plane 1 code 0x2140 into
|
||||
unicode U+FF3C instead of U+005C as on unicode.org's mapping.
|
||||
Because euc-jisx0213 has REVERSE SOLIDUS on 0x5c already and A140
|
||||
is shown as a full width character, mapping to U+FF3C can make
|
||||
more sense.
|
||||
|
||||
The euc-jisx0213 codec is enabled to decode JIS X 0212 codes on
|
||||
codeset 2. Because JIS X 0212 and JIS X 0213 Plane 2 don't have
|
||||
overlapped by each other, it doesn't bother standard conformations
|
||||
(and JIS X 0213 Plane 2 is intended to use so.) On encoding
|
||||
sessions, the codec will try to encode kanji characters in this
|
||||
order:
|
||||
|
||||
JIS X 0213 Plane 1 -> JIS X 0213 Plane 2 -> JIS X 0212
|
||||
|
||||
|
||||
4) euc-jp codec
|
||||
|
||||
The euc-jp codec is a compatibility instance on these points:
|
||||
- U+FF3C FULLWIDTH REVERSE SOLIDUS is mapped to EUC-JP A1C0 (vice versa)
|
||||
- U+00A5 YEN SIGN is mapped to EUC-JP 0x5c. (one way)
|
||||
- U+203E OVERLINE is mapped to EUC-JP 0x7e. (one way)
|
||||
|
||||
|
||||
5) shift-jis codec
|
||||
|
||||
The shift-jis codec is mapping 0x20-0x7e area to U+20-U+7E directly
|
||||
instead of using JIS X 0201 for compatibility. The differences are:
|
||||
- U+005C REVERSE SOLIDUS is mapped to SHIFT-JIS 0x5c.
|
||||
- U+007E TILDE is mapped to SHIFT-JIS 0x7e.
|
||||
- U+FF3C FULL-WIDTH REVERSE SOLIDUS is mapped to SHIFT-JIS 815f.
|
||||
|
||||
@@ -0,0 +1,447 @@
|
||||
/*
|
||||
* _codecs_cn.c: Codecs collection for Mainland Chinese encodings
|
||||
*
|
||||
* Written by Hye-Shik Chang <perky@FreeBSD.org>
|
||||
*/
|
||||
|
||||
#include "cjkcodecs.h"
|
||||
#include "mappings_cn.h"
|
||||
|
||||
/**
|
||||
* hz is predefined as 100 on AIX. So we undefine it to avoid
|
||||
* conflict against hz codec's.
|
||||
*/
|
||||
#ifdef _AIX
|
||||
#undef hz
|
||||
#endif
|
||||
|
||||
/* GBK and GB2312 map differently in few code points that are listed below:
|
||||
*
|
||||
* gb2312 gbk
|
||||
* A1A4 U+30FB KATAKANA MIDDLE DOT U+00B7 MIDDLE DOT
|
||||
* A1AA U+2015 HORIZONTAL BAR U+2014 EM DASH
|
||||
* A844 undefined U+2015 HORIZONTAL BAR
|
||||
*/
|
||||
|
||||
#define GBK_DECODE(dc1, dc2, assi) \
|
||||
if ((dc1) == 0xa1 && (dc2) == 0xaa) (assi) = 0x2014; \
|
||||
else if ((dc1) == 0xa8 && (dc2) == 0x44) (assi) = 0x2015; \
|
||||
else if ((dc1) == 0xa1 && (dc2) == 0xa4) (assi) = 0x00b7; \
|
||||
else TRYMAP_DEC(gb2312, assi, dc1 ^ 0x80, dc2 ^ 0x80); \
|
||||
else TRYMAP_DEC(gbkext, assi, dc1, dc2);
|
||||
|
||||
#define GBK_ENCODE(code, assi) \
|
||||
if ((code) == 0x2014) (assi) = 0xa1aa; \
|
||||
else if ((code) == 0x2015) (assi) = 0xa844; \
|
||||
else if ((code) == 0x00b7) (assi) = 0xa1a4; \
|
||||
else if ((code) != 0x30fb && TRYMAP_ENC_COND(gbcommon, assi, code));
|
||||
|
||||
/*
|
||||
* GB2312 codec
|
||||
*/
|
||||
|
||||
ENCODER(gb2312)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
Py_UNICODE c = IN1;
|
||||
DBCHAR code;
|
||||
|
||||
if (c < 0x80) {
|
||||
WRITE1((unsigned char)c)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
UCS4INVALID(c)
|
||||
|
||||
REQUIRE_OUTBUF(2)
|
||||
TRYMAP_ENC(gbcommon, code, c);
|
||||
else return 1;
|
||||
|
||||
if (code & 0x8000) /* MSB set: GBK */
|
||||
return 1;
|
||||
|
||||
OUT1((code >> 8) | 0x80)
|
||||
OUT2((code & 0xFF) | 0x80)
|
||||
NEXT(1, 2)
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DECODER(gb2312)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
unsigned char c = **inbuf;
|
||||
|
||||
REQUIRE_OUTBUF(1)
|
||||
|
||||
if (c < 0x80) {
|
||||
OUT1(c)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
|
||||
REQUIRE_INBUF(2)
|
||||
TRYMAP_DEC(gb2312, **outbuf, c ^ 0x80, IN2 ^ 0x80) {
|
||||
NEXT(2, 1)
|
||||
}
|
||||
else return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* GBK codec
|
||||
*/
|
||||
|
||||
ENCODER(gbk)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
Py_UNICODE c = IN1;
|
||||
DBCHAR code;
|
||||
|
||||
if (c < 0x80) {
|
||||
WRITE1((unsigned char)c)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
UCS4INVALID(c)
|
||||
|
||||
REQUIRE_OUTBUF(2)
|
||||
|
||||
GBK_ENCODE(c, code)
|
||||
else return 1;
|
||||
|
||||
OUT1((code >> 8) | 0x80)
|
||||
if (code & 0x8000)
|
||||
OUT2((code & 0xFF)) /* MSB set: GBK */
|
||||
else
|
||||
OUT2((code & 0xFF) | 0x80) /* MSB unset: GB2312 */
|
||||
NEXT(1, 2)
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DECODER(gbk)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
unsigned char c = IN1;
|
||||
|
||||
REQUIRE_OUTBUF(1)
|
||||
|
||||
if (c < 0x80) {
|
||||
OUT1(c)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
|
||||
REQUIRE_INBUF(2)
|
||||
|
||||
GBK_DECODE(c, IN2, **outbuf)
|
||||
else return 2;
|
||||
|
||||
NEXT(2, 1)
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* GB18030 codec
|
||||
*/
|
||||
|
||||
ENCODER(gb18030)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
ucs4_t c = IN1;
|
||||
DBCHAR code;
|
||||
|
||||
if (c < 0x80) {
|
||||
WRITE1(c)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
|
||||
DECODE_SURROGATE(c)
|
||||
if (c > 0x10FFFF)
|
||||
#if Py_UNICODE_SIZE == 2
|
||||
return 2; /* surrogates pair */
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
else if (c >= 0x10000) {
|
||||
ucs4_t tc = c - 0x10000;
|
||||
|
||||
REQUIRE_OUTBUF(4)
|
||||
|
||||
OUT4((unsigned char)(tc % 10) + 0x30)
|
||||
tc /= 10;
|
||||
OUT3((unsigned char)(tc % 126) + 0x81)
|
||||
tc /= 126;
|
||||
OUT2((unsigned char)(tc % 10) + 0x30)
|
||||
tc /= 10;
|
||||
OUT1((unsigned char)(tc + 0x90))
|
||||
|
||||
#if Py_UNICODE_SIZE == 2
|
||||
NEXT(2, 4) /* surrogates pair */
|
||||
#else
|
||||
NEXT(1, 4)
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
REQUIRE_OUTBUF(2)
|
||||
|
||||
GBK_ENCODE(c, code)
|
||||
else TRYMAP_ENC(gb18030ext, code, c);
|
||||
else {
|
||||
const struct _gb18030_to_unibmp_ranges *utrrange;
|
||||
|
||||
REQUIRE_OUTBUF(4)
|
||||
|
||||
for (utrrange = gb18030_to_unibmp_ranges;
|
||||
utrrange->first != 0;
|
||||
utrrange++)
|
||||
if (utrrange->first <= c &&
|
||||
c <= utrrange->last) {
|
||||
Py_UNICODE tc;
|
||||
|
||||
tc = c - utrrange->first +
|
||||
utrrange->base;
|
||||
|
||||
OUT4((unsigned char)(tc % 10) + 0x30)
|
||||
tc /= 10;
|
||||
OUT3((unsigned char)(tc % 126) + 0x81)
|
||||
tc /= 126;
|
||||
OUT2((unsigned char)(tc % 10) + 0x30)
|
||||
tc /= 10;
|
||||
OUT1((unsigned char)tc + 0x81)
|
||||
|
||||
NEXT(1, 4)
|
||||
break;
|
||||
}
|
||||
|
||||
if (utrrange->first == 0)
|
||||
return 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
OUT1((code >> 8) | 0x80)
|
||||
if (code & 0x8000)
|
||||
OUT2((code & 0xFF)) /* MSB set: GBK or GB18030ext */
|
||||
else
|
||||
OUT2((code & 0xFF) | 0x80) /* MSB unset: GB2312 */
|
||||
|
||||
NEXT(1, 2)
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DECODER(gb18030)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
unsigned char c = IN1, c2;
|
||||
|
||||
REQUIRE_OUTBUF(1)
|
||||
|
||||
if (c < 0x80) {
|
||||
OUT1(c)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
|
||||
REQUIRE_INBUF(2)
|
||||
|
||||
c2 = IN2;
|
||||
if (c2 >= 0x30 && c2 <= 0x39) { /* 4 bytes seq */
|
||||
const struct _gb18030_to_unibmp_ranges *utr;
|
||||
unsigned char c3, c4;
|
||||
ucs4_t lseq;
|
||||
|
||||
REQUIRE_INBUF(4)
|
||||
c3 = IN3;
|
||||
c4 = IN4;
|
||||
if (c < 0x81 || c > 0xFE ||
|
||||
c3 < 0x81 || c3 > 0xFE ||
|
||||
c4 < 0x30 || c4 > 0x39)
|
||||
return 4;
|
||||
c -= 0x81; c2 -= 0x30;
|
||||
c3 -= 0x81; c4 -= 0x30;
|
||||
|
||||
if (c < 4) { /* U+0080 - U+FFFF */
|
||||
lseq = ((ucs4_t)c * 10 + c2) * 1260 +
|
||||
(ucs4_t)c3 * 10 + c4;
|
||||
if (lseq < 39420) {
|
||||
for (utr = gb18030_to_unibmp_ranges;
|
||||
lseq >= (utr + 1)->base;
|
||||
utr++) ;
|
||||
OUT1(utr->first - utr->base + lseq)
|
||||
NEXT(4, 1)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (c >= 15) { /* U+10000 - U+10FFFF */
|
||||
lseq = 0x10000 + (((ucs4_t)c-15) * 10 + c2)
|
||||
* 1260 + (ucs4_t)c3 * 10 + c4;
|
||||
if (lseq <= 0x10FFFF) {
|
||||
WRITEUCS4(lseq);
|
||||
NEXT_IN(4)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
|
||||
GBK_DECODE(c, c2, **outbuf)
|
||||
else TRYMAP_DEC(gb18030ext, **outbuf, c, c2);
|
||||
else return 2;
|
||||
|
||||
NEXT(2, 1)
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* HZ codec
|
||||
*/
|
||||
|
||||
ENCODER_INIT(hz)
|
||||
{
|
||||
state->i = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ENCODER_RESET(hz)
|
||||
{
|
||||
if (state->i != 0) {
|
||||
WRITE2('~', '}')
|
||||
state->i = 0;
|
||||
NEXT_OUT(2)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ENCODER(hz)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
Py_UNICODE c = IN1;
|
||||
DBCHAR code;
|
||||
|
||||
if (c < 0x80) {
|
||||
if (state->i) {
|
||||
WRITE2('~', '}')
|
||||
NEXT_OUT(2)
|
||||
state->i = 0;
|
||||
}
|
||||
WRITE1((unsigned char)c)
|
||||
NEXT(1, 1)
|
||||
if (c == '~') {
|
||||
WRITE1('~')
|
||||
NEXT_OUT(1)
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
UCS4INVALID(c)
|
||||
|
||||
TRYMAP_ENC(gbcommon, code, c);
|
||||
else return 1;
|
||||
|
||||
if (code & 0x8000) /* MSB set: GBK */
|
||||
return 1;
|
||||
|
||||
if (state->i == 0) {
|
||||
WRITE4('~', '{', code >> 8, code & 0xff)
|
||||
NEXT(1, 4)
|
||||
state->i = 1;
|
||||
}
|
||||
else {
|
||||
WRITE2(code >> 8, code & 0xff)
|
||||
NEXT(1, 2)
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DECODER_INIT(hz)
|
||||
{
|
||||
state->i = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DECODER_RESET(hz)
|
||||
{
|
||||
state->i = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DECODER(hz)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
unsigned char c = IN1;
|
||||
|
||||
if (c == '~') {
|
||||
unsigned char c2 = IN2;
|
||||
|
||||
REQUIRE_INBUF(2)
|
||||
if (c2 == '~' && state->i == 0) {
|
||||
WRITE1('~')
|
||||
NEXT_OUT(1)
|
||||
}
|
||||
else if (c2 == '{' && state->i == 0)
|
||||
state->i = 1; /* set GB */
|
||||
else if (c2 == '\n' && state->i == 0)
|
||||
; /* line-continuation */
|
||||
else if (c2 == '}' && state->i == 1)
|
||||
state->i = 0; /* set ASCII */
|
||||
else
|
||||
return 2;
|
||||
NEXT_IN(2)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c & 0x80)
|
||||
return 1;
|
||||
|
||||
if (state->i == 0) { /* ASCII mode */
|
||||
WRITE1(c)
|
||||
NEXT(1, 1)
|
||||
}
|
||||
else { /* GB mode */
|
||||
REQUIRE_INBUF(2)
|
||||
REQUIRE_OUTBUF(1)
|
||||
TRYMAP_DEC(gb2312, **outbuf, c, IN2) {
|
||||
NEXT(2, 1)
|
||||
}
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
BEGIN_MAPPINGS_LIST
|
||||
MAPPING_DECONLY(gb2312)
|
||||
MAPPING_DECONLY(gbkext)
|
||||
MAPPING_ENCONLY(gbcommon)
|
||||
MAPPING_ENCDEC(gb18030ext)
|
||||
END_MAPPINGS_LIST
|
||||
|
||||
BEGIN_CODECS_LIST
|
||||
CODEC_STATELESS(gb2312)
|
||||
CODEC_STATELESS(gbk)
|
||||
CODEC_STATELESS(gb18030)
|
||||
CODEC_STATEFUL(hz)
|
||||
END_CODECS_LIST
|
||||
|
||||
I_AM_A_MODULE_FOR(cn)
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* _codecs_hk.c: Codecs collection for encodings from Hong Kong
|
||||
*
|
||||
* Written by Hye-Shik Chang <perky@FreeBSD.org>
|
||||
*/
|
||||
|
||||
#define USING_IMPORTED_MAPS
|
||||
|
||||
#include "cjkcodecs.h"
|
||||
#include "mappings_hk.h"
|
||||
|
||||
/*
|
||||
* BIG5HKSCS codec
|
||||
*/
|
||||
|
||||
static const encode_map *big5_encmap = NULL;
|
||||
static const decode_map *big5_decmap = NULL;
|
||||
|
||||
CODEC_INIT(big5hkscs)
|
||||
{
|
||||
static int initialized = 0;
|
||||
|
||||
if (!initialized && IMPORT_MAP(tw, big5, &big5_encmap, &big5_decmap))
|
||||
return -1;
|
||||
initialized = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* There are four possible pair unicode -> big5hkscs maps as in HKSCS 2004:
|
||||
* U+00CA U+0304 -> 8862 (U+00CA alone is mapped to 8866)
|
||||
* U+00CA U+030C -> 8864
|
||||
* U+00EA U+0304 -> 88a3 (U+00EA alone is mapped to 88a7)
|
||||
* U+00EA U+030C -> 88a5
|
||||
* These are handled by not mapping tables but a hand-written code.
|
||||
*/
|
||||
static const DBCHAR big5hkscs_pairenc_table[4] = {0x8862, 0x8864, 0x88a3, 0x88a5};
|
||||
|
||||
ENCODER(big5hkscs)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
ucs4_t c = **inbuf;
|
||||
DBCHAR code;
|
||||
Py_ssize_t insize;
|
||||
|
||||
if (c < 0x80) {
|
||||
REQUIRE_OUTBUF(1)
|
||||
**outbuf = (unsigned char)c;
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
|
||||
DECODE_SURROGATE(c)
|
||||
insize = GET_INSIZE(c);
|
||||
|
||||
REQUIRE_OUTBUF(2)
|
||||
|
||||
if (c < 0x10000) {
|
||||
TRYMAP_ENC(big5hkscs_bmp, code, c) {
|
||||
if (code == MULTIC) {
|
||||
if (inleft >= 2 &&
|
||||
((c & 0xffdf) == 0x00ca) &&
|
||||
(((*inbuf)[1] & 0xfff7) == 0x0304)) {
|
||||
code = big5hkscs_pairenc_table[
|
||||
((c >> 4) |
|
||||
((*inbuf)[1] >> 3)) & 3];
|
||||
insize = 2;
|
||||
}
|
||||
else if (inleft < 2 &&
|
||||
!(flags & MBENC_FLUSH))
|
||||
return MBERR_TOOFEW;
|
||||
else {
|
||||
if (c == 0xca)
|
||||
code = 0x8866;
|
||||
else /* c == 0xea */
|
||||
code = 0x88a7;
|
||||
}
|
||||
}
|
||||
}
|
||||
else TRYMAP_ENC(big5, code, c);
|
||||
else return 1;
|
||||
}
|
||||
else if (c < 0x20000)
|
||||
return insize;
|
||||
else if (c < 0x30000) {
|
||||
TRYMAP_ENC(big5hkscs_nonbmp, code, c & 0xffff);
|
||||
else return insize;
|
||||
}
|
||||
else
|
||||
return insize;
|
||||
|
||||
OUT1(code >> 8)
|
||||
OUT2(code & 0xFF)
|
||||
NEXT(insize, 2)
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define BH2S(c1, c2) (((c1) - 0x87) * (0xfe - 0x40 + 1) + ((c2) - 0x40))
|
||||
|
||||
DECODER(big5hkscs)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
unsigned char c = IN1;
|
||||
ucs4_t decoded;
|
||||
|
||||
REQUIRE_OUTBUF(1)
|
||||
|
||||
if (c < 0x80) {
|
||||
OUT1(c)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
|
||||
REQUIRE_INBUF(2)
|
||||
|
||||
if (0xc6 > c || c > 0xc8 || (c < 0xc7 && IN2 < 0xa1)) {
|
||||
TRYMAP_DEC(big5, **outbuf, c, IN2) {
|
||||
NEXT(2, 1)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
TRYMAP_DEC(big5hkscs, decoded, c, IN2)
|
||||
{
|
||||
int s = BH2S(c, IN2);
|
||||
const unsigned char *hintbase;
|
||||
|
||||
assert(0x87 <= c && c <= 0xfe);
|
||||
assert(0x40 <= IN2 && IN2 <= 0xfe);
|
||||
|
||||
if (BH2S(0x87, 0x40) <= s && s <= BH2S(0xa0, 0xfe)) {
|
||||
hintbase = big5hkscs_phint_0;
|
||||
s -= BH2S(0x87, 0x40);
|
||||
}
|
||||
else if (BH2S(0xc6,0xa1) <= s && s <= BH2S(0xc8,0xfe)){
|
||||
hintbase = big5hkscs_phint_12130;
|
||||
s -= BH2S(0xc6, 0xa1);
|
||||
}
|
||||
else if (BH2S(0xf9,0xd6) <= s && s <= BH2S(0xfe,0xfe)){
|
||||
hintbase = big5hkscs_phint_21924;
|
||||
s -= BH2S(0xf9, 0xd6);
|
||||
}
|
||||
else
|
||||
return MBERR_INTERNAL;
|
||||
|
||||
if (hintbase[s >> 3] & (1 << (s & 7))) {
|
||||
WRITEUCS4(decoded | 0x20000)
|
||||
NEXT_IN(2)
|
||||
}
|
||||
else {
|
||||
OUT1(decoded)
|
||||
NEXT(2, 1)
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
switch ((c << 8) | IN2) {
|
||||
case 0x8862: WRITE2(0x00ca, 0x0304); break;
|
||||
case 0x8864: WRITE2(0x00ca, 0x030c); break;
|
||||
case 0x88a3: WRITE2(0x00ea, 0x0304); break;
|
||||
case 0x88a5: WRITE2(0x00ea, 0x030c); break;
|
||||
default: return 2;
|
||||
}
|
||||
|
||||
NEXT(2, 2) /* all decoded code points are pairs, above. */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
BEGIN_MAPPINGS_LIST
|
||||
MAPPING_DECONLY(big5hkscs)
|
||||
MAPPING_ENCONLY(big5hkscs_bmp)
|
||||
MAPPING_ENCONLY(big5hkscs_nonbmp)
|
||||
END_MAPPINGS_LIST
|
||||
|
||||
BEGIN_CODECS_LIST
|
||||
CODEC_STATELESS_WINIT(big5hkscs)
|
||||
END_CODECS_LIST
|
||||
|
||||
I_AM_A_MODULE_FOR(hk)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,731 @@
|
||||
/*
|
||||
* _codecs_jp.c: Codecs collection for Japanese encodings
|
||||
*
|
||||
* Written by Hye-Shik Chang <perky@FreeBSD.org>
|
||||
*/
|
||||
|
||||
#define USING_BINARY_PAIR_SEARCH
|
||||
#define EMPBASE 0x20000
|
||||
|
||||
#include "cjkcodecs.h"
|
||||
#include "mappings_jp.h"
|
||||
#include "mappings_jisx0213_pair.h"
|
||||
#include "alg_jisx0201.h"
|
||||
#include "emu_jisx0213_2000.h"
|
||||
|
||||
/*
|
||||
* CP932 codec
|
||||
*/
|
||||
|
||||
ENCODER(cp932)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
Py_UNICODE c = IN1;
|
||||
DBCHAR code;
|
||||
unsigned char c1, c2;
|
||||
|
||||
if (c <= 0x80) {
|
||||
WRITE1((unsigned char)c)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
else if (c >= 0xff61 && c <= 0xff9f) {
|
||||
WRITE1(c - 0xfec0)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
else if (c >= 0xf8f0 && c <= 0xf8f3) {
|
||||
/* Windows compatibility */
|
||||
REQUIRE_OUTBUF(1)
|
||||
if (c == 0xf8f0)
|
||||
OUT1(0xa0)
|
||||
else
|
||||
OUT1(c - 0xf8f1 + 0xfd)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
|
||||
UCS4INVALID(c)
|
||||
REQUIRE_OUTBUF(2)
|
||||
|
||||
TRYMAP_ENC(cp932ext, code, c) {
|
||||
OUT1(code >> 8)
|
||||
OUT2(code & 0xff)
|
||||
}
|
||||
else TRYMAP_ENC(jisxcommon, code, c) {
|
||||
if (code & 0x8000) /* MSB set: JIS X 0212 */
|
||||
return 1;
|
||||
|
||||
/* JIS X 0208 */
|
||||
c1 = code >> 8;
|
||||
c2 = code & 0xff;
|
||||
c2 = (((c1 - 0x21) & 1) ? 0x5e : 0) + (c2 - 0x21);
|
||||
c1 = (c1 - 0x21) >> 1;
|
||||
OUT1(c1 < 0x1f ? c1 + 0x81 : c1 + 0xc1)
|
||||
OUT2(c2 < 0x3f ? c2 + 0x40 : c2 + 0x41)
|
||||
}
|
||||
else if (c >= 0xe000 && c < 0xe758) {
|
||||
/* User-defined area */
|
||||
c1 = (Py_UNICODE)(c - 0xe000) / 188;
|
||||
c2 = (Py_UNICODE)(c - 0xe000) % 188;
|
||||
OUT1(c1 + 0xf0)
|
||||
OUT2(c2 < 0x3f ? c2 + 0x40 : c2 + 0x41)
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
|
||||
NEXT(1, 2)
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DECODER(cp932)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
unsigned char c = IN1, c2;
|
||||
|
||||
REQUIRE_OUTBUF(1)
|
||||
if (c <= 0x80) {
|
||||
OUT1(c)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
else if (c >= 0xa0 && c <= 0xdf) {
|
||||
if (c == 0xa0)
|
||||
OUT1(0xf8f0) /* half-width katakana */
|
||||
else
|
||||
OUT1(0xfec0 + c)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
else if (c >= 0xfd/* && c <= 0xff*/) {
|
||||
/* Windows compatibility */
|
||||
OUT1(0xf8f1 - 0xfd + c)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
|
||||
REQUIRE_INBUF(2)
|
||||
c2 = IN2;
|
||||
|
||||
TRYMAP_DEC(cp932ext, **outbuf, c, c2);
|
||||
else if ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c <= 0xea)){
|
||||
if (c2 < 0x40 || (c2 > 0x7e && c2 < 0x80) || c2 > 0xfc)
|
||||
return 2;
|
||||
|
||||
c = (c < 0xe0 ? c - 0x81 : c - 0xc1);
|
||||
c2 = (c2 < 0x80 ? c2 - 0x40 : c2 - 0x41);
|
||||
c = (2 * c + (c2 < 0x5e ? 0 : 1) + 0x21);
|
||||
c2 = (c2 < 0x5e ? c2 : c2 - 0x5e) + 0x21;
|
||||
|
||||
TRYMAP_DEC(jisx0208, **outbuf, c, c2);
|
||||
else return 2;
|
||||
}
|
||||
else if (c >= 0xf0 && c <= 0xf9) {
|
||||
if ((c2 >= 0x40 && c2 <= 0x7e) ||
|
||||
(c2 >= 0x80 && c2 <= 0xfc))
|
||||
OUT1(0xe000 + 188 * (c - 0xf0) +
|
||||
(c2 < 0x80 ? c2 - 0x40 : c2 - 0x41))
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
return 2;
|
||||
|
||||
NEXT(2, 1)
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* EUC-JIS-2004 codec
|
||||
*/
|
||||
|
||||
ENCODER(euc_jis_2004)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
ucs4_t c = IN1;
|
||||
DBCHAR code;
|
||||
Py_ssize_t insize;
|
||||
|
||||
if (c < 0x80) {
|
||||
WRITE1(c)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
|
||||
DECODE_SURROGATE(c)
|
||||
insize = GET_INSIZE(c);
|
||||
|
||||
if (c <= 0xFFFF) {
|
||||
EMULATE_JISX0213_2000_ENCODE_BMP(code, c)
|
||||
else TRYMAP_ENC(jisx0213_bmp, code, c) {
|
||||
if (code == MULTIC) {
|
||||
if (inleft < 2) {
|
||||
if (flags & MBENC_FLUSH) {
|
||||
code = find_pairencmap(
|
||||
(ucs2_t)c, 0,
|
||||
jisx0213_pair_encmap,
|
||||
JISX0213_ENCPAIRS);
|
||||
if (code == DBCINV)
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return MBERR_TOOFEW;
|
||||
}
|
||||
else {
|
||||
code = find_pairencmap(
|
||||
(ucs2_t)c, (*inbuf)[1],
|
||||
jisx0213_pair_encmap,
|
||||
JISX0213_ENCPAIRS);
|
||||
if (code == DBCINV) {
|
||||
code = find_pairencmap(
|
||||
(ucs2_t)c, 0,
|
||||
jisx0213_pair_encmap,
|
||||
JISX0213_ENCPAIRS);
|
||||
if (code == DBCINV)
|
||||
return 1;
|
||||
} else
|
||||
insize = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else TRYMAP_ENC(jisxcommon, code, c);
|
||||
else if (c >= 0xff61 && c <= 0xff9f) {
|
||||
/* JIS X 0201 half-width katakana */
|
||||
WRITE2(0x8e, c - 0xfec0)
|
||||
NEXT(1, 2)
|
||||
continue;
|
||||
}
|
||||
else if (c == 0xff3c)
|
||||
/* F/W REVERSE SOLIDUS (see NOTES) */
|
||||
code = 0x2140;
|
||||
else if (c == 0xff5e)
|
||||
/* F/W TILDE (see NOTES) */
|
||||
code = 0x2232;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
else if (c >> 16 == EMPBASE >> 16) {
|
||||
EMULATE_JISX0213_2000_ENCODE_EMP(code, c)
|
||||
else TRYMAP_ENC(jisx0213_emp, code, c & 0xffff);
|
||||
else return insize;
|
||||
}
|
||||
else
|
||||
return insize;
|
||||
|
||||
if (code & 0x8000) {
|
||||
/* Codeset 2 */
|
||||
WRITE3(0x8f, code >> 8, (code & 0xFF) | 0x80)
|
||||
NEXT(insize, 3)
|
||||
} else {
|
||||
/* Codeset 1 */
|
||||
WRITE2((code >> 8) | 0x80, (code & 0xFF) | 0x80)
|
||||
NEXT(insize, 2)
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DECODER(euc_jis_2004)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
unsigned char c = IN1;
|
||||
ucs4_t code;
|
||||
|
||||
REQUIRE_OUTBUF(1)
|
||||
|
||||
if (c < 0x80) {
|
||||
OUT1(c)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == 0x8e) {
|
||||
/* JIS X 0201 half-width katakana */
|
||||
unsigned char c2;
|
||||
|
||||
REQUIRE_INBUF(2)
|
||||
c2 = IN2;
|
||||
if (c2 >= 0xa1 && c2 <= 0xdf) {
|
||||
OUT1(0xfec0 + c2)
|
||||
NEXT(2, 1)
|
||||
}
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
else if (c == 0x8f) {
|
||||
unsigned char c2, c3;
|
||||
|
||||
REQUIRE_INBUF(3)
|
||||
c2 = IN2 ^ 0x80;
|
||||
c3 = IN3 ^ 0x80;
|
||||
|
||||
/* JIS X 0213 Plane 2 or JIS X 0212 (see NOTES) */
|
||||
EMULATE_JISX0213_2000_DECODE_PLANE2(**outbuf, c2, c3)
|
||||
else TRYMAP_DEC(jisx0213_2_bmp, **outbuf, c2, c3) ;
|
||||
else TRYMAP_DEC(jisx0213_2_emp, code, c2, c3) {
|
||||
WRITEUCS4(EMPBASE | code)
|
||||
NEXT_IN(3)
|
||||
continue;
|
||||
}
|
||||
else TRYMAP_DEC(jisx0212, **outbuf, c2, c3) ;
|
||||
else return 3;
|
||||
NEXT(3, 1)
|
||||
}
|
||||
else {
|
||||
unsigned char c2;
|
||||
|
||||
REQUIRE_INBUF(2)
|
||||
c ^= 0x80;
|
||||
c2 = IN2 ^ 0x80;
|
||||
|
||||
/* JIS X 0213 Plane 1 */
|
||||
EMULATE_JISX0213_2000_DECODE_PLANE1(**outbuf, c, c2)
|
||||
else if (c == 0x21 && c2 == 0x40) **outbuf = 0xff3c;
|
||||
else if (c == 0x22 && c2 == 0x32) **outbuf = 0xff5e;
|
||||
else TRYMAP_DEC(jisx0208, **outbuf, c, c2);
|
||||
else TRYMAP_DEC(jisx0213_1_bmp, **outbuf, c, c2);
|
||||
else TRYMAP_DEC(jisx0213_1_emp, code, c, c2) {
|
||||
WRITEUCS4(EMPBASE | code)
|
||||
NEXT_IN(2)
|
||||
continue;
|
||||
}
|
||||
else TRYMAP_DEC(jisx0213_pair, code, c, c2) {
|
||||
WRITE2(code >> 16, code & 0xffff)
|
||||
NEXT(2, 2)
|
||||
continue;
|
||||
}
|
||||
else return 2;
|
||||
NEXT(2, 1)
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* EUC-JP codec
|
||||
*/
|
||||
|
||||
ENCODER(euc_jp)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
Py_UNICODE c = IN1;
|
||||
DBCHAR code;
|
||||
|
||||
if (c < 0x80) {
|
||||
WRITE1((unsigned char)c)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
|
||||
UCS4INVALID(c)
|
||||
|
||||
TRYMAP_ENC(jisxcommon, code, c);
|
||||
else if (c >= 0xff61 && c <= 0xff9f) {
|
||||
/* JIS X 0201 half-width katakana */
|
||||
WRITE2(0x8e, c - 0xfec0)
|
||||
NEXT(1, 2)
|
||||
continue;
|
||||
}
|
||||
#ifndef STRICT_BUILD
|
||||
else if (c == 0xff3c) /* FULL-WIDTH REVERSE SOLIDUS */
|
||||
code = 0x2140;
|
||||
else if (c == 0xa5) { /* YEN SIGN */
|
||||
WRITE1(0x5c);
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
} else if (c == 0x203e) { /* OVERLINE */
|
||||
WRITE1(0x7e);
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
return 1;
|
||||
|
||||
if (code & 0x8000) {
|
||||
/* JIS X 0212 */
|
||||
WRITE3(0x8f, code >> 8, (code & 0xFF) | 0x80)
|
||||
NEXT(1, 3)
|
||||
} else {
|
||||
/* JIS X 0208 */
|
||||
WRITE2((code >> 8) | 0x80, (code & 0xFF) | 0x80)
|
||||
NEXT(1, 2)
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DECODER(euc_jp)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
unsigned char c = IN1;
|
||||
|
||||
REQUIRE_OUTBUF(1)
|
||||
|
||||
if (c < 0x80) {
|
||||
OUT1(c)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == 0x8e) {
|
||||
/* JIS X 0201 half-width katakana */
|
||||
unsigned char c2;
|
||||
|
||||
REQUIRE_INBUF(2)
|
||||
c2 = IN2;
|
||||
if (c2 >= 0xa1 && c2 <= 0xdf) {
|
||||
OUT1(0xfec0 + c2)
|
||||
NEXT(2, 1)
|
||||
}
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
else if (c == 0x8f) {
|
||||
unsigned char c2, c3;
|
||||
|
||||
REQUIRE_INBUF(3)
|
||||
c2 = IN2;
|
||||
c3 = IN3;
|
||||
/* JIS X 0212 */
|
||||
TRYMAP_DEC(jisx0212, **outbuf, c2 ^ 0x80, c3 ^ 0x80) {
|
||||
NEXT(3, 1)
|
||||
}
|
||||
else
|
||||
return 3;
|
||||
}
|
||||
else {
|
||||
unsigned char c2;
|
||||
|
||||
REQUIRE_INBUF(2)
|
||||
c2 = IN2;
|
||||
/* JIS X 0208 */
|
||||
#ifndef STRICT_BUILD
|
||||
if (c == 0xa1 && c2 == 0xc0)
|
||||
/* FULL-WIDTH REVERSE SOLIDUS */
|
||||
**outbuf = 0xff3c;
|
||||
else
|
||||
#endif
|
||||
TRYMAP_DEC(jisx0208, **outbuf,
|
||||
c ^ 0x80, c2 ^ 0x80) ;
|
||||
else return 2;
|
||||
NEXT(2, 1)
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SHIFT_JIS codec
|
||||
*/
|
||||
|
||||
ENCODER(shift_jis)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
Py_UNICODE c = IN1;
|
||||
DBCHAR code;
|
||||
unsigned char c1, c2;
|
||||
|
||||
#ifdef STRICT_BUILD
|
||||
JISX0201_R_ENCODE(c, code)
|
||||
#else
|
||||
if (c < 0x80) code = c;
|
||||
else if (c == 0x00a5) code = 0x5c; /* YEN SIGN */
|
||||
else if (c == 0x203e) code = 0x7e; /* OVERLINE */
|
||||
#endif
|
||||
else JISX0201_K_ENCODE(c, code)
|
||||
else UCS4INVALID(c)
|
||||
else code = NOCHAR;
|
||||
|
||||
if (code < 0x80 || (code >= 0xa1 && code <= 0xdf)) {
|
||||
REQUIRE_OUTBUF(1)
|
||||
|
||||
OUT1((unsigned char)code)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
|
||||
REQUIRE_OUTBUF(2)
|
||||
|
||||
if (code == NOCHAR) {
|
||||
TRYMAP_ENC(jisxcommon, code, c);
|
||||
#ifndef STRICT_BUILD
|
||||
else if (c == 0xff3c)
|
||||
code = 0x2140; /* FULL-WIDTH REVERSE SOLIDUS */
|
||||
#endif
|
||||
else
|
||||
return 1;
|
||||
|
||||
if (code & 0x8000) /* MSB set: JIS X 0212 */
|
||||
return 1;
|
||||
}
|
||||
|
||||
c1 = code >> 8;
|
||||
c2 = code & 0xff;
|
||||
c2 = (((c1 - 0x21) & 1) ? 0x5e : 0) + (c2 - 0x21);
|
||||
c1 = (c1 - 0x21) >> 1;
|
||||
OUT1(c1 < 0x1f ? c1 + 0x81 : c1 + 0xc1)
|
||||
OUT2(c2 < 0x3f ? c2 + 0x40 : c2 + 0x41)
|
||||
NEXT(1, 2)
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DECODER(shift_jis)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
unsigned char c = IN1;
|
||||
|
||||
REQUIRE_OUTBUF(1)
|
||||
|
||||
#ifdef STRICT_BUILD
|
||||
JISX0201_R_DECODE(c, **outbuf)
|
||||
#else
|
||||
if (c < 0x80) **outbuf = c;
|
||||
#endif
|
||||
else JISX0201_K_DECODE(c, **outbuf)
|
||||
else if ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c <= 0xea)){
|
||||
unsigned char c1, c2;
|
||||
|
||||
REQUIRE_INBUF(2)
|
||||
c2 = IN2;
|
||||
if (c2 < 0x40 || (c2 > 0x7e && c2 < 0x80) || c2 > 0xfc)
|
||||
return 2;
|
||||
|
||||
c1 = (c < 0xe0 ? c - 0x81 : c - 0xc1);
|
||||
c2 = (c2 < 0x80 ? c2 - 0x40 : c2 - 0x41);
|
||||
c1 = (2 * c1 + (c2 < 0x5e ? 0 : 1) + 0x21);
|
||||
c2 = (c2 < 0x5e ? c2 : c2 - 0x5e) + 0x21;
|
||||
|
||||
#ifndef STRICT_BUILD
|
||||
if (c1 == 0x21 && c2 == 0x40) {
|
||||
/* FULL-WIDTH REVERSE SOLIDUS */
|
||||
OUT1(0xff3c)
|
||||
NEXT(2, 1)
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
TRYMAP_DEC(jisx0208, **outbuf, c1, c2) {
|
||||
NEXT(2, 1)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
return 2;
|
||||
|
||||
NEXT(1, 1) /* JIS X 0201 */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SHIFT_JIS-2004 codec
|
||||
*/
|
||||
|
||||
ENCODER(shift_jis_2004)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
ucs4_t c = IN1;
|
||||
DBCHAR code = NOCHAR;
|
||||
int c1, c2;
|
||||
Py_ssize_t insize;
|
||||
|
||||
JISX0201_ENCODE(c, code)
|
||||
else DECODE_SURROGATE(c)
|
||||
|
||||
if (code < 0x80 || (code >= 0xa1 && code <= 0xdf)) {
|
||||
WRITE1((unsigned char)code)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
|
||||
REQUIRE_OUTBUF(2)
|
||||
insize = GET_INSIZE(c);
|
||||
|
||||
if (code == NOCHAR) {
|
||||
if (c <= 0xffff) {
|
||||
EMULATE_JISX0213_2000_ENCODE_BMP(code, c)
|
||||
else TRYMAP_ENC(jisx0213_bmp, code, c) {
|
||||
if (code == MULTIC) {
|
||||
if (inleft < 2) {
|
||||
if (flags & MBENC_FLUSH) {
|
||||
code = find_pairencmap
|
||||
((ucs2_t)c, 0,
|
||||
jisx0213_pair_encmap,
|
||||
JISX0213_ENCPAIRS);
|
||||
if (code == DBCINV)
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return MBERR_TOOFEW;
|
||||
}
|
||||
else {
|
||||
code = find_pairencmap(
|
||||
(ucs2_t)c, IN2,
|
||||
jisx0213_pair_encmap,
|
||||
JISX0213_ENCPAIRS);
|
||||
if (code == DBCINV) {
|
||||
code = find_pairencmap(
|
||||
(ucs2_t)c, 0,
|
||||
jisx0213_pair_encmap,
|
||||
JISX0213_ENCPAIRS);
|
||||
if (code == DBCINV)
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
insize = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else TRYMAP_ENC(jisxcommon, code, c) {
|
||||
/* abandon JIS X 0212 codes */
|
||||
if (code & 0x8000)
|
||||
return 1;
|
||||
}
|
||||
else return 1;
|
||||
}
|
||||
else if (c >> 16 == EMPBASE >> 16) {
|
||||
EMULATE_JISX0213_2000_ENCODE_EMP(code, c)
|
||||
else TRYMAP_ENC(jisx0213_emp, code, c&0xffff);
|
||||
else return insize;
|
||||
}
|
||||
else
|
||||
return insize;
|
||||
}
|
||||
|
||||
c1 = code >> 8;
|
||||
c2 = (code & 0xff) - 0x21;
|
||||
|
||||
if (c1 & 0x80) { /* Plane 2 */
|
||||
if (c1 >= 0xee) c1 -= 0x87;
|
||||
else if (c1 >= 0xac || c1 == 0xa8) c1 -= 0x49;
|
||||
else c1 -= 0x43;
|
||||
}
|
||||
else /* Plane 1 */
|
||||
c1 -= 0x21;
|
||||
|
||||
if (c1 & 1) c2 += 0x5e;
|
||||
c1 >>= 1;
|
||||
OUT1(c1 + (c1 < 0x1f ? 0x81 : 0xc1))
|
||||
OUT2(c2 + (c2 < 0x3f ? 0x40 : 0x41))
|
||||
|
||||
NEXT(insize, 2)
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DECODER(shift_jis_2004)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
unsigned char c = IN1;
|
||||
|
||||
REQUIRE_OUTBUF(1)
|
||||
JISX0201_DECODE(c, **outbuf)
|
||||
else if ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c <= 0xfc)){
|
||||
unsigned char c1, c2;
|
||||
ucs4_t code;
|
||||
|
||||
REQUIRE_INBUF(2)
|
||||
c2 = IN2;
|
||||
if (c2 < 0x40 || (c2 > 0x7e && c2 < 0x80) || c2 > 0xfc)
|
||||
return 2;
|
||||
|
||||
c1 = (c < 0xe0 ? c - 0x81 : c - 0xc1);
|
||||
c2 = (c2 < 0x80 ? c2 - 0x40 : c2 - 0x41);
|
||||
c1 = (2 * c1 + (c2 < 0x5e ? 0 : 1));
|
||||
c2 = (c2 < 0x5e ? c2 : c2 - 0x5e) + 0x21;
|
||||
|
||||
if (c1 < 0x5e) { /* Plane 1 */
|
||||
c1 += 0x21;
|
||||
EMULATE_JISX0213_2000_DECODE_PLANE1(**outbuf,
|
||||
c1, c2)
|
||||
else TRYMAP_DEC(jisx0208, **outbuf, c1, c2) {
|
||||
NEXT_OUT(1)
|
||||
}
|
||||
else TRYMAP_DEC(jisx0213_1_bmp, **outbuf,
|
||||
c1, c2) {
|
||||
NEXT_OUT(1)
|
||||
}
|
||||
else TRYMAP_DEC(jisx0213_1_emp, code, c1, c2) {
|
||||
WRITEUCS4(EMPBASE | code)
|
||||
}
|
||||
else TRYMAP_DEC(jisx0213_pair, code, c1, c2) {
|
||||
WRITE2(code >> 16, code & 0xffff)
|
||||
NEXT_OUT(2)
|
||||
}
|
||||
else
|
||||
return 2;
|
||||
NEXT_IN(2)
|
||||
}
|
||||
else { /* Plane 2 */
|
||||
if (c1 >= 0x67) c1 += 0x07;
|
||||
else if (c1 >= 0x63 || c1 == 0x5f) c1 -= 0x37;
|
||||
else c1 -= 0x3d;
|
||||
|
||||
EMULATE_JISX0213_2000_DECODE_PLANE2(**outbuf,
|
||||
c1, c2)
|
||||
else TRYMAP_DEC(jisx0213_2_bmp, **outbuf,
|
||||
c1, c2) ;
|
||||
else TRYMAP_DEC(jisx0213_2_emp, code, c1, c2) {
|
||||
WRITEUCS4(EMPBASE | code)
|
||||
NEXT_IN(2)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
return 2;
|
||||
NEXT(2, 1)
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
return 2;
|
||||
|
||||
NEXT(1, 1) /* JIS X 0201 */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
BEGIN_MAPPINGS_LIST
|
||||
MAPPING_DECONLY(jisx0208)
|
||||
MAPPING_DECONLY(jisx0212)
|
||||
MAPPING_ENCONLY(jisxcommon)
|
||||
MAPPING_DECONLY(jisx0213_1_bmp)
|
||||
MAPPING_DECONLY(jisx0213_2_bmp)
|
||||
MAPPING_ENCONLY(jisx0213_bmp)
|
||||
MAPPING_DECONLY(jisx0213_1_emp)
|
||||
MAPPING_DECONLY(jisx0213_2_emp)
|
||||
MAPPING_ENCONLY(jisx0213_emp)
|
||||
MAPPING_ENCDEC(jisx0213_pair)
|
||||
MAPPING_ENCDEC(cp932ext)
|
||||
END_MAPPINGS_LIST
|
||||
|
||||
BEGIN_CODECS_LIST
|
||||
CODEC_STATELESS(shift_jis)
|
||||
CODEC_STATELESS(cp932)
|
||||
CODEC_STATELESS(euc_jp)
|
||||
CODEC_STATELESS(shift_jis_2004)
|
||||
CODEC_STATELESS(euc_jis_2004)
|
||||
{ "euc_jisx0213", (void *)2000, NULL, _STATELESS_METHODS(euc_jis_2004) },
|
||||
{ "shift_jisx0213", (void *)2000, NULL, _STATELESS_METHODS(shift_jis_2004) },
|
||||
END_CODECS_LIST
|
||||
|
||||
I_AM_A_MODULE_FOR(jp)
|
||||
@@ -0,0 +1,452 @@
|
||||
/*
|
||||
* _codecs_kr.c: Codecs collection for Korean encodings
|
||||
*
|
||||
* Written by Hye-Shik Chang <perky@FreeBSD.org>
|
||||
*/
|
||||
|
||||
#include "cjkcodecs.h"
|
||||
#include "mappings_kr.h"
|
||||
|
||||
/*
|
||||
* EUC-KR codec
|
||||
*/
|
||||
|
||||
#define EUCKR_JAMO_FIRSTBYTE 0xA4
|
||||
#define EUCKR_JAMO_FILLER 0xD4
|
||||
|
||||
static const unsigned char u2cgk_choseong[19] = {
|
||||
0xa1, 0xa2, 0xa4, 0xa7, 0xa8, 0xa9, 0xb1, 0xb2,
|
||||
0xb3, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb,
|
||||
0xbc, 0xbd, 0xbe
|
||||
};
|
||||
static const unsigned char u2cgk_jungseong[21] = {
|
||||
0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6,
|
||||
0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce,
|
||||
0xcf, 0xd0, 0xd1, 0xd2, 0xd3
|
||||
};
|
||||
static const unsigned char u2cgk_jongseong[28] = {
|
||||
0xd4, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
||||
0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0,
|
||||
0xb1, 0xb2, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xba,
|
||||
0xbb, 0xbc, 0xbd, 0xbe
|
||||
};
|
||||
|
||||
ENCODER(euc_kr)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
Py_UNICODE c = IN1;
|
||||
DBCHAR code;
|
||||
|
||||
if (c < 0x80) {
|
||||
WRITE1((unsigned char)c)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
UCS4INVALID(c)
|
||||
|
||||
REQUIRE_OUTBUF(2)
|
||||
TRYMAP_ENC(cp949, code, c);
|
||||
else return 1;
|
||||
|
||||
if ((code & 0x8000) == 0) {
|
||||
/* KS X 1001 coded character */
|
||||
OUT1((code >> 8) | 0x80)
|
||||
OUT2((code & 0xFF) | 0x80)
|
||||
NEXT(1, 2)
|
||||
}
|
||||
else { /* Mapping is found in CP949 extension,
|
||||
* but we encode it in KS X 1001:1998 Annex 3,
|
||||
* make-up sequence for EUC-KR. */
|
||||
|
||||
REQUIRE_OUTBUF(8)
|
||||
|
||||
/* syllable composition precedence */
|
||||
OUT1(EUCKR_JAMO_FIRSTBYTE)
|
||||
OUT2(EUCKR_JAMO_FILLER)
|
||||
|
||||
/* All code points in CP949 extension are in unicode
|
||||
* Hangul Syllable area. */
|
||||
assert(0xac00 <= c && c <= 0xd7a3);
|
||||
c -= 0xac00;
|
||||
|
||||
OUT3(EUCKR_JAMO_FIRSTBYTE)
|
||||
OUT4(u2cgk_choseong[c / 588])
|
||||
NEXT_OUT(4)
|
||||
|
||||
OUT1(EUCKR_JAMO_FIRSTBYTE)
|
||||
OUT2(u2cgk_jungseong[(c / 28) % 21])
|
||||
OUT3(EUCKR_JAMO_FIRSTBYTE)
|
||||
OUT4(u2cgk_jongseong[c % 28])
|
||||
NEXT(1, 4)
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define NONE 127
|
||||
|
||||
static const unsigned char cgk2u_choseong[] = { /* [A1, BE] */
|
||||
0, 1, NONE, 2, NONE, NONE, 3, 4,
|
||||
5, NONE, NONE, NONE, NONE, NONE, NONE, NONE,
|
||||
6, 7, 8, NONE, 9, 10, 11, 12,
|
||||
13, 14, 15, 16, 17, 18
|
||||
};
|
||||
static const unsigned char cgk2u_jongseong[] = { /* [A1, BE] */
|
||||
1, 2, 3, 4, 5, 6, 7, NONE,
|
||||
8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, NONE, 18, 19, 20, 21, 22,
|
||||
NONE, 23, 24, 25, 26, 27
|
||||
};
|
||||
|
||||
DECODER(euc_kr)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
unsigned char c = IN1;
|
||||
|
||||
REQUIRE_OUTBUF(1)
|
||||
|
||||
if (c < 0x80) {
|
||||
OUT1(c)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
|
||||
REQUIRE_INBUF(2)
|
||||
|
||||
if (c == EUCKR_JAMO_FIRSTBYTE &&
|
||||
IN2 == EUCKR_JAMO_FILLER) {
|
||||
/* KS X 1001:1998 Annex 3 make-up sequence */
|
||||
DBCHAR cho, jung, jong;
|
||||
|
||||
REQUIRE_INBUF(8)
|
||||
if ((*inbuf)[2] != EUCKR_JAMO_FIRSTBYTE ||
|
||||
(*inbuf)[4] != EUCKR_JAMO_FIRSTBYTE ||
|
||||
(*inbuf)[6] != EUCKR_JAMO_FIRSTBYTE)
|
||||
return 8;
|
||||
|
||||
c = (*inbuf)[3];
|
||||
if (0xa1 <= c && c <= 0xbe)
|
||||
cho = cgk2u_choseong[c - 0xa1];
|
||||
else
|
||||
cho = NONE;
|
||||
|
||||
c = (*inbuf)[5];
|
||||
jung = (0xbf <= c && c <= 0xd3) ? c - 0xbf : NONE;
|
||||
|
||||
c = (*inbuf)[7];
|
||||
if (c == EUCKR_JAMO_FILLER)
|
||||
jong = 0;
|
||||
else if (0xa1 <= c && c <= 0xbe)
|
||||
jong = cgk2u_jongseong[c - 0xa1];
|
||||
else
|
||||
jong = NONE;
|
||||
|
||||
if (cho == NONE || jung == NONE || jong == NONE)
|
||||
return 8;
|
||||
|
||||
OUT1(0xac00 + cho*588 + jung*28 + jong);
|
||||
NEXT(8, 1)
|
||||
}
|
||||
else TRYMAP_DEC(ksx1001, **outbuf, c ^ 0x80, IN2 ^ 0x80) {
|
||||
NEXT(2, 1)
|
||||
}
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#undef NONE
|
||||
|
||||
|
||||
/*
|
||||
* CP949 codec
|
||||
*/
|
||||
|
||||
ENCODER(cp949)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
Py_UNICODE c = IN1;
|
||||
DBCHAR code;
|
||||
|
||||
if (c < 0x80) {
|
||||
WRITE1((unsigned char)c)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
UCS4INVALID(c)
|
||||
|
||||
REQUIRE_OUTBUF(2)
|
||||
TRYMAP_ENC(cp949, code, c);
|
||||
else return 1;
|
||||
|
||||
OUT1((code >> 8) | 0x80)
|
||||
if (code & 0x8000)
|
||||
OUT2(code & 0xFF) /* MSB set: CP949 */
|
||||
else
|
||||
OUT2((code & 0xFF) | 0x80) /* MSB unset: ks x 1001 */
|
||||
NEXT(1, 2)
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DECODER(cp949)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
unsigned char c = IN1;
|
||||
|
||||
REQUIRE_OUTBUF(1)
|
||||
|
||||
if (c < 0x80) {
|
||||
OUT1(c)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
|
||||
REQUIRE_INBUF(2)
|
||||
TRYMAP_DEC(ksx1001, **outbuf, c ^ 0x80, IN2 ^ 0x80);
|
||||
else TRYMAP_DEC(cp949ext, **outbuf, c, IN2);
|
||||
else return 2;
|
||||
|
||||
NEXT(2, 1)
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* JOHAB codec
|
||||
*/
|
||||
|
||||
static const unsigned char u2johabidx_choseong[32] = {
|
||||
0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14,
|
||||
};
|
||||
static const unsigned char u2johabidx_jungseong[32] = {
|
||||
0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x1a, 0x1b, 0x1c, 0x1d,
|
||||
};
|
||||
static const unsigned char u2johabidx_jongseong[32] = {
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
|
||||
};
|
||||
static const DBCHAR u2johabjamo[] = {
|
||||
0x8841, 0x8c41, 0x8444, 0x9041, 0x8446, 0x8447, 0x9441,
|
||||
0x9841, 0x9c41, 0x844a, 0x844b, 0x844c, 0x844d, 0x844e, 0x844f,
|
||||
0x8450, 0xa041, 0xa441, 0xa841, 0x8454, 0xac41, 0xb041, 0xb441,
|
||||
0xb841, 0xbc41, 0xc041, 0xc441, 0xc841, 0xcc41, 0xd041, 0x8461,
|
||||
0x8481, 0x84a1, 0x84c1, 0x84e1, 0x8541, 0x8561, 0x8581, 0x85a1,
|
||||
0x85c1, 0x85e1, 0x8641, 0x8661, 0x8681, 0x86a1, 0x86c1, 0x86e1,
|
||||
0x8741, 0x8761, 0x8781, 0x87a1,
|
||||
};
|
||||
|
||||
ENCODER(johab)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
Py_UNICODE c = IN1;
|
||||
DBCHAR code;
|
||||
|
||||
if (c < 0x80) {
|
||||
WRITE1((unsigned char)c)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
UCS4INVALID(c)
|
||||
|
||||
REQUIRE_OUTBUF(2)
|
||||
|
||||
if (c >= 0xac00 && c <= 0xd7a3) {
|
||||
c -= 0xac00;
|
||||
code = 0x8000 |
|
||||
(u2johabidx_choseong[c / 588] << 10) |
|
||||
(u2johabidx_jungseong[(c / 28) % 21] << 5) |
|
||||
u2johabidx_jongseong[c % 28];
|
||||
}
|
||||
else if (c >= 0x3131 && c <= 0x3163)
|
||||
code = u2johabjamo[c - 0x3131];
|
||||
else TRYMAP_ENC(cp949, code, c) {
|
||||
unsigned char c1, c2, t2;
|
||||
unsigned short t1;
|
||||
|
||||
assert((code & 0x8000) == 0);
|
||||
c1 = code >> 8;
|
||||
c2 = code & 0xff;
|
||||
if (((c1 >= 0x21 && c1 <= 0x2c) ||
|
||||
(c1 >= 0x4a && c1 <= 0x7d)) &&
|
||||
(c2 >= 0x21 && c2 <= 0x7e)) {
|
||||
t1 = (c1 < 0x4a ? (c1 - 0x21 + 0x1b2) :
|
||||
(c1 - 0x21 + 0x197));
|
||||
t2 = ((t1 & 1) ? 0x5e : 0) + (c2 - 0x21);
|
||||
OUT1(t1 >> 1)
|
||||
OUT2(t2 < 0x4e ? t2 + 0x31 : t2 + 0x43)
|
||||
NEXT(1, 2)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
|
||||
OUT1(code >> 8)
|
||||
OUT2(code & 0xff)
|
||||
NEXT(1, 2)
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FILL 0xfd
|
||||
#define NONE 0xff
|
||||
|
||||
static const unsigned char johabidx_choseong[32] = {
|
||||
NONE, FILL, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
|
||||
0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
|
||||
0x0e, 0x0f, 0x10, 0x11, 0x12, NONE, NONE, NONE,
|
||||
NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE,
|
||||
};
|
||||
static const unsigned char johabidx_jungseong[32] = {
|
||||
NONE, NONE, FILL, 0x00, 0x01, 0x02, 0x03, 0x04,
|
||||
NONE, NONE, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
|
||||
NONE, NONE, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
|
||||
NONE, NONE, 0x11, 0x12, 0x13, 0x14, NONE, NONE,
|
||||
};
|
||||
static const unsigned char johabidx_jongseong[32] = {
|
||||
NONE, FILL, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
||||
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
|
||||
0x0f, 0x10, NONE, 0x11, 0x12, 0x13, 0x14, 0x15,
|
||||
0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, NONE, NONE,
|
||||
};
|
||||
|
||||
static const unsigned char johabjamo_choseong[32] = {
|
||||
NONE, FILL, 0x31, 0x32, 0x34, 0x37, 0x38, 0x39,
|
||||
0x41, 0x42, 0x43, 0x45, 0x46, 0x47, 0x48, 0x49,
|
||||
0x4a, 0x4b, 0x4c, 0x4d, 0x4e, NONE, NONE, NONE,
|
||||
NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE,
|
||||
};
|
||||
static const unsigned char johabjamo_jungseong[32] = {
|
||||
NONE, NONE, FILL, 0x4f, 0x50, 0x51, 0x52, 0x53,
|
||||
NONE, NONE, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
|
||||
NONE, NONE, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||||
NONE, NONE, 0x60, 0x61, 0x62, 0x63, NONE, NONE,
|
||||
};
|
||||
static const unsigned char johabjamo_jongseong[32] = {
|
||||
NONE, FILL, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
|
||||
0x37, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x40, 0x41, NONE, 0x42, 0x44, 0x45, 0x46, 0x47,
|
||||
0x48, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, NONE, NONE,
|
||||
};
|
||||
|
||||
DECODER(johab)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
unsigned char c = IN1, c2;
|
||||
|
||||
REQUIRE_OUTBUF(1)
|
||||
|
||||
if (c < 0x80) {
|
||||
OUT1(c)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
|
||||
REQUIRE_INBUF(2)
|
||||
c2 = IN2;
|
||||
|
||||
if (c < 0xd8) {
|
||||
/* johab hangul */
|
||||
unsigned char c_cho, c_jung, c_jong;
|
||||
unsigned char i_cho, i_jung, i_jong;
|
||||
|
||||
c_cho = (c >> 2) & 0x1f;
|
||||
c_jung = ((c << 3) | c2 >> 5) & 0x1f;
|
||||
c_jong = c2 & 0x1f;
|
||||
|
||||
i_cho = johabidx_choseong[c_cho];
|
||||
i_jung = johabidx_jungseong[c_jung];
|
||||
i_jong = johabidx_jongseong[c_jong];
|
||||
|
||||
if (i_cho == NONE || i_jung == NONE || i_jong == NONE)
|
||||
return 2;
|
||||
|
||||
/* we don't use U+1100 hangul jamo yet. */
|
||||
if (i_cho == FILL) {
|
||||
if (i_jung == FILL) {
|
||||
if (i_jong == FILL)
|
||||
OUT1(0x3000)
|
||||
else
|
||||
OUT1(0x3100 |
|
||||
johabjamo_jongseong[c_jong])
|
||||
}
|
||||
else {
|
||||
if (i_jong == FILL)
|
||||
OUT1(0x3100 |
|
||||
johabjamo_jungseong[c_jung])
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
if (i_jung == FILL) {
|
||||
if (i_jong == FILL)
|
||||
OUT1(0x3100 |
|
||||
johabjamo_choseong[c_cho])
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
OUT1(0xac00 +
|
||||
i_cho * 588 +
|
||||
i_jung * 28 +
|
||||
(i_jong == FILL ? 0 : i_jong))
|
||||
}
|
||||
NEXT(2, 1)
|
||||
} else {
|
||||
/* KS X 1001 except hangul jamos and syllables */
|
||||
if (c == 0xdf || c > 0xf9 ||
|
||||
c2 < 0x31 || (c2 >= 0x80 && c2 < 0x91) ||
|
||||
(c2 & 0x7f) == 0x7f ||
|
||||
(c == 0xda && (c2 >= 0xa1 && c2 <= 0xd3)))
|
||||
return 2;
|
||||
else {
|
||||
unsigned char t1, t2;
|
||||
|
||||
t1 = (c < 0xe0 ? 2 * (c - 0xd9) :
|
||||
2 * c - 0x197);
|
||||
t2 = (c2 < 0x91 ? c2 - 0x31 : c2 - 0x43);
|
||||
t1 = t1 + (t2 < 0x5e ? 0 : 1) + 0x21;
|
||||
t2 = (t2 < 0x5e ? t2 : t2 - 0x5e) + 0x21;
|
||||
|
||||
TRYMAP_DEC(ksx1001, **outbuf, t1, t2);
|
||||
else return 2;
|
||||
NEXT(2, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#undef NONE
|
||||
#undef FILL
|
||||
|
||||
|
||||
BEGIN_MAPPINGS_LIST
|
||||
MAPPING_DECONLY(ksx1001)
|
||||
MAPPING_ENCONLY(cp949)
|
||||
MAPPING_DECONLY(cp949ext)
|
||||
END_MAPPINGS_LIST
|
||||
|
||||
BEGIN_CODECS_LIST
|
||||
CODEC_STATELESS(euc_kr)
|
||||
CODEC_STATELESS(cp949)
|
||||
CODEC_STATELESS(johab)
|
||||
END_CODECS_LIST
|
||||
|
||||
I_AM_A_MODULE_FOR(kr)
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* _codecs_tw.c: Codecs collection for Taiwan's encodings
|
||||
*
|
||||
* Written by Hye-Shik Chang <perky@FreeBSD.org>
|
||||
*/
|
||||
|
||||
#include "cjkcodecs.h"
|
||||
#include "mappings_tw.h"
|
||||
|
||||
/*
|
||||
* BIG5 codec
|
||||
*/
|
||||
|
||||
ENCODER(big5)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
Py_UNICODE c = **inbuf;
|
||||
DBCHAR code;
|
||||
|
||||
if (c < 0x80) {
|
||||
REQUIRE_OUTBUF(1)
|
||||
**outbuf = (unsigned char)c;
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
UCS4INVALID(c)
|
||||
|
||||
REQUIRE_OUTBUF(2)
|
||||
|
||||
TRYMAP_ENC(big5, code, c);
|
||||
else return 1;
|
||||
|
||||
OUT1(code >> 8)
|
||||
OUT2(code & 0xFF)
|
||||
NEXT(1, 2)
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DECODER(big5)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
unsigned char c = IN1;
|
||||
|
||||
REQUIRE_OUTBUF(1)
|
||||
|
||||
if (c < 0x80) {
|
||||
OUT1(c)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
|
||||
REQUIRE_INBUF(2)
|
||||
TRYMAP_DEC(big5, **outbuf, c, IN2) {
|
||||
NEXT(2, 1)
|
||||
}
|
||||
else return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CP950 codec
|
||||
*/
|
||||
|
||||
ENCODER(cp950)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
Py_UNICODE c = IN1;
|
||||
DBCHAR code;
|
||||
|
||||
if (c < 0x80) {
|
||||
WRITE1((unsigned char)c)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
UCS4INVALID(c)
|
||||
|
||||
REQUIRE_OUTBUF(2)
|
||||
TRYMAP_ENC(cp950ext, code, c);
|
||||
else TRYMAP_ENC(big5, code, c);
|
||||
else return 1;
|
||||
|
||||
OUT1(code >> 8)
|
||||
OUT2(code & 0xFF)
|
||||
NEXT(1, 2)
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DECODER(cp950)
|
||||
{
|
||||
while (inleft > 0) {
|
||||
unsigned char c = IN1;
|
||||
|
||||
REQUIRE_OUTBUF(1)
|
||||
|
||||
if (c < 0x80) {
|
||||
OUT1(c)
|
||||
NEXT(1, 1)
|
||||
continue;
|
||||
}
|
||||
|
||||
REQUIRE_INBUF(2)
|
||||
|
||||
TRYMAP_DEC(cp950ext, **outbuf, c, IN2);
|
||||
else TRYMAP_DEC(big5, **outbuf, c, IN2);
|
||||
else return 2;
|
||||
|
||||
NEXT(2, 1)
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BEGIN_MAPPINGS_LIST
|
||||
MAPPING_ENCDEC(big5)
|
||||
MAPPING_ENCDEC(cp950ext)
|
||||
END_MAPPINGS_LIST
|
||||
|
||||
BEGIN_CODECS_LIST
|
||||
CODEC_STATELESS(big5)
|
||||
CODEC_STATELESS(cp950)
|
||||
END_CODECS_LIST
|
||||
|
||||
I_AM_A_MODULE_FOR(tw)
|
||||
@@ -0,0 +1,24 @@
|
||||
#define JISX0201_R_ENCODE(c, assi) \
|
||||
if ((c) < 0x80 && (c) != 0x5c && (c) != 0x7e) \
|
||||
(assi) = (c); \
|
||||
else if ((c) == 0x00a5) (assi) = 0x5c; \
|
||||
else if ((c) == 0x203e) (assi) = 0x7e;
|
||||
#define JISX0201_K_ENCODE(c, assi) \
|
||||
if ((c) >= 0xff61 && (c) <= 0xff9f) \
|
||||
(assi) = (c) - 0xfec0;
|
||||
#define JISX0201_ENCODE(c, assi) \
|
||||
JISX0201_R_ENCODE(c, assi) \
|
||||
else JISX0201_K_ENCODE(c, assi)
|
||||
|
||||
#define JISX0201_R_DECODE(c, assi) \
|
||||
if ((c) < 0x5c) (assi) = (c); \
|
||||
else if ((c) == 0x5c) (assi) = 0x00a5; \
|
||||
else if ((c) < 0x7e) (assi) = (c); \
|
||||
else if ((c) == 0x7e) (assi) = 0x203e; \
|
||||
else if ((c) == 0x7f) (assi) = 0x7f;
|
||||
#define JISX0201_K_DECODE(c, assi) \
|
||||
if ((c) >= 0xa1 && (c) <= 0xdf) \
|
||||
(assi) = 0xfec0 + (c);
|
||||
#define JISX0201_DECODE(c, assi) \
|
||||
JISX0201_R_DECODE(c, assi) \
|
||||
else JISX0201_K_DECODE(c, assi)
|
||||
@@ -0,0 +1,402 @@
|
||||
/*
|
||||
* cjkcodecs.h: common header for cjkcodecs
|
||||
*
|
||||
* Written by Hye-Shik Chang <perky@FreeBSD.org>
|
||||
*/
|
||||
|
||||
#ifndef _CJKCODECS_H_
|
||||
#define _CJKCODECS_H_
|
||||
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include "Python.h"
|
||||
#include "multibytecodec.h"
|
||||
|
||||
|
||||
/* a unicode "undefined" code point */
|
||||
#define UNIINV 0xFFFE
|
||||
|
||||
/* internal-use DBCS code points which aren't used by any charsets */
|
||||
#define NOCHAR 0xFFFF
|
||||
#define MULTIC 0xFFFE
|
||||
#define DBCINV 0xFFFD
|
||||
|
||||
/* shorter macros to save source size of mapping tables */
|
||||
#define U UNIINV
|
||||
#define N NOCHAR
|
||||
#define M MULTIC
|
||||
#define D DBCINV
|
||||
|
||||
struct dbcs_index {
|
||||
const ucs2_t *map;
|
||||
unsigned char bottom, top;
|
||||
};
|
||||
typedef struct dbcs_index decode_map;
|
||||
|
||||
struct widedbcs_index {
|
||||
const ucs4_t *map;
|
||||
unsigned char bottom, top;
|
||||
};
|
||||
typedef struct widedbcs_index widedecode_map;
|
||||
|
||||
struct unim_index {
|
||||
const DBCHAR *map;
|
||||
unsigned char bottom, top;
|
||||
};
|
||||
typedef struct unim_index encode_map;
|
||||
|
||||
struct unim_index_bytebased {
|
||||
const unsigned char *map;
|
||||
unsigned char bottom, top;
|
||||
};
|
||||
|
||||
struct dbcs_map {
|
||||
const char *charset;
|
||||
const struct unim_index *encmap;
|
||||
const struct dbcs_index *decmap;
|
||||
};
|
||||
|
||||
struct pair_encodemap {
|
||||
ucs4_t uniseq;
|
||||
DBCHAR code;
|
||||
};
|
||||
|
||||
static const MultibyteCodec *codec_list;
|
||||
static const struct dbcs_map *mapping_list;
|
||||
|
||||
#define CODEC_INIT(encoding) \
|
||||
static int encoding##_codec_init(const void *config)
|
||||
|
||||
#define ENCODER_INIT(encoding) \
|
||||
static int encoding##_encode_init( \
|
||||
MultibyteCodec_State *state, const void *config)
|
||||
#define ENCODER(encoding) \
|
||||
static Py_ssize_t encoding##_encode( \
|
||||
MultibyteCodec_State *state, const void *config, \
|
||||
const Py_UNICODE **inbuf, Py_ssize_t inleft, \
|
||||
unsigned char **outbuf, Py_ssize_t outleft, int flags)
|
||||
#define ENCODER_RESET(encoding) \
|
||||
static Py_ssize_t encoding##_encode_reset( \
|
||||
MultibyteCodec_State *state, const void *config, \
|
||||
unsigned char **outbuf, Py_ssize_t outleft)
|
||||
|
||||
#define DECODER_INIT(encoding) \
|
||||
static int encoding##_decode_init( \
|
||||
MultibyteCodec_State *state, const void *config)
|
||||
#define DECODER(encoding) \
|
||||
static Py_ssize_t encoding##_decode( \
|
||||
MultibyteCodec_State *state, const void *config, \
|
||||
const unsigned char **inbuf, Py_ssize_t inleft, \
|
||||
Py_UNICODE **outbuf, Py_ssize_t outleft)
|
||||
#define DECODER_RESET(encoding) \
|
||||
static Py_ssize_t encoding##_decode_reset( \
|
||||
MultibyteCodec_State *state, const void *config)
|
||||
|
||||
#if Py_UNICODE_SIZE == 4
|
||||
#define UCS4INVALID(code) \
|
||||
if ((code) > 0xFFFF) \
|
||||
return 1;
|
||||
#else
|
||||
#define UCS4INVALID(code) \
|
||||
if (0) ;
|
||||
#endif
|
||||
|
||||
#define NEXT_IN(i) \
|
||||
(*inbuf) += (i); \
|
||||
(inleft) -= (i);
|
||||
#define NEXT_OUT(o) \
|
||||
(*outbuf) += (o); \
|
||||
(outleft) -= (o);
|
||||
#define NEXT(i, o) \
|
||||
NEXT_IN(i) NEXT_OUT(o)
|
||||
|
||||
#define REQUIRE_INBUF(n) \
|
||||
if (inleft < (n)) \
|
||||
return MBERR_TOOFEW;
|
||||
#define REQUIRE_OUTBUF(n) \
|
||||
if (outleft < (n)) \
|
||||
return MBERR_TOOSMALL;
|
||||
|
||||
#define IN1 ((*inbuf)[0])
|
||||
#define IN2 ((*inbuf)[1])
|
||||
#define IN3 ((*inbuf)[2])
|
||||
#define IN4 ((*inbuf)[3])
|
||||
|
||||
#define OUT1(c) ((*outbuf)[0]) = (c);
|
||||
#define OUT2(c) ((*outbuf)[1]) = (c);
|
||||
#define OUT3(c) ((*outbuf)[2]) = (c);
|
||||
#define OUT4(c) ((*outbuf)[3]) = (c);
|
||||
|
||||
#define WRITE1(c1) \
|
||||
REQUIRE_OUTBUF(1) \
|
||||
(*outbuf)[0] = (c1);
|
||||
#define WRITE2(c1, c2) \
|
||||
REQUIRE_OUTBUF(2) \
|
||||
(*outbuf)[0] = (c1); \
|
||||
(*outbuf)[1] = (c2);
|
||||
#define WRITE3(c1, c2, c3) \
|
||||
REQUIRE_OUTBUF(3) \
|
||||
(*outbuf)[0] = (c1); \
|
||||
(*outbuf)[1] = (c2); \
|
||||
(*outbuf)[2] = (c3);
|
||||
#define WRITE4(c1, c2, c3, c4) \
|
||||
REQUIRE_OUTBUF(4) \
|
||||
(*outbuf)[0] = (c1); \
|
||||
(*outbuf)[1] = (c2); \
|
||||
(*outbuf)[2] = (c3); \
|
||||
(*outbuf)[3] = (c4);
|
||||
|
||||
#if Py_UNICODE_SIZE == 2
|
||||
# define WRITEUCS4(c) \
|
||||
REQUIRE_OUTBUF(2) \
|
||||
(*outbuf)[0] = 0xd800 + (((c) - 0x10000) >> 10); \
|
||||
(*outbuf)[1] = 0xdc00 + (((c) - 0x10000) & 0x3ff); \
|
||||
NEXT_OUT(2)
|
||||
#else
|
||||
# define WRITEUCS4(c) \
|
||||
REQUIRE_OUTBUF(1) \
|
||||
**outbuf = (Py_UNICODE)(c); \
|
||||
NEXT_OUT(1)
|
||||
#endif
|
||||
|
||||
#define _TRYMAP_ENC(m, assi, val) \
|
||||
((m)->map != NULL && (val) >= (m)->bottom && \
|
||||
(val)<= (m)->top && ((assi) = (m)->map[(val) - \
|
||||
(m)->bottom]) != NOCHAR)
|
||||
#define TRYMAP_ENC_COND(charset, assi, uni) \
|
||||
_TRYMAP_ENC(&charset##_encmap[(uni) >> 8], assi, (uni) & 0xff)
|
||||
#define TRYMAP_ENC(charset, assi, uni) \
|
||||
if TRYMAP_ENC_COND(charset, assi, uni)
|
||||
|
||||
#define _TRYMAP_DEC(m, assi, val) \
|
||||
((m)->map != NULL && (val) >= (m)->bottom && \
|
||||
(val)<= (m)->top && ((assi) = (m)->map[(val) - \
|
||||
(m)->bottom]) != UNIINV)
|
||||
#define TRYMAP_DEC(charset, assi, c1, c2) \
|
||||
if _TRYMAP_DEC(&charset##_decmap[c1], assi, c2)
|
||||
|
||||
#define _TRYMAP_ENC_MPLANE(m, assplane, asshi, asslo, val) \
|
||||
((m)->map != NULL && (val) >= (m)->bottom && \
|
||||
(val)<= (m)->top && \
|
||||
((assplane) = (m)->map[((val) - (m)->bottom)*3]) != 0 && \
|
||||
(((asshi) = (m)->map[((val) - (m)->bottom)*3 + 1]), 1) && \
|
||||
(((asslo) = (m)->map[((val) - (m)->bottom)*3 + 2]), 1))
|
||||
#define TRYMAP_ENC_MPLANE(charset, assplane, asshi, asslo, uni) \
|
||||
if _TRYMAP_ENC_MPLANE(&charset##_encmap[(uni) >> 8], \
|
||||
assplane, asshi, asslo, (uni) & 0xff)
|
||||
#define TRYMAP_DEC_MPLANE(charset, assi, plane, c1, c2) \
|
||||
if _TRYMAP_DEC(&charset##_decmap[plane][c1], assi, c2)
|
||||
|
||||
#if Py_UNICODE_SIZE == 2
|
||||
#define DECODE_SURROGATE(c) \
|
||||
if (c >> 10 == 0xd800 >> 10) { /* high surrogate */ \
|
||||
REQUIRE_INBUF(2) \
|
||||
if (IN2 >> 10 == 0xdc00 >> 10) { /* low surrogate */ \
|
||||
c = 0x10000 + ((ucs4_t)(c - 0xd800) << 10) + \
|
||||
((ucs4_t)(IN2) - 0xdc00); \
|
||||
} \
|
||||
}
|
||||
#define GET_INSIZE(c) ((c) > 0xffff ? 2 : 1)
|
||||
#else
|
||||
#define DECODE_SURROGATE(c) {;}
|
||||
#define GET_INSIZE(c) 1
|
||||
#endif
|
||||
|
||||
#define BEGIN_MAPPINGS_LIST static const struct dbcs_map _mapping_list[] = {
|
||||
#define MAPPING_ENCONLY(enc) {#enc, (void*)enc##_encmap, NULL},
|
||||
#define MAPPING_DECONLY(enc) {#enc, NULL, (void*)enc##_decmap},
|
||||
#define MAPPING_ENCDEC(enc) {#enc, (void*)enc##_encmap, (void*)enc##_decmap},
|
||||
#define END_MAPPINGS_LIST \
|
||||
{"", NULL, NULL} }; \
|
||||
static const struct dbcs_map *mapping_list = \
|
||||
(const struct dbcs_map *)_mapping_list;
|
||||
|
||||
#define BEGIN_CODECS_LIST static const MultibyteCodec _codec_list[] = {
|
||||
#define _STATEFUL_METHODS(enc) \
|
||||
enc##_encode, \
|
||||
enc##_encode_init, \
|
||||
enc##_encode_reset, \
|
||||
enc##_decode, \
|
||||
enc##_decode_init, \
|
||||
enc##_decode_reset,
|
||||
#define _STATELESS_METHODS(enc) \
|
||||
enc##_encode, NULL, NULL, \
|
||||
enc##_decode, NULL, NULL,
|
||||
#define CODEC_STATEFUL(enc) { \
|
||||
#enc, NULL, NULL, \
|
||||
_STATEFUL_METHODS(enc) \
|
||||
},
|
||||
#define CODEC_STATELESS(enc) { \
|
||||
#enc, NULL, NULL, \
|
||||
_STATELESS_METHODS(enc) \
|
||||
},
|
||||
#define CODEC_STATELESS_WINIT(enc) { \
|
||||
#enc, NULL, \
|
||||
enc##_codec_init, \
|
||||
_STATELESS_METHODS(enc) \
|
||||
},
|
||||
#define END_CODECS_LIST \
|
||||
{"", NULL,} }; \
|
||||
static const MultibyteCodec *codec_list = \
|
||||
(const MultibyteCodec *)_codec_list;
|
||||
|
||||
static PyObject *
|
||||
getmultibytecodec(void)
|
||||
{
|
||||
static PyObject *cofunc = NULL;
|
||||
|
||||
if (cofunc == NULL) {
|
||||
PyObject *mod = PyImport_ImportModuleNoBlock("_multibytecodec");
|
||||
if (mod == NULL)
|
||||
return NULL;
|
||||
cofunc = PyObject_GetAttrString(mod, "__create_codec");
|
||||
Py_DECREF(mod);
|
||||
}
|
||||
return cofunc;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
getcodec(PyObject *self, PyObject *encoding)
|
||||
{
|
||||
PyObject *codecobj, *r, *cofunc;
|
||||
const MultibyteCodec *codec;
|
||||
const char *enc;
|
||||
|
||||
if (!PyString_Check(encoding)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"encoding name must be a string.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cofunc = getmultibytecodec();
|
||||
if (cofunc == NULL)
|
||||
return NULL;
|
||||
|
||||
enc = PyString_AS_STRING(encoding);
|
||||
for (codec = codec_list; codec->encoding[0]; codec++)
|
||||
if (strcmp(codec->encoding, enc) == 0)
|
||||
break;
|
||||
|
||||
if (codec->encoding[0] == '\0') {
|
||||
PyErr_SetString(PyExc_LookupError,
|
||||
"no such codec is supported.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
codecobj = PyCapsule_New((void *)codec, PyMultibyteCodec_CAPSULE_NAME, NULL);
|
||||
if (codecobj == NULL)
|
||||
return NULL;
|
||||
|
||||
r = PyObject_CallFunctionObjArgs(cofunc, codecobj, NULL);
|
||||
Py_DECREF(codecobj);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static struct PyMethodDef __methods[] = {
|
||||
{"getcodec", (PyCFunction)getcodec, METH_O, ""},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
static int
|
||||
register_maps(PyObject *module)
|
||||
{
|
||||
const struct dbcs_map *h;
|
||||
|
||||
for (h = mapping_list; h->charset[0] != '\0'; h++) {
|
||||
char mhname[256] = "__map_";
|
||||
int r;
|
||||
strcpy(mhname + sizeof("__map_") - 1, h->charset);
|
||||
r = PyModule_AddObject(module, mhname,
|
||||
PyCapsule_New((void *)h, PyMultibyteCodec_CAPSULE_NAME, NULL));
|
||||
if (r == -1)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef USING_BINARY_PAIR_SEARCH
|
||||
static DBCHAR
|
||||
find_pairencmap(ucs2_t body, ucs2_t modifier,
|
||||
const struct pair_encodemap *haystack, int haystacksize)
|
||||
{
|
||||
int pos, min, max;
|
||||
ucs4_t value = body << 16 | modifier;
|
||||
|
||||
min = 0;
|
||||
max = haystacksize;
|
||||
|
||||
for (pos = haystacksize >> 1; min != max; pos = (min + max) >> 1) {
|
||||
if (value < haystack[pos].uniseq) {
|
||||
if (max != pos) {
|
||||
max = pos;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (value > haystack[pos].uniseq) {
|
||||
if (min != pos) {
|
||||
min = pos;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (value == haystack[pos].uniseq) {
|
||||
return haystack[pos].code;
|
||||
}
|
||||
return DBCINV;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USING_IMPORTED_MAPS
|
||||
#define IMPORT_MAP(locale, charset, encmap, decmap) \
|
||||
importmap("_codecs_" #locale, "__map_" #charset, \
|
||||
(const void**)encmap, (const void**)decmap)
|
||||
|
||||
static int
|
||||
importmap(const char *modname, const char *symbol,
|
||||
const void **encmap, const void **decmap)
|
||||
{
|
||||
PyObject *o, *mod;
|
||||
|
||||
mod = PyImport_ImportModule((char *)modname);
|
||||
if (mod == NULL)
|
||||
return -1;
|
||||
|
||||
o = PyObject_GetAttrString(mod, (char*)symbol);
|
||||
if (o == NULL)
|
||||
goto errorexit;
|
||||
else if (!PyCapsule_IsValid(o, PyMultibyteCodec_CAPSULE_NAME)) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"map data must be a Capsule.");
|
||||
goto errorexit;
|
||||
}
|
||||
else {
|
||||
struct dbcs_map *map;
|
||||
map = PyCapsule_GetPointer(o, PyMultibyteCodec_CAPSULE_NAME);
|
||||
if (encmap != NULL)
|
||||
*encmap = map->encmap;
|
||||
if (decmap != NULL)
|
||||
*decmap = map->decmap;
|
||||
Py_DECREF(o);
|
||||
}
|
||||
|
||||
Py_DECREF(mod);
|
||||
return 0;
|
||||
|
||||
errorexit:
|
||||
Py_DECREF(mod);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define I_AM_A_MODULE_FOR(loc) \
|
||||
void \
|
||||
init_codecs_##loc(void) \
|
||||
{ \
|
||||
PyObject *m = Py_InitModule("_codecs_" #loc, __methods);\
|
||||
if (m != NULL) \
|
||||
(void)register_maps(m); \
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,43 @@
|
||||
/* These routines may be quite inefficient, but it's used only to emulate old
|
||||
* standards. */
|
||||
|
||||
#ifndef EMULATE_JISX0213_2000_ENCODE_INVALID
|
||||
#define EMULATE_JISX0213_2000_ENCODE_INVALID 1
|
||||
#endif
|
||||
|
||||
#define EMULATE_JISX0213_2000_ENCODE_BMP(assi, c) \
|
||||
if (config == (void *)2000 && ( \
|
||||
(c) == 0x9B1C || (c) == 0x4FF1 || \
|
||||
(c) == 0x525D || (c) == 0x541E || \
|
||||
(c) == 0x5653 || (c) == 0x59F8 || \
|
||||
(c) == 0x5C5B || (c) == 0x5E77 || \
|
||||
(c) == 0x7626 || (c) == 0x7E6B)) \
|
||||
return EMULATE_JISX0213_2000_ENCODE_INVALID; \
|
||||
else if (config == (void *)2000 && (c) == 0x9B1D) \
|
||||
(assi) = 0x8000 | 0x7d3b; \
|
||||
|
||||
#define EMULATE_JISX0213_2000_ENCODE_EMP(assi, c) \
|
||||
if (config == (void *)2000 && (c) == 0x20B9F) \
|
||||
return EMULATE_JISX0213_2000_ENCODE_INVALID;
|
||||
|
||||
#ifndef EMULATE_JISX0213_2000_DECODE_INVALID
|
||||
#define EMULATE_JISX0213_2000_DECODE_INVALID 2
|
||||
#endif
|
||||
|
||||
#define EMULATE_JISX0213_2000_DECODE_PLANE1(assi, c1, c2) \
|
||||
if (config == (void *)2000 && \
|
||||
(((c1) == 0x2E && (c2) == 0x21) || \
|
||||
((c1) == 0x2F && (c2) == 0x7E) || \
|
||||
((c1) == 0x4F && (c2) == 0x54) || \
|
||||
((c1) == 0x4F && (c2) == 0x7E) || \
|
||||
((c1) == 0x74 && (c2) == 0x27) || \
|
||||
((c1) == 0x7E && (c2) == 0x7A) || \
|
||||
((c1) == 0x7E && (c2) == 0x7B) || \
|
||||
((c1) == 0x7E && (c2) == 0x7C) || \
|
||||
((c1) == 0x7E && (c2) == 0x7D) || \
|
||||
((c1) == 0x7E && (c2) == 0x7E))) \
|
||||
return EMULATE_JISX0213_2000_DECODE_INVALID;
|
||||
|
||||
#define EMULATE_JISX0213_2000_DECODE_PLANE2(assi, c1, c2) \
|
||||
if (config == (void *)2000 && (c1) == 0x7D && (c2) == 0x3B) \
|
||||
(assi) = 0x9B1D;
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+59
@@ -0,0 +1,59 @@
|
||||
#define JISX0213_ENCPAIRS 46
|
||||
#ifdef EXTERN_JISX0213_PAIR
|
||||
static const struct widedbcs_index *jisx0213_pair_decmap;
|
||||
static const struct pair_encodemap *jisx0213_pair_encmap;
|
||||
#else
|
||||
static const ucs4_t __jisx0213_pair_decmap[49] = {
|
||||
810234010,810365082,810496154,810627226,810758298,816525466,816656538,
|
||||
816787610,816918682,817049754,817574042,818163866,818426010,838283418,
|
||||
15074048,U,U,U,39060224,39060225,42730240,42730241,39387904,39387905,39453440,
|
||||
39453441,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,48825061,48562921,
|
||||
};
|
||||
|
||||
static const struct widedbcs_index jisx0213_pair_decmap[256] = {
|
||||
{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0
|
||||
},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,
|
||||
0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{
|
||||
0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_pair_decmap
|
||||
+0,119,123},{__jisx0213_pair_decmap+5,119,126},{__jisx0213_pair_decmap+13,120,
|
||||
120},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_pair_decmap+14,68,102},{0,0,0
|
||||
},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,
|
||||
0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{
|
||||
0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0
|
||||
},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,
|
||||
0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{
|
||||
0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0
|
||||
},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,
|
||||
0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{
|
||||
0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0
|
||||
},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,
|
||||
0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{
|
||||
0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0
|
||||
},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,
|
||||
0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{
|
||||
0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0
|
||||
},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,
|
||||
0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{
|
||||
0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0
|
||||
},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,
|
||||
0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{
|
||||
0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0
|
||||
},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},
|
||||
};
|
||||
|
||||
static const struct pair_encodemap jisx0213_pair_encmap[JISX0213_ENCPAIRS] = {
|
||||
{0x00e60000,0x295c},{0x00e60300,0x2b44},{0x02540000,0x2b38},{0x02540300,0x2b48
|
||||
},{0x02540301,0x2b49},{0x02590000,0x2b30},{0x02590300,0x2b4c},{0x02590301,
|
||||
0x2b4d},{0x025a0000,0x2b43},{0x025a0300,0x2b4e},{0x025a0301,0x2b4f},{
|
||||
0x028c0000,0x2b37},{0x028c0300,0x2b4a},{0x028c0301,0x2b4b},{0x02e50000,0x2b60
|
||||
},{0x02e502e9,0x2b66},{0x02e90000,0x2b64},{0x02e902e5,0x2b65},{0x304b0000,
|
||||
0x242b},{0x304b309a,0x2477},{0x304d0000,0x242d},{0x304d309a,0x2478},{
|
||||
0x304f0000,0x242f},{0x304f309a,0x2479},{0x30510000,0x2431},{0x3051309a,0x247a
|
||||
},{0x30530000,0x2433},{0x3053309a,0x247b},{0x30ab0000,0x252b},{0x30ab309a,
|
||||
0x2577},{0x30ad0000,0x252d},{0x30ad309a,0x2578},{0x30af0000,0x252f},{
|
||||
0x30af309a,0x2579},{0x30b10000,0x2531},{0x30b1309a,0x257a},{0x30b30000,0x2533
|
||||
},{0x30b3309a,0x257b},{0x30bb0000,0x253b},{0x30bb309a,0x257c},{0x30c40000,
|
||||
0x2544},{0x30c4309a,0x257d},{0x30c80000,0x2548},{0x30c8309a,0x257e},{
|
||||
0x31f70000,0x2675},{0x31f7309a,0x2678},
|
||||
};
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* multibytecodec.h: Common Multibyte Codec Implementation
|
||||
*
|
||||
* Written by Hye-Shik Chang <perky@FreeBSD.org>
|
||||
*/
|
||||
|
||||
#ifndef _PYTHON_MULTIBYTECODEC_H_
|
||||
#define _PYTHON_MULTIBYTECODEC_H_
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef uint32_t
|
||||
typedef uint32_t ucs4_t;
|
||||
#else
|
||||
typedef unsigned int ucs4_t;
|
||||
#endif
|
||||
|
||||
#ifdef uint16_t
|
||||
typedef uint16_t ucs2_t, DBCHAR;
|
||||
#else
|
||||
typedef unsigned short ucs2_t, DBCHAR;
|
||||
#endif
|
||||
|
||||
typedef union {
|
||||
void *p;
|
||||
int i;
|
||||
unsigned char c[8];
|
||||
ucs2_t u2[4];
|
||||
ucs4_t u4[2];
|
||||
} MultibyteCodec_State;
|
||||
|
||||
typedef int (*mbcodec_init)(const void *config);
|
||||
typedef Py_ssize_t (*mbencode_func)(MultibyteCodec_State *state,
|
||||
const void *config,
|
||||
const Py_UNICODE **inbuf, Py_ssize_t inleft,
|
||||
unsigned char **outbuf, Py_ssize_t outleft,
|
||||
int flags);
|
||||
typedef int (*mbencodeinit_func)(MultibyteCodec_State *state,
|
||||
const void *config);
|
||||
typedef Py_ssize_t (*mbencodereset_func)(MultibyteCodec_State *state,
|
||||
const void *config,
|
||||
unsigned char **outbuf, Py_ssize_t outleft);
|
||||
typedef Py_ssize_t (*mbdecode_func)(MultibyteCodec_State *state,
|
||||
const void *config,
|
||||
const unsigned char **inbuf, Py_ssize_t inleft,
|
||||
Py_UNICODE **outbuf, Py_ssize_t outleft);
|
||||
typedef int (*mbdecodeinit_func)(MultibyteCodec_State *state,
|
||||
const void *config);
|
||||
typedef Py_ssize_t (*mbdecodereset_func)(MultibyteCodec_State *state,
|
||||
const void *config);
|
||||
|
||||
typedef struct {
|
||||
const char *encoding;
|
||||
const void *config;
|
||||
mbcodec_init codecinit;
|
||||
mbencode_func encode;
|
||||
mbencodeinit_func encinit;
|
||||
mbencodereset_func encreset;
|
||||
mbdecode_func decode;
|
||||
mbdecodeinit_func decinit;
|
||||
mbdecodereset_func decreset;
|
||||
} MultibyteCodec;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
MultibyteCodec *codec;
|
||||
} MultibyteCodecObject;
|
||||
|
||||
#define MultibyteCodec_Check(op) ((op)->ob_type == &MultibyteCodec_Type)
|
||||
|
||||
#define _MultibyteStatefulCodec_HEAD \
|
||||
PyObject_HEAD \
|
||||
MultibyteCodec *codec; \
|
||||
MultibyteCodec_State state; \
|
||||
PyObject *errors;
|
||||
typedef struct {
|
||||
_MultibyteStatefulCodec_HEAD
|
||||
} MultibyteStatefulCodecContext;
|
||||
|
||||
#define MAXENCPENDING 2
|
||||
#define _MultibyteStatefulEncoder_HEAD \
|
||||
_MultibyteStatefulCodec_HEAD \
|
||||
Py_UNICODE pending[MAXENCPENDING]; \
|
||||
Py_ssize_t pendingsize;
|
||||
typedef struct {
|
||||
_MultibyteStatefulEncoder_HEAD
|
||||
} MultibyteStatefulEncoderContext;
|
||||
|
||||
#define MAXDECPENDING 8
|
||||
#define _MultibyteStatefulDecoder_HEAD \
|
||||
_MultibyteStatefulCodec_HEAD \
|
||||
unsigned char pending[MAXDECPENDING]; \
|
||||
Py_ssize_t pendingsize;
|
||||
typedef struct {
|
||||
_MultibyteStatefulDecoder_HEAD
|
||||
} MultibyteStatefulDecoderContext;
|
||||
|
||||
typedef struct {
|
||||
_MultibyteStatefulEncoder_HEAD
|
||||
} MultibyteIncrementalEncoderObject;
|
||||
|
||||
typedef struct {
|
||||
_MultibyteStatefulDecoder_HEAD
|
||||
} MultibyteIncrementalDecoderObject;
|
||||
|
||||
typedef struct {
|
||||
_MultibyteStatefulDecoder_HEAD
|
||||
PyObject *stream;
|
||||
} MultibyteStreamReaderObject;
|
||||
|
||||
typedef struct {
|
||||
_MultibyteStatefulEncoder_HEAD
|
||||
PyObject *stream;
|
||||
} MultibyteStreamWriterObject;
|
||||
|
||||
/* positive values for illegal sequences */
|
||||
#define MBERR_TOOSMALL (-1) /* insufficient output buffer space */
|
||||
#define MBERR_TOOFEW (-2) /* incomplete input buffer */
|
||||
#define MBERR_INTERNAL (-3) /* internal runtime error */
|
||||
|
||||
#define ERROR_STRICT (PyObject *)(1)
|
||||
#define ERROR_IGNORE (PyObject *)(2)
|
||||
#define ERROR_REPLACE (PyObject *)(3)
|
||||
#define ERROR_ISCUSTOM(p) ((p) < ERROR_STRICT || ERROR_REPLACE < (p))
|
||||
#define ERROR_DECREF(p) do { \
|
||||
if (p != NULL && ERROR_ISCUSTOM(p)) { \
|
||||
Py_DECREF(p); \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define MBENC_FLUSH 0x0001 /* encode all characters encodable */
|
||||
#define MBENC_MAX MBENC_FLUSH
|
||||
|
||||
#define PyMultibyteCodec_CAPSULE_NAME "multibytecodec.__map_*"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
+2563
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,65 @@
|
||||
/* -*- C -*- ***********************************************
|
||||
Copyright (c) 2000, BeOpen.com.
|
||||
Copyright (c) 1995-2000, Corporation for National Research Initiatives.
|
||||
Copyright (c) 1990-1995, Stichting Mathematisch Centrum.
|
||||
All rights reserved.
|
||||
|
||||
See the file "Misc/COPYRIGHT" for information on usage and
|
||||
redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
******************************************************************/
|
||||
|
||||
/* Module configuration */
|
||||
|
||||
/* !!! !!! !!! This file is edited by the makesetup script !!! !!! !!! */
|
||||
|
||||
/* This file contains the table of built-in modules.
|
||||
See init_builtin() in import.c. */
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* -- ADDMODULE MARKER 1 -- */
|
||||
|
||||
extern void PyMarshal_Init(void);
|
||||
extern void initimp(void);
|
||||
extern void initgc(void);
|
||||
extern void init_ast(void);
|
||||
extern void _PyWarnings_Init(void);
|
||||
|
||||
struct _inittab _PyImport_Inittab[] = {
|
||||
|
||||
/* -- ADDMODULE MARKER 2 -- */
|
||||
|
||||
/* This module lives in marshal.c */
|
||||
{"marshal", PyMarshal_Init},
|
||||
|
||||
/* This lives in import.c */
|
||||
{"imp", initimp},
|
||||
|
||||
/* This lives in Python/Python-ast.c */
|
||||
{"_ast", init_ast},
|
||||
|
||||
/* These entries are here for sys.builtin_module_names */
|
||||
{"__main__", NULL},
|
||||
{"__builtin__", NULL},
|
||||
{"sys", NULL},
|
||||
{"exceptions", NULL},
|
||||
|
||||
/* This lives in gcmodule.c */
|
||||
{"gc", initgc},
|
||||
|
||||
/* This lives in _warnings.c */
|
||||
{"_warnings", _PyWarnings_Init},
|
||||
|
||||
/* Sentinel */
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,49 @@
|
||||
/* cryptmodule.c - by Steve Majewski
|
||||
*/
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __VMS
|
||||
#include <openssl/des.h>
|
||||
#endif
|
||||
|
||||
/* Module crypt */
|
||||
|
||||
|
||||
static PyObject *crypt_crypt(PyObject *self, PyObject *args)
|
||||
{
|
||||
char *word, *salt;
|
||||
#ifndef __VMS
|
||||
extern char * crypt(const char *, const char *);
|
||||
#endif
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ss:crypt", &word, &salt)) {
|
||||
return NULL;
|
||||
}
|
||||
/* On some platforms (AtheOS) crypt returns NULL for an invalid
|
||||
salt. Return None in that case. XXX Maybe raise an exception? */
|
||||
return Py_BuildValue("s", crypt(word, salt));
|
||||
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(crypt_crypt__doc__,
|
||||
"crypt(word, salt) -> string\n\
|
||||
word will usually be a user's password. salt is a 2-character string\n\
|
||||
which will be used to select one of 4096 variations of DES. The characters\n\
|
||||
in salt must be either \".\", \"/\", or an alphanumeric character. Returns\n\
|
||||
the hashed password as a string, which will be composed of characters from\n\
|
||||
the same alphabet as the salt.");
|
||||
|
||||
|
||||
static PyMethodDef crypt_methods[] = {
|
||||
{"crypt", crypt_crypt, METH_VARARGS, crypt_crypt__doc__},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC
|
||||
initcrypt(void)
|
||||
{
|
||||
Py_InitModule("crypt", crypt_methods);
|
||||
}
|
||||
+1364
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,419 @@
|
||||
|
||||
/* DBM module using dictionary interface */
|
||||
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
/* Some Linux systems install gdbm/ndbm.h, but not ndbm.h. This supports
|
||||
* whichever configure was able to locate.
|
||||
*/
|
||||
#if defined(HAVE_NDBM_H)
|
||||
#include <ndbm.h>
|
||||
#if defined(PYOS_OS2) && !defined(PYCC_GCC)
|
||||
static char *which_dbm = "ndbm";
|
||||
#else
|
||||
static char *which_dbm = "GNU gdbm"; /* EMX port of GDBM */
|
||||
#endif
|
||||
#elif defined(HAVE_GDBM_NDBM_H)
|
||||
#include <gdbm/ndbm.h>
|
||||
static char *which_dbm = "GNU gdbm";
|
||||
#elif defined(HAVE_GDBM_DASH_NDBM_H)
|
||||
#include <gdbm-ndbm.h>
|
||||
static char *which_dbm = "GNU gdbm";
|
||||
#elif defined(HAVE_BERKDB_H)
|
||||
#include <db.h>
|
||||
static char *which_dbm = "Berkeley DB";
|
||||
#else
|
||||
#error "No ndbm.h available!"
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
int di_size; /* -1 means recompute */
|
||||
DBM *di_dbm;
|
||||
} dbmobject;
|
||||
|
||||
static PyTypeObject Dbmtype;
|
||||
|
||||
#define is_dbmobject(v) (Py_TYPE(v) == &Dbmtype)
|
||||
#define check_dbmobject_open(v) if ((v)->di_dbm == NULL) \
|
||||
{ PyErr_SetString(DbmError, "DBM object has already been closed"); \
|
||||
return NULL; }
|
||||
|
||||
static PyObject *DbmError;
|
||||
|
||||
static PyObject *
|
||||
newdbmobject(char *file, int flags, int mode)
|
||||
{
|
||||
dbmobject *dp;
|
||||
|
||||
dp = PyObject_New(dbmobject, &Dbmtype);
|
||||
if (dp == NULL)
|
||||
return NULL;
|
||||
dp->di_size = -1;
|
||||
if ( (dp->di_dbm = dbm_open(file, flags, mode)) == 0 ) {
|
||||
PyErr_SetFromErrno(DbmError);
|
||||
Py_DECREF(dp);
|
||||
return NULL;
|
||||
}
|
||||
return (PyObject *)dp;
|
||||
}
|
||||
|
||||
/* Methods */
|
||||
|
||||
static void
|
||||
dbm_dealloc(register dbmobject *dp)
|
||||
{
|
||||
if ( dp->di_dbm )
|
||||
dbm_close(dp->di_dbm);
|
||||
PyObject_Del(dp);
|
||||
}
|
||||
|
||||
static Py_ssize_t
|
||||
dbm_length(dbmobject *dp)
|
||||
{
|
||||
if (dp->di_dbm == NULL) {
|
||||
PyErr_SetString(DbmError, "DBM object has already been closed");
|
||||
return -1;
|
||||
}
|
||||
if ( dp->di_size < 0 ) {
|
||||
datum key;
|
||||
int size;
|
||||
|
||||
size = 0;
|
||||
for ( key=dbm_firstkey(dp->di_dbm); key.dptr;
|
||||
key = dbm_nextkey(dp->di_dbm))
|
||||
size++;
|
||||
dp->di_size = size;
|
||||
}
|
||||
return dp->di_size;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
dbm_subscript(dbmobject *dp, register PyObject *key)
|
||||
{
|
||||
datum drec, krec;
|
||||
int tmp_size;
|
||||
|
||||
if (!PyArg_Parse(key, "s#", &krec.dptr, &tmp_size) )
|
||||
return NULL;
|
||||
|
||||
krec.dsize = tmp_size;
|
||||
check_dbmobject_open(dp);
|
||||
drec = dbm_fetch(dp->di_dbm, krec);
|
||||
if ( drec.dptr == 0 ) {
|
||||
PyErr_SetString(PyExc_KeyError,
|
||||
PyString_AS_STRING((PyStringObject *)key));
|
||||
return NULL;
|
||||
}
|
||||
if ( dbm_error(dp->di_dbm) ) {
|
||||
dbm_clearerr(dp->di_dbm);
|
||||
PyErr_SetString(DbmError, "");
|
||||
return NULL;
|
||||
}
|
||||
return PyString_FromStringAndSize(drec.dptr, drec.dsize);
|
||||
}
|
||||
|
||||
static int
|
||||
dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
|
||||
{
|
||||
datum krec, drec;
|
||||
int tmp_size;
|
||||
|
||||
if ( !PyArg_Parse(v, "s#", &krec.dptr, &tmp_size) ) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"dbm mappings have string indices only");
|
||||
return -1;
|
||||
}
|
||||
krec.dsize = tmp_size;
|
||||
if (dp->di_dbm == NULL) {
|
||||
PyErr_SetString(DbmError, "DBM object has already been closed");
|
||||
return -1;
|
||||
}
|
||||
dp->di_size = -1;
|
||||
if (w == NULL) {
|
||||
if ( dbm_delete(dp->di_dbm, krec) < 0 ) {
|
||||
dbm_clearerr(dp->di_dbm);
|
||||
PyErr_SetString(PyExc_KeyError,
|
||||
PyString_AS_STRING((PyStringObject *)v));
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if ( !PyArg_Parse(w, "s#", &drec.dptr, &tmp_size) ) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"dbm mappings have string elements only");
|
||||
return -1;
|
||||
}
|
||||
drec.dsize = tmp_size;
|
||||
if ( dbm_store(dp->di_dbm, krec, drec, DBM_REPLACE) < 0 ) {
|
||||
dbm_clearerr(dp->di_dbm);
|
||||
PyErr_SetString(DbmError,
|
||||
"cannot add item to database");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if ( dbm_error(dp->di_dbm) ) {
|
||||
dbm_clearerr(dp->di_dbm);
|
||||
PyErr_SetString(DbmError, "");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dbm_contains(register dbmobject *dp, PyObject *v)
|
||||
{
|
||||
datum key, val;
|
||||
char *ptr;
|
||||
Py_ssize_t size;
|
||||
|
||||
if (PyString_AsStringAndSize(v, &ptr, &size))
|
||||
return -1;
|
||||
key.dptr = ptr;
|
||||
key.dsize = size;
|
||||
|
||||
/* Expand check_dbmobject_open to return -1 */
|
||||
if (dp->di_dbm == NULL) {
|
||||
PyErr_SetString(DbmError, "DBM object has already been closed");
|
||||
return -1;
|
||||
}
|
||||
val = dbm_fetch(dp->di_dbm, key);
|
||||
return val.dptr != NULL;
|
||||
}
|
||||
|
||||
static PySequenceMethods dbm_as_sequence = {
|
||||
(lenfunc)dbm_length, /*_length*/
|
||||
0, /*sq_concat*/
|
||||
0, /*sq_repeat*/
|
||||
0, /*sq_item*/
|
||||
0, /*sq_slice*/
|
||||
0, /*sq_ass_item*/
|
||||
0, /*sq_ass_slice*/
|
||||
(objobjproc)dbm_contains, /*sq_contains*/
|
||||
0, /*sq_inplace_concat*/
|
||||
0 /*sq_inplace_repeat*/
|
||||
};
|
||||
|
||||
static PyMappingMethods dbm_as_mapping = {
|
||||
(lenfunc)dbm_length, /*mp_length*/
|
||||
(binaryfunc)dbm_subscript, /*mp_subscript*/
|
||||
(objobjargproc)dbm_ass_sub, /*mp_ass_subscript*/
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
dbm__close(register dbmobject *dp, PyObject *unused)
|
||||
{
|
||||
if (dp->di_dbm)
|
||||
dbm_close(dp->di_dbm);
|
||||
dp->di_dbm = NULL;
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
dbm_keys(register dbmobject *dp, PyObject *unused)
|
||||
{
|
||||
register PyObject *v, *item;
|
||||
datum key;
|
||||
int err;
|
||||
|
||||
check_dbmobject_open(dp);
|
||||
v = PyList_New(0);
|
||||
if (v == NULL)
|
||||
return NULL;
|
||||
for (key = dbm_firstkey(dp->di_dbm); key.dptr;
|
||||
key = dbm_nextkey(dp->di_dbm)) {
|
||||
item = PyString_FromStringAndSize(key.dptr, key.dsize);
|
||||
if (item == NULL) {
|
||||
Py_DECREF(v);
|
||||
return NULL;
|
||||
}
|
||||
err = PyList_Append(v, item);
|
||||
Py_DECREF(item);
|
||||
if (err != 0) {
|
||||
Py_DECREF(v);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
dbm_has_key(register dbmobject *dp, PyObject *args)
|
||||
{
|
||||
char *tmp_ptr;
|
||||
datum key, val;
|
||||
int tmp_size;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s#:has_key", &tmp_ptr, &tmp_size))
|
||||
return NULL;
|
||||
key.dptr = tmp_ptr;
|
||||
key.dsize = tmp_size;
|
||||
check_dbmobject_open(dp);
|
||||
val = dbm_fetch(dp->di_dbm, key);
|
||||
return PyInt_FromLong(val.dptr != NULL);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
dbm_get(register dbmobject *dp, PyObject *args)
|
||||
{
|
||||
datum key, val;
|
||||
PyObject *defvalue = Py_None;
|
||||
char *tmp_ptr;
|
||||
int tmp_size;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s#|O:get",
|
||||
&tmp_ptr, &tmp_size, &defvalue))
|
||||
return NULL;
|
||||
key.dptr = tmp_ptr;
|
||||
key.dsize = tmp_size;
|
||||
check_dbmobject_open(dp);
|
||||
val = dbm_fetch(dp->di_dbm, key);
|
||||
if (val.dptr != NULL)
|
||||
return PyString_FromStringAndSize(val.dptr, val.dsize);
|
||||
else {
|
||||
Py_INCREF(defvalue);
|
||||
return defvalue;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
dbm_setdefault(register dbmobject *dp, PyObject *args)
|
||||
{
|
||||
datum key, val;
|
||||
PyObject *defvalue = NULL;
|
||||
char *tmp_ptr;
|
||||
int tmp_size;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s#|S:setdefault",
|
||||
&tmp_ptr, &tmp_size, &defvalue))
|
||||
return NULL;
|
||||
key.dptr = tmp_ptr;
|
||||
key.dsize = tmp_size;
|
||||
check_dbmobject_open(dp);
|
||||
val = dbm_fetch(dp->di_dbm, key);
|
||||
if (val.dptr != NULL)
|
||||
return PyString_FromStringAndSize(val.dptr, val.dsize);
|
||||
if (defvalue == NULL) {
|
||||
defvalue = PyString_FromStringAndSize(NULL, 0);
|
||||
if (defvalue == NULL)
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
Py_INCREF(defvalue);
|
||||
val.dptr = PyString_AS_STRING(defvalue);
|
||||
val.dsize = PyString_GET_SIZE(defvalue);
|
||||
if (dbm_store(dp->di_dbm, key, val, DBM_INSERT) < 0) {
|
||||
dbm_clearerr(dp->di_dbm);
|
||||
PyErr_SetString(DbmError, "cannot add item to database");
|
||||
return NULL;
|
||||
}
|
||||
return defvalue;
|
||||
}
|
||||
|
||||
static PyMethodDef dbm_methods[] = {
|
||||
{"close", (PyCFunction)dbm__close, METH_NOARGS,
|
||||
"close()\nClose the database."},
|
||||
{"keys", (PyCFunction)dbm_keys, METH_NOARGS,
|
||||
"keys() -> list\nReturn a list of all keys in the database."},
|
||||
{"has_key", (PyCFunction)dbm_has_key, METH_VARARGS,
|
||||
"has_key(key} -> boolean\nReturn true iff key is in the database."},
|
||||
{"get", (PyCFunction)dbm_get, METH_VARARGS,
|
||||
"get(key[, default]) -> value\n"
|
||||
"Return the value for key if present, otherwise default."},
|
||||
{"setdefault", (PyCFunction)dbm_setdefault, METH_VARARGS,
|
||||
"setdefault(key[, default]) -> value\n"
|
||||
"Return the value for key if present, otherwise default. If key\n"
|
||||
"is not in the database, it is inserted with default as the value."},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
dbm_getattr(dbmobject *dp, char *name)
|
||||
{
|
||||
return Py_FindMethod(dbm_methods, (PyObject *)dp, name);
|
||||
}
|
||||
|
||||
static PyTypeObject Dbmtype = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"dbm.dbm",
|
||||
sizeof(dbmobject),
|
||||
0,
|
||||
(destructor)dbm_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
(getattrfunc)dbm_getattr, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
0, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
&dbm_as_sequence, /*tp_as_sequence*/
|
||||
&dbm_as_mapping, /*tp_as_mapping*/
|
||||
0, /*tp_hash*/
|
||||
0, /*tp_call*/
|
||||
0, /*tp_str*/
|
||||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT, /*tp_xxx4*/
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
|
||||
static PyObject *
|
||||
dbmopen(PyObject *self, PyObject *args)
|
||||
{
|
||||
char *name;
|
||||
char *flags = "r";
|
||||
int iflags;
|
||||
int mode = 0666;
|
||||
|
||||
if ( !PyArg_ParseTuple(args, "s|si:open", &name, &flags, &mode) )
|
||||
return NULL;
|
||||
if ( strcmp(flags, "r") == 0 )
|
||||
iflags = O_RDONLY;
|
||||
else if ( strcmp(flags, "w") == 0 )
|
||||
iflags = O_RDWR;
|
||||
else if ( strcmp(flags, "rw") == 0 ) /* B/W compat */
|
||||
iflags = O_RDWR|O_CREAT;
|
||||
else if ( strcmp(flags, "c") == 0 )
|
||||
iflags = O_RDWR|O_CREAT;
|
||||
else if ( strcmp(flags, "n") == 0 )
|
||||
iflags = O_RDWR|O_CREAT|O_TRUNC;
|
||||
else {
|
||||
PyErr_SetString(DbmError,
|
||||
"arg 2 to open should be 'r', 'w', 'c', or 'n'");
|
||||
return NULL;
|
||||
}
|
||||
return newdbmobject(name, iflags, mode);
|
||||
}
|
||||
|
||||
static PyMethodDef dbmmodule_methods[] = {
|
||||
{ "open", (PyCFunction)dbmopen, METH_VARARGS,
|
||||
"open(path[, flag[, mode]]) -> mapping\n"
|
||||
"Return a database object."},
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC
|
||||
initdbm(void) {
|
||||
PyObject *m, *d, *s;
|
||||
|
||||
Dbmtype.ob_type = &PyType_Type;
|
||||
m = Py_InitModule("dbm", dbmmodule_methods);
|
||||
if (m == NULL)
|
||||
return;
|
||||
d = PyModule_GetDict(m);
|
||||
if (DbmError == NULL)
|
||||
DbmError = PyErr_NewException("dbm.error", NULL, NULL);
|
||||
s = PyString_FromString(which_dbm);
|
||||
if (s != NULL) {
|
||||
PyDict_SetItemString(d, "library", s);
|
||||
Py_DECREF(s);
|
||||
}
|
||||
if (DbmError != NULL)
|
||||
PyDict_SetItemString(d, "error", DbmError);
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
|
||||
/* dl module */
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#ifdef __VMS
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifndef RTLD_LAZY
|
||||
#define RTLD_LAZY 1
|
||||
#endif
|
||||
|
||||
typedef void *PyUnivPtr;
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PyUnivPtr *dl_handle;
|
||||
} dlobject;
|
||||
|
||||
static PyTypeObject Dltype;
|
||||
|
||||
static PyObject *Dlerror;
|
||||
|
||||
static PyObject *
|
||||
newdlobject(PyUnivPtr *handle)
|
||||
{
|
||||
dlobject *xp;
|
||||
xp = PyObject_New(dlobject, &Dltype);
|
||||
if (xp == NULL)
|
||||
return NULL;
|
||||
xp->dl_handle = handle;
|
||||
return (PyObject *)xp;
|
||||
}
|
||||
|
||||
static void
|
||||
dl_dealloc(dlobject *xp)
|
||||
{
|
||||
if (xp->dl_handle != NULL)
|
||||
dlclose(xp->dl_handle);
|
||||
PyObject_Del(xp);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
dl_close(dlobject *xp)
|
||||
{
|
||||
if (xp->dl_handle != NULL) {
|
||||
dlclose(xp->dl_handle);
|
||||
xp->dl_handle = NULL;
|
||||
}
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
dl_sym(dlobject *xp, PyObject *args)
|
||||
{
|
||||
char *name;
|
||||
PyUnivPtr *func;
|
||||
if (PyString_Check(args)) {
|
||||
name = PyString_AS_STRING(args);
|
||||
} else {
|
||||
PyErr_Format(PyExc_TypeError, "expected string, found %.200s",
|
||||
Py_TYPE(args)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
func = dlsym(xp->dl_handle, name);
|
||||
if (func == NULL) {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
return PyInt_FromLong((long)func);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
dl_call(dlobject *xp, PyObject *args)
|
||||
{
|
||||
PyObject *name;
|
||||
long (*func)(long, long, long, long, long,
|
||||
long, long, long, long, long);
|
||||
long alist[10];
|
||||
long res;
|
||||
Py_ssize_t i;
|
||||
Py_ssize_t n = PyTuple_Size(args);
|
||||
if (n < 1) {
|
||||
PyErr_SetString(PyExc_TypeError, "at least a name is needed");
|
||||
return NULL;
|
||||
}
|
||||
name = PyTuple_GetItem(args, 0);
|
||||
if (!PyString_Check(name)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"function name must be a string");
|
||||
return NULL;
|
||||
}
|
||||
func = (long (*)(long, long, long, long, long,
|
||||
long, long, long, long, long))
|
||||
dlsym(xp->dl_handle, PyString_AsString(name));
|
||||
if (func == NULL) {
|
||||
PyErr_SetString(PyExc_ValueError, dlerror());
|
||||
return NULL;
|
||||
}
|
||||
if (n-1 > 10) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"too many arguments (max 10)");
|
||||
return NULL;
|
||||
}
|
||||
for (i = 1; i < n; i++) {
|
||||
PyObject *v = PyTuple_GetItem(args, i);
|
||||
if (_PyAnyInt_Check(v)) {
|
||||
alist[i-1] = PyInt_AsLong(v);
|
||||
if (alist[i-1] == -1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
}
|
||||
else if (PyString_Check(v))
|
||||
alist[i-1] = (long)PyString_AsString(v);
|
||||
else if (v == Py_None)
|
||||
alist[i-1] = (long) ((char *)NULL);
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"arguments must be int, string or None");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
for (; i <= 10; i++)
|
||||
alist[i-1] = 0;
|
||||
res = (*func)(alist[0], alist[1], alist[2], alist[3], alist[4],
|
||||
alist[5], alist[6], alist[7], alist[8], alist[9]);
|
||||
return PyInt_FromLong(res);
|
||||
}
|
||||
|
||||
static PyMethodDef dlobject_methods[] = {
|
||||
{"call", (PyCFunction)dl_call, METH_VARARGS},
|
||||
{"sym", (PyCFunction)dl_sym, METH_O},
|
||||
{"close", (PyCFunction)dl_close, METH_NOARGS},
|
||||
{NULL, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
dl_getattr(dlobject *xp, char *name)
|
||||
{
|
||||
return Py_FindMethod(dlobject_methods, (PyObject *)xp, name);
|
||||
}
|
||||
|
||||
|
||||
static PyTypeObject Dltype = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"dl.dl", /*tp_name*/
|
||||
sizeof(dlobject), /*tp_basicsize*/
|
||||
0, /*tp_itemsize*/
|
||||
/* methods */
|
||||
(destructor)dl_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
(getattrfunc)dl_getattr,/*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
0, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
0, /*tp_hash*/
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
dl_open(PyObject *self, PyObject *args)
|
||||
{
|
||||
char *name;
|
||||
int mode;
|
||||
PyUnivPtr *handle;
|
||||
if (sizeof(int) != sizeof(long) ||
|
||||
sizeof(long) != sizeof(char *)) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"module dl requires sizeof(int) == sizeof(long) == sizeof(char*)");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (PyArg_ParseTuple(args, "z:open", &name))
|
||||
mode = RTLD_LAZY;
|
||||
else {
|
||||
PyErr_Clear();
|
||||
if (!PyArg_ParseTuple(args, "zi:open", &name, &mode))
|
||||
return NULL;
|
||||
#ifndef RTLD_NOW
|
||||
if (mode != RTLD_LAZY) {
|
||||
PyErr_SetString(PyExc_ValueError, "mode must be 1");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
handle = dlopen(name, mode);
|
||||
if (handle == NULL) {
|
||||
char *errmsg = dlerror();
|
||||
if (!errmsg)
|
||||
errmsg = "dlopen() error";
|
||||
PyErr_SetString(Dlerror, errmsg);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef __VMS
|
||||
/* Under OpenVMS dlopen doesn't do any check, just save the name
|
||||
* for later use, so we have to check if the file is readable,
|
||||
* the name can be a logical or a file from SYS$SHARE.
|
||||
*/
|
||||
if (access(name, R_OK)) {
|
||||
char fname[strlen(name) + 20];
|
||||
strcpy(fname, "SYS$SHARE:");
|
||||
strcat(fname, name);
|
||||
strcat(fname, ".EXE");
|
||||
if (access(fname, R_OK)) {
|
||||
dlclose(handle);
|
||||
PyErr_SetString(Dlerror,
|
||||
"File not found or protection violation");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return newdlobject(handle);
|
||||
}
|
||||
|
||||
static PyMethodDef dl_methods[] = {
|
||||
{"open", dl_open, METH_VARARGS},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
/* From socketmodule.c
|
||||
* Convenience routine to export an integer value.
|
||||
*
|
||||
* Errors are silently ignored, for better or for worse...
|
||||
*/
|
||||
static void
|
||||
insint(PyObject *d, char *name, int value)
|
||||
{
|
||||
PyObject *v = PyInt_FromLong((long) value);
|
||||
if (!v || PyDict_SetItemString(d, name, v))
|
||||
PyErr_Clear();
|
||||
|
||||
Py_XDECREF(v);
|
||||
}
|
||||
|
||||
PyMODINIT_FUNC
|
||||
initdl(void)
|
||||
{
|
||||
PyObject *m, *d, *x;
|
||||
|
||||
if (PyErr_WarnPy3k("the dl module has been removed in "
|
||||
"Python 3.0; use the ctypes module instead", 2) < 0)
|
||||
return;
|
||||
|
||||
/* Initialize object type */
|
||||
Py_TYPE(&Dltype) = &PyType_Type;
|
||||
|
||||
/* Create the module and add the functions */
|
||||
m = Py_InitModule("dl", dl_methods);
|
||||
if (m == NULL)
|
||||
return;
|
||||
|
||||
/* Add some symbolic constants to the module */
|
||||
d = PyModule_GetDict(m);
|
||||
Dlerror = x = PyErr_NewException("dl.error", NULL, NULL);
|
||||
PyDict_SetItemString(d, "error", x);
|
||||
x = PyInt_FromLong((long)RTLD_LAZY);
|
||||
PyDict_SetItemString(d, "RTLD_LAZY", x);
|
||||
#define INSINT(X) insint(d,#X,X)
|
||||
#ifdef RTLD_NOW
|
||||
INSINT(RTLD_NOW);
|
||||
#endif
|
||||
#ifdef RTLD_NOLOAD
|
||||
INSINT(RTLD_NOLOAD);
|
||||
#endif
|
||||
#ifdef RTLD_GLOBAL
|
||||
INSINT(RTLD_GLOBAL);
|
||||
#endif
|
||||
#ifdef RTLD_LOCAL
|
||||
INSINT(RTLD_LOCAL);
|
||||
#endif
|
||||
#ifdef RTLD_PARENT
|
||||
INSINT(RTLD_PARENT);
|
||||
#endif
|
||||
#ifdef RTLD_GROUP
|
||||
INSINT(RTLD_GROUP);
|
||||
#endif
|
||||
#ifdef RTLD_WORLD
|
||||
INSINT(RTLD_WORLD);
|
||||
#endif
|
||||
#ifdef RTLD_NODELETE
|
||||
INSINT(RTLD_NODELETE);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,791 @@
|
||||
|
||||
/* Errno module */
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
/* Windows socket errors (WSA*) */
|
||||
#ifdef MS_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Pull in the system error definitions
|
||||
*/
|
||||
|
||||
static PyMethodDef errno_methods[] = {
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* Helper function doing the dictionary inserting */
|
||||
|
||||
static void
|
||||
_inscode(PyObject *d, PyObject *de, char *name, int code)
|
||||
{
|
||||
PyObject *u = PyString_FromString(name);
|
||||
PyObject *v = PyInt_FromLong((long) code);
|
||||
|
||||
/* Don't bother checking for errors; they'll be caught at the end
|
||||
* of the module initialization function by the caller of
|
||||
* initerrno().
|
||||
*/
|
||||
if (u && v) {
|
||||
/* insert in modules dict */
|
||||
PyDict_SetItem(d, u, v);
|
||||
/* insert in errorcode dict */
|
||||
PyDict_SetItem(de, v, u);
|
||||
}
|
||||
Py_XDECREF(u);
|
||||
Py_XDECREF(v);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(errno__doc__,
|
||||
"This module makes available standard errno system symbols.\n\
|
||||
\n\
|
||||
The value of each symbol is the corresponding integer value,\n\
|
||||
e.g., on most systems, errno.ENOENT equals the integer 2.\n\
|
||||
\n\
|
||||
The dictionary errno.errorcode maps numeric codes to symbol names,\n\
|
||||
e.g., errno.errorcode[2] could be the string 'ENOENT'.\n\
|
||||
\n\
|
||||
Symbols that are not relevant to the underlying system are not defined.\n\
|
||||
\n\
|
||||
To map error codes to error messages, use the function os.strerror(),\n\
|
||||
e.g. os.strerror(2) could return 'No such file or directory'.");
|
||||
|
||||
PyMODINIT_FUNC
|
||||
initerrno(void)
|
||||
{
|
||||
PyObject *m, *d, *de;
|
||||
m = Py_InitModule3("errno", errno_methods, errno__doc__);
|
||||
if (m == NULL)
|
||||
return;
|
||||
d = PyModule_GetDict(m);
|
||||
de = PyDict_New();
|
||||
if (!d || !de || PyDict_SetItemString(d, "errorcode", de) < 0)
|
||||
return;
|
||||
|
||||
/* Macro so I don't have to edit each and every line below... */
|
||||
#define inscode(d, ds, de, name, code, comment) _inscode(d, de, name, code)
|
||||
|
||||
/*
|
||||
* The names and comments are borrowed from linux/include/errno.h,
|
||||
* which should be pretty all-inclusive
|
||||
*/
|
||||
|
||||
#ifdef ENODEV
|
||||
inscode(d, ds, de, "ENODEV", ENODEV, "No such device");
|
||||
#endif
|
||||
#ifdef ENOCSI
|
||||
inscode(d, ds, de, "ENOCSI", ENOCSI, "No CSI structure available");
|
||||
#endif
|
||||
#ifdef EHOSTUNREACH
|
||||
inscode(d, ds, de, "EHOSTUNREACH", EHOSTUNREACH, "No route to host");
|
||||
#else
|
||||
#ifdef WSAEHOSTUNREACH
|
||||
inscode(d, ds, de, "EHOSTUNREACH", WSAEHOSTUNREACH, "No route to host");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ENOMSG
|
||||
inscode(d, ds, de, "ENOMSG", ENOMSG, "No message of desired type");
|
||||
#endif
|
||||
#ifdef EUCLEAN
|
||||
inscode(d, ds, de, "EUCLEAN", EUCLEAN, "Structure needs cleaning");
|
||||
#endif
|
||||
#ifdef EL2NSYNC
|
||||
inscode(d, ds, de, "EL2NSYNC", EL2NSYNC, "Level 2 not synchronized");
|
||||
#endif
|
||||
#ifdef EL2HLT
|
||||
inscode(d, ds, de, "EL2HLT", EL2HLT, "Level 2 halted");
|
||||
#endif
|
||||
#ifdef ENODATA
|
||||
inscode(d, ds, de, "ENODATA", ENODATA, "No data available");
|
||||
#endif
|
||||
#ifdef ENOTBLK
|
||||
inscode(d, ds, de, "ENOTBLK", ENOTBLK, "Block device required");
|
||||
#endif
|
||||
#ifdef ENOSYS
|
||||
inscode(d, ds, de, "ENOSYS", ENOSYS, "Function not implemented");
|
||||
#endif
|
||||
#ifdef EPIPE
|
||||
inscode(d, ds, de, "EPIPE", EPIPE, "Broken pipe");
|
||||
#endif
|
||||
#ifdef EINVAL
|
||||
inscode(d, ds, de, "EINVAL", EINVAL, "Invalid argument");
|
||||
#else
|
||||
#ifdef WSAEINVAL
|
||||
inscode(d, ds, de, "EINVAL", WSAEINVAL, "Invalid argument");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef EOVERFLOW
|
||||
inscode(d, ds, de, "EOVERFLOW", EOVERFLOW, "Value too large for defined data type");
|
||||
#endif
|
||||
#ifdef EADV
|
||||
inscode(d, ds, de, "EADV", EADV, "Advertise error");
|
||||
#endif
|
||||
#ifdef EINTR
|
||||
inscode(d, ds, de, "EINTR", EINTR, "Interrupted system call");
|
||||
#else
|
||||
#ifdef WSAEINTR
|
||||
inscode(d, ds, de, "EINTR", WSAEINTR, "Interrupted system call");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef EUSERS
|
||||
inscode(d, ds, de, "EUSERS", EUSERS, "Too many users");
|
||||
#else
|
||||
#ifdef WSAEUSERS
|
||||
inscode(d, ds, de, "EUSERS", WSAEUSERS, "Too many users");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ENOTEMPTY
|
||||
inscode(d, ds, de, "ENOTEMPTY", ENOTEMPTY, "Directory not empty");
|
||||
#else
|
||||
#ifdef WSAENOTEMPTY
|
||||
inscode(d, ds, de, "ENOTEMPTY", WSAENOTEMPTY, "Directory not empty");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ENOBUFS
|
||||
inscode(d, ds, de, "ENOBUFS", ENOBUFS, "No buffer space available");
|
||||
#else
|
||||
#ifdef WSAENOBUFS
|
||||
inscode(d, ds, de, "ENOBUFS", WSAENOBUFS, "No buffer space available");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef EPROTO
|
||||
inscode(d, ds, de, "EPROTO", EPROTO, "Protocol error");
|
||||
#endif
|
||||
#ifdef EREMOTE
|
||||
inscode(d, ds, de, "EREMOTE", EREMOTE, "Object is remote");
|
||||
#else
|
||||
#ifdef WSAEREMOTE
|
||||
inscode(d, ds, de, "EREMOTE", WSAEREMOTE, "Object is remote");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ENAVAIL
|
||||
inscode(d, ds, de, "ENAVAIL", ENAVAIL, "No XENIX semaphores available");
|
||||
#endif
|
||||
#ifdef ECHILD
|
||||
inscode(d, ds, de, "ECHILD", ECHILD, "No child processes");
|
||||
#endif
|
||||
#ifdef ELOOP
|
||||
inscode(d, ds, de, "ELOOP", ELOOP, "Too many symbolic links encountered");
|
||||
#else
|
||||
#ifdef WSAELOOP
|
||||
inscode(d, ds, de, "ELOOP", WSAELOOP, "Too many symbolic links encountered");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef EXDEV
|
||||
inscode(d, ds, de, "EXDEV", EXDEV, "Cross-device link");
|
||||
#endif
|
||||
#ifdef E2BIG
|
||||
inscode(d, ds, de, "E2BIG", E2BIG, "Arg list too long");
|
||||
#endif
|
||||
#ifdef ESRCH
|
||||
inscode(d, ds, de, "ESRCH", ESRCH, "No such process");
|
||||
#endif
|
||||
#ifdef EMSGSIZE
|
||||
inscode(d, ds, de, "EMSGSIZE", EMSGSIZE, "Message too long");
|
||||
#else
|
||||
#ifdef WSAEMSGSIZE
|
||||
inscode(d, ds, de, "EMSGSIZE", WSAEMSGSIZE, "Message too long");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef EAFNOSUPPORT
|
||||
inscode(d, ds, de, "EAFNOSUPPORT", EAFNOSUPPORT, "Address family not supported by protocol");
|
||||
#else
|
||||
#ifdef WSAEAFNOSUPPORT
|
||||
inscode(d, ds, de, "EAFNOSUPPORT", WSAEAFNOSUPPORT, "Address family not supported by protocol");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef EBADR
|
||||
inscode(d, ds, de, "EBADR", EBADR, "Invalid request descriptor");
|
||||
#endif
|
||||
#ifdef EHOSTDOWN
|
||||
inscode(d, ds, de, "EHOSTDOWN", EHOSTDOWN, "Host is down");
|
||||
#else
|
||||
#ifdef WSAEHOSTDOWN
|
||||
inscode(d, ds, de, "EHOSTDOWN", WSAEHOSTDOWN, "Host is down");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef EPFNOSUPPORT
|
||||
inscode(d, ds, de, "EPFNOSUPPORT", EPFNOSUPPORT, "Protocol family not supported");
|
||||
#else
|
||||
#ifdef WSAEPFNOSUPPORT
|
||||
inscode(d, ds, de, "EPFNOSUPPORT", WSAEPFNOSUPPORT, "Protocol family not supported");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ENOPROTOOPT
|
||||
inscode(d, ds, de, "ENOPROTOOPT", ENOPROTOOPT, "Protocol not available");
|
||||
#else
|
||||
#ifdef WSAENOPROTOOPT
|
||||
inscode(d, ds, de, "ENOPROTOOPT", WSAENOPROTOOPT, "Protocol not available");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef EBUSY
|
||||
inscode(d, ds, de, "EBUSY", EBUSY, "Device or resource busy");
|
||||
#endif
|
||||
#ifdef EWOULDBLOCK
|
||||
inscode(d, ds, de, "EWOULDBLOCK", EWOULDBLOCK, "Operation would block");
|
||||
#else
|
||||
#ifdef WSAEWOULDBLOCK
|
||||
inscode(d, ds, de, "EWOULDBLOCK", WSAEWOULDBLOCK, "Operation would block");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef EBADFD
|
||||
inscode(d, ds, de, "EBADFD", EBADFD, "File descriptor in bad state");
|
||||
#endif
|
||||
#ifdef EDOTDOT
|
||||
inscode(d, ds, de, "EDOTDOT", EDOTDOT, "RFS specific error");
|
||||
#endif
|
||||
#ifdef EISCONN
|
||||
inscode(d, ds, de, "EISCONN", EISCONN, "Transport endpoint is already connected");
|
||||
#else
|
||||
#ifdef WSAEISCONN
|
||||
inscode(d, ds, de, "EISCONN", WSAEISCONN, "Transport endpoint is already connected");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ENOANO
|
||||
inscode(d, ds, de, "ENOANO", ENOANO, "No anode");
|
||||
#endif
|
||||
#ifdef ESHUTDOWN
|
||||
inscode(d, ds, de, "ESHUTDOWN", ESHUTDOWN, "Cannot send after transport endpoint shutdown");
|
||||
#else
|
||||
#ifdef WSAESHUTDOWN
|
||||
inscode(d, ds, de, "ESHUTDOWN", WSAESHUTDOWN, "Cannot send after transport endpoint shutdown");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ECHRNG
|
||||
inscode(d, ds, de, "ECHRNG", ECHRNG, "Channel number out of range");
|
||||
#endif
|
||||
#ifdef ELIBBAD
|
||||
inscode(d, ds, de, "ELIBBAD", ELIBBAD, "Accessing a corrupted shared library");
|
||||
#endif
|
||||
#ifdef ENONET
|
||||
inscode(d, ds, de, "ENONET", ENONET, "Machine is not on the network");
|
||||
#endif
|
||||
#ifdef EBADE
|
||||
inscode(d, ds, de, "EBADE", EBADE, "Invalid exchange");
|
||||
#endif
|
||||
#ifdef EBADF
|
||||
inscode(d, ds, de, "EBADF", EBADF, "Bad file number");
|
||||
#else
|
||||
#ifdef WSAEBADF
|
||||
inscode(d, ds, de, "EBADF", WSAEBADF, "Bad file number");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef EMULTIHOP
|
||||
inscode(d, ds, de, "EMULTIHOP", EMULTIHOP, "Multihop attempted");
|
||||
#endif
|
||||
#ifdef EIO
|
||||
inscode(d, ds, de, "EIO", EIO, "I/O error");
|
||||
#endif
|
||||
#ifdef EUNATCH
|
||||
inscode(d, ds, de, "EUNATCH", EUNATCH, "Protocol driver not attached");
|
||||
#endif
|
||||
#ifdef EPROTOTYPE
|
||||
inscode(d, ds, de, "EPROTOTYPE", EPROTOTYPE, "Protocol wrong type for socket");
|
||||
#else
|
||||
#ifdef WSAEPROTOTYPE
|
||||
inscode(d, ds, de, "EPROTOTYPE", WSAEPROTOTYPE, "Protocol wrong type for socket");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ENOSPC
|
||||
inscode(d, ds, de, "ENOSPC", ENOSPC, "No space left on device");
|
||||
#endif
|
||||
#ifdef ENOEXEC
|
||||
inscode(d, ds, de, "ENOEXEC", ENOEXEC, "Exec format error");
|
||||
#endif
|
||||
#ifdef EALREADY
|
||||
inscode(d, ds, de, "EALREADY", EALREADY, "Operation already in progress");
|
||||
#else
|
||||
#ifdef WSAEALREADY
|
||||
inscode(d, ds, de, "EALREADY", WSAEALREADY, "Operation already in progress");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ENETDOWN
|
||||
inscode(d, ds, de, "ENETDOWN", ENETDOWN, "Network is down");
|
||||
#else
|
||||
#ifdef WSAENETDOWN
|
||||
inscode(d, ds, de, "ENETDOWN", WSAENETDOWN, "Network is down");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ENOTNAM
|
||||
inscode(d, ds, de, "ENOTNAM", ENOTNAM, "Not a XENIX named type file");
|
||||
#endif
|
||||
#ifdef EACCES
|
||||
inscode(d, ds, de, "EACCES", EACCES, "Permission denied");
|
||||
#else
|
||||
#ifdef WSAEACCES
|
||||
inscode(d, ds, de, "EACCES", WSAEACCES, "Permission denied");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ELNRNG
|
||||
inscode(d, ds, de, "ELNRNG", ELNRNG, "Link number out of range");
|
||||
#endif
|
||||
#ifdef EILSEQ
|
||||
inscode(d, ds, de, "EILSEQ", EILSEQ, "Illegal byte sequence");
|
||||
#endif
|
||||
#ifdef ENOTDIR
|
||||
inscode(d, ds, de, "ENOTDIR", ENOTDIR, "Not a directory");
|
||||
#endif
|
||||
#ifdef ENOTUNIQ
|
||||
inscode(d, ds, de, "ENOTUNIQ", ENOTUNIQ, "Name not unique on network");
|
||||
#endif
|
||||
#ifdef EPERM
|
||||
inscode(d, ds, de, "EPERM", EPERM, "Operation not permitted");
|
||||
#endif
|
||||
#ifdef EDOM
|
||||
inscode(d, ds, de, "EDOM", EDOM, "Math argument out of domain of func");
|
||||
#endif
|
||||
#ifdef EXFULL
|
||||
inscode(d, ds, de, "EXFULL", EXFULL, "Exchange full");
|
||||
#endif
|
||||
#ifdef ECONNREFUSED
|
||||
inscode(d, ds, de, "ECONNREFUSED", ECONNREFUSED, "Connection refused");
|
||||
#else
|
||||
#ifdef WSAECONNREFUSED
|
||||
inscode(d, ds, de, "ECONNREFUSED", WSAECONNREFUSED, "Connection refused");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef EISDIR
|
||||
inscode(d, ds, de, "EISDIR", EISDIR, "Is a directory");
|
||||
#endif
|
||||
#ifdef EPROTONOSUPPORT
|
||||
inscode(d, ds, de, "EPROTONOSUPPORT", EPROTONOSUPPORT, "Protocol not supported");
|
||||
#else
|
||||
#ifdef WSAEPROTONOSUPPORT
|
||||
inscode(d, ds, de, "EPROTONOSUPPORT", WSAEPROTONOSUPPORT, "Protocol not supported");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef EROFS
|
||||
inscode(d, ds, de, "EROFS", EROFS, "Read-only file system");
|
||||
#endif
|
||||
#ifdef EADDRNOTAVAIL
|
||||
inscode(d, ds, de, "EADDRNOTAVAIL", EADDRNOTAVAIL, "Cannot assign requested address");
|
||||
#else
|
||||
#ifdef WSAEADDRNOTAVAIL
|
||||
inscode(d, ds, de, "EADDRNOTAVAIL", WSAEADDRNOTAVAIL, "Cannot assign requested address");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef EIDRM
|
||||
inscode(d, ds, de, "EIDRM", EIDRM, "Identifier removed");
|
||||
#endif
|
||||
#ifdef ECOMM
|
||||
inscode(d, ds, de, "ECOMM", ECOMM, "Communication error on send");
|
||||
#endif
|
||||
#ifdef ESRMNT
|
||||
inscode(d, ds, de, "ESRMNT", ESRMNT, "Srmount error");
|
||||
#endif
|
||||
#ifdef EREMOTEIO
|
||||
inscode(d, ds, de, "EREMOTEIO", EREMOTEIO, "Remote I/O error");
|
||||
#endif
|
||||
#ifdef EL3RST
|
||||
inscode(d, ds, de, "EL3RST", EL3RST, "Level 3 reset");
|
||||
#endif
|
||||
#ifdef EBADMSG
|
||||
inscode(d, ds, de, "EBADMSG", EBADMSG, "Not a data message");
|
||||
#endif
|
||||
#ifdef ENFILE
|
||||
inscode(d, ds, de, "ENFILE", ENFILE, "File table overflow");
|
||||
#endif
|
||||
#ifdef ELIBMAX
|
||||
inscode(d, ds, de, "ELIBMAX", ELIBMAX, "Attempting to link in too many shared libraries");
|
||||
#endif
|
||||
#ifdef ESPIPE
|
||||
inscode(d, ds, de, "ESPIPE", ESPIPE, "Illegal seek");
|
||||
#endif
|
||||
#ifdef ENOLINK
|
||||
inscode(d, ds, de, "ENOLINK", ENOLINK, "Link has been severed");
|
||||
#endif
|
||||
#ifdef ENETRESET
|
||||
inscode(d, ds, de, "ENETRESET", ENETRESET, "Network dropped connection because of reset");
|
||||
#else
|
||||
#ifdef WSAENETRESET
|
||||
inscode(d, ds, de, "ENETRESET", WSAENETRESET, "Network dropped connection because of reset");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ETIMEDOUT
|
||||
inscode(d, ds, de, "ETIMEDOUT", ETIMEDOUT, "Connection timed out");
|
||||
#else
|
||||
#ifdef WSAETIMEDOUT
|
||||
inscode(d, ds, de, "ETIMEDOUT", WSAETIMEDOUT, "Connection timed out");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ENOENT
|
||||
inscode(d, ds, de, "ENOENT", ENOENT, "No such file or directory");
|
||||
#endif
|
||||
#ifdef EEXIST
|
||||
inscode(d, ds, de, "EEXIST", EEXIST, "File exists");
|
||||
#endif
|
||||
#ifdef EDQUOT
|
||||
inscode(d, ds, de, "EDQUOT", EDQUOT, "Quota exceeded");
|
||||
#else
|
||||
#ifdef WSAEDQUOT
|
||||
inscode(d, ds, de, "EDQUOT", WSAEDQUOT, "Quota exceeded");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ENOSTR
|
||||
inscode(d, ds, de, "ENOSTR", ENOSTR, "Device not a stream");
|
||||
#endif
|
||||
#ifdef EBADSLT
|
||||
inscode(d, ds, de, "EBADSLT", EBADSLT, "Invalid slot");
|
||||
#endif
|
||||
#ifdef EBADRQC
|
||||
inscode(d, ds, de, "EBADRQC", EBADRQC, "Invalid request code");
|
||||
#endif
|
||||
#ifdef ELIBACC
|
||||
inscode(d, ds, de, "ELIBACC", ELIBACC, "Can not access a needed shared library");
|
||||
#endif
|
||||
#ifdef EFAULT
|
||||
inscode(d, ds, de, "EFAULT", EFAULT, "Bad address");
|
||||
#else
|
||||
#ifdef WSAEFAULT
|
||||
inscode(d, ds, de, "EFAULT", WSAEFAULT, "Bad address");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef EFBIG
|
||||
inscode(d, ds, de, "EFBIG", EFBIG, "File too large");
|
||||
#endif
|
||||
#ifdef EDEADLK
|
||||
inscode(d, ds, de, "EDEADLK", EDEADLK, "Resource deadlock would occur");
|
||||
#endif
|
||||
#ifdef ENOTCONN
|
||||
inscode(d, ds, de, "ENOTCONN", ENOTCONN, "Transport endpoint is not connected");
|
||||
#else
|
||||
#ifdef WSAENOTCONN
|
||||
inscode(d, ds, de, "ENOTCONN", WSAENOTCONN, "Transport endpoint is not connected");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef EDESTADDRREQ
|
||||
inscode(d, ds, de, "EDESTADDRREQ", EDESTADDRREQ, "Destination address required");
|
||||
#else
|
||||
#ifdef WSAEDESTADDRREQ
|
||||
inscode(d, ds, de, "EDESTADDRREQ", WSAEDESTADDRREQ, "Destination address required");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ELIBSCN
|
||||
inscode(d, ds, de, "ELIBSCN", ELIBSCN, ".lib section in a.out corrupted");
|
||||
#endif
|
||||
#ifdef ENOLCK
|
||||
inscode(d, ds, de, "ENOLCK", ENOLCK, "No record locks available");
|
||||
#endif
|
||||
#ifdef EISNAM
|
||||
inscode(d, ds, de, "EISNAM", EISNAM, "Is a named type file");
|
||||
#endif
|
||||
#ifdef ECONNABORTED
|
||||
inscode(d, ds, de, "ECONNABORTED", ECONNABORTED, "Software caused connection abort");
|
||||
#else
|
||||
#ifdef WSAECONNABORTED
|
||||
inscode(d, ds, de, "ECONNABORTED", WSAECONNABORTED, "Software caused connection abort");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ENETUNREACH
|
||||
inscode(d, ds, de, "ENETUNREACH", ENETUNREACH, "Network is unreachable");
|
||||
#else
|
||||
#ifdef WSAENETUNREACH
|
||||
inscode(d, ds, de, "ENETUNREACH", WSAENETUNREACH, "Network is unreachable");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ESTALE
|
||||
inscode(d, ds, de, "ESTALE", ESTALE, "Stale NFS file handle");
|
||||
#else
|
||||
#ifdef WSAESTALE
|
||||
inscode(d, ds, de, "ESTALE", WSAESTALE, "Stale NFS file handle");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ENOSR
|
||||
inscode(d, ds, de, "ENOSR", ENOSR, "Out of streams resources");
|
||||
#endif
|
||||
#ifdef ENOMEM
|
||||
inscode(d, ds, de, "ENOMEM", ENOMEM, "Out of memory");
|
||||
#endif
|
||||
#ifdef ENOTSOCK
|
||||
inscode(d, ds, de, "ENOTSOCK", ENOTSOCK, "Socket operation on non-socket");
|
||||
#else
|
||||
#ifdef WSAENOTSOCK
|
||||
inscode(d, ds, de, "ENOTSOCK", WSAENOTSOCK, "Socket operation on non-socket");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ESTRPIPE
|
||||
inscode(d, ds, de, "ESTRPIPE", ESTRPIPE, "Streams pipe error");
|
||||
#endif
|
||||
#ifdef EMLINK
|
||||
inscode(d, ds, de, "EMLINK", EMLINK, "Too many links");
|
||||
#endif
|
||||
#ifdef ERANGE
|
||||
inscode(d, ds, de, "ERANGE", ERANGE, "Math result not representable");
|
||||
#endif
|
||||
#ifdef ELIBEXEC
|
||||
inscode(d, ds, de, "ELIBEXEC", ELIBEXEC, "Cannot exec a shared library directly");
|
||||
#endif
|
||||
#ifdef EL3HLT
|
||||
inscode(d, ds, de, "EL3HLT", EL3HLT, "Level 3 halted");
|
||||
#endif
|
||||
#ifdef ECONNRESET
|
||||
inscode(d, ds, de, "ECONNRESET", ECONNRESET, "Connection reset by peer");
|
||||
#else
|
||||
#ifdef WSAECONNRESET
|
||||
inscode(d, ds, de, "ECONNRESET", WSAECONNRESET, "Connection reset by peer");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef EADDRINUSE
|
||||
inscode(d, ds, de, "EADDRINUSE", EADDRINUSE, "Address already in use");
|
||||
#else
|
||||
#ifdef WSAEADDRINUSE
|
||||
inscode(d, ds, de, "EADDRINUSE", WSAEADDRINUSE, "Address already in use");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef EOPNOTSUPP
|
||||
inscode(d, ds, de, "EOPNOTSUPP", EOPNOTSUPP, "Operation not supported on transport endpoint");
|
||||
#else
|
||||
#ifdef WSAEOPNOTSUPP
|
||||
inscode(d, ds, de, "EOPNOTSUPP", WSAEOPNOTSUPP, "Operation not supported on transport endpoint");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef EREMCHG
|
||||
inscode(d, ds, de, "EREMCHG", EREMCHG, "Remote address changed");
|
||||
#endif
|
||||
#ifdef EAGAIN
|
||||
inscode(d, ds, de, "EAGAIN", EAGAIN, "Try again");
|
||||
#endif
|
||||
#ifdef ENAMETOOLONG
|
||||
inscode(d, ds, de, "ENAMETOOLONG", ENAMETOOLONG, "File name too long");
|
||||
#else
|
||||
#ifdef WSAENAMETOOLONG
|
||||
inscode(d, ds, de, "ENAMETOOLONG", WSAENAMETOOLONG, "File name too long");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ENOTTY
|
||||
inscode(d, ds, de, "ENOTTY", ENOTTY, "Not a typewriter");
|
||||
#endif
|
||||
#ifdef ERESTART
|
||||
inscode(d, ds, de, "ERESTART", ERESTART, "Interrupted system call should be restarted");
|
||||
#endif
|
||||
#ifdef ESOCKTNOSUPPORT
|
||||
inscode(d, ds, de, "ESOCKTNOSUPPORT", ESOCKTNOSUPPORT, "Socket type not supported");
|
||||
#else
|
||||
#ifdef WSAESOCKTNOSUPPORT
|
||||
inscode(d, ds, de, "ESOCKTNOSUPPORT", WSAESOCKTNOSUPPORT, "Socket type not supported");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ETIME
|
||||
inscode(d, ds, de, "ETIME", ETIME, "Timer expired");
|
||||
#endif
|
||||
#ifdef EBFONT
|
||||
inscode(d, ds, de, "EBFONT", EBFONT, "Bad font file format");
|
||||
#endif
|
||||
#ifdef EDEADLOCK
|
||||
inscode(d, ds, de, "EDEADLOCK", EDEADLOCK, "Error EDEADLOCK");
|
||||
#endif
|
||||
#ifdef ETOOMANYREFS
|
||||
inscode(d, ds, de, "ETOOMANYREFS", ETOOMANYREFS, "Too many references: cannot splice");
|
||||
#else
|
||||
#ifdef WSAETOOMANYREFS
|
||||
inscode(d, ds, de, "ETOOMANYREFS", WSAETOOMANYREFS, "Too many references: cannot splice");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef EMFILE
|
||||
inscode(d, ds, de, "EMFILE", EMFILE, "Too many open files");
|
||||
#else
|
||||
#ifdef WSAEMFILE
|
||||
inscode(d, ds, de, "EMFILE", WSAEMFILE, "Too many open files");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ETXTBSY
|
||||
inscode(d, ds, de, "ETXTBSY", ETXTBSY, "Text file busy");
|
||||
#endif
|
||||
#ifdef EINPROGRESS
|
||||
inscode(d, ds, de, "EINPROGRESS", EINPROGRESS, "Operation now in progress");
|
||||
#else
|
||||
#ifdef WSAEINPROGRESS
|
||||
inscode(d, ds, de, "EINPROGRESS", WSAEINPROGRESS, "Operation now in progress");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ENXIO
|
||||
inscode(d, ds, de, "ENXIO", ENXIO, "No such device or address");
|
||||
#endif
|
||||
#ifdef ENOPKG
|
||||
inscode(d, ds, de, "ENOPKG", ENOPKG, "Package not installed");
|
||||
#endif
|
||||
#ifdef WSASY
|
||||
inscode(d, ds, de, "WSASY", WSASY, "Error WSASY");
|
||||
#endif
|
||||
#ifdef WSAEHOSTDOWN
|
||||
inscode(d, ds, de, "WSAEHOSTDOWN", WSAEHOSTDOWN, "Host is down");
|
||||
#endif
|
||||
#ifdef WSAENETDOWN
|
||||
inscode(d, ds, de, "WSAENETDOWN", WSAENETDOWN, "Network is down");
|
||||
#endif
|
||||
#ifdef WSAENOTSOCK
|
||||
inscode(d, ds, de, "WSAENOTSOCK", WSAENOTSOCK, "Socket operation on non-socket");
|
||||
#endif
|
||||
#ifdef WSAEHOSTUNREACH
|
||||
inscode(d, ds, de, "WSAEHOSTUNREACH", WSAEHOSTUNREACH, "No route to host");
|
||||
#endif
|
||||
#ifdef WSAELOOP
|
||||
inscode(d, ds, de, "WSAELOOP", WSAELOOP, "Too many symbolic links encountered");
|
||||
#endif
|
||||
#ifdef WSAEMFILE
|
||||
inscode(d, ds, de, "WSAEMFILE", WSAEMFILE, "Too many open files");
|
||||
#endif
|
||||
#ifdef WSAESTALE
|
||||
inscode(d, ds, de, "WSAESTALE", WSAESTALE, "Stale NFS file handle");
|
||||
#endif
|
||||
#ifdef WSAVERNOTSUPPORTED
|
||||
inscode(d, ds, de, "WSAVERNOTSUPPORTED", WSAVERNOTSUPPORTED, "Error WSAVERNOTSUPPORTED");
|
||||
#endif
|
||||
#ifdef WSAENETUNREACH
|
||||
inscode(d, ds, de, "WSAENETUNREACH", WSAENETUNREACH, "Network is unreachable");
|
||||
#endif
|
||||
#ifdef WSAEPROCLIM
|
||||
inscode(d, ds, de, "WSAEPROCLIM", WSAEPROCLIM, "Error WSAEPROCLIM");
|
||||
#endif
|
||||
#ifdef WSAEFAULT
|
||||
inscode(d, ds, de, "WSAEFAULT", WSAEFAULT, "Bad address");
|
||||
#endif
|
||||
#ifdef WSANOTINITIALISED
|
||||
inscode(d, ds, de, "WSANOTINITIALISED", WSANOTINITIALISED, "Error WSANOTINITIALISED");
|
||||
#endif
|
||||
#ifdef WSAEUSERS
|
||||
inscode(d, ds, de, "WSAEUSERS", WSAEUSERS, "Too many users");
|
||||
#endif
|
||||
#ifdef WSAMAKEASYNCREPL
|
||||
inscode(d, ds, de, "WSAMAKEASYNCREPL", WSAMAKEASYNCREPL, "Error WSAMAKEASYNCREPL");
|
||||
#endif
|
||||
#ifdef WSAENOPROTOOPT
|
||||
inscode(d, ds, de, "WSAENOPROTOOPT", WSAENOPROTOOPT, "Protocol not available");
|
||||
#endif
|
||||
#ifdef WSAECONNABORTED
|
||||
inscode(d, ds, de, "WSAECONNABORTED", WSAECONNABORTED, "Software caused connection abort");
|
||||
#endif
|
||||
#ifdef WSAENAMETOOLONG
|
||||
inscode(d, ds, de, "WSAENAMETOOLONG", WSAENAMETOOLONG, "File name too long");
|
||||
#endif
|
||||
#ifdef WSAENOTEMPTY
|
||||
inscode(d, ds, de, "WSAENOTEMPTY", WSAENOTEMPTY, "Directory not empty");
|
||||
#endif
|
||||
#ifdef WSAESHUTDOWN
|
||||
inscode(d, ds, de, "WSAESHUTDOWN", WSAESHUTDOWN, "Cannot send after transport endpoint shutdown");
|
||||
#endif
|
||||
#ifdef WSAEAFNOSUPPORT
|
||||
inscode(d, ds, de, "WSAEAFNOSUPPORT", WSAEAFNOSUPPORT, "Address family not supported by protocol");
|
||||
#endif
|
||||
#ifdef WSAETOOMANYREFS
|
||||
inscode(d, ds, de, "WSAETOOMANYREFS", WSAETOOMANYREFS, "Too many references: cannot splice");
|
||||
#endif
|
||||
#ifdef WSAEACCES
|
||||
inscode(d, ds, de, "WSAEACCES", WSAEACCES, "Permission denied");
|
||||
#endif
|
||||
#ifdef WSATR
|
||||
inscode(d, ds, de, "WSATR", WSATR, "Error WSATR");
|
||||
#endif
|
||||
#ifdef WSABASEERR
|
||||
inscode(d, ds, de, "WSABASEERR", WSABASEERR, "Error WSABASEERR");
|
||||
#endif
|
||||
#ifdef WSADESCRIPTIO
|
||||
inscode(d, ds, de, "WSADESCRIPTIO", WSADESCRIPTIO, "Error WSADESCRIPTIO");
|
||||
#endif
|
||||
#ifdef WSAEMSGSIZE
|
||||
inscode(d, ds, de, "WSAEMSGSIZE", WSAEMSGSIZE, "Message too long");
|
||||
#endif
|
||||
#ifdef WSAEBADF
|
||||
inscode(d, ds, de, "WSAEBADF", WSAEBADF, "Bad file number");
|
||||
#endif
|
||||
#ifdef WSAECONNRESET
|
||||
inscode(d, ds, de, "WSAECONNRESET", WSAECONNRESET, "Connection reset by peer");
|
||||
#endif
|
||||
#ifdef WSAGETSELECTERRO
|
||||
inscode(d, ds, de, "WSAGETSELECTERRO", WSAGETSELECTERRO, "Error WSAGETSELECTERRO");
|
||||
#endif
|
||||
#ifdef WSAETIMEDOUT
|
||||
inscode(d, ds, de, "WSAETIMEDOUT", WSAETIMEDOUT, "Connection timed out");
|
||||
#endif
|
||||
#ifdef WSAENOBUFS
|
||||
inscode(d, ds, de, "WSAENOBUFS", WSAENOBUFS, "No buffer space available");
|
||||
#endif
|
||||
#ifdef WSAEDISCON
|
||||
inscode(d, ds, de, "WSAEDISCON", WSAEDISCON, "Error WSAEDISCON");
|
||||
#endif
|
||||
#ifdef WSAEINTR
|
||||
inscode(d, ds, de, "WSAEINTR", WSAEINTR, "Interrupted system call");
|
||||
#endif
|
||||
#ifdef WSAEPROTOTYPE
|
||||
inscode(d, ds, de, "WSAEPROTOTYPE", WSAEPROTOTYPE, "Protocol wrong type for socket");
|
||||
#endif
|
||||
#ifdef WSAHOS
|
||||
inscode(d, ds, de, "WSAHOS", WSAHOS, "Error WSAHOS");
|
||||
#endif
|
||||
#ifdef WSAEADDRINUSE
|
||||
inscode(d, ds, de, "WSAEADDRINUSE", WSAEADDRINUSE, "Address already in use");
|
||||
#endif
|
||||
#ifdef WSAEADDRNOTAVAIL
|
||||
inscode(d, ds, de, "WSAEADDRNOTAVAIL", WSAEADDRNOTAVAIL, "Cannot assign requested address");
|
||||
#endif
|
||||
#ifdef WSAEALREADY
|
||||
inscode(d, ds, de, "WSAEALREADY", WSAEALREADY, "Operation already in progress");
|
||||
#endif
|
||||
#ifdef WSAEPROTONOSUPPORT
|
||||
inscode(d, ds, de, "WSAEPROTONOSUPPORT", WSAEPROTONOSUPPORT, "Protocol not supported");
|
||||
#endif
|
||||
#ifdef WSASYSNOTREADY
|
||||
inscode(d, ds, de, "WSASYSNOTREADY", WSASYSNOTREADY, "Error WSASYSNOTREADY");
|
||||
#endif
|
||||
#ifdef WSAEWOULDBLOCK
|
||||
inscode(d, ds, de, "WSAEWOULDBLOCK", WSAEWOULDBLOCK, "Operation would block");
|
||||
#endif
|
||||
#ifdef WSAEPFNOSUPPORT
|
||||
inscode(d, ds, de, "WSAEPFNOSUPPORT", WSAEPFNOSUPPORT, "Protocol family not supported");
|
||||
#endif
|
||||
#ifdef WSAEOPNOTSUPP
|
||||
inscode(d, ds, de, "WSAEOPNOTSUPP", WSAEOPNOTSUPP, "Operation not supported on transport endpoint");
|
||||
#endif
|
||||
#ifdef WSAEISCONN
|
||||
inscode(d, ds, de, "WSAEISCONN", WSAEISCONN, "Transport endpoint is already connected");
|
||||
#endif
|
||||
#ifdef WSAEDQUOT
|
||||
inscode(d, ds, de, "WSAEDQUOT", WSAEDQUOT, "Quota exceeded");
|
||||
#endif
|
||||
#ifdef WSAENOTCONN
|
||||
inscode(d, ds, de, "WSAENOTCONN", WSAENOTCONN, "Transport endpoint is not connected");
|
||||
#endif
|
||||
#ifdef WSAEREMOTE
|
||||
inscode(d, ds, de, "WSAEREMOTE", WSAEREMOTE, "Object is remote");
|
||||
#endif
|
||||
#ifdef WSAEINVAL
|
||||
inscode(d, ds, de, "WSAEINVAL", WSAEINVAL, "Invalid argument");
|
||||
#endif
|
||||
#ifdef WSAEINPROGRESS
|
||||
inscode(d, ds, de, "WSAEINPROGRESS", WSAEINPROGRESS, "Operation now in progress");
|
||||
#endif
|
||||
#ifdef WSAGETSELECTEVEN
|
||||
inscode(d, ds, de, "WSAGETSELECTEVEN", WSAGETSELECTEVEN, "Error WSAGETSELECTEVEN");
|
||||
#endif
|
||||
#ifdef WSAESOCKTNOSUPPORT
|
||||
inscode(d, ds, de, "WSAESOCKTNOSUPPORT", WSAESOCKTNOSUPPORT, "Socket type not supported");
|
||||
#endif
|
||||
#ifdef WSAGETASYNCERRO
|
||||
inscode(d, ds, de, "WSAGETASYNCERRO", WSAGETASYNCERRO, "Error WSAGETASYNCERRO");
|
||||
#endif
|
||||
#ifdef WSAMAKESELECTREPL
|
||||
inscode(d, ds, de, "WSAMAKESELECTREPL", WSAMAKESELECTREPL, "Error WSAMAKESELECTREPL");
|
||||
#endif
|
||||
#ifdef WSAGETASYNCBUFLE
|
||||
inscode(d, ds, de, "WSAGETASYNCBUFLE", WSAGETASYNCBUFLE, "Error WSAGETASYNCBUFLE");
|
||||
#endif
|
||||
#ifdef WSAEDESTADDRREQ
|
||||
inscode(d, ds, de, "WSAEDESTADDRREQ", WSAEDESTADDRREQ, "Destination address required");
|
||||
#endif
|
||||
#ifdef WSAECONNREFUSED
|
||||
inscode(d, ds, de, "WSAECONNREFUSED", WSAECONNREFUSED, "Connection refused");
|
||||
#endif
|
||||
#ifdef WSAENETRESET
|
||||
inscode(d, ds, de, "WSAENETRESET", WSAENETRESET, "Network dropped connection because of reset");
|
||||
#endif
|
||||
#ifdef WSAN
|
||||
inscode(d, ds, de, "WSAN", WSAN, "Error WSAN");
|
||||
#endif
|
||||
#ifdef ENOTSUP
|
||||
inscode(d, ds, de, "ENOTSUP", ENOTSUP, "Operation not supported");
|
||||
#endif
|
||||
|
||||
Py_DECREF(de);
|
||||
}
|
||||
@@ -0,0 +1,622 @@
|
||||
|
||||
/* fcntl module */
|
||||
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
#ifdef HAVE_SYS_FILE_H
|
||||
#include <sys/file.h>
|
||||
#endif
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_STROPTS_H
|
||||
#include <stropts.h>
|
||||
#endif
|
||||
|
||||
static int
|
||||
conv_descriptor(PyObject *object, int *target)
|
||||
{
|
||||
int fd = PyObject_AsFileDescriptor(object);
|
||||
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
*target = fd;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* fcntl(fd, op, [arg]) */
|
||||
|
||||
static PyObject *
|
||||
fcntl_fcntl(PyObject *self, PyObject *args)
|
||||
{
|
||||
int fd;
|
||||
int code;
|
||||
int arg;
|
||||
int ret;
|
||||
char *str;
|
||||
Py_ssize_t len;
|
||||
char buf[1024];
|
||||
|
||||
if (PyArg_ParseTuple(args, "O&is#:fcntl",
|
||||
conv_descriptor, &fd, &code, &str, &len)) {
|
||||
if (len > sizeof buf) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"fcntl string arg too long");
|
||||
return NULL;
|
||||
}
|
||||
memcpy(buf, str, len);
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
ret = fcntl(fd, code, buf);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (ret < 0) {
|
||||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
return NULL;
|
||||
}
|
||||
return PyString_FromStringAndSize(buf, len);
|
||||
}
|
||||
|
||||
PyErr_Clear();
|
||||
arg = 0;
|
||||
if (!PyArg_ParseTuple(args,
|
||||
"O&i|I;fcntl requires a file or file descriptor,"
|
||||
" an integer and optionally a third integer or a string",
|
||||
conv_descriptor, &fd, &code, &arg)) {
|
||||
return NULL;
|
||||
}
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
ret = fcntl(fd, code, arg);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (ret < 0) {
|
||||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
return NULL;
|
||||
}
|
||||
return PyInt_FromLong((long)ret);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(fcntl_doc,
|
||||
"fcntl(fd, op, [arg])\n\
|
||||
\n\
|
||||
Perform the operation op on file descriptor fd. The values used\n\
|
||||
for op are operating system dependent, and are available\n\
|
||||
as constants in the fcntl module, using the same names as used in\n\
|
||||
the relevant C header files. The argument arg is optional, and\n\
|
||||
defaults to 0; it may be an int or a string. If arg is given as a string,\n\
|
||||
the return value of fcntl is a string of that length, containing the\n\
|
||||
resulting value put in the arg buffer by the operating system. The length\n\
|
||||
of the arg string is not allowed to exceed 1024 bytes. If the arg given\n\
|
||||
is an integer or if none is specified, the result value is an integer\n\
|
||||
corresponding to the return value of the fcntl call in the C code.");
|
||||
|
||||
|
||||
/* ioctl(fd, op, [arg]) */
|
||||
|
||||
static PyObject *
|
||||
fcntl_ioctl(PyObject *self, PyObject *args)
|
||||
{
|
||||
#define IOCTL_BUFSZ 1024
|
||||
int fd;
|
||||
/* In PyArg_ParseTuple below, we use the unsigned non-checked 'I'
|
||||
format for the 'code' parameter because Python turns 0x8000000
|
||||
into either a large positive number (PyLong or PyInt on 64-bit
|
||||
platforms) or a negative number on others (32-bit PyInt)
|
||||
whereas the system expects it to be a 32bit bit field value
|
||||
regardless of it being passed as an int or unsigned long on
|
||||
various platforms. See the termios.TIOCSWINSZ constant across
|
||||
platforms for an example of this.
|
||||
|
||||
If any of the 64bit platforms ever decide to use more than 32bits
|
||||
in their unsigned long ioctl codes this will break and need
|
||||
special casing based on the platform being built on.
|
||||
*/
|
||||
unsigned int code;
|
||||
int arg;
|
||||
int ret;
|
||||
char *str;
|
||||
Py_ssize_t len;
|
||||
int mutate_arg = 1;
|
||||
char buf[IOCTL_BUFSZ+1]; /* argument plus NUL byte */
|
||||
|
||||
if (PyArg_ParseTuple(args, "O&Iw#|i:ioctl",
|
||||
conv_descriptor, &fd, &code,
|
||||
&str, &len, &mutate_arg)) {
|
||||
char *arg;
|
||||
|
||||
if (mutate_arg) {
|
||||
if (len <= IOCTL_BUFSZ) {
|
||||
memcpy(buf, str, len);
|
||||
buf[len] = '\0';
|
||||
arg = buf;
|
||||
}
|
||||
else {
|
||||
arg = str;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (len > IOCTL_BUFSZ) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"ioctl string arg too long");
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
memcpy(buf, str, len);
|
||||
buf[len] = '\0';
|
||||
arg = buf;
|
||||
}
|
||||
}
|
||||
if (buf == arg) {
|
||||
Py_BEGIN_ALLOW_THREADS /* think array.resize() */
|
||||
ret = ioctl(fd, code, arg);
|
||||
Py_END_ALLOW_THREADS
|
||||
}
|
||||
else {
|
||||
ret = ioctl(fd, code, arg);
|
||||
}
|
||||
if (mutate_arg && (len <= IOCTL_BUFSZ)) {
|
||||
memcpy(str, buf, len);
|
||||
}
|
||||
if (ret < 0) {
|
||||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
return NULL;
|
||||
}
|
||||
if (mutate_arg) {
|
||||
return PyInt_FromLong(ret);
|
||||
}
|
||||
else {
|
||||
return PyString_FromStringAndSize(buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
PyErr_Clear();
|
||||
if (PyArg_ParseTuple(args, "O&Is#:ioctl",
|
||||
conv_descriptor, &fd, &code, &str, &len)) {
|
||||
if (len > IOCTL_BUFSZ) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"ioctl string arg too long");
|
||||
return NULL;
|
||||
}
|
||||
memcpy(buf, str, len);
|
||||
buf[len] = '\0';
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
ret = ioctl(fd, code, buf);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (ret < 0) {
|
||||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
return NULL;
|
||||
}
|
||||
return PyString_FromStringAndSize(buf, len);
|
||||
}
|
||||
|
||||
PyErr_Clear();
|
||||
arg = 0;
|
||||
if (!PyArg_ParseTuple(args,
|
||||
"O&I|i;ioctl requires a file or file descriptor,"
|
||||
" an integer and optionally an integer or buffer argument",
|
||||
conv_descriptor, &fd, &code, &arg)) {
|
||||
return NULL;
|
||||
}
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
#ifdef __VMS
|
||||
ret = ioctl(fd, code, (void *)arg);
|
||||
#else
|
||||
ret = ioctl(fd, code, arg);
|
||||
#endif
|
||||
Py_END_ALLOW_THREADS
|
||||
if (ret < 0) {
|
||||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
return NULL;
|
||||
}
|
||||
return PyInt_FromLong((long)ret);
|
||||
#undef IOCTL_BUFSZ
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(ioctl_doc,
|
||||
"ioctl(fd, op[, arg[, mutate_flag]])\n\
|
||||
\n\
|
||||
Perform the operation op on file descriptor fd. The values used for op\n\
|
||||
are operating system dependent, and are available as constants in the\n\
|
||||
fcntl or termios library modules, using the same names as used in the\n\
|
||||
relevant C header files.\n\
|
||||
\n\
|
||||
The argument arg is optional, and defaults to 0; it may be an int or a\n\
|
||||
buffer containing character data (most likely a string or an array). \n\
|
||||
\n\
|
||||
If the argument is a mutable buffer (such as an array) and if the\n\
|
||||
mutate_flag argument (which is only allowed in this case) is true then the\n\
|
||||
buffer is (in effect) passed to the operating system and changes made by\n\
|
||||
the OS will be reflected in the contents of the buffer after the call has\n\
|
||||
returned. The return value is the integer returned by the ioctl system\n\
|
||||
call.\n\
|
||||
\n\
|
||||
If the argument is a mutable buffer and the mutable_flag argument is not\n\
|
||||
passed or is false, the behavior is as if a string had been passed. This\n\
|
||||
behavior will change in future releases of Python.\n\
|
||||
\n\
|
||||
If the argument is an immutable buffer (most likely a string) then a copy\n\
|
||||
of the buffer is passed to the operating system and the return value is a\n\
|
||||
string of the same length containing whatever the operating system put in\n\
|
||||
the buffer. The length of the arg buffer in this case is not allowed to\n\
|
||||
exceed 1024 bytes.\n\
|
||||
\n\
|
||||
If the arg given is an integer or if none is specified, the result value is\n\
|
||||
an integer corresponding to the return value of the ioctl call in the C\n\
|
||||
code.");
|
||||
|
||||
|
||||
/* flock(fd, operation) */
|
||||
|
||||
static PyObject *
|
||||
fcntl_flock(PyObject *self, PyObject *args)
|
||||
{
|
||||
int fd;
|
||||
int code;
|
||||
int ret;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O&i:flock",
|
||||
conv_descriptor, &fd, &code))
|
||||
return NULL;
|
||||
|
||||
#ifdef HAVE_FLOCK
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
ret = flock(fd, code);
|
||||
Py_END_ALLOW_THREADS
|
||||
#else
|
||||
|
||||
#ifndef LOCK_SH
|
||||
#define LOCK_SH 1 /* shared lock */
|
||||
#define LOCK_EX 2 /* exclusive lock */
|
||||
#define LOCK_NB 4 /* don't block when locking */
|
||||
#define LOCK_UN 8 /* unlock */
|
||||
#endif
|
||||
{
|
||||
struct flock l;
|
||||
if (code == LOCK_UN)
|
||||
l.l_type = F_UNLCK;
|
||||
else if (code & LOCK_SH)
|
||||
l.l_type = F_RDLCK;
|
||||
else if (code & LOCK_EX)
|
||||
l.l_type = F_WRLCK;
|
||||
else {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"unrecognized flock argument");
|
||||
return NULL;
|
||||
}
|
||||
l.l_whence = l.l_start = l.l_len = 0;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
ret = fcntl(fd, (code & LOCK_NB) ? F_SETLK : F_SETLKW, &l);
|
||||
Py_END_ALLOW_THREADS
|
||||
}
|
||||
#endif /* HAVE_FLOCK */
|
||||
if (ret < 0) {
|
||||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(flock_doc,
|
||||
"flock(fd, operation)\n\
|
||||
\n\
|
||||
Perform the lock operation op on file descriptor fd. See the Unix \n\
|
||||
manual page for flock(2) for details. (On some systems, this function is\n\
|
||||
emulated using fcntl().)");
|
||||
|
||||
|
||||
/* lockf(fd, operation) */
|
||||
static PyObject *
|
||||
fcntl_lockf(PyObject *self, PyObject *args)
|
||||
{
|
||||
int fd, code, ret, whence = 0;
|
||||
PyObject *lenobj = NULL, *startobj = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O&i|OOi:lockf",
|
||||
conv_descriptor, &fd, &code,
|
||||
&lenobj, &startobj, &whence))
|
||||
return NULL;
|
||||
|
||||
#if defined(PYOS_OS2) && defined(PYCC_GCC)
|
||||
PyErr_SetString(PyExc_NotImplementedError,
|
||||
"lockf not supported on OS/2 (EMX)");
|
||||
return NULL;
|
||||
#else
|
||||
#ifndef LOCK_SH
|
||||
#define LOCK_SH 1 /* shared lock */
|
||||
#define LOCK_EX 2 /* exclusive lock */
|
||||
#define LOCK_NB 4 /* don't block when locking */
|
||||
#define LOCK_UN 8 /* unlock */
|
||||
#endif /* LOCK_SH */
|
||||
{
|
||||
struct flock l;
|
||||
if (code == LOCK_UN)
|
||||
l.l_type = F_UNLCK;
|
||||
else if (code & LOCK_SH)
|
||||
l.l_type = F_RDLCK;
|
||||
else if (code & LOCK_EX)
|
||||
l.l_type = F_WRLCK;
|
||||
else {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"unrecognized lockf argument");
|
||||
return NULL;
|
||||
}
|
||||
l.l_start = l.l_len = 0;
|
||||
if (startobj != NULL) {
|
||||
#if !defined(HAVE_LARGEFILE_SUPPORT)
|
||||
l.l_start = PyInt_AsLong(startobj);
|
||||
#else
|
||||
l.l_start = PyLong_Check(startobj) ?
|
||||
PyLong_AsLongLong(startobj) :
|
||||
PyInt_AsLong(startobj);
|
||||
#endif
|
||||
if (PyErr_Occurred())
|
||||
return NULL;
|
||||
}
|
||||
if (lenobj != NULL) {
|
||||
#if !defined(HAVE_LARGEFILE_SUPPORT)
|
||||
l.l_len = PyInt_AsLong(lenobj);
|
||||
#else
|
||||
l.l_len = PyLong_Check(lenobj) ?
|
||||
PyLong_AsLongLong(lenobj) :
|
||||
PyInt_AsLong(lenobj);
|
||||
#endif
|
||||
if (PyErr_Occurred())
|
||||
return NULL;
|
||||
}
|
||||
l.l_whence = whence;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
ret = fcntl(fd, (code & LOCK_NB) ? F_SETLK : F_SETLKW, &l);
|
||||
Py_END_ALLOW_THREADS
|
||||
}
|
||||
if (ret < 0) {
|
||||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
#endif /* defined(PYOS_OS2) && defined(PYCC_GCC) */
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(lockf_doc,
|
||||
"lockf (fd, operation, length=0, start=0, whence=0)\n\
|
||||
\n\
|
||||
This is essentially a wrapper around the fcntl() locking calls. fd is the\n\
|
||||
file descriptor of the file to lock or unlock, and operation is one of the\n\
|
||||
following values:\n\
|
||||
\n\
|
||||
LOCK_UN - unlock\n\
|
||||
LOCK_SH - acquire a shared lock\n\
|
||||
LOCK_EX - acquire an exclusive lock\n\
|
||||
\n\
|
||||
When operation is LOCK_SH or LOCK_EX, it can also be bitwise ORed with\n\
|
||||
LOCK_NB to avoid blocking on lock acquisition. If LOCK_NB is used and the\n\
|
||||
lock cannot be acquired, an IOError will be raised and the exception will\n\
|
||||
have an errno attribute set to EACCES or EAGAIN (depending on the operating\n\
|
||||
system -- for portability, check for either value).\n\
|
||||
\n\
|
||||
length is the number of bytes to lock, with the default meaning to lock to\n\
|
||||
EOF. start is the byte offset, relative to whence, to that the lock\n\
|
||||
starts. whence is as with fileobj.seek(), specifically:\n\
|
||||
\n\
|
||||
0 - relative to the start of the file (SEEK_SET)\n\
|
||||
1 - relative to the current buffer position (SEEK_CUR)\n\
|
||||
2 - relative to the end of the file (SEEK_END)");
|
||||
|
||||
/* List of functions */
|
||||
|
||||
static PyMethodDef fcntl_methods[] = {
|
||||
{"fcntl", fcntl_fcntl, METH_VARARGS, fcntl_doc},
|
||||
{"ioctl", fcntl_ioctl, METH_VARARGS, ioctl_doc},
|
||||
{"flock", fcntl_flock, METH_VARARGS, flock_doc},
|
||||
{"lockf", fcntl_lockf, METH_VARARGS, lockf_doc},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
|
||||
PyDoc_STRVAR(module_doc,
|
||||
"This module performs file control and I/O control on file \n\
|
||||
descriptors. It is an interface to the fcntl() and ioctl() Unix\n\
|
||||
routines. File descriptors can be obtained with the fileno() method of\n\
|
||||
a file or socket object.");
|
||||
|
||||
/* Module initialisation */
|
||||
|
||||
static int
|
||||
ins(PyObject* d, char* symbol, long value)
|
||||
{
|
||||
PyObject* v = PyInt_FromLong(value);
|
||||
if (!v || PyDict_SetItemString(d, symbol, v) < 0)
|
||||
return -1;
|
||||
|
||||
Py_DECREF(v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define INS(x) if (ins(d, #x, (long)x)) return -1
|
||||
|
||||
static int
|
||||
all_ins(PyObject* d)
|
||||
{
|
||||
if (ins(d, "LOCK_SH", (long)LOCK_SH)) return -1;
|
||||
if (ins(d, "LOCK_EX", (long)LOCK_EX)) return -1;
|
||||
if (ins(d, "LOCK_NB", (long)LOCK_NB)) return -1;
|
||||
if (ins(d, "LOCK_UN", (long)LOCK_UN)) return -1;
|
||||
/* GNU extensions, as of glibc 2.2.4 */
|
||||
#ifdef LOCK_MAND
|
||||
if (ins(d, "LOCK_MAND", (long)LOCK_MAND)) return -1;
|
||||
#endif
|
||||
#ifdef LOCK_READ
|
||||
if (ins(d, "LOCK_READ", (long)LOCK_READ)) return -1;
|
||||
#endif
|
||||
#ifdef LOCK_WRITE
|
||||
if (ins(d, "LOCK_WRITE", (long)LOCK_WRITE)) return -1;
|
||||
#endif
|
||||
#ifdef LOCK_RW
|
||||
if (ins(d, "LOCK_RW", (long)LOCK_RW)) return -1;
|
||||
#endif
|
||||
|
||||
#ifdef F_DUPFD
|
||||
if (ins(d, "F_DUPFD", (long)F_DUPFD)) return -1;
|
||||
#endif
|
||||
#ifdef F_GETFD
|
||||
if (ins(d, "F_GETFD", (long)F_GETFD)) return -1;
|
||||
#endif
|
||||
#ifdef F_SETFD
|
||||
if (ins(d, "F_SETFD", (long)F_SETFD)) return -1;
|
||||
#endif
|
||||
#ifdef F_GETFL
|
||||
if (ins(d, "F_GETFL", (long)F_GETFL)) return -1;
|
||||
#endif
|
||||
#ifdef F_SETFL
|
||||
if (ins(d, "F_SETFL", (long)F_SETFL)) return -1;
|
||||
#endif
|
||||
#ifdef F_GETLK
|
||||
if (ins(d, "F_GETLK", (long)F_GETLK)) return -1;
|
||||
#endif
|
||||
#ifdef F_SETLK
|
||||
if (ins(d, "F_SETLK", (long)F_SETLK)) return -1;
|
||||
#endif
|
||||
#ifdef F_SETLKW
|
||||
if (ins(d, "F_SETLKW", (long)F_SETLKW)) return -1;
|
||||
#endif
|
||||
#ifdef F_GETOWN
|
||||
if (ins(d, "F_GETOWN", (long)F_GETOWN)) return -1;
|
||||
#endif
|
||||
#ifdef F_SETOWN
|
||||
if (ins(d, "F_SETOWN", (long)F_SETOWN)) return -1;
|
||||
#endif
|
||||
#ifdef F_GETSIG
|
||||
if (ins(d, "F_GETSIG", (long)F_GETSIG)) return -1;
|
||||
#endif
|
||||
#ifdef F_SETSIG
|
||||
if (ins(d, "F_SETSIG", (long)F_SETSIG)) return -1;
|
||||
#endif
|
||||
#ifdef F_RDLCK
|
||||
if (ins(d, "F_RDLCK", (long)F_RDLCK)) return -1;
|
||||
#endif
|
||||
#ifdef F_WRLCK
|
||||
if (ins(d, "F_WRLCK", (long)F_WRLCK)) return -1;
|
||||
#endif
|
||||
#ifdef F_UNLCK
|
||||
if (ins(d, "F_UNLCK", (long)F_UNLCK)) return -1;
|
||||
#endif
|
||||
/* LFS constants */
|
||||
#ifdef F_GETLK64
|
||||
if (ins(d, "F_GETLK64", (long)F_GETLK64)) return -1;
|
||||
#endif
|
||||
#ifdef F_SETLK64
|
||||
if (ins(d, "F_SETLK64", (long)F_SETLK64)) return -1;
|
||||
#endif
|
||||
#ifdef F_SETLKW64
|
||||
if (ins(d, "F_SETLKW64", (long)F_SETLKW64)) return -1;
|
||||
#endif
|
||||
/* GNU extensions, as of glibc 2.2.4. */
|
||||
#ifdef FASYNC
|
||||
if (ins(d, "FASYNC", (long)FASYNC)) return -1;
|
||||
#endif
|
||||
#ifdef F_SETLEASE
|
||||
if (ins(d, "F_SETLEASE", (long)F_SETLEASE)) return -1;
|
||||
#endif
|
||||
#ifdef F_GETLEASE
|
||||
if (ins(d, "F_GETLEASE", (long)F_GETLEASE)) return -1;
|
||||
#endif
|
||||
#ifdef F_NOTIFY
|
||||
if (ins(d, "F_NOTIFY", (long)F_NOTIFY)) return -1;
|
||||
#endif
|
||||
/* Old BSD flock(). */
|
||||
#ifdef F_EXLCK
|
||||
if (ins(d, "F_EXLCK", (long)F_EXLCK)) return -1;
|
||||
#endif
|
||||
#ifdef F_SHLCK
|
||||
if (ins(d, "F_SHLCK", (long)F_SHLCK)) return -1;
|
||||
#endif
|
||||
|
||||
/* OS X (and maybe others) let you tell the storage device to flush to physical media */
|
||||
#ifdef F_FULLFSYNC
|
||||
if (ins(d, "F_FULLFSYNC", (long)F_FULLFSYNC)) return -1;
|
||||
#endif
|
||||
|
||||
/* For F_{GET|SET}FL */
|
||||
#ifdef FD_CLOEXEC
|
||||
if (ins(d, "FD_CLOEXEC", (long)FD_CLOEXEC)) return -1;
|
||||
#endif
|
||||
|
||||
/* For F_NOTIFY */
|
||||
#ifdef DN_ACCESS
|
||||
if (ins(d, "DN_ACCESS", (long)DN_ACCESS)) return -1;
|
||||
#endif
|
||||
#ifdef DN_MODIFY
|
||||
if (ins(d, "DN_MODIFY", (long)DN_MODIFY)) return -1;
|
||||
#endif
|
||||
#ifdef DN_CREATE
|
||||
if (ins(d, "DN_CREATE", (long)DN_CREATE)) return -1;
|
||||
#endif
|
||||
#ifdef DN_DELETE
|
||||
if (ins(d, "DN_DELETE", (long)DN_DELETE)) return -1;
|
||||
#endif
|
||||
#ifdef DN_RENAME
|
||||
if (ins(d, "DN_RENAME", (long)DN_RENAME)) return -1;
|
||||
#endif
|
||||
#ifdef DN_ATTRIB
|
||||
if (ins(d, "DN_ATTRIB", (long)DN_ATTRIB)) return -1;
|
||||
#endif
|
||||
#ifdef DN_MULTISHOT
|
||||
if (ins(d, "DN_MULTISHOT", (long)DN_MULTISHOT)) return -1;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STROPTS_H
|
||||
/* Unix 98 guarantees that these are in stropts.h. */
|
||||
INS(I_PUSH);
|
||||
INS(I_POP);
|
||||
INS(I_LOOK);
|
||||
INS(I_FLUSH);
|
||||
INS(I_FLUSHBAND);
|
||||
INS(I_SETSIG);
|
||||
INS(I_GETSIG);
|
||||
INS(I_FIND);
|
||||
INS(I_PEEK);
|
||||
INS(I_SRDOPT);
|
||||
INS(I_GRDOPT);
|
||||
INS(I_NREAD);
|
||||
INS(I_FDINSERT);
|
||||
INS(I_STR);
|
||||
INS(I_SWROPT);
|
||||
#ifdef I_GWROPT
|
||||
/* despite the comment above, old-ish glibcs miss a couple... */
|
||||
INS(I_GWROPT);
|
||||
#endif
|
||||
INS(I_SENDFD);
|
||||
INS(I_RECVFD);
|
||||
INS(I_LIST);
|
||||
INS(I_ATMARK);
|
||||
INS(I_CKBAND);
|
||||
INS(I_GETBAND);
|
||||
INS(I_CANPUT);
|
||||
INS(I_SETCLTIME);
|
||||
#ifdef I_GETCLTIME
|
||||
INS(I_GETCLTIME);
|
||||
#endif
|
||||
INS(I_LINK);
|
||||
INS(I_UNLINK);
|
||||
INS(I_PLINK);
|
||||
INS(I_PUNLINK);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyMODINIT_FUNC
|
||||
initfcntl(void)
|
||||
{
|
||||
PyObject *m, *d;
|
||||
|
||||
/* Create the module and add the functions and documentation */
|
||||
m = Py_InitModule3("fcntl", fcntl_methods, module_doc);
|
||||
if (m == NULL)
|
||||
return;
|
||||
|
||||
/* Add some symbolic constants to the module */
|
||||
d = PyModule_GetDict(m);
|
||||
all_ins(d);
|
||||
}
|
||||
+2139
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,268 @@
|
||||
|
||||
/* Font Manager module */
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
#include <gl.h>
|
||||
#include <device.h>
|
||||
#include <fmclient.h>
|
||||
|
||||
|
||||
/* Font Handle object implementation */
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
fmfonthandle fh_fh;
|
||||
} fhobject;
|
||||
|
||||
static PyTypeObject Fhtype;
|
||||
|
||||
#define is_fhobject(v) ((v)->ob_type == &Fhtype)
|
||||
|
||||
static PyObject *
|
||||
newfhobject(fmfonthandle fh)
|
||||
{
|
||||
fhobject *fhp;
|
||||
if (fh == NULL) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"error creating new font handle");
|
||||
return NULL;
|
||||
}
|
||||
fhp = PyObject_New(fhobject, &Fhtype);
|
||||
if (fhp == NULL)
|
||||
return NULL;
|
||||
fhp->fh_fh = fh;
|
||||
return (PyObject *)fhp;
|
||||
}
|
||||
|
||||
/* Font Handle methods */
|
||||
|
||||
static PyObject *
|
||||
fh_scalefont(fhobject *self, PyObject *args)
|
||||
{
|
||||
double size;
|
||||
if (!PyArg_ParseTuple(args, "d", &size))
|
||||
return NULL;
|
||||
return newfhobject(fmscalefont(self->fh_fh, size));
|
||||
}
|
||||
|
||||
/* XXX fmmakefont */
|
||||
|
||||
static PyObject *
|
||||
fh_setfont(fhobject *self)
|
||||
{
|
||||
fmsetfont(self->fh_fh);
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
fh_getfontname(fhobject *self)
|
||||
{
|
||||
char fontname[256];
|
||||
int len;
|
||||
len = fmgetfontname(self->fh_fh, sizeof fontname, fontname);
|
||||
if (len < 0) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "error in fmgetfontname");
|
||||
return NULL;
|
||||
}
|
||||
return PyString_FromStringAndSize(fontname, len);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
fh_getcomment(fhobject *self)
|
||||
{
|
||||
char comment[256];
|
||||
int len;
|
||||
len = fmgetcomment(self->fh_fh, sizeof comment, comment);
|
||||
if (len < 0) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "error in fmgetcomment");
|
||||
return NULL;
|
||||
}
|
||||
return PyString_FromStringAndSize(comment, len);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
fh_getfontinfo(fhobject *self)
|
||||
{
|
||||
fmfontinfo info;
|
||||
if (fmgetfontinfo(self->fh_fh, &info) < 0) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "error in fmgetfontinfo");
|
||||
return NULL;
|
||||
}
|
||||
return Py_BuildValue("(llllllll)",
|
||||
info.printermatched,
|
||||
info.fixed_width,
|
||||
info.xorig,
|
||||
info.yorig,
|
||||
info.xsize,
|
||||
info.ysize,
|
||||
info.height,
|
||||
info.nglyphs);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static PyObject *
|
||||
fh_getwholemetrics(fhobject *self, PyObject *args)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static PyObject *
|
||||
fh_getstrwidth(fhobject *self, PyObject *args)
|
||||
{
|
||||
char *str;
|
||||
if (!PyArg_ParseTuple(args, "s", &str))
|
||||
return NULL;
|
||||
return PyInt_FromLong(fmgetstrwidth(self->fh_fh, str));
|
||||
}
|
||||
|
||||
static PyMethodDef fh_methods[] = {
|
||||
{"scalefont", (PyCFunction)fh_scalefont, METH_VARARGS},
|
||||
{"setfont", (PyCFunction)fh_setfont, METH_NOARGS},
|
||||
{"getfontname", (PyCFunction)fh_getfontname, METH_NOARGS},
|
||||
{"getcomment", (PyCFunction)fh_getcomment, METH_NOARGS},
|
||||
{"getfontinfo", (PyCFunction)fh_getfontinfo, METH_NOARGS},
|
||||
#if 0
|
||||
{"getwholemetrics", (PyCFunction)fh_getwholemetrics, METH_VARARGS},
|
||||
#endif
|
||||
{"getstrwidth", (PyCFunction)fh_getstrwidth, METH_VARARGS},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
fh_getattr(fhobject *fhp, char *name)
|
||||
{
|
||||
return Py_FindMethod(fh_methods, (PyObject *)fhp, name);
|
||||
}
|
||||
|
||||
static void
|
||||
fh_dealloc(fhobject *fhp)
|
||||
{
|
||||
fmfreefont(fhp->fh_fh);
|
||||
PyObject_Del(fhp);
|
||||
}
|
||||
|
||||
static PyTypeObject Fhtype = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0, /*ob_size*/
|
||||
"fm.font handle", /*tp_name*/
|
||||
sizeof(fhobject), /*tp_size*/
|
||||
0, /*tp_itemsize*/
|
||||
/* methods */
|
||||
(destructor)fh_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
(getattrfunc)fh_getattr, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
0, /*tp_repr*/
|
||||
};
|
||||
|
||||
|
||||
/* Font Manager functions */
|
||||
|
||||
static PyObject *
|
||||
fm_init(PyObject *self)
|
||||
{
|
||||
fminit();
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
fm_findfont(PyObject *self, PyObject *args)
|
||||
{
|
||||
char *str;
|
||||
if (!PyArg_ParseTuple(args, "s", &str))
|
||||
return NULL;
|
||||
return newfhobject(fmfindfont(str));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
fm_prstr(PyObject *self, PyObject *args)
|
||||
{
|
||||
char *str;
|
||||
if (!PyArg_ParseTuple(args, "s", &str))
|
||||
return NULL;
|
||||
fmprstr(str);
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
/* XXX This uses a global variable as temporary! Not re-entrant! */
|
||||
|
||||
static PyObject *fontlist;
|
||||
|
||||
static void
|
||||
clientproc(char *fontname)
|
||||
{
|
||||
int err;
|
||||
PyObject *v;
|
||||
if (fontlist == NULL)
|
||||
return;
|
||||
v = PyString_FromString(fontname);
|
||||
if (v == NULL)
|
||||
err = -1;
|
||||
else {
|
||||
err = PyList_Append(fontlist, v);
|
||||
Py_DECREF(v);
|
||||
}
|
||||
if (err != 0) {
|
||||
Py_DECREF(fontlist);
|
||||
fontlist = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
fm_enumerate(PyObject *self)
|
||||
{
|
||||
PyObject *res;
|
||||
fontlist = PyList_New(0);
|
||||
if (fontlist == NULL)
|
||||
return NULL;
|
||||
fmenumerate(clientproc);
|
||||
res = fontlist;
|
||||
fontlist = NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
fm_setpath(PyObject *self, PyObject *args)
|
||||
{
|
||||
char *str;
|
||||
if (!PyArg_ParseTuple(args, "s", &str))
|
||||
return NULL;
|
||||
fmsetpath(str);
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
fm_fontpath(PyObject *self)
|
||||
{
|
||||
return PyString_FromString(fmfontpath());
|
||||
}
|
||||
|
||||
static PyMethodDef fm_methods[] = {
|
||||
{"init", fm_init, METH_NOARGS},
|
||||
{"findfont", fm_findfont, METH_VARARGS},
|
||||
{"enumerate", fm_enumerate, METH_NOARGS},
|
||||
{"prstr", fm_prstr, METH_VARARGS},
|
||||
{"setpath", fm_setpath, METH_VARARGS},
|
||||
{"fontpath", fm_fontpath, METH_NOARGS},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
initfm(void)
|
||||
{
|
||||
if (PyErr_WarnPy3k("the fm module has been removed in "
|
||||
"Python 3.0", 2) < 0)
|
||||
return;
|
||||
|
||||
Py_InitModule("fm", fm_methods);
|
||||
if (m == NULL)
|
||||
return;
|
||||
fminit();
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
---------------------------------------------------------------------
|
||||
/ Copyright (c) 1996. \
|
||||
| The Regents of the University of California. |
|
||||
| All rights reserved. |
|
||||
| |
|
||||
| Permission to use, copy, modify, and distribute this software for |
|
||||
| any purpose without fee is hereby granted, provided that this en- |
|
||||
| tire notice is included in all copies of any software which is or |
|
||||
| includes a copy or modification of this software and in all |
|
||||
| copies of the supporting documentation for such software. |
|
||||
| |
|
||||
| This work was produced at the University of California, Lawrence |
|
||||
| Livermore National Laboratory under contract no. W-7405-ENG-48 |
|
||||
| between the U.S. Department of Energy and The Regents of the |
|
||||
| University of California for the operation of UC LLNL. |
|
||||
| |
|
||||
| DISCLAIMER |
|
||||
| |
|
||||
| This software was prepared as an account of work sponsored by an |
|
||||
| agency of the United States Government. Neither the United States |
|
||||
| Government nor the University of California nor any of their em- |
|
||||
| ployees, makes any warranty, express or implied, or assumes any |
|
||||
| liability or responsibility for the accuracy, completeness, or |
|
||||
| usefulness of any information, apparatus, product, or process |
|
||||
| disclosed, or represents that its use would not infringe |
|
||||
| privately-owned rights. Reference herein to any specific commer- |
|
||||
| cial products, process, or service by trade name, trademark, |
|
||||
| manufacturer, or otherwise, does not necessarily constitute or |
|
||||
| imply its endorsement, recommendation, or favoring by the United |
|
||||
| States Government or the University of California. The views and |
|
||||
| opinions of authors expressed herein do not necessarily state or |
|
||||
| reflect those of the United States Government or the University |
|
||||
| of California, and shall not be used for advertising or product |
|
||||
\ endorsement purposes. /
|
||||
---------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
Floating point exception control module.
|
||||
|
||||
This Python module provides bare-bones control over floating point
|
||||
units from several hardware manufacturers. Specifically, it allows
|
||||
the user to turn on the generation of SIGFPE whenever any of the
|
||||
three serious IEEE 754 exceptions (Division by Zero, Overflow,
|
||||
Invalid Operation) occurs. We currently ignore Underflow and
|
||||
Inexact Result exceptions, although those could certainly be added
|
||||
if desired.
|
||||
|
||||
The module also establishes a signal handler for SIGFPE during
|
||||
initialization. This builds on code found in the Python
|
||||
distribution at Include/pyfpe.h and Python/pyfpe.c. If those files
|
||||
are not in your Python distribution, find them in a patch at
|
||||
ftp://icf.llnl.gov/pub/python/busby/patches.961108.tgz.
|
||||
|
||||
This module is only useful to you if it happens to include code
|
||||
specific for your hardware and software environment. If you can
|
||||
contribute OS-specific code for new platforms, or corrections for
|
||||
the code provided, it will be greatly appreciated.
|
||||
|
||||
** Version 1.0: September 20, 1996. Lee Busby, LLNL.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "Python.h"
|
||||
#include <signal.h>
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
# include <ieeefp.h>
|
||||
#elif defined(__VMS)
|
||||
#define __NEW_STARLET
|
||||
#include <starlet.h>
|
||||
#include <ieeedef.h>
|
||||
#endif
|
||||
|
||||
#ifndef WANT_SIGFPE_HANDLER
|
||||
/* Define locally if they are not defined in Python. This gives only
|
||||
* the limited control to induce a core dump in case of an exception.
|
||||
*/
|
||||
#include <setjmp.h>
|
||||
static jmp_buf PyFPE_jbuf;
|
||||
static int PyFPE_counter = 0;
|
||||
#endif
|
||||
|
||||
typedef void Sigfunc(int);
|
||||
static Sigfunc sigfpe_handler;
|
||||
static void fpe_reset(Sigfunc *);
|
||||
|
||||
static PyObject *fpe_error;
|
||||
PyMODINIT_FUNC initfpectl(void);
|
||||
static PyObject *turnon_sigfpe (PyObject *self,PyObject *args);
|
||||
static PyObject *turnoff_sigfpe (PyObject *self,PyObject *args);
|
||||
|
||||
static PyMethodDef fpectl_methods[] = {
|
||||
{"turnon_sigfpe", (PyCFunction) turnon_sigfpe, METH_VARARGS},
|
||||
{"turnoff_sigfpe", (PyCFunction) turnoff_sigfpe, METH_VARARGS},
|
||||
{0,0}
|
||||
};
|
||||
|
||||
static PyObject *turnon_sigfpe(PyObject *self,PyObject *args)
|
||||
{
|
||||
/* Do any architecture-specific one-time only initialization here. */
|
||||
|
||||
fpe_reset(sigfpe_handler);
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static void fpe_reset(Sigfunc *handler)
|
||||
{
|
||||
/* Reset the exception handling machinery, and reset the signal
|
||||
* handler for SIGFPE to the given handler.
|
||||
*/
|
||||
|
||||
/*-- IRIX -----------------------------------------------------------------*/
|
||||
#if defined(sgi)
|
||||
/* See man page on handle_sigfpes -- must link with -lfpe
|
||||
* My usage doesn't follow the man page exactly. Maybe somebody
|
||||
* else can explain handle_sigfpes to me....
|
||||
* cc -c -I/usr/local/python/include fpectlmodule.c
|
||||
* ld -shared -o fpectlmodule.so fpectlmodule.o -lfpe
|
||||
*/
|
||||
#include <sigfpe.h>
|
||||
typedef void user_routine (unsigned[5], int[2]);
|
||||
typedef void abort_routine (unsigned long);
|
||||
handle_sigfpes(_OFF, 0,
|
||||
(user_routine *)0,
|
||||
_TURN_OFF_HANDLER_ON_ERROR,
|
||||
NULL);
|
||||
handle_sigfpes(_ON, _EN_OVERFL | _EN_DIVZERO | _EN_INVALID,
|
||||
(user_routine *)0,
|
||||
_ABORT_ON_ERROR,
|
||||
NULL);
|
||||
PyOS_setsig(SIGFPE, handler);
|
||||
|
||||
/*-- SunOS and Solaris ----------------------------------------------------*/
|
||||
#elif defined(sun)
|
||||
/* References: ieee_handler, ieee_sun, ieee_functions, and ieee_flags
|
||||
man pages (SunOS or Solaris)
|
||||
cc -c -I/usr/local/python/include fpectlmodule.c
|
||||
ld -G -o fpectlmodule.so -L/opt/SUNWspro/lib fpectlmodule.o -lsunmath -lm
|
||||
*/
|
||||
#include <math.h>
|
||||
#ifndef _SUNMATH_H
|
||||
extern void nonstandard_arithmetic(void);
|
||||
extern int ieee_flags(const char*, const char*, const char*, char **);
|
||||
extern long ieee_handler(const char*, const char*, sigfpe_handler_type);
|
||||
#endif
|
||||
|
||||
char *mode="exception", *in="all", *out;
|
||||
(void) nonstandard_arithmetic();
|
||||
(void) ieee_flags("clearall",mode,in,&out);
|
||||
(void) ieee_handler("set","common",(sigfpe_handler_type)handler);
|
||||
PyOS_setsig(SIGFPE, handler);
|
||||
|
||||
/*-- HPUX -----------------------------------------------------------------*/
|
||||
#elif defined(__hppa) || defined(hppa)
|
||||
/* References: fpsetmask man page */
|
||||
/* cc -Aa +z -c -I/usr/local/python/include fpectlmodule.c */
|
||||
/* ld -b -o fpectlmodule.sl fpectlmodule.o -lm */
|
||||
#include <math.h>
|
||||
fpsetdefaults();
|
||||
PyOS_setsig(SIGFPE, handler);
|
||||
|
||||
/*-- IBM AIX --------------------------------------------------------------*/
|
||||
#elif defined(__AIX) || defined(_AIX)
|
||||
/* References: fp_trap, fp_enable man pages */
|
||||
#include <fptrap.h>
|
||||
fp_trap(FP_TRAP_SYNC);
|
||||
fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW);
|
||||
PyOS_setsig(SIGFPE, handler);
|
||||
|
||||
/*-- DEC ALPHA OSF --------------------------------------------------------*/
|
||||
#elif defined(__alpha) && defined(__osf__)
|
||||
/* References: exception_intro, ieee man pages */
|
||||
/* cc -c -I/usr/local/python/include fpectlmodule.c */
|
||||
/* ld -shared -o fpectlmodule.so fpectlmodule.o */
|
||||
#include <machine/fpu.h>
|
||||
unsigned long fp_control =
|
||||
IEEE_TRAP_ENABLE_INV | IEEE_TRAP_ENABLE_DZE | IEEE_TRAP_ENABLE_OVF;
|
||||
ieee_set_fp_control(fp_control);
|
||||
PyOS_setsig(SIGFPE, handler);
|
||||
|
||||
/*-- DEC ALPHA LINUX ------------------------------------------------------*/
|
||||
#elif defined(__alpha) && defined(linux)
|
||||
#include <asm/fpu.h>
|
||||
unsigned long fp_control =
|
||||
IEEE_TRAP_ENABLE_INV | IEEE_TRAP_ENABLE_DZE | IEEE_TRAP_ENABLE_OVF;
|
||||
ieee_set_fp_control(fp_control);
|
||||
PyOS_setsig(SIGFPE, handler);
|
||||
|
||||
/*-- DEC ALPHA VMS --------------------------------------------------------*/
|
||||
#elif defined(__ALPHA) && defined(__VMS)
|
||||
IEEE clrmsk;
|
||||
IEEE setmsk;
|
||||
clrmsk.ieee$q_flags =
|
||||
IEEE$M_TRAP_ENABLE_UNF | IEEE$M_TRAP_ENABLE_INE |
|
||||
IEEE$M_MAP_UMZ;
|
||||
setmsk.ieee$q_flags =
|
||||
IEEE$M_TRAP_ENABLE_INV | IEEE$M_TRAP_ENABLE_DZE |
|
||||
IEEE$M_TRAP_ENABLE_OVF;
|
||||
sys$ieee_set_fp_control(&clrmsk, &setmsk, 0);
|
||||
PyOS_setsig(SIGFPE, handler);
|
||||
|
||||
/*-- HP IA64 VMS --------------------------------------------------------*/
|
||||
#elif defined(__ia64) && defined(__VMS)
|
||||
PyOS_setsig(SIGFPE, handler);
|
||||
|
||||
/*-- Cray Unicos ----------------------------------------------------------*/
|
||||
#elif defined(cray)
|
||||
/* UNICOS delivers SIGFPE by default, but no matherr */
|
||||
#ifdef HAS_LIBMSET
|
||||
libmset(-1);
|
||||
#endif
|
||||
PyOS_setsig(SIGFPE, handler);
|
||||
|
||||
/*-- FreeBSD ----------------------------------------------------------------*/
|
||||
#elif defined(__FreeBSD__)
|
||||
fpresetsticky(fpgetsticky());
|
||||
fpsetmask(FP_X_INV | FP_X_DZ | FP_X_OFL);
|
||||
PyOS_setsig(SIGFPE, handler);
|
||||
|
||||
/*-- Linux ----------------------------------------------------------------*/
|
||||
#elif defined(linux)
|
||||
#ifdef __GLIBC__
|
||||
#include <fpu_control.h>
|
||||
#else
|
||||
#include <i386/fpu_control.h>
|
||||
#endif
|
||||
#ifdef _FPU_SETCW
|
||||
{
|
||||
fpu_control_t cw = 0x1372;
|
||||
_FPU_SETCW(cw);
|
||||
}
|
||||
#else
|
||||
__setfpucw(0x1372);
|
||||
#endif
|
||||
PyOS_setsig(SIGFPE, handler);
|
||||
|
||||
/*-- Microsoft Windows, NT ------------------------------------------------*/
|
||||
#elif defined(_MSC_VER)
|
||||
/* Reference: Visual C++ Books Online 4.2,
|
||||
Run-Time Library Reference, _control87, _controlfp */
|
||||
#include <float.h>
|
||||
unsigned int cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW;
|
||||
(void)_controlfp(0, cw);
|
||||
PyOS_setsig(SIGFPE, handler);
|
||||
|
||||
/*-- Give Up --------------------------------------------------------------*/
|
||||
#else
|
||||
fputs("Operation not implemented\n", stderr);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static PyObject *turnoff_sigfpe(PyObject *self,PyObject *args)
|
||||
{
|
||||
#ifdef __FreeBSD__
|
||||
fpresetsticky(fpgetsticky());
|
||||
fpsetmask(0);
|
||||
#elif defined(__VMS)
|
||||
IEEE clrmsk;
|
||||
clrmsk.ieee$q_flags =
|
||||
IEEE$M_TRAP_ENABLE_UNF | IEEE$M_TRAP_ENABLE_INE |
|
||||
IEEE$M_MAP_UMZ | IEEE$M_TRAP_ENABLE_INV |
|
||||
IEEE$M_TRAP_ENABLE_DZE | IEEE$M_TRAP_ENABLE_OVF |
|
||||
IEEE$M_INHERIT;
|
||||
sys$ieee_set_fp_control(&clrmsk, 0, 0);
|
||||
#else
|
||||
fputs("Operation not implemented\n", stderr);
|
||||
#endif
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static void sigfpe_handler(int signo)
|
||||
{
|
||||
fpe_reset(sigfpe_handler);
|
||||
if(PyFPE_counter) {
|
||||
longjmp(PyFPE_jbuf, 1);
|
||||
} else {
|
||||
Py_FatalError("Unprotected floating point exception");
|
||||
}
|
||||
}
|
||||
|
||||
PyMODINIT_FUNC initfpectl(void)
|
||||
{
|
||||
PyObject *m, *d;
|
||||
m = Py_InitModule("fpectl", fpectl_methods);
|
||||
if (m == NULL)
|
||||
return;
|
||||
d = PyModule_GetDict(m);
|
||||
fpe_error = PyErr_NewException("fpectl.error", NULL, NULL);
|
||||
if (fpe_error != NULL)
|
||||
PyDict_SetItemString(d, "error", fpe_error);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
---------------------------------------------------------------------
|
||||
/ Copyright (c) 1996. \
|
||||
| The Regents of the University of California. |
|
||||
| All rights reserved. |
|
||||
| |
|
||||
| Permission to use, copy, modify, and distribute this software for |
|
||||
| any purpose without fee is hereby granted, provided that this en- |
|
||||
| tire notice is included in all copies of any software which is or |
|
||||
| includes a copy or modification of this software and in all |
|
||||
| copies of the supporting documentation for such software. |
|
||||
| |
|
||||
| This work was produced at the University of California, Lawrence |
|
||||
| Livermore National Laboratory under contract no. W-7405-ENG-48 |
|
||||
| between the U.S. Department of Energy and The Regents of the |
|
||||
| University of California for the operation of UC LLNL. |
|
||||
| |
|
||||
| DISCLAIMER |
|
||||
| |
|
||||
| This software was prepared as an account of work sponsored by an |
|
||||
| agency of the United States Government. Neither the United States |
|
||||
| Government nor the University of California nor any of their em- |
|
||||
| ployees, makes any warranty, express or implied, or assumes any |
|
||||
| liability or responsibility for the accuracy, completeness, or |
|
||||
| usefulness of any information, apparatus, product, or process |
|
||||
| disclosed, or represents that its use would not infringe |
|
||||
| privately-owned rights. Reference herein to any specific commer- |
|
||||
| cial products, process, or service by trade name, trademark, |
|
||||
| manufacturer, or otherwise, does not necessarily constitute or |
|
||||
| imply its endorsement, recommendation, or favoring by the United |
|
||||
| States Government or the University of California. The views and |
|
||||
| opinions of authors expressed herein do not necessarily state or |
|
||||
| reflect those of the United States Government or the University |
|
||||
| of California, and shall not be used for advertising or product |
|
||||
\ endorsement purposes. /
|
||||
---------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
Floating point exception test module.
|
||||
|
||||
*/
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
static PyObject *fpe_error;
|
||||
PyMODINIT_FUNC initfpetest(void);
|
||||
static PyObject *test(PyObject *self,PyObject *args);
|
||||
static double db0(double);
|
||||
static double overflow(double);
|
||||
static double nest1(int, double);
|
||||
static double nest2(int, double);
|
||||
static double nest3(double);
|
||||
static void printerr(double);
|
||||
|
||||
static PyMethodDef fpetest_methods[] = {
|
||||
{"test", (PyCFunction) test, METH_VARARGS},
|
||||
{0,0}
|
||||
};
|
||||
|
||||
static PyObject *test(PyObject *self,PyObject *args)
|
||||
{
|
||||
double r;
|
||||
|
||||
fprintf(stderr,"overflow");
|
||||
r = overflow(1.e160);
|
||||
printerr(r);
|
||||
|
||||
fprintf(stderr,"\ndiv by 0");
|
||||
r = db0(0.0);
|
||||
printerr(r);
|
||||
|
||||
fprintf(stderr,"\nnested outer");
|
||||
r = nest1(0, 0.0);
|
||||
printerr(r);
|
||||
|
||||
fprintf(stderr,"\nnested inner");
|
||||
r = nest1(1, 1.0);
|
||||
printerr(r);
|
||||
|
||||
fprintf(stderr,"\ntrailing outer");
|
||||
r = nest1(2, 2.0);
|
||||
printerr(r);
|
||||
|
||||
fprintf(stderr,"\nnested prior");
|
||||
r = nest2(0, 0.0);
|
||||
printerr(r);
|
||||
|
||||
fprintf(stderr,"\nnested interior");
|
||||
r = nest2(1, 1.0);
|
||||
printerr(r);
|
||||
|
||||
fprintf(stderr,"\nnested trailing");
|
||||
r = nest2(2, 2.0);
|
||||
printerr(r);
|
||||
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static void printerr(double r)
|
||||
{
|
||||
if(r == 3.1416){
|
||||
fprintf(stderr,"\tPASS\n");
|
||||
PyErr_Print();
|
||||
}else{
|
||||
fprintf(stderr,"\tFAIL\n");
|
||||
}
|
||||
PyErr_Clear();
|
||||
}
|
||||
|
||||
static double nest1(int i, double x)
|
||||
{
|
||||
double a = 1.0;
|
||||
|
||||
PyFPE_START_PROTECT("Division by zero, outer zone", return 3.1416)
|
||||
if(i == 0){
|
||||
a = 1./x;
|
||||
}else if(i == 1){
|
||||
/* This (following) message is never seen. */
|
||||
PyFPE_START_PROTECT("Division by zero, inner zone", return 3.1416)
|
||||
a = 1./(1. - x);
|
||||
PyFPE_END_PROTECT(a)
|
||||
}else if(i == 2){
|
||||
a = 1./(2. - x);
|
||||
}
|
||||
PyFPE_END_PROTECT(a)
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
static double nest2(int i, double x)
|
||||
{
|
||||
double a = 1.0;
|
||||
PyFPE_START_PROTECT("Division by zero, prior error", return 3.1416)
|
||||
if(i == 0){
|
||||
a = 1./x;
|
||||
}else if(i == 1){
|
||||
a = nest3(x);
|
||||
}else if(i == 2){
|
||||
a = 1./(2. - x);
|
||||
}
|
||||
PyFPE_END_PROTECT(a)
|
||||
return a;
|
||||
}
|
||||
|
||||
static double nest3(double x)
|
||||
{
|
||||
double result;
|
||||
/* This (following) message is never seen. */
|
||||
PyFPE_START_PROTECT("Division by zero, nest3 error", return 3.1416)
|
||||
result = 1./(1. - x);
|
||||
PyFPE_END_PROTECT(result)
|
||||
return result;
|
||||
}
|
||||
|
||||
static double db0(double x)
|
||||
{
|
||||
double a;
|
||||
PyFPE_START_PROTECT("Division by zero", return 3.1416)
|
||||
a = 1./x;
|
||||
PyFPE_END_PROTECT(a)
|
||||
return a;
|
||||
}
|
||||
|
||||
static double overflow(double b)
|
||||
{
|
||||
double a;
|
||||
PyFPE_START_PROTECT("Overflow", return 3.1416)
|
||||
a = b*b;
|
||||
PyFPE_END_PROTECT(a)
|
||||
return a;
|
||||
}
|
||||
|
||||
PyMODINIT_FUNC initfpetest(void)
|
||||
{
|
||||
PyObject *m, *d;
|
||||
|
||||
m = Py_InitModule("fpetest", fpetest_methods);
|
||||
if (m == NULL)
|
||||
return;
|
||||
d = PyModule_GetDict(m);
|
||||
fpe_error = PyErr_NewException("fpetest.error", NULL, NULL);
|
||||
if (fpe_error != NULL)
|
||||
PyDict_SetItemString(d, "error", fpe_error);
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
|
||||
/* future_builtins module */
|
||||
|
||||
/* This module provides functions that will be builtins in Python 3.0,
|
||||
but that conflict with builtins that already exist in Python
|
||||
2.x. */
|
||||
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
PyDoc_STRVAR(module_doc,
|
||||
"This module provides functions that will be builtins in Python 3.0,\n\
|
||||
but that conflict with builtins that already exist in Python 2.x.\n\
|
||||
\n\
|
||||
Functions:\n\
|
||||
\n\
|
||||
ascii(arg) -- Returns the canonical string representation of an object.\n\
|
||||
filter(pred, iterable) -- Returns an iterator yielding those items of \n\
|
||||
iterable for which pred(item) is true.\n\
|
||||
hex(arg) -- Returns the hexadecimal representation of an integer.\n\
|
||||
map(func, *iterables) -- Returns an iterator that computes the function \n\
|
||||
using arguments from each of the iterables.\n\
|
||||
oct(arg) -- Returns the octal representation of an integer.\n\
|
||||
zip(iter1 [,iter2 [...]]) -- Returns a zip object whose .next() method \n\
|
||||
returns a tuple where the i-th element comes from the i-th iterable \n\
|
||||
argument.\n\
|
||||
\n\
|
||||
The typical usage of this module is to replace existing builtins in a\n\
|
||||
module's namespace:\n \n\
|
||||
from future_builtins import ascii, filter, map, hex, oct, zip\n");
|
||||
|
||||
static PyObject *
|
||||
builtin_hex(PyObject *self, PyObject *v)
|
||||
{
|
||||
return PyNumber_ToBase(v, 16);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(hex_doc,
|
||||
"hex(number) -> string\n\
|
||||
\n\
|
||||
Return the hexadecimal representation of an integer or long integer.");
|
||||
|
||||
|
||||
static PyObject *
|
||||
builtin_oct(PyObject *self, PyObject *v)
|
||||
{
|
||||
return PyNumber_ToBase(v, 8);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(oct_doc,
|
||||
"oct(number) -> string\n\
|
||||
\n\
|
||||
Return the octal representation of an integer or long integer.");
|
||||
|
||||
|
||||
static PyObject *
|
||||
builtin_ascii(PyObject *self, PyObject *v)
|
||||
{
|
||||
return PyObject_Repr(v);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(ascii_doc,
|
||||
"ascii(object) -> string\n\
|
||||
\n\
|
||||
Return the same as repr(). In Python 3.x, the repr() result will\n\
|
||||
contain printable characters unescaped, while the ascii() result\n\
|
||||
will have such characters backslash-escaped.");
|
||||
|
||||
/* List of functions exported by this module */
|
||||
|
||||
static PyMethodDef module_functions[] = {
|
||||
{"hex", builtin_hex, METH_O, hex_doc},
|
||||
{"oct", builtin_oct, METH_O, oct_doc},
|
||||
{"ascii", builtin_ascii, METH_O, ascii_doc},
|
||||
{NULL, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
||||
/* Initialize this module. */
|
||||
|
||||
PyMODINIT_FUNC
|
||||
initfuture_builtins(void)
|
||||
{
|
||||
PyObject *m, *itertools, *iter_func;
|
||||
char *it_funcs[] = {"imap", "ifilter", "izip", NULL};
|
||||
char **cur_func;
|
||||
|
||||
m = Py_InitModule3("future_builtins", module_functions, module_doc);
|
||||
if (m == NULL)
|
||||
return;
|
||||
|
||||
itertools = PyImport_ImportModuleNoBlock("itertools");
|
||||
if (itertools == NULL)
|
||||
return;
|
||||
|
||||
/* If anything in the following loop fails, we fall through. */
|
||||
for (cur_func = it_funcs; *cur_func; ++cur_func){
|
||||
iter_func = PyObject_GetAttrString(itertools, *cur_func);
|
||||
if (iter_func == NULL ||
|
||||
PyModule_AddObject(m, *cur_func+1, iter_func) < 0)
|
||||
break;
|
||||
}
|
||||
Py_DECREF(itertools);
|
||||
/* any other initialization needed */
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
Intro
|
||||
=====
|
||||
|
||||
The basic rule for dealing with weakref callbacks (and __del__ methods too,
|
||||
for that matter) during cyclic gc:
|
||||
|
||||
Once gc has computed the set of unreachable objects, no Python-level
|
||||
code can be allowed to access an unreachable object.
|
||||
|
||||
If that can happen, then the Python code can resurrect unreachable objects
|
||||
too, and gc can't detect that without starting over. Since gc eventually
|
||||
runs tp_clear on all unreachable objects, if an unreachable object is
|
||||
resurrected then tp_clear will eventually be called on it (or may already
|
||||
have been called before resurrection). At best (and this has been an
|
||||
historically common bug), tp_clear empties an instance's __dict__, and
|
||||
"impossible" AttributeErrors result. At worst, tp_clear leaves behind an
|
||||
insane object at the C level, and segfaults result (historically, most
|
||||
often by setting a new-style class's mro pointer to NULL, after which
|
||||
attribute lookups performed by the class can segfault).
|
||||
|
||||
OTOH, it's OK to run Python-level code that can't access unreachable
|
||||
objects, and sometimes that's necessary. The chief example is the callback
|
||||
attached to a reachable weakref W to an unreachable object O. Since O is
|
||||
going away, and W is still alive, the callback must be invoked. Because W
|
||||
is still alive, everything reachable from its callback is also reachable,
|
||||
so it's also safe to invoke the callback (although that's trickier than it
|
||||
sounds, since other reachable weakrefs to other unreachable objects may
|
||||
still exist, and be accessible to the callback -- there are lots of painful
|
||||
details like this covered in the rest of this file).
|
||||
|
||||
Python 2.4/2.3.5
|
||||
================
|
||||
|
||||
The "Before 2.3.3" section below turned out to be wrong in some ways, but
|
||||
I'm leaving it as-is because it's more right than wrong, and serves as a
|
||||
wonderful example of how painful analysis can miss not only the forest for
|
||||
the trees, but also miss the trees for the aphids sucking the trees
|
||||
dry <wink>.
|
||||
|
||||
The primary thing it missed is that when a weakref to a piece of cyclic
|
||||
trash (CT) exists, then any call to any Python code whatsoever can end up
|
||||
materializing a strong reference to that weakref's CT referent, and so
|
||||
possibly resurrect an insane object (one for which cyclic gc has called-- or
|
||||
will call before it's done --tp_clear()). It's not even necessarily that a
|
||||
weakref callback or __del__ method does something nasty on purpose: as
|
||||
soon as we execute Python code, threads other than the gc thread can run
|
||||
too, and they can do ordinary things with weakrefs that end up resurrecting
|
||||
CT while gc is running.
|
||||
|
||||
http://www.python.org/sf/1055820
|
||||
|
||||
shows how innocent it can be, and also how nasty. Variants of the three
|
||||
focussed test cases attached to that bug report are now part of Python's
|
||||
standard Lib/test/test_gc.py.
|
||||
|
||||
Jim Fulton gave the best nutshell summary of the new (in 2.4 and 2.3.5)
|
||||
approach:
|
||||
|
||||
Clearing cyclic trash can call Python code. If there are weakrefs to
|
||||
any of the cyclic trash, then those weakrefs can be used to resurrect
|
||||
the objects. Therefore, *before* clearing cyclic trash, we need to
|
||||
remove any weakrefs. If any of the weakrefs being removed have
|
||||
callbacks, then we need to save the callbacks and call them *after* all
|
||||
of the weakrefs have been cleared.
|
||||
|
||||
Alas, doing just that much doesn't work, because it overlooks what turned
|
||||
out to be the much subtler problems that were fixed earlier, and described
|
||||
below. We do clear all weakrefs to CT now before breaking cycles, but not
|
||||
all callbacks encountered can be run later. That's explained in horrid
|
||||
detail below.
|
||||
|
||||
Older text follows, with a some later comments in [] brackets:
|
||||
|
||||
Before 2.3.3
|
||||
============
|
||||
|
||||
Before 2.3.3, Python's cyclic gc didn't pay any attention to weakrefs.
|
||||
Segfaults in Zope3 resulted.
|
||||
|
||||
weakrefs in Python are designed to, at worst, let *other* objects learn
|
||||
that a given object has died, via a callback function. The weakly
|
||||
referenced object itself is not passed to the callback, and the presumption
|
||||
is that the weakly referenced object is unreachable trash at the time the
|
||||
callback is invoked.
|
||||
|
||||
That's usually true, but not always. Suppose a weakly referenced object
|
||||
becomes part of a clump of cyclic trash. When enough cycles are broken by
|
||||
cyclic gc that the object is reclaimed, the callback is invoked. If it's
|
||||
possible for the callback to get at objects in the cycle(s), then it may be
|
||||
possible for those objects to access (via strong references in the cycle)
|
||||
the weakly referenced object being torn down, or other objects in the cycle
|
||||
that have already suffered a tp_clear() call. There's no guarantee that an
|
||||
object is in a sane state after tp_clear(). Bad things (including
|
||||
segfaults) can happen right then, during the callback's execution, or can
|
||||
happen at any later time if the callback manages to resurrect an insane
|
||||
object.
|
||||
|
||||
[That missed that, in addition, a weakref to CT can exist outside CT, and
|
||||
any callback into Python can use such a non-CT weakref to resurrect its CT
|
||||
referent. The same bad kinds of things can happen then.]
|
||||
|
||||
Note that if it's possible for the callback to get at objects in the trash
|
||||
cycles, it must also be the case that the callback itself is part of the
|
||||
trash cycles. Else the callback would have acted as an external root to
|
||||
the current collection, and nothing reachable from it would be in cyclic
|
||||
trash either.
|
||||
|
||||
[Except that a non-CT callback can also use a non-CT weakref to get at
|
||||
CT objects.]
|
||||
|
||||
More, if the callback itself is in cyclic trash, then the weakref to which
|
||||
the callback is attached must also be trash, and for the same kind of
|
||||
reason: if the weakref acted as an external root, then the callback could
|
||||
not have been cyclic trash.
|
||||
|
||||
So a problem here requires that a weakref, that weakref's callback, and the
|
||||
weakly referenced object, all be in cyclic trash at the same time. This
|
||||
isn't easy to stumble into by accident while Python is running, and, indeed,
|
||||
it took quite a while to dream up failing test cases. Zope3 saw segfaults
|
||||
during shutdown, during the second call of gc in Py_Finalize, after most
|
||||
modules had been torn down. That creates many trash cycles (esp. those
|
||||
involving new-style classes), making the problem much more likely. Once you
|
||||
know what's required to provoke the problem, though, it's easy to create
|
||||
tests that segfault before shutdown.
|
||||
|
||||
In 2.3.3, before breaking cycles, we first clear all the weakrefs with
|
||||
callbacks in cyclic trash. Since the weakrefs *are* trash, and there's no
|
||||
defined-- or even predictable --order in which tp_clear() gets called on
|
||||
cyclic trash, it's defensible to first clear weakrefs with callbacks. It's
|
||||
a feature of Python's weakrefs too that when a weakref goes away, the
|
||||
callback (if any) associated with it is thrown away too, unexecuted.
|
||||
|
||||
[In 2.4/2.3.5, we first clear all weakrefs to CT objects, whether or not
|
||||
those weakrefs are themselves CT, and whether or not they have callbacks.
|
||||
The callbacks (if any) on non-CT weakrefs (if any) are invoked later,
|
||||
after all weakrefs-to-CT have been cleared. The callbacks (if any) on CT
|
||||
weakrefs (if any) are never invoked, for the excruciating reasons
|
||||
explained here.]
|
||||
|
||||
Just that much is almost enough to prevent problems, by throwing away
|
||||
*almost* all the weakref callbacks that could get triggered by gc. The
|
||||
problem remaining is that clearing a weakref with a callback decrefs the
|
||||
callback object, and the callback object may *itself* be weakly referenced,
|
||||
via another weakref with another callback. So the process of clearing
|
||||
weakrefs can trigger callbacks attached to other weakrefs, and those
|
||||
latter weakrefs may or may not be part of cyclic trash.
|
||||
|
||||
So, to prevent any Python code from running while gc is invoking tp_clear()
|
||||
on all the objects in cyclic trash,
|
||||
|
||||
[That was always wrong: we can't stop Python code from running when gc
|
||||
is breaking cycles. If an object with a __del__ method is not itself in
|
||||
a cycle, but is reachable only from CT, then breaking cycles will, as a
|
||||
matter of course, drop the refcount on that object to 0, and its __del__
|
||||
will run right then. What we can and must stop is running any Python
|
||||
code that could access CT.]
|
||||
it's not quite enough just to invoke
|
||||
tp_clear() on weakrefs with callbacks first. Instead the weakref module
|
||||
grew a new private function (_PyWeakref_ClearRef) that does only part of
|
||||
tp_clear(): it removes the weakref from the weakly-referenced object's list
|
||||
of weakrefs, but does not decref the callback object. So calling
|
||||
_PyWeakref_ClearRef(wr) ensures that wr's callback object will never
|
||||
trigger, and (unlike weakref's tp_clear()) also prevents any callback
|
||||
associated *with* wr's callback object from triggering.
|
||||
|
||||
[Although we may trigger such callbacks later, as explained below.]
|
||||
|
||||
Then we can call tp_clear on all the cyclic objects and never trigger
|
||||
Python code.
|
||||
|
||||
[As above, not so: it means never trigger Python code that can access CT.]
|
||||
|
||||
After we do that, the callback objects still need to be decref'ed. Callbacks
|
||||
(if any) *on* the callback objects that were also part of cyclic trash won't
|
||||
get invoked, because we cleared all trash weakrefs with callbacks at the
|
||||
start. Callbacks on the callback objects that were not part of cyclic trash
|
||||
acted as external roots to everything reachable from them, so nothing
|
||||
reachable from them was part of cyclic trash, so gc didn't do any damage to
|
||||
objects reachable from them, and it's safe to call them at the end of gc.
|
||||
|
||||
[That's so. In addition, now we also invoke (if any) the callbacks on
|
||||
non-CT weakrefs to CT objects, during the same pass that decrefs the
|
||||
callback objects.]
|
||||
|
||||
An alternative would have been to treat objects with callbacks like objects
|
||||
with __del__ methods, refusing to collect them, appending them to gc.garbage
|
||||
instead. That would have been much easier. Jim Fulton gave a strong
|
||||
argument against that (on Python-Dev):
|
||||
|
||||
There's a big difference between __del__ and weakref callbacks.
|
||||
The __del__ method is "internal" to a design. When you design a
|
||||
class with a del method, you know you have to avoid including the
|
||||
class in cycles.
|
||||
|
||||
Now, suppose you have a design that makes has no __del__ methods but
|
||||
that does use cyclic data structures. You reason about the design,
|
||||
run tests, and convince yourself you don't have a leak.
|
||||
|
||||
Now, suppose some external code creates a weakref to one of your
|
||||
objects. All of a sudden, you start leaking. You can look at your
|
||||
code all you want and you won't find a reason for the leak.
|
||||
|
||||
IOW, a class designer can out-think __del__ problems, but has no control
|
||||
over who creates weakrefs to his classes or class instances. The class
|
||||
user has little chance either of predicting when the weakrefs he creates
|
||||
may end up in cycles.
|
||||
|
||||
Callbacks on weakref callbacks are executed in an arbitrary order, and
|
||||
that's not good (a primary reason not to collect cycles with objects with
|
||||
__del__ methods is to avoid running finalizers in an arbitrary order).
|
||||
However, a weakref callback on a weakref callback has got to be rare.
|
||||
It's possible to do such a thing, so gc has to be robust against it, but
|
||||
I doubt anyone has done it outside the test case I wrote for it.
|
||||
|
||||
[The callbacks (if any) on non-CT weakrefs to CT objects are also executed
|
||||
in an arbitrary order now. But they were before too, depending on the
|
||||
vagaries of when tp_clear() happened to break enough cycles to trigger
|
||||
them. People simply shouldn't try to use __del__ or weakref callbacks to
|
||||
do fancy stuff.]
|
||||
+1571
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,548 @@
|
||||
|
||||
/* DBM module using dictionary interface */
|
||||
/* Author: Anthony Baxter, after dbmmodule.c */
|
||||
/* Doc strings: Mitch Chapman */
|
||||
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include "gdbm.h"
|
||||
|
||||
#if defined(WIN32) && !defined(__CYGWIN__)
|
||||
#include "gdbmerrno.h"
|
||||
extern const char * gdbm_strerror(gdbm_error);
|
||||
#endif
|
||||
|
||||
PyDoc_STRVAR(gdbmmodule__doc__,
|
||||
"This module provides an interface to the GNU DBM (GDBM) library.\n\
|
||||
\n\
|
||||
This module is quite similar to the dbm module, but uses GDBM instead to\n\
|
||||
provide some additional functionality. Please note that the file formats\n\
|
||||
created by GDBM and dbm are incompatible. \n\
|
||||
\n\
|
||||
GDBM objects behave like mappings (dictionaries), except that keys and\n\
|
||||
values are always strings. Printing a GDBM object doesn't print the\n\
|
||||
keys and values, and the items() and values() methods are not\n\
|
||||
supported.");
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
int di_size; /* -1 means recompute */
|
||||
GDBM_FILE di_dbm;
|
||||
} dbmobject;
|
||||
|
||||
static PyTypeObject Dbmtype;
|
||||
|
||||
#define is_dbmobject(v) (Py_TYPE(v) == &Dbmtype)
|
||||
#define check_dbmobject_open(v) if ((v)->di_dbm == NULL) \
|
||||
{ PyErr_SetString(DbmError, "GDBM object has already been closed"); \
|
||||
return NULL; }
|
||||
|
||||
|
||||
|
||||
static PyObject *DbmError;
|
||||
|
||||
PyDoc_STRVAR(gdbm_object__doc__,
|
||||
"This object represents a GDBM database.\n\
|
||||
GDBM objects behave like mappings (dictionaries), except that keys and\n\
|
||||
values are always strings. Printing a GDBM object doesn't print the\n\
|
||||
keys and values, and the items() and values() methods are not\n\
|
||||
supported.\n\
|
||||
\n\
|
||||
GDBM objects also support additional operations such as firstkey,\n\
|
||||
nextkey, reorganize, and sync.");
|
||||
|
||||
static PyObject *
|
||||
newdbmobject(char *file, int flags, int mode)
|
||||
{
|
||||
dbmobject *dp;
|
||||
|
||||
dp = PyObject_New(dbmobject, &Dbmtype);
|
||||
if (dp == NULL)
|
||||
return NULL;
|
||||
dp->di_size = -1;
|
||||
errno = 0;
|
||||
if ((dp->di_dbm = gdbm_open(file, 0, flags, mode, NULL)) == 0) {
|
||||
if (errno != 0)
|
||||
PyErr_SetFromErrno(DbmError);
|
||||
else
|
||||
PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
|
||||
Py_DECREF(dp);
|
||||
return NULL;
|
||||
}
|
||||
return (PyObject *)dp;
|
||||
}
|
||||
|
||||
/* Methods */
|
||||
|
||||
static void
|
||||
dbm_dealloc(register dbmobject *dp)
|
||||
{
|
||||
if (dp->di_dbm)
|
||||
gdbm_close(dp->di_dbm);
|
||||
PyObject_Del(dp);
|
||||
}
|
||||
|
||||
static Py_ssize_t
|
||||
dbm_length(dbmobject *dp)
|
||||
{
|
||||
if (dp->di_dbm == NULL) {
|
||||
PyErr_SetString(DbmError, "GDBM object has already been closed");
|
||||
return -1;
|
||||
}
|
||||
if (dp->di_size < 0) {
|
||||
datum key,okey;
|
||||
int size;
|
||||
okey.dsize=0;
|
||||
okey.dptr=NULL;
|
||||
|
||||
size = 0;
|
||||
for (key=gdbm_firstkey(dp->di_dbm); key.dptr;
|
||||
key = gdbm_nextkey(dp->di_dbm,okey)) {
|
||||
size++;
|
||||
if(okey.dsize) free(okey.dptr);
|
||||
okey=key;
|
||||
}
|
||||
dp->di_size = size;
|
||||
}
|
||||
return dp->di_size;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
dbm_subscript(dbmobject *dp, register PyObject *key)
|
||||
{
|
||||
PyObject *v;
|
||||
datum drec, krec;
|
||||
|
||||
if (!PyArg_Parse(key, "s#", &krec.dptr, &krec.dsize) )
|
||||
return NULL;
|
||||
|
||||
if (dp->di_dbm == NULL) {
|
||||
PyErr_SetString(DbmError,
|
||||
"GDBM object has already been closed");
|
||||
return NULL;
|
||||
}
|
||||
drec = gdbm_fetch(dp->di_dbm, krec);
|
||||
if (drec.dptr == 0) {
|
||||
PyErr_SetString(PyExc_KeyError,
|
||||
PyString_AS_STRING((PyStringObject *)key));
|
||||
return NULL;
|
||||
}
|
||||
v = PyString_FromStringAndSize(drec.dptr, drec.dsize);
|
||||
free(drec.dptr);
|
||||
return v;
|
||||
}
|
||||
|
||||
static int
|
||||
dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
|
||||
{
|
||||
datum krec, drec;
|
||||
|
||||
if (!PyArg_Parse(v, "s#", &krec.dptr, &krec.dsize) ) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"gdbm mappings have string indices only");
|
||||
return -1;
|
||||
}
|
||||
if (dp->di_dbm == NULL) {
|
||||
PyErr_SetString(DbmError,
|
||||
"GDBM object has already been closed");
|
||||
return -1;
|
||||
}
|
||||
dp->di_size = -1;
|
||||
if (w == NULL) {
|
||||
if (gdbm_delete(dp->di_dbm, krec) < 0) {
|
||||
PyErr_SetString(PyExc_KeyError,
|
||||
PyString_AS_STRING((PyStringObject *)v));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!PyArg_Parse(w, "s#", &drec.dptr, &drec.dsize)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"gdbm mappings have string elements only");
|
||||
return -1;
|
||||
}
|
||||
errno = 0;
|
||||
if (gdbm_store(dp->di_dbm, krec, drec, GDBM_REPLACE) < 0) {
|
||||
if (errno != 0)
|
||||
PyErr_SetFromErrno(DbmError);
|
||||
else
|
||||
PyErr_SetString(DbmError,
|
||||
gdbm_strerror(gdbm_errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dbm_contains(register dbmobject *dp, PyObject *arg)
|
||||
{
|
||||
datum key;
|
||||
|
||||
if ((dp)->di_dbm == NULL) {
|
||||
PyErr_SetString(DbmError,
|
||||
"GDBM object has already been closed");
|
||||
return -1;
|
||||
}
|
||||
if (!PyString_Check(arg)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"gdbm key must be string, not %.100s",
|
||||
arg->ob_type->tp_name);
|
||||
return -1;
|
||||
}
|
||||
key.dptr = PyString_AS_STRING(arg);
|
||||
key.dsize = PyString_GET_SIZE(arg);
|
||||
return gdbm_exists(dp->di_dbm, key);
|
||||
}
|
||||
|
||||
static PySequenceMethods dbm_as_sequence = {
|
||||
(lenfunc)dbm_length, /*_length*/
|
||||
0, /*sq_concat*/
|
||||
0, /*sq_repeat*/
|
||||
0, /*sq_item*/
|
||||
0, /*sq_slice*/
|
||||
0, /*sq_ass_item*/
|
||||
0, /*sq_ass_slice*/
|
||||
(objobjproc)dbm_contains, /*sq_contains*/
|
||||
0, /*sq_inplace_concat*/
|
||||
0 /*sq_inplace_repeat*/
|
||||
};
|
||||
|
||||
static PyMappingMethods dbm_as_mapping = {
|
||||
(lenfunc)dbm_length, /*mp_length*/
|
||||
(binaryfunc)dbm_subscript, /*mp_subscript*/
|
||||
(objobjargproc)dbm_ass_sub, /*mp_ass_subscript*/
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(dbm_close__doc__,
|
||||
"close() -> None\n\
|
||||
Closes the database.");
|
||||
|
||||
static PyObject *
|
||||
dbm_close(register dbmobject *dp, PyObject *unused)
|
||||
{
|
||||
if (dp->di_dbm)
|
||||
gdbm_close(dp->di_dbm);
|
||||
dp->di_dbm = NULL;
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(dbm_keys__doc__,
|
||||
"keys() -> list_of_keys\n\
|
||||
Get a list of all keys in the database.");
|
||||
|
||||
static PyObject *
|
||||
dbm_keys(register dbmobject *dp, PyObject *unused)
|
||||
{
|
||||
register PyObject *v, *item;
|
||||
datum key, nextkey;
|
||||
int err;
|
||||
|
||||
if (dp == NULL || !is_dbmobject(dp)) {
|
||||
PyErr_BadInternalCall();
|
||||
return NULL;
|
||||
}
|
||||
check_dbmobject_open(dp);
|
||||
|
||||
v = PyList_New(0);
|
||||
if (v == NULL)
|
||||
return NULL;
|
||||
|
||||
key = gdbm_firstkey(dp->di_dbm);
|
||||
while (key.dptr) {
|
||||
item = PyString_FromStringAndSize(key.dptr, key.dsize);
|
||||
if (item == NULL) {
|
||||
free(key.dptr);
|
||||
Py_DECREF(v);
|
||||
return NULL;
|
||||
}
|
||||
err = PyList_Append(v, item);
|
||||
Py_DECREF(item);
|
||||
if (err != 0) {
|
||||
free(key.dptr);
|
||||
Py_DECREF(v);
|
||||
return NULL;
|
||||
}
|
||||
nextkey = gdbm_nextkey(dp->di_dbm, key);
|
||||
free(key.dptr);
|
||||
key = nextkey;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(dbm_has_key__doc__,
|
||||
"has_key(key) -> boolean\n\
|
||||
Find out whether or not the database contains a given key.");
|
||||
|
||||
static PyObject *
|
||||
dbm_has_key(register dbmobject *dp, PyObject *args)
|
||||
{
|
||||
datum key;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s#:has_key", &key.dptr, &key.dsize))
|
||||
return NULL;
|
||||
check_dbmobject_open(dp);
|
||||
return PyInt_FromLong((long) gdbm_exists(dp->di_dbm, key));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(dbm_firstkey__doc__,
|
||||
"firstkey() -> key\n\
|
||||
It's possible to loop over every key in the database using this method\n\
|
||||
and the nextkey() method. The traversal is ordered by GDBM's internal\n\
|
||||
hash values, and won't be sorted by the key values. This method\n\
|
||||
returns the starting key.");
|
||||
|
||||
static PyObject *
|
||||
dbm_firstkey(register dbmobject *dp, PyObject *unused)
|
||||
{
|
||||
register PyObject *v;
|
||||
datum key;
|
||||
|
||||
check_dbmobject_open(dp);
|
||||
key = gdbm_firstkey(dp->di_dbm);
|
||||
if (key.dptr) {
|
||||
v = PyString_FromStringAndSize(key.dptr, key.dsize);
|
||||
free(key.dptr);
|
||||
return v;
|
||||
}
|
||||
else {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(dbm_nextkey__doc__,
|
||||
"nextkey(key) -> next_key\n\
|
||||
Returns the key that follows key in the traversal.\n\
|
||||
The following code prints every key in the database db, without having\n\
|
||||
to create a list in memory that contains them all:\n\
|
||||
\n\
|
||||
k = db.firstkey()\n\
|
||||
while k != None:\n\
|
||||
print k\n\
|
||||
k = db.nextkey(k)");
|
||||
|
||||
static PyObject *
|
||||
dbm_nextkey(register dbmobject *dp, PyObject *args)
|
||||
{
|
||||
register PyObject *v;
|
||||
datum key, nextkey;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s#:nextkey", &key.dptr, &key.dsize))
|
||||
return NULL;
|
||||
check_dbmobject_open(dp);
|
||||
nextkey = gdbm_nextkey(dp->di_dbm, key);
|
||||
if (nextkey.dptr) {
|
||||
v = PyString_FromStringAndSize(nextkey.dptr, nextkey.dsize);
|
||||
free(nextkey.dptr);
|
||||
return v;
|
||||
}
|
||||
else {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(dbm_reorganize__doc__,
|
||||
"reorganize() -> None\n\
|
||||
If you have carried out a lot of deletions and would like to shrink\n\
|
||||
the space used by the GDBM file, this routine will reorganize the\n\
|
||||
database. GDBM will not shorten the length of a database file except\n\
|
||||
by using this reorganization; otherwise, deleted file space will be\n\
|
||||
kept and reused as new (key,value) pairs are added.");
|
||||
|
||||
static PyObject *
|
||||
dbm_reorganize(register dbmobject *dp, PyObject *unused)
|
||||
{
|
||||
check_dbmobject_open(dp);
|
||||
errno = 0;
|
||||
if (gdbm_reorganize(dp->di_dbm) < 0) {
|
||||
if (errno != 0)
|
||||
PyErr_SetFromErrno(DbmError);
|
||||
else
|
||||
PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(dbm_sync__doc__,
|
||||
"sync() -> None\n\
|
||||
When the database has been opened in fast mode, this method forces\n\
|
||||
any unwritten data to be written to the disk.");
|
||||
|
||||
static PyObject *
|
||||
dbm_sync(register dbmobject *dp, PyObject *unused)
|
||||
{
|
||||
check_dbmobject_open(dp);
|
||||
gdbm_sync(dp->di_dbm);
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyMethodDef dbm_methods[] = {
|
||||
{"close", (PyCFunction)dbm_close, METH_NOARGS, dbm_close__doc__},
|
||||
{"keys", (PyCFunction)dbm_keys, METH_NOARGS, dbm_keys__doc__},
|
||||
{"has_key", (PyCFunction)dbm_has_key, METH_VARARGS, dbm_has_key__doc__},
|
||||
{"firstkey", (PyCFunction)dbm_firstkey,METH_NOARGS, dbm_firstkey__doc__},
|
||||
{"nextkey", (PyCFunction)dbm_nextkey, METH_VARARGS, dbm_nextkey__doc__},
|
||||
{"reorganize",(PyCFunction)dbm_reorganize,METH_NOARGS, dbm_reorganize__doc__},
|
||||
{"sync", (PyCFunction)dbm_sync, METH_NOARGS, dbm_sync__doc__},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
dbm_getattr(dbmobject *dp, char *name)
|
||||
{
|
||||
return Py_FindMethod(dbm_methods, (PyObject *)dp, name);
|
||||
}
|
||||
|
||||
static PyTypeObject Dbmtype = {
|
||||
PyVarObject_HEAD_INIT(0, 0)
|
||||
"gdbm.gdbm",
|
||||
sizeof(dbmobject),
|
||||
0,
|
||||
(destructor)dbm_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
(getattrfunc)dbm_getattr, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
0, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
&dbm_as_sequence, /*tp_as_sequence*/
|
||||
&dbm_as_mapping, /*tp_as_mapping*/
|
||||
0, /*tp_hash*/
|
||||
0, /*tp_call*/
|
||||
0, /*tp_str*/
|
||||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT, /*tp_xxx4*/
|
||||
gdbm_object__doc__, /*tp_doc*/
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
|
||||
PyDoc_STRVAR(dbmopen__doc__,
|
||||
"open(filename, [flags, [mode]]) -> dbm_object\n\
|
||||
Open a dbm database and return a dbm object. The filename argument is\n\
|
||||
the name of the database file.\n\
|
||||
\n\
|
||||
The optional flags argument can be 'r' (to open an existing database\n\
|
||||
for reading only -- default), 'w' (to open an existing database for\n\
|
||||
reading and writing), 'c' (which creates the database if it doesn't\n\
|
||||
exist), or 'n' (which always creates a new empty database).\n\
|
||||
\n\
|
||||
Some versions of gdbm support additional flags which must be\n\
|
||||
appended to one of the flags described above. The module constant\n\
|
||||
'open_flags' is a string of valid additional flags. The 'f' flag\n\
|
||||
opens the database in fast mode; altered data will not automatically\n\
|
||||
be written to the disk after every change. This results in faster\n\
|
||||
writes to the database, but may result in an inconsistent database\n\
|
||||
if the program crashes while the database is still open. Use the\n\
|
||||
sync() method to force any unwritten data to be written to the disk.\n\
|
||||
The 's' flag causes all database operations to be synchronized to\n\
|
||||
disk. The 'u' flag disables locking of the database file.\n\
|
||||
\n\
|
||||
The optional mode argument is the Unix mode of the file, used only\n\
|
||||
when the database has to be created. It defaults to octal 0666. ");
|
||||
|
||||
static PyObject *
|
||||
dbmopen(PyObject *self, PyObject *args)
|
||||
{
|
||||
char *name;
|
||||
char *flags = "r";
|
||||
int iflags;
|
||||
int mode = 0666;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s|si:open", &name, &flags, &mode))
|
||||
return NULL;
|
||||
switch (flags[0]) {
|
||||
case 'r':
|
||||
iflags = GDBM_READER;
|
||||
break;
|
||||
case 'w':
|
||||
iflags = GDBM_WRITER;
|
||||
break;
|
||||
case 'c':
|
||||
iflags = GDBM_WRCREAT;
|
||||
break;
|
||||
case 'n':
|
||||
iflags = GDBM_NEWDB;
|
||||
break;
|
||||
default:
|
||||
PyErr_SetString(DbmError,
|
||||
"First flag must be one of 'r', 'w', 'c' or 'n'");
|
||||
return NULL;
|
||||
}
|
||||
for (flags++; *flags != '\0'; flags++) {
|
||||
char buf[40];
|
||||
switch (*flags) {
|
||||
#ifdef GDBM_FAST
|
||||
case 'f':
|
||||
iflags |= GDBM_FAST;
|
||||
break;
|
||||
#endif
|
||||
#ifdef GDBM_SYNC
|
||||
case 's':
|
||||
iflags |= GDBM_SYNC;
|
||||
break;
|
||||
#endif
|
||||
#ifdef GDBM_NOLOCK
|
||||
case 'u':
|
||||
iflags |= GDBM_NOLOCK;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
PyOS_snprintf(buf, sizeof(buf), "Flag '%c' is not supported.",
|
||||
*flags);
|
||||
PyErr_SetString(DbmError, buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return newdbmobject(name, iflags, mode);
|
||||
}
|
||||
|
||||
static char dbmmodule_open_flags[] = "rwcn"
|
||||
#ifdef GDBM_FAST
|
||||
"f"
|
||||
#endif
|
||||
#ifdef GDBM_SYNC
|
||||
"s"
|
||||
#endif
|
||||
#ifdef GDBM_NOLOCK
|
||||
"u"
|
||||
#endif
|
||||
;
|
||||
|
||||
static PyMethodDef dbmmodule_methods[] = {
|
||||
{ "open", (PyCFunction)dbmopen, METH_VARARGS, dbmopen__doc__},
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC
|
||||
initgdbm(void) {
|
||||
PyObject *m, *d, *s;
|
||||
|
||||
Dbmtype.ob_type = &PyType_Type;
|
||||
m = Py_InitModule4("gdbm", dbmmodule_methods,
|
||||
gdbmmodule__doc__, (PyObject *)NULL,
|
||||
PYTHON_API_VERSION);
|
||||
if (m == NULL)
|
||||
return;
|
||||
d = PyModule_GetDict(m);
|
||||
DbmError = PyErr_NewException("gdbm.error", NULL, NULL);
|
||||
if (DbmError != NULL) {
|
||||
PyDict_SetItemString(d, "error", DbmError);
|
||||
s = PyString_FromString(dbmmodule_open_flags);
|
||||
PyDict_SetItemString(d, "open_flags", s);
|
||||
Py_DECREF(s);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,638 @@
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. Neither the name of the project 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 PROJECT 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 PROJECT 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
|
||||
*
|
||||
* Issues to be discussed:
|
||||
* - Thread safe-ness must be checked.
|
||||
* - Return values. There are nonstandard return values defined and used
|
||||
* in the source code. This is because RFC2133 is silent about which error
|
||||
* code must be returned for which situation.
|
||||
* - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <arpa/nameser.h>
|
||||
#include <netdb.h>
|
||||
#include <resolv.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "addrinfo.h"
|
||||
#endif
|
||||
|
||||
#if defined(__KAME__) && defined(ENABLE_IPV6)
|
||||
# define FAITH
|
||||
#endif
|
||||
|
||||
#define SUCCESS 0
|
||||
#define GAI_ANY 0
|
||||
#define YES 1
|
||||
#define NO 0
|
||||
|
||||
#ifdef FAITH
|
||||
static int translate = NO;
|
||||
static struct in6_addr faith_prefix = IN6ADDR_GAI_ANY_INIT;
|
||||
#endif
|
||||
|
||||
static const char in_addrany[] = { 0, 0, 0, 0 };
|
||||
static const char in6_addrany[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
static const char in_loopback[] = { 127, 0, 0, 1 };
|
||||
static const char in6_loopback[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
|
||||
};
|
||||
|
||||
struct sockinet {
|
||||
u_char si_len;
|
||||
u_char si_family;
|
||||
u_short si_port;
|
||||
};
|
||||
|
||||
static struct gai_afd {
|
||||
int a_af;
|
||||
int a_addrlen;
|
||||
int a_socklen;
|
||||
int a_off;
|
||||
const char *a_addrany;
|
||||
const char *a_loopback;
|
||||
} gai_afdl [] = {
|
||||
#ifdef ENABLE_IPV6
|
||||
#define N_INET6 0
|
||||
{PF_INET6, sizeof(struct in6_addr),
|
||||
sizeof(struct sockaddr_in6),
|
||||
offsetof(struct sockaddr_in6, sin6_addr),
|
||||
in6_addrany, in6_loopback},
|
||||
#define N_INET 1
|
||||
#else
|
||||
#define N_INET 0
|
||||
#endif
|
||||
{PF_INET, sizeof(struct in_addr),
|
||||
sizeof(struct sockaddr_in),
|
||||
offsetof(struct sockaddr_in, sin_addr),
|
||||
in_addrany, in_loopback},
|
||||
{0, 0, 0, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
#define PTON_MAX 16
|
||||
#else
|
||||
#define PTON_MAX 4
|
||||
#endif
|
||||
|
||||
#ifndef IN_MULTICAST
|
||||
#define IN_MULTICAST(i) (((i) & 0xf0000000U) == 0xe0000000U)
|
||||
#endif
|
||||
|
||||
#ifndef IN_EXPERIMENTAL
|
||||
#define IN_EXPERIMENTAL(i) (((i) & 0xe0000000U) == 0xe0000000U)
|
||||
#endif
|
||||
|
||||
#ifndef IN_LOOPBACKNET
|
||||
#define IN_LOOPBACKNET 127
|
||||
#endif
|
||||
|
||||
static int get_name Py_PROTO((const char *, struct gai_afd *,
|
||||
struct addrinfo **, char *, struct addrinfo *,
|
||||
int));
|
||||
static int get_addr Py_PROTO((const char *, int, struct addrinfo **,
|
||||
struct addrinfo *, int));
|
||||
static int str_isnumber Py_PROTO((const char *));
|
||||
|
||||
static char *ai_errlist[] = {
|
||||
"success.",
|
||||
"address family for hostname not supported.", /* EAI_ADDRFAMILY */
|
||||
"temporary failure in name resolution.", /* EAI_AGAIN */
|
||||
"invalid value for ai_flags.", /* EAI_BADFLAGS */
|
||||
"non-recoverable failure in name resolution.", /* EAI_FAIL */
|
||||
"ai_family not supported.", /* EAI_FAMILY */
|
||||
"memory allocation failure.", /* EAI_MEMORY */
|
||||
"no address associated with hostname.", /* EAI_NODATA */
|
||||
"hostname nor servname provided, or not known.",/* EAI_NONAME */
|
||||
"servname not supported for ai_socktype.", /* EAI_SERVICE */
|
||||
"ai_socktype not supported.", /* EAI_SOCKTYPE */
|
||||
"system error returned in errno.", /* EAI_SYSTEM */
|
||||
"invalid value for hints.", /* EAI_BADHINTS */
|
||||
"resolved protocol is unknown.", /* EAI_PROTOCOL */
|
||||
"unknown error.", /* EAI_MAX */
|
||||
};
|
||||
|
||||
#define GET_CANONNAME(ai, str) \
|
||||
if (pai->ai_flags & AI_CANONNAME) {\
|
||||
if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\
|
||||
strcpy((ai)->ai_canonname, (str));\
|
||||
} else {\
|
||||
error = EAI_MEMORY;\
|
||||
goto free;\
|
||||
}\
|
||||
}
|
||||
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
#define GET_AI(ai, gai_afd, addr, port) {\
|
||||
char *p;\
|
||||
if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
|
||||
((gai_afd)->a_socklen)))\
|
||||
== NULL) goto free;\
|
||||
memcpy(ai, pai, sizeof(struct addrinfo));\
|
||||
(ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
|
||||
memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\
|
||||
(ai)->ai_addr->sa_len = (ai)->ai_addrlen = (gai_afd)->a_socklen;\
|
||||
(ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\
|
||||
((struct sockinet *)(ai)->ai_addr)->si_port = port;\
|
||||
p = (char *)((ai)->ai_addr);\
|
||||
memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\
|
||||
}
|
||||
#else
|
||||
#define GET_AI(ai, gai_afd, addr, port) {\
|
||||
char *p;\
|
||||
if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
|
||||
((gai_afd)->a_socklen)))\
|
||||
== NULL) goto free;\
|
||||
memcpy(ai, pai, sizeof(struct addrinfo));\
|
||||
(ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
|
||||
memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\
|
||||
(ai)->ai_addrlen = (gai_afd)->a_socklen;\
|
||||
(ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\
|
||||
((struct sockinet *)(ai)->ai_addr)->si_port = port;\
|
||||
p = (char *)((ai)->ai_addr);\
|
||||
memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\
|
||||
}
|
||||
#endif
|
||||
|
||||
#define ERR(err) { error = (err); goto bad; }
|
||||
|
||||
char *
|
||||
gai_strerror(int ecode)
|
||||
{
|
||||
if (ecode < 0 || ecode > EAI_MAX)
|
||||
ecode = EAI_MAX;
|
||||
return ai_errlist[ecode];
|
||||
}
|
||||
|
||||
void
|
||||
freeaddrinfo(struct addrinfo *ai)
|
||||
{
|
||||
struct addrinfo *next;
|
||||
|
||||
do {
|
||||
next = ai->ai_next;
|
||||
if (ai->ai_canonname)
|
||||
free(ai->ai_canonname);
|
||||
/* no need to free(ai->ai_addr) */
|
||||
free(ai);
|
||||
} while ((ai = next) != NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
str_isnumber(const char *p)
|
||||
{
|
||||
unsigned char *q = (unsigned char *)p;
|
||||
while (*q) {
|
||||
if (! isdigit(*q))
|
||||
return NO;
|
||||
q++;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
int
|
||||
getaddrinfo(const char*hostname, const char*servname,
|
||||
const struct addrinfo *hints, struct addrinfo **res)
|
||||
{
|
||||
struct addrinfo sentinel;
|
||||
struct addrinfo *top = NULL;
|
||||
struct addrinfo *cur;
|
||||
int i, error = 0;
|
||||
char pton[PTON_MAX];
|
||||
struct addrinfo ai;
|
||||
struct addrinfo *pai;
|
||||
u_short port;
|
||||
|
||||
#ifdef FAITH
|
||||
static int firsttime = 1;
|
||||
|
||||
if (firsttime) {
|
||||
/* translator hack */
|
||||
{
|
||||
char *q = getenv("GAI");
|
||||
if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1)
|
||||
translate = YES;
|
||||
}
|
||||
firsttime = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* initialize file static vars */
|
||||
sentinel.ai_next = NULL;
|
||||
cur = &sentinel;
|
||||
pai = &ai;
|
||||
pai->ai_flags = 0;
|
||||
pai->ai_family = PF_UNSPEC;
|
||||
pai->ai_socktype = GAI_ANY;
|
||||
pai->ai_protocol = GAI_ANY;
|
||||
pai->ai_addrlen = 0;
|
||||
pai->ai_canonname = NULL;
|
||||
pai->ai_addr = NULL;
|
||||
pai->ai_next = NULL;
|
||||
port = GAI_ANY;
|
||||
|
||||
if (hostname == NULL && servname == NULL)
|
||||
return EAI_NONAME;
|
||||
if (hints) {
|
||||
/* error check for hints */
|
||||
if (hints->ai_addrlen || hints->ai_canonname ||
|
||||
hints->ai_addr || hints->ai_next)
|
||||
ERR(EAI_BADHINTS); /* xxx */
|
||||
if (hints->ai_flags & ~AI_MASK)
|
||||
ERR(EAI_BADFLAGS);
|
||||
switch (hints->ai_family) {
|
||||
case PF_UNSPEC:
|
||||
case PF_INET:
|
||||
#ifdef ENABLE_IPV6
|
||||
case PF_INET6:
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
ERR(EAI_FAMILY);
|
||||
}
|
||||
memcpy(pai, hints, sizeof(*pai));
|
||||
switch (pai->ai_socktype) {
|
||||
case GAI_ANY:
|
||||
switch (pai->ai_protocol) {
|
||||
case GAI_ANY:
|
||||
break;
|
||||
case IPPROTO_UDP:
|
||||
pai->ai_socktype = SOCK_DGRAM;
|
||||
break;
|
||||
case IPPROTO_TCP:
|
||||
pai->ai_socktype = SOCK_STREAM;
|
||||
break;
|
||||
default:
|
||||
pai->ai_socktype = SOCK_RAW;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SOCK_RAW:
|
||||
break;
|
||||
case SOCK_DGRAM:
|
||||
if (pai->ai_protocol != IPPROTO_UDP &&
|
||||
pai->ai_protocol != GAI_ANY)
|
||||
ERR(EAI_BADHINTS); /*xxx*/
|
||||
pai->ai_protocol = IPPROTO_UDP;
|
||||
break;
|
||||
case SOCK_STREAM:
|
||||
if (pai->ai_protocol != IPPROTO_TCP &&
|
||||
pai->ai_protocol != GAI_ANY)
|
||||
ERR(EAI_BADHINTS); /*xxx*/
|
||||
pai->ai_protocol = IPPROTO_TCP;
|
||||
break;
|
||||
default:
|
||||
ERR(EAI_SOCKTYPE);
|
||||
/* unreachable */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* service port
|
||||
*/
|
||||
if (servname) {
|
||||
if (str_isnumber(servname)) {
|
||||
if (pai->ai_socktype == GAI_ANY) {
|
||||
/* caller accept *GAI_ANY* socktype */
|
||||
pai->ai_socktype = SOCK_DGRAM;
|
||||
pai->ai_protocol = IPPROTO_UDP;
|
||||
}
|
||||
port = htons((u_short)atoi(servname));
|
||||
} else {
|
||||
struct servent *sp;
|
||||
char *proto;
|
||||
|
||||
proto = NULL;
|
||||
switch (pai->ai_socktype) {
|
||||
case GAI_ANY:
|
||||
proto = NULL;
|
||||
break;
|
||||
case SOCK_DGRAM:
|
||||
proto = "udp";
|
||||
break;
|
||||
case SOCK_STREAM:
|
||||
proto = "tcp";
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "panic!\n");
|
||||
break;
|
||||
}
|
||||
if ((sp = getservbyname(servname, proto)) == NULL)
|
||||
ERR(EAI_SERVICE);
|
||||
port = sp->s_port;
|
||||
if (pai->ai_socktype == GAI_ANY) {
|
||||
if (strcmp(sp->s_proto, "udp") == 0) {
|
||||
pai->ai_socktype = SOCK_DGRAM;
|
||||
pai->ai_protocol = IPPROTO_UDP;
|
||||
} else if (strcmp(sp->s_proto, "tcp") == 0) {
|
||||
pai->ai_socktype = SOCK_STREAM;
|
||||
pai->ai_protocol = IPPROTO_TCP;
|
||||
} else
|
||||
ERR(EAI_PROTOCOL); /*xxx*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* hostname == NULL.
|
||||
* passive socket -> anyaddr (0.0.0.0 or ::)
|
||||
* non-passive socket -> localhost (127.0.0.1 or ::1)
|
||||
*/
|
||||
if (hostname == NULL) {
|
||||
struct gai_afd *gai_afd;
|
||||
|
||||
for (gai_afd = &gai_afdl[0]; gai_afd->a_af; gai_afd++) {
|
||||
if (!(pai->ai_family == PF_UNSPEC
|
||||
|| pai->ai_family == gai_afd->a_af)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pai->ai_flags & AI_PASSIVE) {
|
||||
GET_AI(cur->ai_next, gai_afd, gai_afd->a_addrany, port);
|
||||
/* xxx meaningless?
|
||||
* GET_CANONNAME(cur->ai_next, "anyaddr");
|
||||
*/
|
||||
} else {
|
||||
GET_AI(cur->ai_next, gai_afd, gai_afd->a_loopback,
|
||||
port);
|
||||
/* xxx meaningless?
|
||||
* GET_CANONNAME(cur->ai_next, "localhost");
|
||||
*/
|
||||
}
|
||||
cur = cur->ai_next;
|
||||
}
|
||||
top = sentinel.ai_next;
|
||||
if (top)
|
||||
goto good;
|
||||
else
|
||||
ERR(EAI_FAMILY);
|
||||
}
|
||||
|
||||
/* hostname as numeric name */
|
||||
for (i = 0; gai_afdl[i].a_af; i++) {
|
||||
if (inet_pton(gai_afdl[i].a_af, hostname, pton)) {
|
||||
u_long v4a;
|
||||
#ifdef ENABLE_IPV6
|
||||
u_char pfx;
|
||||
#endif
|
||||
|
||||
switch (gai_afdl[i].a_af) {
|
||||
case AF_INET:
|
||||
v4a = ((struct in_addr *)pton)->s_addr;
|
||||
v4a = ntohl(v4a);
|
||||
if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
|
||||
pai->ai_flags &= ~AI_CANONNAME;
|
||||
v4a >>= IN_CLASSA_NSHIFT;
|
||||
if (v4a == 0 || v4a == IN_LOOPBACKNET)
|
||||
pai->ai_flags &= ~AI_CANONNAME;
|
||||
break;
|
||||
#ifdef ENABLE_IPV6
|
||||
case AF_INET6:
|
||||
pfx = ((struct in6_addr *)pton)->s6_addr[0];
|
||||
if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
|
||||
pai->ai_flags &= ~AI_CANONNAME;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (pai->ai_family == gai_afdl[i].a_af ||
|
||||
pai->ai_family == PF_UNSPEC) {
|
||||
if (! (pai->ai_flags & AI_CANONNAME)) {
|
||||
GET_AI(top, &gai_afdl[i], pton, port);
|
||||
goto good;
|
||||
}
|
||||
/*
|
||||
* if AI_CANONNAME and if reverse lookup
|
||||
* fail, return ai anyway to pacify
|
||||
* calling application.
|
||||
*
|
||||
* XXX getaddrinfo() is a name->address
|
||||
* translation function, and it looks strange
|
||||
* that we do addr->name translation here.
|
||||
*/
|
||||
get_name(pton, &gai_afdl[i], &top, pton, pai, port);
|
||||
goto good;
|
||||
} else
|
||||
ERR(EAI_FAMILY); /*xxx*/
|
||||
}
|
||||
}
|
||||
|
||||
if (pai->ai_flags & AI_NUMERICHOST)
|
||||
ERR(EAI_NONAME);
|
||||
|
||||
/* hostname as alphabetical name */
|
||||
error = get_addr(hostname, pai->ai_family, &top, pai, port);
|
||||
if (error == 0) {
|
||||
if (top) {
|
||||
good:
|
||||
*res = top;
|
||||
return SUCCESS;
|
||||
} else
|
||||
error = EAI_FAIL;
|
||||
}
|
||||
free:
|
||||
if (top)
|
||||
freeaddrinfo(top);
|
||||
bad:
|
||||
*res = NULL;
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
get_name(addr, gai_afd, res, numaddr, pai, port0)
|
||||
const char *addr;
|
||||
struct gai_afd *gai_afd;
|
||||
struct addrinfo **res;
|
||||
char *numaddr;
|
||||
struct addrinfo *pai;
|
||||
int port0;
|
||||
{
|
||||
u_short port = port0 & 0xffff;
|
||||
struct hostent *hp;
|
||||
struct addrinfo *cur;
|
||||
int error = 0;
|
||||
#ifdef ENABLE_IPV6
|
||||
int h_error;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
hp = getipnodebyaddr(addr, gai_afd->a_addrlen, gai_afd->a_af, &h_error);
|
||||
#else
|
||||
hp = gethostbyaddr(addr, gai_afd->a_addrlen, AF_INET);
|
||||
#endif
|
||||
if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
|
||||
GET_AI(cur, gai_afd, hp->h_addr_list[0], port);
|
||||
GET_CANONNAME(cur, hp->h_name);
|
||||
} else
|
||||
GET_AI(cur, gai_afd, numaddr, port);
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
if (hp)
|
||||
freehostent(hp);
|
||||
#endif
|
||||
*res = cur;
|
||||
return SUCCESS;
|
||||
free:
|
||||
if (cur)
|
||||
freeaddrinfo(cur);
|
||||
#ifdef ENABLE_IPV6
|
||||
if (hp)
|
||||
freehostent(hp);
|
||||
#endif
|
||||
/* bad: */
|
||||
*res = NULL;
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
get_addr(hostname, af, res, pai, port0)
|
||||
const char *hostname;
|
||||
int af;
|
||||
struct addrinfo **res;
|
||||
struct addrinfo *pai;
|
||||
int port0;
|
||||
{
|
||||
u_short port = port0 & 0xffff;
|
||||
struct addrinfo sentinel;
|
||||
struct hostent *hp;
|
||||
struct addrinfo *top, *cur;
|
||||
struct gai_afd *gai_afd;
|
||||
int i, error = 0, h_error;
|
||||
char *ap;
|
||||
|
||||
top = NULL;
|
||||
sentinel.ai_next = NULL;
|
||||
cur = &sentinel;
|
||||
#ifdef ENABLE_IPV6
|
||||
if (af == AF_UNSPEC) {
|
||||
hp = getipnodebyname(hostname, AF_INET6,
|
||||
AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error);
|
||||
} else
|
||||
hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error);
|
||||
#else
|
||||
hp = gethostbyname(hostname);
|
||||
h_error = h_errno;
|
||||
#endif
|
||||
if (hp == NULL) {
|
||||
switch (h_error) {
|
||||
case HOST_NOT_FOUND:
|
||||
case NO_DATA:
|
||||
error = EAI_NODATA;
|
||||
break;
|
||||
case TRY_AGAIN:
|
||||
error = EAI_AGAIN;
|
||||
break;
|
||||
case NO_RECOVERY:
|
||||
default:
|
||||
error = EAI_FAIL;
|
||||
break;
|
||||
}
|
||||
goto free;
|
||||
}
|
||||
|
||||
if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
|
||||
(hp->h_addr_list[0] == NULL)) {
|
||||
error = EAI_FAIL;
|
||||
goto free;
|
||||
}
|
||||
|
||||
for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) {
|
||||
switch (af) {
|
||||
#ifdef ENABLE_IPV6
|
||||
case AF_INET6:
|
||||
gai_afd = &gai_afdl[N_INET6];
|
||||
break;
|
||||
#endif
|
||||
#ifndef ENABLE_IPV6
|
||||
default: /* AF_UNSPEC */
|
||||
#endif
|
||||
case AF_INET:
|
||||
gai_afd = &gai_afdl[N_INET];
|
||||
break;
|
||||
#ifdef ENABLE_IPV6
|
||||
default: /* AF_UNSPEC */
|
||||
if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
|
||||
ap += sizeof(struct in6_addr) -
|
||||
sizeof(struct in_addr);
|
||||
gai_afd = &gai_afdl[N_INET];
|
||||
} else
|
||||
gai_afd = &gai_afdl[N_INET6];
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
#ifdef FAITH
|
||||
if (translate && gai_afd->a_af == AF_INET) {
|
||||
struct in6_addr *in6;
|
||||
|
||||
GET_AI(cur->ai_next, &gai_afdl[N_INET6], ap, port);
|
||||
in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr;
|
||||
memcpy(&in6->s6_addr32[0], &faith_prefix,
|
||||
sizeof(struct in6_addr) - sizeof(struct in_addr));
|
||||
memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr));
|
||||
} else
|
||||
#endif /* FAITH */
|
||||
GET_AI(cur->ai_next, gai_afd, ap, port);
|
||||
if (cur == &sentinel) {
|
||||
top = cur->ai_next;
|
||||
GET_CANONNAME(top, hp->h_name);
|
||||
}
|
||||
cur = cur->ai_next;
|
||||
}
|
||||
#ifdef ENABLE_IPV6
|
||||
freehostent(hp);
|
||||
#endif
|
||||
*res = top;
|
||||
return SUCCESS;
|
||||
free:
|
||||
if (top)
|
||||
freeaddrinfo(top);
|
||||
#ifdef ENABLE_IPV6
|
||||
if (hp)
|
||||
freehostent(hp);
|
||||
#endif
|
||||
/* bad: */
|
||||
*res = NULL;
|
||||
return error;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
#include "Python.h"
|
||||
|
||||
#ifndef DONT_HAVE_STDIO_H
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#ifndef DATE
|
||||
#ifdef __DATE__
|
||||
#define DATE __DATE__
|
||||
#else
|
||||
#define DATE "xx/xx/xx"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef TIME
|
||||
#ifdef __TIME__
|
||||
#define TIME __TIME__
|
||||
#else
|
||||
#define TIME "xx:xx:xx"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* XXX Only unix build process has been tested */
|
||||
#ifndef GITVERSION
|
||||
#define GITVERSION ""
|
||||
#endif
|
||||
#ifndef GITTAG
|
||||
#define GITTAG ""
|
||||
#endif
|
||||
#ifndef GITBRANCH
|
||||
#define GITBRANCH ""
|
||||
#endif
|
||||
|
||||
const char *
|
||||
Py_GetBuildInfo(void)
|
||||
{
|
||||
static char buildinfo[50 + sizeof(GITVERSION) +
|
||||
((sizeof(GITTAG) > sizeof(GITBRANCH)) ?
|
||||
sizeof(GITTAG) : sizeof(GITBRANCH))];
|
||||
const char *revision = _Py_gitversion();
|
||||
const char *sep = *revision ? ":" : "";
|
||||
const char *gitid = _Py_gitidentifier();
|
||||
if (!(*gitid))
|
||||
gitid = "default";
|
||||
PyOS_snprintf(buildinfo, sizeof(buildinfo),
|
||||
"%s%s%s, %.20s, %.9s", gitid, sep, revision,
|
||||
DATE, TIME);
|
||||
return buildinfo;
|
||||
}
|
||||
|
||||
const char *
|
||||
_Py_gitversion(void)
|
||||
{
|
||||
return GITVERSION;
|
||||
}
|
||||
|
||||
const char *
|
||||
_Py_gitidentifier(void)
|
||||
{
|
||||
const char *gittag, *gitid;
|
||||
gittag = GITTAG;
|
||||
if ((*gittag) && strcmp(gittag, "undefined") != 0)
|
||||
gitid = gittag;
|
||||
else
|
||||
gitid = GITBRANCH;
|
||||
return gitid;
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. Neither the name of the project 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 PROJECT 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 PROJECT 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Issues to be discussed:
|
||||
* - Thread safe-ness must be checked
|
||||
* - Return values. There seems to be no standard for return value (RFC2133)
|
||||
* but INRIA implementation returns EAI_xxx defined for getaddrinfo().
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <arpa/nameser.h>
|
||||
#include <netdb.h>
|
||||
#include <resolv.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "addrinfo.h"
|
||||
#endif
|
||||
|
||||
#define SUCCESS 0
|
||||
#define YES 1
|
||||
#define NO 0
|
||||
|
||||
static struct gni_afd {
|
||||
int a_af;
|
||||
int a_addrlen;
|
||||
int a_socklen;
|
||||
int a_off;
|
||||
} gni_afdl [] = {
|
||||
#ifdef ENABLE_IPV6
|
||||
{PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
|
||||
offsetof(struct sockaddr_in6, sin6_addr)},
|
||||
#endif
|
||||
{PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
|
||||
offsetof(struct sockaddr_in, sin_addr)},
|
||||
{0, 0, 0},
|
||||
};
|
||||
|
||||
struct gni_sockinet {
|
||||
u_char si_len;
|
||||
u_char si_family;
|
||||
u_short si_port;
|
||||
};
|
||||
|
||||
#define ENI_NOSOCKET 0
|
||||
#define ENI_NOSERVNAME 1
|
||||
#define ENI_NOHOSTNAME 2
|
||||
#define ENI_MEMORY 3
|
||||
#define ENI_SYSTEM 4
|
||||
#define ENI_FAMILY 5
|
||||
#define ENI_SALEN 6
|
||||
|
||||
/* forward declaration to make gcc happy */
|
||||
int getnameinfo Py_PROTO((const struct sockaddr *, size_t, char *, size_t,
|
||||
char *, size_t, int));
|
||||
|
||||
int
|
||||
getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
|
||||
const struct sockaddr *sa;
|
||||
size_t salen;
|
||||
char *host;
|
||||
size_t hostlen;
|
||||
char *serv;
|
||||
size_t servlen;
|
||||
int flags;
|
||||
{
|
||||
struct gni_afd *gni_afd;
|
||||
struct servent *sp;
|
||||
struct hostent *hp;
|
||||
u_short port;
|
||||
int family, len, i;
|
||||
char *addr, *p;
|
||||
u_long v4a;
|
||||
#ifdef ENABLE_IPV6
|
||||
u_char pfx;
|
||||
#endif
|
||||
int h_error;
|
||||
char numserv[512];
|
||||
char numaddr[512];
|
||||
|
||||
if (sa == NULL)
|
||||
return ENI_NOSOCKET;
|
||||
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
len = sa->sa_len;
|
||||
if (len != salen) return ENI_SALEN;
|
||||
#else
|
||||
len = salen;
|
||||
#endif
|
||||
|
||||
family = sa->sa_family;
|
||||
for (i = 0; gni_afdl[i].a_af; i++)
|
||||
if (gni_afdl[i].a_af == family) {
|
||||
gni_afd = &gni_afdl[i];
|
||||
goto found;
|
||||
}
|
||||
return ENI_FAMILY;
|
||||
|
||||
found:
|
||||
if (len != gni_afd->a_socklen) return ENI_SALEN;
|
||||
|
||||
port = ((struct gni_sockinet *)sa)->si_port; /* network byte order */
|
||||
addr = (char *)sa + gni_afd->a_off;
|
||||
|
||||
if (serv == NULL || servlen == 0) {
|
||||
/* what we should do? */
|
||||
} else if (flags & NI_NUMERICSERV) {
|
||||
sprintf(numserv, "%d", ntohs(port));
|
||||
if (strlen(numserv) > servlen)
|
||||
return ENI_MEMORY;
|
||||
strcpy(serv, numserv);
|
||||
} else {
|
||||
sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp");
|
||||
if (sp) {
|
||||
if (strlen(sp->s_name) > servlen)
|
||||
return ENI_MEMORY;
|
||||
strcpy(serv, sp->s_name);
|
||||
} else
|
||||
return ENI_NOSERVNAME;
|
||||
}
|
||||
|
||||
switch (sa->sa_family) {
|
||||
case AF_INET:
|
||||
v4a = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
|
||||
if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
|
||||
flags |= NI_NUMERICHOST;
|
||||
v4a >>= IN_CLASSA_NSHIFT;
|
||||
if (v4a == 0 || v4a == IN_LOOPBACKNET)
|
||||
flags |= NI_NUMERICHOST;
|
||||
break;
|
||||
#ifdef ENABLE_IPV6
|
||||
case AF_INET6:
|
||||
pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[0];
|
||||
if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
|
||||
flags |= NI_NUMERICHOST;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
if (host == NULL || hostlen == 0) {
|
||||
/* what should we do? */
|
||||
} else if (flags & NI_NUMERICHOST) {
|
||||
if (inet_ntop(gni_afd->a_af, addr, numaddr, sizeof(numaddr))
|
||||
== NULL)
|
||||
return ENI_SYSTEM;
|
||||
if (strlen(numaddr) > hostlen)
|
||||
return ENI_MEMORY;
|
||||
strcpy(host, numaddr);
|
||||
} else {
|
||||
#ifdef ENABLE_IPV6
|
||||
hp = getipnodebyaddr(addr, gni_afd->a_addrlen, gni_afd->a_af, &h_error);
|
||||
#else
|
||||
hp = gethostbyaddr(addr, gni_afd->a_addrlen, gni_afd->a_af);
|
||||
h_error = h_errno;
|
||||
#endif
|
||||
|
||||
if (hp) {
|
||||
if (flags & NI_NOFQDN) {
|
||||
p = strchr(hp->h_name, '.');
|
||||
if (p) *p = '\0';
|
||||
}
|
||||
if (strlen(hp->h_name) > hostlen) {
|
||||
#ifdef ENABLE_IPV6
|
||||
freehostent(hp);
|
||||
#endif
|
||||
return ENI_MEMORY;
|
||||
}
|
||||
strcpy(host, hp->h_name);
|
||||
#ifdef ENABLE_IPV6
|
||||
freehostent(hp);
|
||||
#endif
|
||||
} else {
|
||||
if (flags & NI_NAMEREQD)
|
||||
return ENI_NOHOSTNAME;
|
||||
if (inet_ntop(gni_afd->a_af, addr, numaddr, sizeof(numaddr))
|
||||
== NULL)
|
||||
return ENI_NOHOSTNAME;
|
||||
if (strlen(numaddr) > hostlen)
|
||||
return ENI_MEMORY;
|
||||
strcpy(host, numaddr);
|
||||
}
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,693 @@
|
||||
/* Return the initial module search path. */
|
||||
|
||||
#include "Python.h"
|
||||
#include "osdefs.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <mach-o/dyld.h>
|
||||
#endif
|
||||
|
||||
/* Search in some common locations for the associated Python libraries.
|
||||
*
|
||||
* Two directories must be found, the platform independent directory
|
||||
* (prefix), containing the common .py and .pyc files, and the platform
|
||||
* dependent directory (exec_prefix), containing the shared library
|
||||
* modules. Note that prefix and exec_prefix can be the same directory,
|
||||
* but for some installations, they are different.
|
||||
*
|
||||
* Py_GetPath() carries out separate searches for prefix and exec_prefix.
|
||||
* Each search tries a number of different locations until a ``landmark''
|
||||
* file or directory is found. If no prefix or exec_prefix is found, a
|
||||
* warning message is issued and the preprocessor defined PREFIX and
|
||||
* EXEC_PREFIX are used (even though they will not work); python carries on
|
||||
* as best as is possible, but most imports will fail.
|
||||
*
|
||||
* Before any searches are done, the location of the executable is
|
||||
* determined. If argv[0] has one or more slashes in it, it is used
|
||||
* unchanged. Otherwise, it must have been invoked from the shell's path,
|
||||
* so we search $PATH for the named executable and use that. If the
|
||||
* executable was not found on $PATH (or there was no $PATH environment
|
||||
* variable), the original argv[0] string is used.
|
||||
*
|
||||
* Next, the executable location is examined to see if it is a symbolic
|
||||
* link. If so, the link is chased (correctly interpreting a relative
|
||||
* pathname if one is found) and the directory of the link target is used.
|
||||
*
|
||||
* Finally, argv0_path is set to the directory containing the executable
|
||||
* (i.e. the last component is stripped).
|
||||
*
|
||||
* With argv0_path in hand, we perform a number of steps. The same steps
|
||||
* are performed for prefix and for exec_prefix, but with a different
|
||||
* landmark.
|
||||
*
|
||||
* Step 1. Are we running python out of the build directory? This is
|
||||
* checked by looking for a different kind of landmark relative to
|
||||
* argv0_path. For prefix, the landmark's path is derived from the VPATH
|
||||
* preprocessor variable (taking into account that its value is almost, but
|
||||
* not quite, what we need). For exec_prefix, the landmark is
|
||||
* Modules/Setup. If the landmark is found, we're done.
|
||||
*
|
||||
* For the remaining steps, the prefix landmark will always be
|
||||
* lib/python$VERSION/os.py and the exec_prefix will always be
|
||||
* lib/python$VERSION/lib-dynload, where $VERSION is Python's version
|
||||
* number as supplied by the Makefile. Note that this means that no more
|
||||
* build directory checking is performed; if the first step did not find
|
||||
* the landmarks, the assumption is that python is running from an
|
||||
* installed setup.
|
||||
*
|
||||
* Step 2. See if the $PYTHONHOME environment variable points to the
|
||||
* installed location of the Python libraries. If $PYTHONHOME is set, then
|
||||
* it points to prefix and exec_prefix. $PYTHONHOME can be a single
|
||||
* directory, which is used for both, or the prefix and exec_prefix
|
||||
* directories separated by a colon.
|
||||
*
|
||||
* Step 3. Try to find prefix and exec_prefix relative to argv0_path,
|
||||
* backtracking up the path until it is exhausted. This is the most common
|
||||
* step to succeed. Note that if prefix and exec_prefix are different,
|
||||
* exec_prefix is more likely to be found; however if exec_prefix is a
|
||||
* subdirectory of prefix, both will be found.
|
||||
*
|
||||
* Step 4. Search the directories pointed to by the preprocessor variables
|
||||
* PREFIX and EXEC_PREFIX. These are supplied by the Makefile but can be
|
||||
* passed in as options to the configure script.
|
||||
*
|
||||
* That's it!
|
||||
*
|
||||
* Well, almost. Once we have determined prefix and exec_prefix, the
|
||||
* preprocessor variable PYTHONPATH is used to construct a path. Each
|
||||
* relative path on PYTHONPATH is prefixed with prefix. Then the directory
|
||||
* containing the shared library modules is appended. The environment
|
||||
* variable $PYTHONPATH is inserted in front of it all. Finally, the
|
||||
* prefix and exec_prefix globals are tweaked so they reflect the values
|
||||
* expected by other code, by stripping the "lib/python$VERSION/..." stuff
|
||||
* off. If either points to the build directory, the globals are reset to
|
||||
* the corresponding preprocessor variables (so sys.prefix will reflect the
|
||||
* installation location, even though sys.path points into the build
|
||||
* directory). This seems to make more sense given that currently the only
|
||||
* known use of sys.prefix and sys.exec_prefix is for the ILU installation
|
||||
* process to find the installed Python tree.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(PREFIX) || !defined(EXEC_PREFIX) || !defined(VERSION) || !defined(VPATH)
|
||||
#error "PREFIX, EXEC_PREFIX, VERSION, and VPATH must be constant defined"
|
||||
#endif
|
||||
|
||||
#ifndef LANDMARK
|
||||
#define LANDMARK "os.py"
|
||||
#endif
|
||||
|
||||
static char prefix[MAXPATHLEN+1];
|
||||
static char exec_prefix[MAXPATHLEN+1];
|
||||
static char progpath[MAXPATHLEN+1];
|
||||
static char *module_search_path = NULL;
|
||||
static char lib_python[] = "lib/python" VERSION;
|
||||
|
||||
static void
|
||||
reduce(char *dir)
|
||||
{
|
||||
size_t i = strlen(dir);
|
||||
while (i > 0 && dir[i] != SEP)
|
||||
--i;
|
||||
dir[i] = '\0';
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
isfile(char *filename) /* Is file, not directory */
|
||||
{
|
||||
struct stat buf;
|
||||
if (stat(filename, &buf) != 0)
|
||||
return 0;
|
||||
if (!S_ISREG(buf.st_mode))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ismodule(char *filename) /* Is module -- check for .pyc/.pyo too */
|
||||
{
|
||||
if (isfile(filename))
|
||||
return 1;
|
||||
|
||||
/* Check for the compiled version of prefix. */
|
||||
if (strlen(filename) < MAXPATHLEN) {
|
||||
strcat(filename, Py_OptimizeFlag ? "o" : "c");
|
||||
if (isfile(filename))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
isxfile(char *filename) /* Is executable file */
|
||||
{
|
||||
struct stat buf;
|
||||
if (stat(filename, &buf) != 0)
|
||||
return 0;
|
||||
if (!S_ISREG(buf.st_mode))
|
||||
return 0;
|
||||
if ((buf.st_mode & 0111) == 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
isdir(char *filename) /* Is directory */
|
||||
{
|
||||
struct stat buf;
|
||||
if (stat(filename, &buf) != 0)
|
||||
return 0;
|
||||
if (!S_ISDIR(buf.st_mode))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Add a path component, by appending stuff to buffer.
|
||||
buffer must have at least MAXPATHLEN + 1 bytes allocated, and contain a
|
||||
NUL-terminated string with no more than MAXPATHLEN characters (not counting
|
||||
the trailing NUL). It's a fatal error if it contains a string longer than
|
||||
that (callers must be careful!). If these requirements are met, it's
|
||||
guaranteed that buffer will still be a NUL-terminated string with no more
|
||||
than MAXPATHLEN characters at exit. If stuff is too long, only as much of
|
||||
stuff as fits will be appended.
|
||||
*/
|
||||
static void
|
||||
joinpath(char *buffer, char *stuff)
|
||||
{
|
||||
size_t n, k;
|
||||
if (stuff[0] == SEP)
|
||||
n = 0;
|
||||
else {
|
||||
n = strlen(buffer);
|
||||
if (n > 0 && buffer[n-1] != SEP && n < MAXPATHLEN)
|
||||
buffer[n++] = SEP;
|
||||
}
|
||||
if (n > MAXPATHLEN)
|
||||
Py_FatalError("buffer overflow in getpath.c's joinpath()");
|
||||
k = strlen(stuff);
|
||||
if (n + k > MAXPATHLEN)
|
||||
k = MAXPATHLEN - n;
|
||||
strncpy(buffer+n, stuff, k);
|
||||
buffer[n+k] = '\0';
|
||||
}
|
||||
|
||||
/* copy_absolute requires that path be allocated at least
|
||||
MAXPATHLEN + 1 bytes and that p be no more than MAXPATHLEN bytes. */
|
||||
static void
|
||||
copy_absolute(char *path, char *p)
|
||||
{
|
||||
if (p[0] == SEP)
|
||||
strcpy(path, p);
|
||||
else {
|
||||
if (!getcwd(path, MAXPATHLEN)) {
|
||||
/* unable to get the current directory */
|
||||
strcpy(path, p);
|
||||
return;
|
||||
}
|
||||
if (p[0] == '.' && p[1] == SEP)
|
||||
p += 2;
|
||||
joinpath(path, p);
|
||||
}
|
||||
}
|
||||
|
||||
/* absolutize() requires that path be allocated at least MAXPATHLEN+1 bytes. */
|
||||
static void
|
||||
absolutize(char *path)
|
||||
{
|
||||
char buffer[MAXPATHLEN + 1];
|
||||
|
||||
if (path[0] == SEP)
|
||||
return;
|
||||
copy_absolute(buffer, path);
|
||||
strcpy(path, buffer);
|
||||
}
|
||||
|
||||
/* search_for_prefix requires that argv0_path be no more than MAXPATHLEN
|
||||
bytes long.
|
||||
*/
|
||||
static int
|
||||
search_for_prefix(char *argv0_path, char *home)
|
||||
{
|
||||
size_t n;
|
||||
char *vpath;
|
||||
|
||||
/* If PYTHONHOME is set, we believe it unconditionally */
|
||||
if (home) {
|
||||
char *delim;
|
||||
strncpy(prefix, home, MAXPATHLEN);
|
||||
delim = strchr(prefix, DELIM);
|
||||
if (delim)
|
||||
*delim = '\0';
|
||||
joinpath(prefix, lib_python);
|
||||
joinpath(prefix, LANDMARK);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check to see if argv[0] is in the build directory */
|
||||
strcpy(prefix, argv0_path);
|
||||
joinpath(prefix, "Modules/Setup");
|
||||
if (isfile(prefix)) {
|
||||
/* Check VPATH to see if argv0_path is in the build directory. */
|
||||
vpath = VPATH;
|
||||
strcpy(prefix, argv0_path);
|
||||
joinpath(prefix, vpath);
|
||||
joinpath(prefix, "Lib");
|
||||
joinpath(prefix, LANDMARK);
|
||||
if (ismodule(prefix))
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Search from argv0_path, until root is found */
|
||||
copy_absolute(prefix, argv0_path);
|
||||
do {
|
||||
n = strlen(prefix);
|
||||
joinpath(prefix, lib_python);
|
||||
joinpath(prefix, LANDMARK);
|
||||
if (ismodule(prefix))
|
||||
return 1;
|
||||
prefix[n] = '\0';
|
||||
reduce(prefix);
|
||||
} while (prefix[0]);
|
||||
|
||||
/* Look at configure's PREFIX */
|
||||
strncpy(prefix, PREFIX, MAXPATHLEN);
|
||||
joinpath(prefix, lib_python);
|
||||
joinpath(prefix, LANDMARK);
|
||||
if (ismodule(prefix))
|
||||
return 1;
|
||||
|
||||
/* Fail */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* search_for_exec_prefix requires that argv0_path be no more than
|
||||
MAXPATHLEN bytes long.
|
||||
*/
|
||||
static int
|
||||
search_for_exec_prefix(char *argv0_path, char *home)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
/* If PYTHONHOME is set, we believe it unconditionally */
|
||||
if (home) {
|
||||
char *delim;
|
||||
delim = strchr(home, DELIM);
|
||||
if (delim)
|
||||
strncpy(exec_prefix, delim+1, MAXPATHLEN);
|
||||
else
|
||||
strncpy(exec_prefix, home, MAXPATHLEN);
|
||||
joinpath(exec_prefix, lib_python);
|
||||
joinpath(exec_prefix, "lib-dynload");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check to see if argv[0] is in the build directory. "pybuilddir.txt"
|
||||
is written by setup.py and contains the relative path to the location
|
||||
of shared library modules. */
|
||||
strcpy(exec_prefix, argv0_path);
|
||||
joinpath(exec_prefix, "pybuilddir.txt");
|
||||
if (isfile(exec_prefix)) {
|
||||
FILE *f = fopen(exec_prefix, "r");
|
||||
if (f == NULL)
|
||||
errno = 0;
|
||||
else {
|
||||
char rel_builddir_path[MAXPATHLEN+1];
|
||||
size_t n;
|
||||
n = fread(rel_builddir_path, 1, MAXPATHLEN, f);
|
||||
rel_builddir_path[n] = '\0';
|
||||
fclose(f);
|
||||
strcpy(exec_prefix, argv0_path);
|
||||
joinpath(exec_prefix, rel_builddir_path);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Search from argv0_path, until root is found */
|
||||
copy_absolute(exec_prefix, argv0_path);
|
||||
do {
|
||||
n = strlen(exec_prefix);
|
||||
joinpath(exec_prefix, lib_python);
|
||||
joinpath(exec_prefix, "lib-dynload");
|
||||
if (isdir(exec_prefix))
|
||||
return 1;
|
||||
exec_prefix[n] = '\0';
|
||||
reduce(exec_prefix);
|
||||
} while (exec_prefix[0]);
|
||||
|
||||
/* Look at configure's EXEC_PREFIX */
|
||||
strncpy(exec_prefix, EXEC_PREFIX, MAXPATHLEN);
|
||||
joinpath(exec_prefix, lib_python);
|
||||
joinpath(exec_prefix, "lib-dynload");
|
||||
if (isdir(exec_prefix))
|
||||
return 1;
|
||||
|
||||
/* Fail */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
calculate_path(void)
|
||||
{
|
||||
extern char *Py_GetProgramName(void);
|
||||
|
||||
static char delimiter[2] = {DELIM, '\0'};
|
||||
static char separator[2] = {SEP, '\0'};
|
||||
char *pythonpath = PYTHONPATH;
|
||||
char *rtpypath = Py_GETENV("PYTHONPATH");
|
||||
char *home = Py_GetPythonHome();
|
||||
char *path = getenv("PATH");
|
||||
char *prog = Py_GetProgramName();
|
||||
char argv0_path[MAXPATHLEN+1];
|
||||
char zip_path[MAXPATHLEN+1];
|
||||
int pfound, efound; /* 1 if found; -1 if found build directory */
|
||||
char *buf;
|
||||
size_t bufsz;
|
||||
size_t prefixsz;
|
||||
char *defpath = pythonpath;
|
||||
#ifdef WITH_NEXT_FRAMEWORK
|
||||
NSModule pythonModule;
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
|
||||
uint32_t nsexeclength = MAXPATHLEN;
|
||||
#else
|
||||
unsigned long nsexeclength = MAXPATHLEN;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* If there is no slash in the argv0 path, then we have to
|
||||
* assume python is on the user's $PATH, since there's no
|
||||
* other way to find a directory to start the search from. If
|
||||
* $PATH isn't exported, you lose.
|
||||
*/
|
||||
if (strchr(prog, SEP))
|
||||
strncpy(progpath, prog, MAXPATHLEN);
|
||||
#ifdef __APPLE__
|
||||
/* On Mac OS X, if a script uses an interpreter of the form
|
||||
* "#!/opt/python2.3/bin/python", the kernel only passes "python"
|
||||
* as argv[0], which falls through to the $PATH search below.
|
||||
* If /opt/python2.3/bin isn't in your path, or is near the end,
|
||||
* this algorithm may incorrectly find /usr/bin/python. To work
|
||||
* around this, we can use _NSGetExecutablePath to get a better
|
||||
* hint of what the intended interpreter was, although this
|
||||
* will fail if a relative path was used. but in that case,
|
||||
* absolutize() should help us out below
|
||||
*/
|
||||
else if(0 == _NSGetExecutablePath(progpath, &nsexeclength) && progpath[0] == SEP)
|
||||
;
|
||||
#endif /* __APPLE__ */
|
||||
else if (path) {
|
||||
while (1) {
|
||||
char *delim = strchr(path, DELIM);
|
||||
|
||||
if (delim) {
|
||||
size_t len = delim - path;
|
||||
if (len > MAXPATHLEN)
|
||||
len = MAXPATHLEN;
|
||||
strncpy(progpath, path, len);
|
||||
*(progpath + len) = '\0';
|
||||
}
|
||||
else
|
||||
strncpy(progpath, path, MAXPATHLEN);
|
||||
|
||||
joinpath(progpath, prog);
|
||||
if (isxfile(progpath))
|
||||
break;
|
||||
|
||||
if (!delim) {
|
||||
progpath[0] = '\0';
|
||||
break;
|
||||
}
|
||||
path = delim + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
progpath[0] = '\0';
|
||||
if (progpath[0] != SEP && progpath[0] != '\0')
|
||||
absolutize(progpath);
|
||||
strncpy(argv0_path, progpath, MAXPATHLEN);
|
||||
argv0_path[MAXPATHLEN] = '\0';
|
||||
|
||||
#ifdef WITH_NEXT_FRAMEWORK
|
||||
/* On Mac OS X we have a special case if we're running from a framework.
|
||||
** This is because the python home should be set relative to the library,
|
||||
** which is in the framework, not relative to the executable, which may
|
||||
** be outside of the framework. Except when we're in the build directory...
|
||||
*/
|
||||
pythonModule = NSModuleForSymbol(NSLookupAndBindSymbol("_Py_Initialize"));
|
||||
/* Use dylib functions to find out where the framework was loaded from */
|
||||
buf = (char *)NSLibraryNameForModule(pythonModule);
|
||||
if (buf != NULL) {
|
||||
/* We're in a framework. */
|
||||
/* See if we might be in the build directory. The framework in the
|
||||
** build directory is incomplete, it only has the .dylib and a few
|
||||
** needed symlinks, it doesn't have the Lib directories and such.
|
||||
** If we're running with the framework from the build directory we must
|
||||
** be running the interpreter in the build directory, so we use the
|
||||
** build-directory-specific logic to find Lib and such.
|
||||
*/
|
||||
strncpy(argv0_path, buf, MAXPATHLEN);
|
||||
reduce(argv0_path);
|
||||
joinpath(argv0_path, lib_python);
|
||||
joinpath(argv0_path, LANDMARK);
|
||||
if (!ismodule(argv0_path)) {
|
||||
/* We are in the build directory so use the name of the
|
||||
executable - we know that the absolute path is passed */
|
||||
strncpy(argv0_path, progpath, MAXPATHLEN);
|
||||
}
|
||||
else {
|
||||
/* Use the location of the library as the progpath */
|
||||
strncpy(argv0_path, buf, MAXPATHLEN);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HAVE_READLINK
|
||||
{
|
||||
char tmpbuffer[MAXPATHLEN+1];
|
||||
int linklen = readlink(progpath, tmpbuffer, MAXPATHLEN);
|
||||
while (linklen != -1) {
|
||||
/* It's not null terminated! */
|
||||
tmpbuffer[linklen] = '\0';
|
||||
if (tmpbuffer[0] == SEP)
|
||||
/* tmpbuffer should never be longer than MAXPATHLEN,
|
||||
but extra check does not hurt */
|
||||
strncpy(argv0_path, tmpbuffer, MAXPATHLEN + 1);
|
||||
else {
|
||||
/* Interpret relative to progpath */
|
||||
reduce(argv0_path);
|
||||
joinpath(argv0_path, tmpbuffer);
|
||||
}
|
||||
linklen = readlink(argv0_path, tmpbuffer, MAXPATHLEN);
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_READLINK */
|
||||
|
||||
reduce(argv0_path);
|
||||
/* At this point, argv0_path is guaranteed to be less than
|
||||
MAXPATHLEN bytes long.
|
||||
*/
|
||||
|
||||
if (!(pfound = search_for_prefix(argv0_path, home))) {
|
||||
if (!Py_FrozenFlag)
|
||||
fprintf(stderr,
|
||||
"Could not find platform independent libraries <prefix>\n");
|
||||
strncpy(prefix, PREFIX, MAXPATHLEN);
|
||||
joinpath(prefix, lib_python);
|
||||
}
|
||||
else
|
||||
reduce(prefix);
|
||||
|
||||
strncpy(zip_path, prefix, MAXPATHLEN);
|
||||
zip_path[MAXPATHLEN] = '\0';
|
||||
if (pfound > 0) { /* Use the reduced prefix returned by Py_GetPrefix() */
|
||||
reduce(zip_path);
|
||||
reduce(zip_path);
|
||||
}
|
||||
else
|
||||
strncpy(zip_path, PREFIX, MAXPATHLEN);
|
||||
joinpath(zip_path, "lib/python00.zip");
|
||||
bufsz = strlen(zip_path); /* Replace "00" with version */
|
||||
zip_path[bufsz - 6] = VERSION[0];
|
||||
zip_path[bufsz - 5] = VERSION[2];
|
||||
|
||||
if (!(efound = search_for_exec_prefix(argv0_path, home))) {
|
||||
if (!Py_FrozenFlag)
|
||||
fprintf(stderr,
|
||||
"Could not find platform dependent libraries <exec_prefix>\n");
|
||||
strncpy(exec_prefix, EXEC_PREFIX, MAXPATHLEN);
|
||||
joinpath(exec_prefix, "lib/lib-dynload");
|
||||
}
|
||||
/* If we found EXEC_PREFIX do *not* reduce it! (Yet.) */
|
||||
|
||||
if ((!pfound || !efound) && !Py_FrozenFlag)
|
||||
fprintf(stderr,
|
||||
"Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]\n");
|
||||
|
||||
/* Calculate size of return buffer.
|
||||
*/
|
||||
bufsz = 0;
|
||||
|
||||
if (rtpypath)
|
||||
bufsz += strlen(rtpypath) + 1;
|
||||
|
||||
prefixsz = strlen(prefix) + 1;
|
||||
|
||||
while (1) {
|
||||
char *delim = strchr(defpath, DELIM);
|
||||
|
||||
if (defpath[0] != SEP)
|
||||
/* Paths are relative to prefix */
|
||||
bufsz += prefixsz;
|
||||
|
||||
if (delim)
|
||||
bufsz += delim - defpath + 1;
|
||||
else {
|
||||
bufsz += strlen(defpath) + 1;
|
||||
break;
|
||||
}
|
||||
defpath = delim + 1;
|
||||
}
|
||||
|
||||
bufsz += strlen(zip_path) + 1;
|
||||
bufsz += strlen(exec_prefix) + 1;
|
||||
|
||||
/* This is the only malloc call in this file */
|
||||
buf = (char *)PyMem_Malloc(bufsz);
|
||||
|
||||
if (buf == NULL) {
|
||||
/* We can't exit, so print a warning and limp along */
|
||||
fprintf(stderr, "Not enough memory for dynamic PYTHONPATH.\n");
|
||||
fprintf(stderr, "Using default static PYTHONPATH.\n");
|
||||
module_search_path = PYTHONPATH;
|
||||
}
|
||||
else {
|
||||
/* Run-time value of $PYTHONPATH goes first */
|
||||
if (rtpypath) {
|
||||
strcpy(buf, rtpypath);
|
||||
strcat(buf, delimiter);
|
||||
}
|
||||
else
|
||||
buf[0] = '\0';
|
||||
|
||||
/* Next is the default zip path */
|
||||
strcat(buf, zip_path);
|
||||
strcat(buf, delimiter);
|
||||
|
||||
/* Next goes merge of compile-time $PYTHONPATH with
|
||||
* dynamically located prefix.
|
||||
*/
|
||||
defpath = pythonpath;
|
||||
while (1) {
|
||||
char *delim = strchr(defpath, DELIM);
|
||||
|
||||
if (defpath[0] != SEP) {
|
||||
strcat(buf, prefix);
|
||||
if (prefixsz >= 2 && prefix[prefixsz - 2] != SEP &&
|
||||
defpath[0] != (delim ? DELIM : L'\0')) { /* not empty */
|
||||
strcat(buf, separator);
|
||||
}
|
||||
}
|
||||
|
||||
if (delim) {
|
||||
size_t len = delim - defpath + 1;
|
||||
size_t end = strlen(buf) + len;
|
||||
strncat(buf, defpath, len);
|
||||
*(buf + end) = '\0';
|
||||
}
|
||||
else {
|
||||
strcat(buf, defpath);
|
||||
break;
|
||||
}
|
||||
defpath = delim + 1;
|
||||
}
|
||||
strcat(buf, delimiter);
|
||||
|
||||
/* Finally, on goes the directory for dynamic-load modules */
|
||||
strcat(buf, exec_prefix);
|
||||
|
||||
/* And publish the results */
|
||||
module_search_path = buf;
|
||||
}
|
||||
|
||||
/* Reduce prefix and exec_prefix to their essence,
|
||||
* e.g. /usr/local/lib/python1.5 is reduced to /usr/local.
|
||||
* If we're loading relative to the build directory,
|
||||
* return the compiled-in defaults instead.
|
||||
*/
|
||||
if (pfound > 0) {
|
||||
reduce(prefix);
|
||||
reduce(prefix);
|
||||
/* The prefix is the root directory, but reduce() chopped
|
||||
* off the "/". */
|
||||
if (!prefix[0])
|
||||
strcpy(prefix, separator);
|
||||
}
|
||||
else
|
||||
strncpy(prefix, PREFIX, MAXPATHLEN);
|
||||
|
||||
if (efound > 0) {
|
||||
reduce(exec_prefix);
|
||||
reduce(exec_prefix);
|
||||
reduce(exec_prefix);
|
||||
if (!exec_prefix[0])
|
||||
strcpy(exec_prefix, separator);
|
||||
}
|
||||
else
|
||||
strncpy(exec_prefix, EXEC_PREFIX, MAXPATHLEN);
|
||||
}
|
||||
|
||||
|
||||
/* External interface */
|
||||
|
||||
char *
|
||||
Py_GetPath(void)
|
||||
{
|
||||
if (!module_search_path)
|
||||
calculate_path();
|
||||
return module_search_path;
|
||||
}
|
||||
|
||||
char *
|
||||
Py_GetPrefix(void)
|
||||
{
|
||||
if (!module_search_path)
|
||||
calculate_path();
|
||||
return prefix;
|
||||
}
|
||||
|
||||
char *
|
||||
Py_GetExecPrefix(void)
|
||||
{
|
||||
if (!module_search_path)
|
||||
calculate_path();
|
||||
return exec_prefix;
|
||||
}
|
||||
|
||||
char *
|
||||
Py_GetProgramFullPath(void)
|
||||
{
|
||||
if (!module_search_path)
|
||||
calculate_path();
|
||||
return progpath;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
+7632
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,204 @@
|
||||
|
||||
/* UNIX group file access module */
|
||||
|
||||
#include "Python.h"
|
||||
#include "structseq.h"
|
||||
#include "posixmodule.h"
|
||||
|
||||
#include <grp.h>
|
||||
|
||||
static PyStructSequence_Field struct_group_type_fields[] = {
|
||||
{"gr_name", "group name"},
|
||||
{"gr_passwd", "password"},
|
||||
{"gr_gid", "group id"},
|
||||
{"gr_mem", "group members"},
|
||||
{0}
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(struct_group__doc__,
|
||||
"grp.struct_group: Results from getgr*() routines.\n\n\
|
||||
This object may be accessed either as a tuple of\n\
|
||||
(gr_name,gr_passwd,gr_gid,gr_mem)\n\
|
||||
or via the object attributes as named in the above tuple.\n");
|
||||
|
||||
static PyStructSequence_Desc struct_group_type_desc = {
|
||||
"grp.struct_group",
|
||||
struct_group__doc__,
|
||||
struct_group_type_fields,
|
||||
4,
|
||||
};
|
||||
|
||||
|
||||
static int initialized;
|
||||
static PyTypeObject StructGrpType;
|
||||
|
||||
static PyObject *
|
||||
mkgrent(struct group *p)
|
||||
{
|
||||
int setIndex = 0;
|
||||
PyObject *v = PyStructSequence_New(&StructGrpType), *w;
|
||||
char **member;
|
||||
|
||||
if (v == NULL)
|
||||
return NULL;
|
||||
|
||||
if ((w = PyList_New(0)) == NULL) {
|
||||
Py_DECREF(v);
|
||||
return NULL;
|
||||
}
|
||||
for (member = p->gr_mem; *member != NULL; member++) {
|
||||
PyObject *x = PyString_FromString(*member);
|
||||
if (x == NULL || PyList_Append(w, x) != 0) {
|
||||
Py_XDECREF(x);
|
||||
Py_DECREF(w);
|
||||
Py_DECREF(v);
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(x);
|
||||
}
|
||||
|
||||
#define SET(i,val) PyStructSequence_SET_ITEM(v, i, val)
|
||||
SET(setIndex++, PyString_FromString(p->gr_name));
|
||||
#ifdef __VMS
|
||||
SET(setIndex++, Py_None);
|
||||
Py_INCREF(Py_None);
|
||||
#else
|
||||
if (p->gr_passwd)
|
||||
SET(setIndex++, PyString_FromString(p->gr_passwd));
|
||||
else {
|
||||
SET(setIndex++, Py_None);
|
||||
Py_INCREF(Py_None);
|
||||
}
|
||||
#endif
|
||||
SET(setIndex++, _PyInt_FromGid(p->gr_gid));
|
||||
SET(setIndex++, w);
|
||||
#undef SET
|
||||
|
||||
if (PyErr_Occurred()) {
|
||||
Py_DECREF(v);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
grp_getgrgid(PyObject *self, PyObject *pyo_id)
|
||||
{
|
||||
PyObject *py_int_id;
|
||||
gid_t gid;
|
||||
struct group *p;
|
||||
|
||||
py_int_id = PyNumber_Int(pyo_id);
|
||||
if (!py_int_id)
|
||||
return NULL;
|
||||
if (!_Py_Gid_Converter(py_int_id, &gid)) {
|
||||
Py_DECREF(py_int_id);
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(py_int_id);
|
||||
|
||||
if ((p = getgrgid(gid)) == NULL) {
|
||||
if (gid < 0)
|
||||
PyErr_Format(PyExc_KeyError,
|
||||
"getgrgid(): gid not found: %ld", (long)gid);
|
||||
else
|
||||
PyErr_Format(PyExc_KeyError,
|
||||
"getgrgid(): gid not found: %lu", (unsigned long)gid);
|
||||
return NULL;
|
||||
}
|
||||
return mkgrent(p);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
grp_getgrnam(PyObject *self, PyObject *pyo_name)
|
||||
{
|
||||
PyObject *py_str_name;
|
||||
char *name;
|
||||
struct group *p;
|
||||
|
||||
py_str_name = PyObject_Str(pyo_name);
|
||||
if (!py_str_name)
|
||||
return NULL;
|
||||
name = PyString_AS_STRING(py_str_name);
|
||||
|
||||
if ((p = getgrnam(name)) == NULL) {
|
||||
PyErr_Format(PyExc_KeyError, "getgrnam(): name not found: %s", name);
|
||||
Py_DECREF(py_str_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_DECREF(py_str_name);
|
||||
return mkgrent(p);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
grp_getgrall(PyObject *self, PyObject *ignore)
|
||||
{
|
||||
PyObject *d;
|
||||
struct group *p;
|
||||
|
||||
if ((d = PyList_New(0)) == NULL)
|
||||
return NULL;
|
||||
setgrent();
|
||||
while ((p = getgrent()) != NULL) {
|
||||
PyObject *v = mkgrent(p);
|
||||
if (v == NULL || PyList_Append(d, v) != 0) {
|
||||
Py_XDECREF(v);
|
||||
Py_DECREF(d);
|
||||
endgrent();
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(v);
|
||||
}
|
||||
endgrent();
|
||||
return d;
|
||||
}
|
||||
|
||||
static PyMethodDef grp_methods[] = {
|
||||
{"getgrgid", grp_getgrgid, METH_O,
|
||||
"getgrgid(id) -> (gr_name,gr_passwd,gr_gid,gr_mem)\n\
|
||||
Return the group database entry for the given numeric group ID. If\n\
|
||||
id is not valid, raise KeyError."},
|
||||
{"getgrnam", grp_getgrnam, METH_O,
|
||||
"getgrnam(name) -> (gr_name,gr_passwd,gr_gid,gr_mem)\n\
|
||||
Return the group database entry for the given group name. If\n\
|
||||
name is not valid, raise KeyError."},
|
||||
{"getgrall", grp_getgrall, METH_NOARGS,
|
||||
"getgrall() -> list of tuples\n\
|
||||
Return a list of all available group entries, in arbitrary order.\n\
|
||||
An entry whose name starts with '+' or '-' represents an instruction\n\
|
||||
to use YP/NIS and may not be accessible via getgrnam or getgrgid."},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(grp__doc__,
|
||||
"Access to the Unix group database.\n\
|
||||
\n\
|
||||
Group entries are reported as 4-tuples containing the following fields\n\
|
||||
from the group database, in order:\n\
|
||||
\n\
|
||||
gr_name - name of the group\n\
|
||||
gr_passwd - group password (encrypted); often empty\n\
|
||||
gr_gid - numeric ID of the group\n\
|
||||
gr_mem - list of members\n\
|
||||
\n\
|
||||
The gid is an integer, name and password are strings. (Note that most\n\
|
||||
users are not explicitly listed as members of the groups they are in\n\
|
||||
according to the password database. Check both databases to get\n\
|
||||
complete membership information.)");
|
||||
|
||||
|
||||
PyMODINIT_FUNC
|
||||
initgrp(void)
|
||||
{
|
||||
PyObject *m, *d;
|
||||
m = Py_InitModule3("grp", grp_methods, grp__doc__);
|
||||
if (m == NULL)
|
||||
return;
|
||||
d = PyModule_GetDict(m);
|
||||
if (!initialized)
|
||||
PyStructSequence_InitType(&StructGrpType, &struct_group_type_desc);
|
||||
PyDict_SetItemString(d, "struct_group", (PyObject *) &StructGrpType);
|
||||
initialized = 1;
|
||||
}
|
||||
@@ -0,0 +1,797 @@
|
||||
|
||||
/* imageopmodule - Various operations on pictures */
|
||||
|
||||
#ifdef sun
|
||||
#define signed
|
||||
#endif
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
#if SIZEOF_INT == 4
|
||||
typedef int Py_Int32;
|
||||
typedef unsigned int Py_UInt32;
|
||||
#else
|
||||
#if SIZEOF_LONG == 4
|
||||
typedef long Py_Int32;
|
||||
typedef unsigned long Py_UInt32;
|
||||
#else
|
||||
#error "No 4-byte integral type"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define CHARP(cp, xmax, x, y) ((char *)(cp+y*xmax+x))
|
||||
#define SHORTP(cp, xmax, x, y) ((short *)(cp+2*(y*xmax+x)))
|
||||
#define LONGP(cp, xmax, x, y) ((Py_Int32 *)(cp+4*(y*xmax+x)))
|
||||
|
||||
static PyObject *ImageopError;
|
||||
static PyObject *ImageopDict;
|
||||
|
||||
/**
|
||||
* Check a coordonnate, make sure that (0 < value).
|
||||
* Return 0 on error.
|
||||
*/
|
||||
static int
|
||||
check_coordonnate(int value, const char* name)
|
||||
{
|
||||
if ( 0 < value)
|
||||
return 1;
|
||||
PyErr_Format(PyExc_ValueError, "%s value is negative or nul", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check integer overflow to make sure that product == x*y*size.
|
||||
* Return 0 on error.
|
||||
*/
|
||||
static int
|
||||
check_multiply_size(int product, int x, const char* xname, int y, const char* yname, int size)
|
||||
{
|
||||
if ( !check_coordonnate(x, xname) )
|
||||
return 0;
|
||||
if ( !check_coordonnate(y, yname) )
|
||||
return 0;
|
||||
if ( product % y == 0 ) {
|
||||
product /= y;
|
||||
if ( product % x == 0 && size == product / x )
|
||||
return 1;
|
||||
}
|
||||
PyErr_SetString(ImageopError, "String has incorrect length");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check integer overflow to make sure that product == x*y.
|
||||
* Return 0 on error.
|
||||
*/
|
||||
static int
|
||||
check_multiply(int product, int x, int y)
|
||||
{
|
||||
return check_multiply_size(product, x, "x", y, "y", 1);
|
||||
}
|
||||
|
||||
/* If this function returns true (the default if anything goes wrong), we're
|
||||
behaving in a backward-compatible way with respect to how multi-byte pixels
|
||||
are stored in the strings. The code in this module was originally written
|
||||
for an SGI which is a big-endian system, and so the old code assumed that
|
||||
4-byte integers hold the R, G, and B values in a particular order.
|
||||
However, on little-endian systems the order is reversed, and so not
|
||||
actually compatible with what gl.lrectwrite and imgfile expect.
|
||||
(gl.lrectwrite and imgfile are also SGI-specific, however, it is
|
||||
conceivable that the data handled here comes from or goes to an SGI or that
|
||||
it is otherwise used in the expectation that the byte order in the strings
|
||||
is as specified.)
|
||||
|
||||
The function returns the value of the module variable
|
||||
"backward_compatible", or 1 if the variable does not exist or is not an
|
||||
int.
|
||||
*/
|
||||
|
||||
static int
|
||||
imageop_backward_compatible(void)
|
||||
{
|
||||
static PyObject *bcos;
|
||||
PyObject *bco;
|
||||
long rc;
|
||||
|
||||
if (ImageopDict == NULL) /* "cannot happen" */
|
||||
return 1;
|
||||
if (bcos == NULL) {
|
||||
/* cache string object for future use */
|
||||
bcos = PyString_FromString("backward_compatible");
|
||||
if (bcos == NULL)
|
||||
return 1;
|
||||
}
|
||||
bco = PyDict_GetItem(ImageopDict, bcos);
|
||||
if (bco == NULL)
|
||||
return 1;
|
||||
if (!PyInt_Check(bco))
|
||||
return 1;
|
||||
rc = PyInt_AsLong(bco);
|
||||
if (PyErr_Occurred()) {
|
||||
/* not an integer, or too large, or something */
|
||||
PyErr_Clear();
|
||||
rc = 1;
|
||||
}
|
||||
return rc != 0; /* convert to values 0, 1 */
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
imageop_crop(PyObject *self, PyObject *args)
|
||||
{
|
||||
char *cp, *ncp;
|
||||
short *nsp;
|
||||
Py_Int32 *nlp;
|
||||
int len, size, x, y, newx1, newx2, newy1, newy2, nlen;
|
||||
int ix, iy, xstep, ystep;
|
||||
PyObject *rv;
|
||||
|
||||
if ( !PyArg_ParseTuple(args, "s#iiiiiii", &cp, &len, &size, &x, &y,
|
||||
&newx1, &newy1, &newx2, &newy2) )
|
||||
return 0;
|
||||
|
||||
if ( size != 1 && size != 2 && size != 4 ) {
|
||||
PyErr_SetString(ImageopError, "Size should be 1, 2 or 4");
|
||||
return 0;
|
||||
}
|
||||
if ( !check_multiply_size(len, x, "x", y, "y", size) )
|
||||
return 0;
|
||||
|
||||
xstep = (newx1 < newx2)? 1 : -1;
|
||||
ystep = (newy1 < newy2)? 1 : -1;
|
||||
|
||||
nlen = (abs(newx2-newx1)+1)*(abs(newy2-newy1)+1)*size;
|
||||
if ( !check_multiply_size(nlen, abs(newx2-newx1)+1, "abs(newx2-newx1)+1", abs(newy2-newy1)+1, "abs(newy2-newy1)+1", size) )
|
||||
return 0;
|
||||
rv = PyString_FromStringAndSize(NULL, nlen);
|
||||
if ( rv == 0 )
|
||||
return 0;
|
||||
ncp = (char *)PyString_AsString(rv);
|
||||
nsp = (short *)ncp;
|
||||
nlp = (Py_Int32 *)ncp;
|
||||
newy2 += ystep;
|
||||
newx2 += xstep;
|
||||
for( iy = newy1; iy != newy2; iy+=ystep ) {
|
||||
for ( ix = newx1; ix != newx2; ix+=xstep ) {
|
||||
if ( iy < 0 || iy >= y || ix < 0 || ix >= x ) {
|
||||
if ( size == 1 )
|
||||
*ncp++ = 0;
|
||||
else
|
||||
*nlp++ = 0;
|
||||
} else {
|
||||
if ( size == 1 )
|
||||
*ncp++ = *CHARP(cp, x, ix, iy);
|
||||
else if ( size == 2 )
|
||||
*nsp++ = *SHORTP(cp, x, ix, iy);
|
||||
else
|
||||
*nlp++ = *LONGP(cp, x, ix, iy);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
imageop_scale(PyObject *self, PyObject *args)
|
||||
{
|
||||
char *cp, *ncp;
|
||||
short *nsp;
|
||||
Py_Int32 *nlp;
|
||||
int len, size, x, y, newx, newy, nlen;
|
||||
int ix, iy;
|
||||
int oix, oiy;
|
||||
PyObject *rv;
|
||||
|
||||
if ( !PyArg_ParseTuple(args, "s#iiiii",
|
||||
&cp, &len, &size, &x, &y, &newx, &newy) )
|
||||
return 0;
|
||||
|
||||
if ( size != 1 && size != 2 && size != 4 ) {
|
||||
PyErr_SetString(ImageopError, "Size should be 1, 2 or 4");
|
||||
return 0;
|
||||
}
|
||||
if ( !check_multiply_size(len, x, "x", y, "y", size) )
|
||||
return 0;
|
||||
nlen = newx*newy*size;
|
||||
if ( !check_multiply_size(nlen, newx, "newx", newy, "newy", size) )
|
||||
return 0;
|
||||
|
||||
rv = PyString_FromStringAndSize(NULL, nlen);
|
||||
if ( rv == 0 )
|
||||
return 0;
|
||||
ncp = (char *)PyString_AsString(rv);
|
||||
nsp = (short *)ncp;
|
||||
nlp = (Py_Int32 *)ncp;
|
||||
for( iy = 0; iy < newy; iy++ ) {
|
||||
for ( ix = 0; ix < newx; ix++ ) {
|
||||
oix = ix * x / newx;
|
||||
oiy = iy * y / newy;
|
||||
if ( size == 1 )
|
||||
*ncp++ = *CHARP(cp, x, oix, oiy);
|
||||
else if ( size == 2 )
|
||||
*nsp++ = *SHORTP(cp, x, oix, oiy);
|
||||
else
|
||||
*nlp++ = *LONGP(cp, x, oix, oiy);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* Note: this routine can use a bit of optimizing */
|
||||
|
||||
static PyObject *
|
||||
imageop_tovideo(PyObject *self, PyObject *args)
|
||||
{
|
||||
int maxx, maxy, x, y, len;
|
||||
int i;
|
||||
unsigned char *cp, *ncp;
|
||||
int width;
|
||||
PyObject *rv;
|
||||
|
||||
|
||||
if ( !PyArg_ParseTuple(args, "s#iii", &cp, &len, &width, &maxx, &maxy) )
|
||||
return 0;
|
||||
|
||||
if ( width != 1 && width != 4 ) {
|
||||
PyErr_SetString(ImageopError, "Size should be 1 or 4");
|
||||
return 0;
|
||||
}
|
||||
if ( !check_multiply_size(len, maxx, "max", maxy, "maxy", width) )
|
||||
return 0;
|
||||
|
||||
rv = PyString_FromStringAndSize(NULL, len);
|
||||
if ( rv == 0 )
|
||||
return 0;
|
||||
ncp = (unsigned char *)PyString_AsString(rv);
|
||||
|
||||
if ( width == 1 ) {
|
||||
memcpy(ncp, cp, maxx); /* Copy first line */
|
||||
ncp += maxx;
|
||||
for (y=1; y<maxy; y++) { /* Interpolate other lines */
|
||||
for(x=0; x<maxx; x++) {
|
||||
i = y*maxx + x;
|
||||
*ncp++ = ((int)cp[i] + (int)cp[i-maxx]) >> 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
memcpy(ncp, cp, maxx*4); /* Copy first line */
|
||||
ncp += maxx*4;
|
||||
for (y=1; y<maxy; y++) { /* Interpolate other lines */
|
||||
for(x=0; x<maxx; x++) {
|
||||
i = (y*maxx + x)*4 + 1;
|
||||
*ncp++ = 0; /* Skip alfa comp */
|
||||
*ncp++ = ((int)cp[i] + (int)cp[i-4*maxx]) >> 1;
|
||||
i++;
|
||||
*ncp++ = ((int)cp[i] + (int)cp[i-4*maxx]) >> 1;
|
||||
i++;
|
||||
*ncp++ = ((int)cp[i] + (int)cp[i-4*maxx]) >> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
imageop_grey2mono(PyObject *self, PyObject *args)
|
||||
{
|
||||
int tres, x, y, len;
|
||||
unsigned char *cp, *ncp;
|
||||
unsigned char ovalue;
|
||||
PyObject *rv;
|
||||
int i, bit;
|
||||
|
||||
|
||||
if ( !PyArg_ParseTuple(args, "s#iii", &cp, &len, &x, &y, &tres) )
|
||||
return 0;
|
||||
|
||||
if ( !check_multiply(len, x, y) )
|
||||
return 0;
|
||||
|
||||
rv = PyString_FromStringAndSize(NULL, (len+7)/8);
|
||||
if ( rv == 0 )
|
||||
return 0;
|
||||
ncp = (unsigned char *)PyString_AsString(rv);
|
||||
|
||||
bit = 0x80;
|
||||
ovalue = 0;
|
||||
for ( i=0; i < len; i++ ) {
|
||||
if ( (int)cp[i] > tres )
|
||||
ovalue |= bit;
|
||||
bit >>= 1;
|
||||
if ( bit == 0 ) {
|
||||
*ncp++ = ovalue;
|
||||
bit = 0x80;
|
||||
ovalue = 0;
|
||||
}
|
||||
}
|
||||
if ( bit != 0x80 )
|
||||
*ncp++ = ovalue;
|
||||
return rv;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
imageop_grey2grey4(PyObject *self, PyObject *args)
|
||||
{
|
||||
int x, y, len;
|
||||
unsigned char *cp, *ncp;
|
||||
unsigned char ovalue;
|
||||
PyObject *rv;
|
||||
int i;
|
||||
int pos;
|
||||
|
||||
|
||||
if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
|
||||
return 0;
|
||||
|
||||
if ( !check_multiply(len, x, y) )
|
||||
return 0;
|
||||
|
||||
rv = PyString_FromStringAndSize(NULL, (len+1)/2);
|
||||
if ( rv == 0 )
|
||||
return 0;
|
||||
ncp = (unsigned char *)PyString_AsString(rv);
|
||||
pos = 0;
|
||||
ovalue = 0;
|
||||
for ( i=0; i < len; i++ ) {
|
||||
ovalue |= ((int)cp[i] & 0xf0) >> pos;
|
||||
pos += 4;
|
||||
if ( pos == 8 ) {
|
||||
*ncp++ = ovalue;
|
||||
ovalue = 0;
|
||||
pos = 0;
|
||||
}
|
||||
}
|
||||
if ( pos != 0 )
|
||||
*ncp++ = ovalue;
|
||||
return rv;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
imageop_grey2grey2(PyObject *self, PyObject *args)
|
||||
{
|
||||
int x, y, len;
|
||||
unsigned char *cp, *ncp;
|
||||
unsigned char ovalue;
|
||||
PyObject *rv;
|
||||
int i;
|
||||
int pos;
|
||||
|
||||
|
||||
if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
|
||||
return 0;
|
||||
|
||||
if ( !check_multiply(len, x, y) )
|
||||
return 0;
|
||||
|
||||
rv = PyString_FromStringAndSize(NULL, (len+3)/4);
|
||||
if ( rv == 0 )
|
||||
return 0;
|
||||
ncp = (unsigned char *)PyString_AsString(rv);
|
||||
pos = 0;
|
||||
ovalue = 0;
|
||||
for ( i=0; i < len; i++ ) {
|
||||
ovalue |= ((int)cp[i] & 0xc0) >> pos;
|
||||
pos += 2;
|
||||
if ( pos == 8 ) {
|
||||
*ncp++ = ovalue;
|
||||
ovalue = 0;
|
||||
pos = 0;
|
||||
}
|
||||
}
|
||||
if ( pos != 0 )
|
||||
*ncp++ = ovalue;
|
||||
return rv;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
imageop_dither2mono(PyObject *self, PyObject *args)
|
||||
{
|
||||
int sum, x, y, len;
|
||||
unsigned char *cp, *ncp;
|
||||
unsigned char ovalue;
|
||||
PyObject *rv;
|
||||
int i, bit;
|
||||
|
||||
|
||||
if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
|
||||
return 0;
|
||||
|
||||
if ( !check_multiply(len, x, y) )
|
||||
return 0;
|
||||
|
||||
rv = PyString_FromStringAndSize(NULL, (len+7)/8);
|
||||
if ( rv == 0 )
|
||||
return 0;
|
||||
ncp = (unsigned char *)PyString_AsString(rv);
|
||||
|
||||
bit = 0x80;
|
||||
ovalue = 0;
|
||||
sum = 0;
|
||||
for ( i=0; i < len; i++ ) {
|
||||
sum += cp[i];
|
||||
if ( sum >= 256 ) {
|
||||
sum -= 256;
|
||||
ovalue |= bit;
|
||||
}
|
||||
bit >>= 1;
|
||||
if ( bit == 0 ) {
|
||||
*ncp++ = ovalue;
|
||||
bit = 0x80;
|
||||
ovalue = 0;
|
||||
}
|
||||
}
|
||||
if ( bit != 0x80 )
|
||||
*ncp++ = ovalue;
|
||||
return rv;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
imageop_dither2grey2(PyObject *self, PyObject *args)
|
||||
{
|
||||
int x, y, len;
|
||||
unsigned char *cp, *ncp;
|
||||
unsigned char ovalue;
|
||||
PyObject *rv;
|
||||
int i;
|
||||
int pos;
|
||||
int sum = 0, nvalue;
|
||||
|
||||
|
||||
if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
|
||||
return 0;
|
||||
|
||||
if ( !check_multiply(len, x, y) )
|
||||
return 0;
|
||||
|
||||
rv = PyString_FromStringAndSize(NULL, (len+3)/4);
|
||||
if ( rv == 0 )
|
||||
return 0;
|
||||
ncp = (unsigned char *)PyString_AsString(rv);
|
||||
pos = 1;
|
||||
ovalue = 0;
|
||||
for ( i=0; i < len; i++ ) {
|
||||
sum += cp[i];
|
||||
nvalue = sum & 0x180;
|
||||
sum -= nvalue;
|
||||
ovalue |= nvalue >> pos;
|
||||
pos += 2;
|
||||
if ( pos == 9 ) {
|
||||
*ncp++ = ovalue;
|
||||
ovalue = 0;
|
||||
pos = 1;
|
||||
}
|
||||
}
|
||||
if ( pos != 0 )
|
||||
*ncp++ = ovalue;
|
||||
return rv;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
imageop_mono2grey(PyObject *self, PyObject *args)
|
||||
{
|
||||
int v0, v1, x, y, len, nlen;
|
||||
unsigned char *cp, *ncp;
|
||||
PyObject *rv;
|
||||
int i, bit;
|
||||
|
||||
if ( !PyArg_ParseTuple(args, "s#iiii", &cp, &len, &x, &y, &v0, &v1) )
|
||||
return 0;
|
||||
|
||||
nlen = x*y;
|
||||
if ( !check_multiply(nlen, x, y) )
|
||||
return 0;
|
||||
if ( (nlen+7)/8 != len ) {
|
||||
PyErr_SetString(ImageopError, "String has incorrect length");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv = PyString_FromStringAndSize(NULL, nlen);
|
||||
if ( rv == 0 )
|
||||
return 0;
|
||||
ncp = (unsigned char *)PyString_AsString(rv);
|
||||
|
||||
bit = 0x80;
|
||||
for ( i=0; i < nlen; i++ ) {
|
||||
if ( *cp & bit )
|
||||
*ncp++ = v1;
|
||||
else
|
||||
*ncp++ = v0;
|
||||
bit >>= 1;
|
||||
if ( bit == 0 ) {
|
||||
bit = 0x80;
|
||||
cp++;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
imageop_grey22grey(PyObject *self, PyObject *args)
|
||||
{
|
||||
int x, y, len, nlen;
|
||||
unsigned char *cp, *ncp;
|
||||
PyObject *rv;
|
||||
int i, pos, value = 0, nvalue;
|
||||
|
||||
if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
|
||||
return 0;
|
||||
|
||||
nlen = x*y;
|
||||
if ( !check_multiply(nlen, x, y) ) {
|
||||
return 0;
|
||||
}
|
||||
if ( (nlen+3)/4 != len ) {
|
||||
PyErr_SetString(ImageopError, "String has incorrect length");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv = PyString_FromStringAndSize(NULL, nlen);
|
||||
if ( rv == 0 )
|
||||
return 0;
|
||||
ncp = (unsigned char *)PyString_AsString(rv);
|
||||
|
||||
pos = 0;
|
||||
for ( i=0; i < nlen; i++ ) {
|
||||
if ( pos == 0 ) {
|
||||
value = *cp++;
|
||||
pos = 8;
|
||||
}
|
||||
pos -= 2;
|
||||
nvalue = (value >> pos) & 0x03;
|
||||
*ncp++ = nvalue | (nvalue << 2) |
|
||||
(nvalue << 4) | (nvalue << 6);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
imageop_grey42grey(PyObject *self, PyObject *args)
|
||||
{
|
||||
int x, y, len, nlen;
|
||||
unsigned char *cp, *ncp;
|
||||
PyObject *rv;
|
||||
int i, pos, value = 0, nvalue;
|
||||
|
||||
if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
|
||||
return 0;
|
||||
|
||||
nlen = x*y;
|
||||
if ( !check_multiply(nlen, x, y) )
|
||||
return 0;
|
||||
if ( (nlen+1)/2 != len ) {
|
||||
PyErr_SetString(ImageopError, "String has incorrect length");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv = PyString_FromStringAndSize(NULL, nlen);
|
||||
if ( rv == 0 )
|
||||
return 0;
|
||||
ncp = (unsigned char *)PyString_AsString(rv);
|
||||
|
||||
pos = 0;
|
||||
for ( i=0; i < nlen; i++ ) {
|
||||
if ( pos == 0 ) {
|
||||
value = *cp++;
|
||||
pos = 8;
|
||||
}
|
||||
pos -= 4;
|
||||
nvalue = (value >> pos) & 0x0f;
|
||||
*ncp++ = nvalue | (nvalue << 4);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
imageop_rgb2rgb8(PyObject *self, PyObject *args)
|
||||
{
|
||||
int x, y, len, nlen;
|
||||
unsigned char *cp;
|
||||
unsigned char *ncp;
|
||||
PyObject *rv;
|
||||
int i, r, g, b;
|
||||
int backward_compatible = imageop_backward_compatible();
|
||||
|
||||
if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
|
||||
return 0;
|
||||
|
||||
if ( !check_multiply_size(len, x, "x", y, "y", 4) )
|
||||
return 0;
|
||||
nlen = x*y;
|
||||
if ( !check_multiply(nlen, x, y) )
|
||||
return 0;
|
||||
|
||||
rv = PyString_FromStringAndSize(NULL, nlen);
|
||||
if ( rv == 0 )
|
||||
return 0;
|
||||
ncp = (unsigned char *)PyString_AsString(rv);
|
||||
|
||||
for ( i=0; i < nlen; i++ ) {
|
||||
/* Bits in source: aaaaaaaa BBbbbbbb GGGggggg RRRrrrrr */
|
||||
if (backward_compatible) {
|
||||
Py_UInt32 value = * (Py_UInt32 *) cp;
|
||||
cp += 4;
|
||||
r = (int) ((value & 0xff) / 255. * 7. + .5);
|
||||
g = (int) (((value >> 8) & 0xff) / 255. * 7. + .5);
|
||||
b = (int) (((value >> 16) & 0xff) / 255. * 3. + .5);
|
||||
} else {
|
||||
cp++; /* skip alpha channel */
|
||||
b = (int) (*cp++ / 255. * 3. + .5);
|
||||
g = (int) (*cp++ / 255. * 7. + .5);
|
||||
r = (int) (*cp++ / 255. * 7. + .5);
|
||||
}
|
||||
*ncp++ = (unsigned char)((r<<5) | (b<<3) | g);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
imageop_rgb82rgb(PyObject *self, PyObject *args)
|
||||
{
|
||||
int x, y, len, nlen;
|
||||
unsigned char *cp;
|
||||
unsigned char *ncp;
|
||||
PyObject *rv;
|
||||
int i, r, g, b;
|
||||
unsigned char value;
|
||||
int backward_compatible = imageop_backward_compatible();
|
||||
|
||||
if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
|
||||
return 0;
|
||||
|
||||
if ( !check_multiply(len, x, y) )
|
||||
return 0;
|
||||
nlen = x*y*4;
|
||||
if ( !check_multiply_size(nlen, x, "x", y, "y", 4) )
|
||||
return 0;
|
||||
|
||||
rv = PyString_FromStringAndSize(NULL, nlen);
|
||||
if ( rv == 0 )
|
||||
return 0;
|
||||
ncp = (unsigned char *)PyString_AsString(rv);
|
||||
|
||||
for ( i=0; i < len; i++ ) {
|
||||
/* Bits in source: RRRBBGGG
|
||||
** Red and Green are multiplied by 36.5, Blue by 85
|
||||
*/
|
||||
value = *cp++;
|
||||
r = (value >> 5) & 7;
|
||||
g = (value ) & 7;
|
||||
b = (value >> 3) & 3;
|
||||
r = (r<<5) | (r<<3) | (r>>1);
|
||||
g = (g<<5) | (g<<3) | (g>>1);
|
||||
b = (b<<6) | (b<<4) | (b<<2) | b;
|
||||
if (backward_compatible) {
|
||||
Py_UInt32 nvalue = r | (g<<8) | (b<<16);
|
||||
* (Py_UInt32 *) ncp = nvalue;
|
||||
ncp += 4;
|
||||
} else {
|
||||
*ncp++ = 0;
|
||||
*ncp++ = b;
|
||||
*ncp++ = g;
|
||||
*ncp++ = r;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
imageop_rgb2grey(PyObject *self, PyObject *args)
|
||||
{
|
||||
int x, y, len, nlen;
|
||||
unsigned char *cp;
|
||||
unsigned char *ncp;
|
||||
PyObject *rv;
|
||||
int i, r, g, b;
|
||||
int nvalue;
|
||||
int backward_compatible = imageop_backward_compatible();
|
||||
|
||||
if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
|
||||
return 0;
|
||||
|
||||
if ( !check_multiply_size(len, x, "x", y, "y", 4) )
|
||||
return 0;
|
||||
nlen = x*y;
|
||||
if ( !check_multiply(nlen, x, y) )
|
||||
return 0;
|
||||
|
||||
rv = PyString_FromStringAndSize(NULL, nlen);
|
||||
if ( rv == 0 )
|
||||
return 0;
|
||||
ncp = (unsigned char *)PyString_AsString(rv);
|
||||
|
||||
for ( i=0; i < nlen; i++ ) {
|
||||
if (backward_compatible) {
|
||||
Py_UInt32 value = * (Py_UInt32 *) cp;
|
||||
cp += 4;
|
||||
r = (int) ((value & 0xff) / 255. * 7. + .5);
|
||||
g = (int) (((value >> 8) & 0xff) / 255. * 7. + .5);
|
||||
b = (int) (((value >> 16) & 0xff) / 255. * 3. + .5);
|
||||
} else {
|
||||
cp++; /* skip alpha channel */
|
||||
b = *cp++;
|
||||
g = *cp++;
|
||||
r = *cp++;
|
||||
}
|
||||
nvalue = (int)(0.30*r + 0.59*g + 0.11*b);
|
||||
if ( nvalue > 255 ) nvalue = 255;
|
||||
*ncp++ = (unsigned char)nvalue;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
imageop_grey2rgb(PyObject *self, PyObject *args)
|
||||
{
|
||||
int x, y, len, nlen;
|
||||
unsigned char *cp;
|
||||
unsigned char *ncp;
|
||||
PyObject *rv;
|
||||
int i;
|
||||
unsigned char value;
|
||||
int backward_compatible = imageop_backward_compatible();
|
||||
|
||||
if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
|
||||
return 0;
|
||||
|
||||
if ( !check_multiply(len, x, y) )
|
||||
return 0;
|
||||
nlen = x*y*4;
|
||||
if ( !check_multiply_size(nlen, x, "x", y, "y", 4) )
|
||||
return 0;
|
||||
|
||||
rv = PyString_FromStringAndSize(NULL, nlen);
|
||||
if ( rv == 0 )
|
||||
return 0;
|
||||
ncp = (unsigned char *)PyString_AsString(rv);
|
||||
|
||||
for ( i=0; i < len; i++ ) {
|
||||
value = *cp++;
|
||||
if (backward_compatible) {
|
||||
* (Py_UInt32 *) ncp = (Py_UInt32) value | ((Py_UInt32) value << 8 ) | ((Py_UInt32) value << 16);
|
||||
ncp += 4;
|
||||
} else {
|
||||
*ncp++ = 0;
|
||||
*ncp++ = value;
|
||||
*ncp++ = value;
|
||||
*ncp++ = value;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static PyMethodDef imageop_methods[] = {
|
||||
{ "crop", imageop_crop, METH_VARARGS },
|
||||
{ "scale", imageop_scale, METH_VARARGS },
|
||||
{ "grey2mono", imageop_grey2mono, METH_VARARGS },
|
||||
{ "grey2grey2", imageop_grey2grey2, METH_VARARGS },
|
||||
{ "grey2grey4", imageop_grey2grey4, METH_VARARGS },
|
||||
{ "dither2mono", imageop_dither2mono, METH_VARARGS },
|
||||
{ "dither2grey2", imageop_dither2grey2, METH_VARARGS },
|
||||
{ "mono2grey", imageop_mono2grey, METH_VARARGS },
|
||||
{ "grey22grey", imageop_grey22grey, METH_VARARGS },
|
||||
{ "grey42grey", imageop_grey42grey, METH_VARARGS },
|
||||
{ "tovideo", imageop_tovideo, METH_VARARGS },
|
||||
{ "rgb2rgb8", imageop_rgb2rgb8, METH_VARARGS },
|
||||
{ "rgb82rgb", imageop_rgb82rgb, METH_VARARGS },
|
||||
{ "rgb2grey", imageop_rgb2grey, METH_VARARGS },
|
||||
{ "grey2rgb", imageop_grey2rgb, METH_VARARGS },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
PyMODINIT_FUNC
|
||||
initimageop(void)
|
||||
{
|
||||
PyObject *m;
|
||||
|
||||
if (PyErr_WarnPy3k("the imageop module has been removed in "
|
||||
"Python 3.0", 2) < 0)
|
||||
return;
|
||||
|
||||
m = Py_InitModule("imageop", imageop_methods);
|
||||
if (m == NULL)
|
||||
return;
|
||||
ImageopDict = PyModule_GetDict(m);
|
||||
ImageopError = PyErr_NewException("imageop.error", NULL, NULL);
|
||||
if (ImageopError != NULL)
|
||||
PyDict_SetItemString(ImageopDict, "error", ImageopError);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user