aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Grammar72
-rw-r--r--src/Makefile508
-rw-r--r--src/PROTO.h79
-rw-r--r--src/README11
-rw-r--r--src/To.do11
-rw-r--r--src/acceler.c136
-rw-r--r--src/allobjects.h50
-rw-r--r--src/amoebamodule.c774
-rw-r--r--src/asa.c494
-rw-r--r--src/asa.h33
-rw-r--r--src/assert.h25
-rw-r--r--src/audiomodule.c615
-rw-r--r--src/bitset.c99
-rw-r--r--src/bitset.h46
-rw-r--r--src/bltinmodule.c559
-rw-r--r--src/bltinmodule.h27
-rw-r--r--src/ceval.c1436
-rw-r--r--src/ceval.h33
-rw-r--r--src/cgen458
-rw-r--r--src/cgensupport.c393
-rw-r--r--src/cgensupport.h39
-rw-r--r--src/classobject.c298
-rw-r--r--src/classobject.h44
-rw-r--r--src/compile.c1772
-rw-r--r--src/compile.h47
-rw-r--r--src/config.c180
-rw-r--r--src/configmac.c109
-rw-r--r--src/cstubs999
-rw-r--r--src/dictobject.c605
-rw-r--r--src/dictobject.h44
-rw-r--r--src/errcode.h36
-rw-r--r--src/errors.c196
-rw-r--r--src/errors.h58
-rw-r--r--src/fgetsintr.c94
-rw-r--r--src/fgetsintr.h25
-rw-r--r--src/fileobject.c293
-rw-r--r--src/fileobject.h33
-rw-r--r--src/firstsets.c133
-rw-r--r--src/floatobject.c271
-rw-r--r--src/floatobject.h44
-rw-r--r--src/fmod.c51
-rw-r--r--src/frameobject.c156
-rw-r--r--src/frameobject.h80
-rw-r--r--src/funcobject.c113
-rw-r--r--src/funcobject.h33
-rw-r--r--src/getcwd.c102
-rw-r--r--src/graminit.c1094
-rw-r--r--src/graminit.h66
-rw-r--r--src/grammar.c233
-rw-r--r--src/grammar.h105
-rw-r--r--src/grammar1.c75
-rw-r--r--src/import.c259
-rw-r--r--src/import.h31
-rw-r--r--src/intobject.c307
-rw-r--r--src/intobject.h72
-rw-r--r--src/intrcheck.c144
-rw-r--r--src/listnode.c93
-rw-r--r--src/listobject.c519
-rw-r--r--src/listobject.h59
-rw-r--r--src/macmodule.c246
-rw-r--r--src/malloc.h63
-rw-r--r--src/mathmodule.c180
-rw-r--r--src/metagrammar.c176
-rw-r--r--src/metagrammar.h30
-rw-r--r--src/methodobject.c147
-rw-r--r--src/methodobject.h42
-rw-r--r--src/modsupport.c381
-rw-r--r--src/modsupport.h27
-rw-r--r--src/moduleobject.c154
-rw-r--r--src/moduleobject.h33
-rw-r--r--src/node.c100
-rw-r--r--src/node.h58
-rw-r--r--src/object.c290
-rw-r--r--src/object.h324
-rw-r--r--src/objimpl.h50
-rw-r--r--src/opcode.h109
-rw-r--r--src/panelmodule.c1090
-rw-r--r--src/parser.c423
-rw-r--r--src/parser.h50
-rw-r--r--src/parsetok.c158
-rw-r--r--src/parsetok.h29
-rw-r--r--src/patchlevel.h1
-rw-r--r--src/pgen.c751
-rw-r--r--src/pgen.h30
-rw-r--r--src/pgenheaders.h50
-rw-r--r--src/pgenmain.c148
-rw-r--r--src/posixmodule.c427
-rw-r--r--src/printgrammar.c149
-rw-r--r--src/profmain.c133
-rw-r--r--src/pythonmain.c440
-rw-r--r--src/pythonrun.h47
-rw-r--r--src/regexp.c1394
-rw-r--r--src/regexp.h51
-rw-r--r--src/regexpmodule.c191
-rw-r--r--src/regmagic.h29
-rw-r--r--src/regsub.c115
-rw-r--r--src/rltokenizer.c26
-rw-r--r--src/sc_errors.c145
-rw-r--r--src/sc_errors.h41
-rw-r--r--src/sc_global.h137
-rw-r--r--src/sc_interpr.c1352
-rw-r--r--src/scdbg.c152
-rw-r--r--src/sigtype.h51
-rw-r--r--src/stdwinmodule.c1697
-rw-r--r--src/stdwinobject.h31
-rw-r--r--src/strdup.c39
-rw-r--r--src/strerror.c47
-rw-r--r--src/stringobject.c347
-rw-r--r--src/stringobject.h63
-rw-r--r--src/strtol.c122
-rw-r--r--src/structmember.c158
-rw-r--r--src/structmember.h64
-rw-r--r--src/stubcode.h28
-rw-r--r--src/sysmodule.c214
-rw-r--r--src/sysmodule.h30
-rw-r--r--src/timemodule.c229
-rw-r--r--src/token.h69
-rw-r--r--src/tokenizer.c523
-rw-r--r--src/tokenizer.h53
-rw-r--r--src/traceback.c217
-rw-r--r--src/traceback.h30
-rw-r--r--src/tupleobject.c287
-rw-r--r--src/tupleobject.h56
-rw-r--r--src/typeobject.c61
-rw-r--r--src/xxobject.c131
125 files changed, 29287 insertions, 0 deletions
diff --git a/src/Grammar b/src/Grammar
new file mode 100644
index 0000000..574acd6
--- /dev/null
+++ b/src/Grammar
@@ -0,0 +1,72 @@
+# Grammar for Python, version 4
+
+# Changes compared to version 3:
+# Removed 'dir' statement.
+# Function call argument is a testlist instead of exprlist.
+
+# Changes compared to version 2:
+# The syntax of Boolean operations is changed to use more
+# conventional priorities: or < and < not.
+
+# Changes compared to version 1:
+# modules and scripts are unified;
+# 'quit' is gone (use ^D);
+# empty_stmt is gone, replaced by explicit NEWLINE where appropriate;
+# 'import' and 'def' aren't special any more;
+# added 'from' NAME option on import clause, and '*' to import all;
+# added class definition.
+
+# Start symbols for the grammar:
+# single_input is a single interactive statement;
+# file_input is a module or sequence of commands read from an input file;
+# expr_input is the input for the input() function;
+# eval_input is the input for the eval() function.
+
+# NB: compound_stmt in single_input is followed by extra NEWLINE!
+single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE
+file_input: (NEWLINE | stmt)* ENDMARKER
+expr_input: testlist NEWLINE
+eval_input: testlist ENDMARKER
+
+funcdef: 'def' NAME parameters ':' suite
+parameters: '(' [fplist] ')'
+fplist: fpdef (',' fpdef)*
+fpdef: NAME | '(' fplist ')'
+
+stmt: simple_stmt | compound_stmt
+simple_stmt: expr_stmt | print_stmt | pass_stmt | del_stmt | flow_stmt | import_stmt
+expr_stmt: (exprlist '=')* exprlist NEWLINE
+# For assignments, additional restrictions enforced by the interpreter
+print_stmt: 'print' (test ',')* [test] NEWLINE
+del_stmt: 'del' exprlist NEWLINE
+pass_stmt: 'pass' NEWLINE
+flow_stmt: break_stmt | return_stmt | raise_stmt
+break_stmt: 'break' NEWLINE
+return_stmt: 'return' [testlist] NEWLINE
+raise_stmt: 'raise' expr [',' expr] NEWLINE
+import_stmt: 'import' NAME (',' NAME)* NEWLINE | 'from' NAME 'import' ('*' | NAME (',' NAME)*) NEWLINE
+compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef
+if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
+while_stmt: 'while' test ':' suite ['else' ':' suite]
+for_stmt: 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite]
+try_stmt: 'try' ':' suite (except_clause ':' suite)* ['finally' ':' suite]
+except_clause: 'except' [expr [',' expr]]
+suite: simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT
+
+test: and_test ('or' and_test)*
+and_test: not_test ('and' not_test)*
+not_test: 'not' not_test | comparison
+comparison: expr (comp_op expr)*
+comp_op: '<'|'>'|'='|'>' '='|'<' '='|'<' '>'|'in'|'not' 'in'|'is'|'is' 'not'
+expr: term (('+'|'-') term)*
+term: factor (('*'|'/'|'%') factor)*
+factor: ('+'|'-') factor | atom trailer*
+atom: '(' [testlist] ')' | '[' [testlist] ']' | '{' '}' | '`' testlist '`' | NAME | NUMBER | STRING
+trailer: '(' [testlist] ')' | '[' subscript ']' | '.' NAME
+subscript: expr | [expr] ':' [expr]
+exprlist: expr (',' expr)* [',']
+testlist: test (',' test)* [',']
+
+classdef: 'class' NAME parameters ['=' baselist] ':' suite
+baselist: atom arguments (',' atom arguments)*
+arguments: '(' [testlist] ')'
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..d47eceb
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,508 @@
+# /***********************************************************
+# Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The
+# Netherlands.
+#
+# All Rights Reserved
+#
+# Permission to use, copy, modify, and distribute this software and its
+# documentation for any purpose and without fee is hereby granted,
+# provided that the above copyright notice appear in all copies and that
+# both that copyright notice and this permission notice appear in
+# supporting documentation, and that the names of Stichting Mathematisch
+# Centrum or CWI not be used in advertising or publicity pertaining to
+# distribution of the software without specific, written prior permission.
+#
+# STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+# FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+# ******************************************************************/
+
+# Makefile for Python
+# ===================
+#
+# If you are in a hurry, you can just edit this Makefile to choose the
+# correct settings for SYSV and RANLIB below, and type "make" in this
+# directory. If you are using a recent version of SunOS (or Ultrix?)
+# you don't even have to edit: the Makefile comes pre-configured for
+# such systems with all configurable options turned off, building the
+# minimal portable version of the Python interpreter.
+#
+# If have more time, read the section on configurable options below.
+# It may still be wise to begin building the minimal portable Python,
+# to see if it works at all, and select options later. You don't have
+# to rebuild all objects when you turn on options; all dependencies
+# are concentrated in the file "config.c" which is rebuilt whenever
+# the Makefile changes. (Except if you turn on the GNU Readline option
+# you may have to toss out the tokenizer.o object.)
+
+
+# Operating System Defines (ALWAYS READ THIS)
+# ===========================================
+
+# Uncomment the following line if you are using a System V derivative.
+# This must be used, for instance, on an SGI IRIS. Don't use it for
+# SunOS. (This is only needed by posixmodule.c...)
+
+#SYSVDEF= -DSYSV
+
+# Choose one of the following two lines depending on whether your system
+# requires the use of 'ranlib' after creating a library, or not.
+
+#RANLIB = true # For System V
+RANLIB = ranlib # For BSD
+
+# If your system doesn't have symbolic links, uncomment the following
+# line.
+
+#NOSYMLINKDEF= -DNO_LSTAT
+
+
+# Installation Options
+# ====================
+
+# You may want to change DEFPYTHONPATH to reflect where you install the
+# Python module library. The default contains "../lib" so running
+# the interpreter from the source/build directory as distributed will
+# find the library (admittedly a hack).
+
+DEFPYTHONPATH= .:/usr/local/lib/python:/ufs/guido/lib/python:../lib
+
+
+# For "Pure" BSD Systems
+# ======================
+#
+# "Pure" BSD systems (as opposed to enhanced BSD derivatives like SunOS)
+# often miss certain standard library functions. Source for
+# these is provided, you just have to turn it on. This may work for
+# other systems as well, where these things are needed.
+
+# If your system does not have a strerror() function in the library,
+# uncomment the following two lines to use one I wrote. (Actually, this
+# is missing in most systems I have encountered, so it is turned on
+# in the Makefile. Turn it off if your system doesn't have sys_errlist.)
+
+STRERROR_SRC= strerror.c
+STRERROR_OBJ= strerror.o
+
+# If your BSD system does not have a fmod() function in the library,
+# uncomment the following two lines to use one I wrote.
+
+#FMOD_SRC= fmod.c
+#FMOD_OBJ= fmod.o
+
+# If your BSD system does not have a strtol() function in the library,
+# uncomment the following two lines to use one I wrote.
+
+#STRTOL_SRC= strtol.c
+#STRTOL_OBJ= strtol.o
+
+# If your BSD system does not have a getcwd() function in the library,
+# but it does have a getwd() function, uncomment the following two lines
+# to use one I wrote. (If you don't have getwd() either, turn on the
+# NO_GETWD #define in getcwd.c.)
+
+#GETCWD_SRC= getcwd.c
+#GETCWD_OBJ= getcwd.o
+
+# If your signal() function believes signal handlers return int,
+# uncomment the following line.
+
+#SIGTYPEDEF= -DSIGTYPE=int
+
+
+# Further porting hints
+# =====================
+#
+# If you don't have the header file <string.h>, but you do have
+# <strings.h>, create a file "string.h" in this directory which contains
+# the single line "#include <strings.h>", and add "-I." to CFLAGS.
+# If you don't have the functions strchr and strrchr, add definitions
+# "-Dstrchr=index -Dstrrchr=rindex" to CFLAGS. (NB: CFLAGS is not
+# defined in this Makefile.)
+
+
+# Configurable Options
+# ====================
+#
+# Python can be configured to interface to various system libraries that
+# are not available on all systems. It is also possible to configure
+# the input module to use the GNU Readline library for interactive
+# input. For each configuration choice you must uncomment the relevant
+# section of the Makefile below. Note: you may also have to change a
+# pathname and/or an architecture identifier that is hardcoded in the
+# Makefile.
+#
+# Read the comments to determine if you can use the option. (You can
+# always leave all options off and build a minimal portable version of
+# Python.)
+
+
+# BSD Time Option
+# ===============
+#
+# This option does not add a new module but adds two functions to
+# an existing module.
+#
+# It implements time.millisleep() and time.millitimer()
+# using the BSD system calls select() and gettimeofday().
+#
+# Uncomment the following line to select this option.
+
+#BSDTIMEDEF= -DBSD_TIME
+
+
+# GNU Readline Option
+# ===================
+#
+# If you have the sources of the GNU Readline library you can have
+# full interactive command line editing and history in Python.
+# The GNU Readline library is distributed with the BASH shell
+# (I only know of version 1.05). You must build the GNU Readline
+# library and the alloca routine it needs in their own source
+# directories (which are subdirectories of the basg source directory),
+# and plant a pointer to the BASH source directory in this Makefile.
+#
+# Uncomment and edit the following block to use the GNU Readline option.
+# - Edit the definition of BASHDIR to point to the bash source tree.
+# You may have to fix the definition of LIBTERMCAP; leave the LIBALLOCA
+# definition commented if alloca() is in your C library.
+
+#BASHDIR= ../../bash-1.05
+#LIBREADLINE= $(BASHDIR)/readline/libreadline.a
+#LIBALLOCA= $(BASHDIR)/alloc-files/alloca.o
+#LIBTERMCAP= -ltermcap
+#RL_USE = -DUSE_READLINE
+#RL_LIBS= $(LIBREADLINE) $(LIBALLOCA) $(LIBTERMCAP)
+#RL_LIBDEPS= $(LIBREADLINE) $(LIBALLOCA)
+
+
+# STDWIN Option
+# =============
+#
+# If you have the sources of STDWIN (by the same author) you can
+# configure Python to incorporate the built-in module 'stdwin'.
+# This requires a fairly recent version of STDWIN (dated late 1990).
+#
+# Uncomment and edit the following block to use the STDWIN option.
+# - Edit the STDWINDIR defition to reflect the top of the STDWIN source
+# tree.
+# - Edit the ARCH definition to reflect your system's architecture
+# (usually the program 'arch' or 'machine' returns this).
+# You may have to edit the LIBX11 defition to reflect the location of
+# the X11 runtime library if it is non-standard.
+
+#STDWINDIR= ../../stdwin
+#ARCH= sgi
+#LIBSTDWIN= $(STDWINDIR)/Build/$(ARCH)/x11/lib/lib.a
+#LIBX11 = -lX11
+#STDW_INCL= -I$(STDWINDIR)/H
+#STDW_USE= -DUSE_STDWIN
+#STDW_LIBS= $(LIBSTDWIN) $(LIBX11)
+#STDW_LIBDEPS= $(LIBSTDWIN)
+#STDW_SRC= stdwinmodule.c
+#STDW_OBJ= stdwinmodule.o
+
+
+# Amoeba Option
+# =============
+#
+# If you have the Amoeba 4.0 distribution (Beta or otherwise) you can
+# configure Python to incorporate the built-in module 'amoeba'.
+# (Python can also be built for native Amoeba, but it requires more
+# work and thought. Contact the author.)
+#
+# Uncomment and edit the following block to use the Amoeba option.
+# - Edit the AMOEBADIR defition to reflect the top of the Amoeba source
+# tree.
+# - Edit the AM_CONF definition to reflect the machine/operating system
+# configuration needed by Amoeba (this is the name of a subdirectory
+# of $(AMOEBADIR)/conf/unix, e.g., vax.ultrix).
+
+#AMOEBADIR= /usr/amoeba
+#AM_CONF= mipseb.irix
+#LIBAMUNIX= $(AMOEBADIR)/conf/unix/$(AM_CONF)/lib/amunix/libamunix.a
+#AM_INCL= -I$(AMOEBADIR)/src/h
+#AM_USE = -DUSE_AMOEBA
+#AM_LIBDEPS= $(LIBAMUNIX)
+#AM_LIBS= $(LIBAMUNIX)
+#AM_SRC = amoebamodule.c sc_interpr.c sc_errors.c
+#AM_OBJ = amoebamodule.o sc_interpr.o sc_errors.o
+
+
+# Silicon Graphics IRIS Options
+# =============================
+#
+# The following three options are only relevant if you are using a
+# Silicon Graphics IRIS machine. These have been tested with IRIX 3.3.1
+# on a 4D/25.
+
+
+# GL Option
+# =========
+#
+# This option incorporates the built-in module 'gl', which provides a
+# complete interface to the Silicon Graphics GL library. It adds
+# about 70K to the Python text size and about 260K to the unstripped
+# binary size.
+#
+# NOTE WHEN BUILDING FOR THE FIRST TIME:
+# There is a circular dependency in the build process: you need to have
+# a working Python interpreter before you can build a Python interpreter
+# that incorporates the 'gl' module -- the source file 'glmodule.c' is
+# not distributed (it's about 140K!) and a Python script is used to
+# create it. Thus, you first have to build python without the the GL
+# and Panel options, then edit the Makefile to turn them (or at least GL)
+# on and rebuild. You may also have to set PYTHONPATH to point to
+# the place where the module library is for the generation script to
+# work.
+#
+# Uncomment the following block to use the GL option.
+
+#GL_USE = -DUSE_GL
+#GL_LIBDEPS=
+#GL_LIBS= -lgl_s
+#GL_SRC = glmodule.c cgensupport.c
+#GL_OBJ = glmodule.o cgensupport.o
+
+
+# Panel Option
+# ============
+#
+# If you have source to the NASA Ames Panel Library, you can configure
+# Python to incorporate the built-in module 'pnl', which is used byu
+# the standard module 'panel' to provide an interface to most features
+# of the Panel Library. This option requires that you also turn on the
+# GL option. It adds about 100K to the Python text size and about 160K
+# to the unstripped binary size. This requires Panel Library version 9.7
+# (for lower versions you may have to remove some functionality -- send
+# me the patches if you bothered to do this).
+#
+# Uncomment and edit the following block to use the Panel option.
+# - Edit the PANELDIR definition to point to the top-level directory
+# of the Panel distribution tree.
+
+#PANELDIR= /usr/people/guido/src/pl
+#PANELLIBDIR= $(PANELDIR)/library
+#LIBPANEL= $(PANELLIBDIR)/lib/libpanel.a
+#PANEL_USE= -DUSE_PANEL
+#PANEL_INCL= -I$(PANELLIBDIR)/include
+#PANEL_LIBDEPS= $(LIBPANEL)
+#PANEL_LIBS= $(LIBPANEL)
+#PANEL_SRC= panelmodule.c
+#PANEL_OBJ= panelmodule.o
+
+
+# Audio Option
+# ============
+#
+# This option lets you play with /dev/audio on the IRIS 4D/25.
+# It incorporates the built-in module 'audio'.
+# Warning: using the asynchronous I/O facilities of this module can
+# create a second 'thread', which looks in the listings of 'ps' like a
+# forked child. However, it shares its address space with the parent.
+#
+# Uncomment the following block to use the Audio option.
+
+#AUDIO_USE= -DUSE_AUDIO
+#AUDIO_SRC= audiomodule.c asa.c
+#AUDIO_OBJ= audiomodule.o asa.o
+
+
+# Major Definitions
+# =================
+
+STANDARD_OBJ= acceler.o bltinmodule.o ceval.o classobject.o \
+ compile.o dictobject.o errors.o fgetsintr.o \
+ fileobject.o floatobject.o $(FMOD_OBJ) frameobject.o \
+ funcobject.o $(GETCWD_OBJ) \
+ graminit.o grammar1.o import.o \
+ intobject.o intrcheck.o listnode.o listobject.o \
+ mathmodule.o methodobject.o modsupport.o \
+ moduleobject.o node.o object.o parser.o \
+ parsetok.o posixmodule.o regexp.o regexpmodule.o \
+ strdup.o $(STRERROR_OBJ) \
+ stringobject.o $(STRTOL_OBJ) structmember.o \
+ sysmodule.o timemodule.o tokenizer.o traceback.o \
+ tupleobject.o typeobject.o
+
+STANDARD_SRC= acceler.c bltinmodule.c ceval.c classobject.c \
+ compile.c dictobject.c errors.c fgetsintr.c \
+ fileobject.c floatobject.c $(FMOD_SRC) frameobject.c \
+ funcobject.c $(GETCWD_SRC) \
+ graminit.c grammar1.c import.c \
+ intobject.c intrcheck.c listnode.c listobject.c \
+ mathmodule.c methodobject.c modsupport.c \
+ moduleobject.c node.c object.c parser.c \
+ parsetok.c posixmodule.c regexp.c regexpmodule.c \
+ strdup.c $(STRERROR_SRC) \
+ stringobject.c $(STRTOL_SRC) structmember.c \
+ sysmodule.c timemodule.c tokenizer.c traceback.c \
+ tupleobject.c typeobject.c
+
+CONFIGDEFS= $(STDW_USE) $(AM_USE) $(AUDIO_USE) $(GL_USE) $(PANEL_USE) \
+ '-DPYTHONPATH="$(DEFPYTHONPATH)"'
+
+CONFIGINCLS= $(STDW_INCL)
+
+LIBDEPS= libpython.a $(STDW_LIBDEPS) $(AM_LIBDEPS) \
+ $(GL_LIBDEPS) $(PANEL_LIBSDEP) $(RL_LIBDEPS)
+
+# NB: the ordering of items in LIBS is significant!
+LIBS= libpython.a $(STDW_LIBS) $(AM_LIBS) \
+ $(PANEL_LIBS) $(GL_LIBS) $(RL_LIBS) -lm
+
+LIBOBJECTS= $(STANDARD_OBJ) $(STDW_OBJ) $(AM_OBJ) $(AUDIO_OBJ) \
+ $(GL_OBJ) $(PANEL_OBJ)
+
+LIBSOURCES= $(STANDARD_SRC) $(STDW_SRC) $(AM_SRC) $(AUDIO_SRC) \
+ $(GL_SRC) $(PANEL_SRC)
+
+OBJECTS= pythonmain.o config.o
+
+SOURCES= $(LIBSOURCES) pythonmain.c config.c
+
+GENOBJECTS= acceler.o fgetsintr.o grammar1.o \
+ intrcheck.o listnode.o node.o parser.o \
+ parsetok.o strdup.o tokenizer.o bitset.o \
+ firstsets.o grammar.o metagrammar.o pgen.o \
+ pgenmain.o printgrammar.o
+
+GENSOURCES= acceler.c fgetsintr.c grammar1.c \
+ intrcheck.c listnode.c node.c parser.c \
+ parsetok.c strdup.c tokenizer.c bitset.c \
+ firstsets.c grammar.c metagrammar.c pgen.c \
+ pgenmain.c printgrammar.c
+
+
+# Main Targets
+# ============
+
+python: libpython.a $(OBJECTS) $(LIBDEPS) Makefile
+ $(CC) $(CFLAGS) $(OBJECTS) $(LIBS) -o @python
+ mv @python python
+
+libpython.a: $(LIBOBJECTS)
+ -rm -f @lib
+ ar cr @lib $(LIBOBJECTS)
+ $(RANLIB) @lib
+ mv @lib libpython.a
+
+python_gen: $(GENOBJECTS) $(RL_LIBDEPS)
+ $(CC) $(CFLAGS) $(GENOBJECTS) $(RL_LIBS) -o python_gen
+
+
+# Utility Targets
+# ===============
+
+# Don't take the output from lint too seriously. I have not attempted
+# to make Python lint-free. But I use function prototypes.
+
+LINTFLAGS= -h
+
+LINTCPPFLAGS= $(CONFIGDEFS) $(CONFIGINCLS) $(SYSVDEF) \
+ $(AM_INCL) $(PANEL_INCL)
+
+LINT= lint
+
+lint:: $(SOURCES)
+ $(LINT) $(LINTFLAGS) $(LINTCPPFLAGS) $(SOURCES)
+
+lint:: $(GENSOURCES)
+ $(LINT) $(LINTFLAGS) $(GENSOURCES)
+
+# Generating dependencies is only necessary if you intend to hack Python.
+# You may change $(MKDEP) to your favorite dependency generator (it should
+# edit the Makefile in place).
+
+MKDEP= mkdep
+
+depend::
+ $(MKDEP) $(LINTCPPFLAGS) $(SOURCES) $(GENSOURCES)
+
+# You may change $(CTAGS) to suit your taste...
+
+CTAGS= ctags -t -w
+
+HEADERS= *.h
+
+tags: $(SOURCES) $(GENSOURCES) $(HEADERS)
+ $(CTAGS) $(SOURCES) $(GENSOURCES) $(HEADERS)
+
+clean::
+ -rm -f *.o core [,#@]*
+
+clobber:: clean
+ -rm -f python python_gen libpython.a tags
+
+
+# Build Special Objects
+# =====================
+
+# You may change $(COMPILE) to reflect the default .c.o rule...
+
+COMPILE= $(CC) -c $(CFLAGS)
+
+amoebamodule.o: amoebamodule.c
+ $(COMPILE) $(AM_INCL) $*.c
+
+config.o: config.c Makefile
+ $(COMPILE) $(CONFIGDEFS) $(CONFIGINCLS) $*.c
+
+fgetsintr.o: fgetsintr.c
+ $(COMPILE) $(SIGTYPEDEF) $*.c
+
+intrcheck.o: intrcheck.c
+ $(COMPILE) $(SIGTYPEDEF) $*.c
+
+panelmodule.o: panelmodule.c
+ $(COMPILE) $(PANEL_INCL) $*.c
+
+posixmodule.o: posixmodule.c
+ $(COMPILE) $(SYSVDEF) $(NOSYMLINKDEF) $*.c
+
+sc_interpr.o: sc_interpr.c
+ $(COMPILE) $(AM_INCL) $*.c
+
+sc_error.o: sc_error.c
+ $(COMPILE) $(AM_INCL) $*.c
+
+stdwinmodule.o: stdwinmodule.c
+ $(COMPILE) $(STDW_INCL) $*.c
+
+timemodule.o: timemodule.c
+ $(COMPILE) $(SIGTYPEDEF) $(BSDTIMEDEF) $*.c
+
+tokenizer.o: tokenizer.c
+ $(COMPILE) $(RL_USE) $*.c
+
+.PRECIOUS: python libpython.a glmodule.c graminit.c graminit.h
+
+
+# Generated Sources
+# =================
+#
+# Some source files are (or may be) generated.
+# The rules for doing so are given here.
+
+# Build "glmodule.c", the GL interface.
+# See important note at "GL Option" above.
+# You may have to set and export PYTHONPATH for this to work.
+# Ignore the messages emitted by the cgen script as long as its exit
+# status is zero.
+# Also ignore the warnings emitted while compiling glmodule.c; it works.
+
+glmodule.c: cstubs cgen
+ python cgen <cstubs >@glmodule.c
+ mv @glmodule.c glmodule.c
+
+# The dependencies for graminit.[ch] are not turned on in the
+# distributed Makefile because the files themselves are distributed.
+# Turn them on if you want to hack the grammar.
+
+#graminit.c graminit.h: Grammar python_gen
+# python_gen Grammar
diff --git a/src/PROTO.h b/src/PROTO.h
new file mode 100644
index 0000000..88b94fe
--- /dev/null
+++ b/src/PROTO.h
@@ -0,0 +1,79 @@
+/***********************************************************
+Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The
+Netherlands.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+/*
+The macro PROTO(x) is used to put function prototypes in the source.
+This is defined differently for compilers that support prototypes than
+for compilers that don't. It should be used as follows:
+ int some_function PROTO((int arg1, char *arg2));
+A variant FPROTO(x) is used for cases where Standard C allows prototypes
+but Think C doesn't (mostly function pointers).
+
+This file also defines the macro HAVE_PROTOTYPES if and only if
+the PROTO() macro expands the prototype. It is also allowed to predefine
+HAVE_PROTOTYPES to force prototypes on.
+*/
+
+#ifndef PROTO
+
+#ifdef __STDC__
+#define HAVE_PROTOTYPES
+#endif
+
+#ifdef THINK_C
+#undef HAVE_PROTOTYPES
+#define HAVE_PROTOTYPES
+#endif
+
+#ifdef sgi
+#ifdef mips
+#define HAVE_PROTOTYPES
+#endif
+#endif
+
+#ifdef HAVE_PROTOTYPES
+#define PROTO(x) x
+#else
+#define PROTO(x) ()
+#endif
+
+#endif /* PROTO */
+
+
+/* FPROTO() is for cases where Think C doesn't like prototypes */
+
+#ifdef THINK_C
+#define FPROTO(arglist) ()
+#else /* !THINK_C */
+#define FPROTO(arglist) PROTO(arglist)
+#endif /* !THINK_C */
+
+#ifndef HAVE_PROTOTYPES
+#define const /*empty*/
+#else /* HAVE_PROTOTYPES */
+#ifdef THINK_C
+#undef const
+#define const /*empty*/
+#endif /* THINK_C */
+#endif /* HAVE_PROTOTYPES */
diff --git a/src/README b/src/README
new file mode 100644
index 0000000..714cd5b
--- /dev/null
+++ b/src/README
@@ -0,0 +1,11 @@
+This directory contains the source for the Python interpreter.
+
+To build the interpreter, edit the Makefile, follow the instructions
+there, and type "make python".
+
+To use the interpreter, you must set the environment variable PYTHONPATH
+to point to the directory containing the standard modules. These are
+distributed as a sister directory called 'lib' of this source directory.
+Try importing the module 'testall' to see if everything works.
+
+Good Luck!
diff --git a/src/To.do b/src/To.do
new file mode 100644
index 0000000..893e96d
--- /dev/null
+++ b/src/To.do
@@ -0,0 +1,11 @@
+- return better errors for file objects (also check read/write allowed, etc.)
+
+- introduce more specific exceptions (e.g., zero divide, index failure, ...)
+
+- why do reads from stdin fail when I suspend the process?
+
+- introduce macros to set/inspect errno for syscalls, to support things
+ like getoserr()
+
+- fix interrupt handling (interruptable system calls should call
+ intrcheck() to clear the interrupt status)
diff --git a/src/acceler.c b/src/acceler.c
new file mode 100644
index 0000000..5ed37d3
--- /dev/null
+++ b/src/acceler.c
@@ -0,0 +1,136 @@
+/***********************************************************
+Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The
+Netherlands.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+/* Parser accelerator module */
+
+/* The parser as originally conceived had disappointing performance.
+ This module does some precomputation that speeds up the selection
+ of a DFA based upon a token, turning a search through an array
+ into a simple indexing operation. The parser now cannot work
+ without the accelerators installed. Note that the accelerators
+ are installed dynamically when the parser is initialized, they
+ are not part of the static data structure written on graminit.[ch]
+ by the parser generator. */
+
+#include "pgenheaders.h"
+#include "grammar.h"
+#include "token.h"
+#include "parser.h"
+
+/* Forward references */
+static void fixdfa PROTO((grammar *, dfa *));
+static void fixstate PROTO((grammar *, dfa *, state *));
+
+void
+addaccelerators(g)
+ grammar *g;
+{
+ dfa *d;
+ int i;
+#ifdef DEBUG
+ printf("Adding parser accellerators ...\n");
+#endif
+ d = g->g_dfa;
+ for (i = g->g_ndfas; --i >= 0; d++)
+ fixdfa(g, d);
+ g->g_accel = 1;
+#ifdef DEBUG
+ printf("Done.\n");
+#endif
+}
+
+static void
+fixdfa(g, d)
+ grammar *g;
+ dfa *d;
+{
+ state *s;
+ int j;
+ s = d->d_state;
+ for (j = 0; j < d->d_nstates; j++, s++)
+ fixstate(g, d, s);
+}
+
+static void
+fixstate(g, d, s)
+ grammar *g;
+ dfa *d;
+ state *s;
+{
+ arc *a;
+ int k;
+ int *accel;
+ int nl = g->g_ll.ll_nlabels;
+ s->s_accept = 0;
+ accel = NEW(int, nl);
+ for (k = 0; k < nl; k++)
+ accel[k] = -1;
+ a = s->s_arc;
+ for (k = s->s_narcs; --k >= 0; a++) {
+ int lbl = a->a_lbl;
+ label *l = &g->g_ll.ll_label[lbl];
+ int type = l->lb_type;
+ if (a->a_arrow >= (1 << 7)) {
+ printf("XXX too many states!\n");
+ continue;
+ }
+ if (ISNONTERMINAL(type)) {
+ dfa *d1 = finddfa(g, type);
+ int ibit;
+ if (type - NT_OFFSET >= (1 << 7)) {
+ printf("XXX too high nonterminal number!\n");
+ continue;
+ }
+ for (ibit = 0; ibit < g->g_ll.ll_nlabels; ibit++) {
+ if (testbit(d1->d_first, ibit)) {
+ if (accel[ibit] != -1)
+ printf("XXX ambiguity!\n");
+ accel[ibit] = a->a_arrow | (1 << 7) |
+ ((type - NT_OFFSET) << 8);
+ }
+ }
+ }
+ else if (lbl == EMPTY)
+ s->s_accept = 1;
+ else if (lbl >= 0 && lbl < nl)
+ accel[lbl] = a->a_arrow;
+ }
+ while (nl > 0 && accel[nl-1] == -1)
+ nl--;
+ for (k = 0; k < nl && accel[k] == -1;)
+ k++;
+ if (k < nl) {
+ int i;
+ s->s_accel = NEW(int, nl-k);
+ if (s->s_accel == NULL) {
+ fprintf(stderr, "no mem to add parser accelerators\n");
+ exit(1);
+ }
+ s->s_lower = k;
+ s->s_upper = nl;
+ for (i = 0; k < nl; i++, k++)
+ s->s_accel[i] = accel[k];
+ }
+ DEL(accel);
+}
diff --git a/src/allobjects.h b/src/allobjects.h
new file mode 100644
index 0000000..b6b487b
--- /dev/null
+++ b/src/allobjects.h
@@ -0,0 +1,50 @@
+/***********************************************************
+Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The
+Netherlands.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+/* "allobjects.c" -- Source for precompiled header "allobjects.h" */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "PROTO.h"
+
+#include "object.h"
+#include "objimpl.h"
+
+#include "intobject.h"
+#include "floatobject.h"
+#include "stringobject.h"
+#include "tupleobject.h"
+#include "listobject.h"
+#include "dictobject.h"
+#include "methodobject.h"
+#include "moduleobject.h"
+#include "funcobject.h"
+#include "classobject.h"
+#include "fileobject.h"
+
+#include "errors.h"
+#include "malloc.h"
+
+extern char *strdup PROTO((const char *));
diff --git a/src/amoebamodule.c b/src/amoebamodule.c
new file mode 100644
index 0000000..c9131b7
--- /dev/null
+++ b/src/amoebamodule.c
@@ -0,0 +1,774 @@
+/***********************************************************
+Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The
+Netherlands.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+/* Amoeba module implementation */
+
+/* Amoeba includes */
+#include <amoeba.h>
+#include <cmdreg.h>
+#include <stdcom.h>
+#include <stderr.h>
+#include <caplist.h>
+#include <server/bullet/bullet.h>
+#include <server/tod/tod.h>
+#include <module/name.h>
+#include <module/direct.h>
+#include <module/mutex.h>
+#include <module/prv.h>
+#include <module/stdcmd.h>
+
+/* C includes */
+#include <stdlib.h>
+#include <ctype.h>
+
+/* POSIX includes */
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/* Python includes */
+#include "allobjects.h"
+#include "modsupport.h"
+#include "sc_global.h"
+#include "stubcode.h"
+
+extern char *err_why();
+extern char *ar_cap();
+
+#define STUBCODE "+stubcode"
+
+static object *AmoebaError;
+object *StubcodeError;
+
+static object *sc_dict;
+
+/* Module initialization */
+
+extern struct methodlist amoeba_methods[]; /* Forward */
+extern object *convertcapv(); /* Forward */
+
+static void
+ins(d, name, v)
+ object *d;
+ char *name;
+ object *v;
+{
+ if (v == NULL || dictinsert(d, name, v) != 0)
+ fatal("can't initialize amoeba module");
+}
+
+void
+initamoeba()
+{
+ object *m, *d, *v;
+
+ m = initmodule("amoeba", amoeba_methods);
+ d = getmoduledict(m);
+
+ /* Define capv */
+ v = convertcapv();
+ ins(d, "capv", v);
+ DECREF(v);
+
+ /* Set timeout */
+ timeout((interval)2000);
+
+ /* Initialize amoeba.error exception */
+ AmoebaError = newstringobject("amoeba.error");
+ ins(d, "error", AmoebaError);
+ StubcodeError = newstringobject("amoeba.stubcode_error");
+ ins(d, "stubcode_error", StubcodeError);
+ sc_dict = newdictobject();
+}
+
+
+/* Set an Amoeba-specific error, and return NULL */
+
+object *
+amoeba_error(err)
+ errstat err;
+{
+ object *v = newtupleobject(2);
+ if (v != NULL) {
+ settupleitem(v, 0, newintobject((long)err));
+ settupleitem(v, 1, newstringobject(err_why(err)));
+ }
+ err_setval(AmoebaError, v);
+ if (v != NULL)
+ DECREF(v);
+ return NULL;
+}
+
+
+/* Capability object implementation */
+
+extern typeobject Captype; /* Forward */
+
+#define is_capobject(v) ((v)->ob_type == &Captype)
+
+typedef struct {
+ OB_HEAD
+ capability ob_cap;
+} capobject;
+
+object *
+newcapobject(cap)
+ capability *cap;
+{
+ capobject *v = NEWOBJ(capobject, &Captype);
+ if (v == NULL)
+ return NULL;
+ v->ob_cap = *cap;
+ return (object *)v;
+}
+
+getcapability(v, cap)
+ object *v;
+ capability *cap;
+{
+
+ if (!is_capobject(v))
+ return err_badarg();
+ *cap = ((capobject *)v)->ob_cap;
+ return 0;
+}
+
+/*
+ * is_capobj exports the is_capobject macro to the stubcode modules
+ */
+
+int
+is_capobj(v)
+ object *v;
+{
+
+ return is_capobject(v);
+}
+
+/* Methods */
+
+static void
+capprint(v, fp, flags)
+ capobject *v;
+ FILE *fp;
+ int flags;
+{
+ /* XXX needs lock when multi-threading */
+ fputs(ar_cap(&v->ob_cap), fp);
+}
+
+static object *
+caprepr(v)
+ capobject *v;
+{
+ /* XXX needs lock when multi-threading */
+ return newstringobject(ar_cap(&v->ob_cap));
+}
+
+extern object *sc_interpreter();
+
+extern struct methodlist cap_methods[]; /* Forward */
+
+object *
+sc_makeself(cap, stubcode, name)
+ object *cap, *stubcode;
+ char *name;
+{
+ object *sc_name, *sc_self;
+
+ sc_name = newstringobject(name);
+ if (sc_name == NULL)
+ return NULL;
+ sc_self = newtupleobject(3);
+ if (sc_self == NULL) {
+ DECREF(sc_name);
+ return NULL;
+ }
+ if (settupleitem(sc_self, NAME, sc_name) != 0) {
+ DECREF(sc_self);
+ return NULL;
+ }
+ INCREF(cap);
+ if (settupleitem(sc_self, CAP, cap) != 0) {
+ DECREF(sc_self);
+ return NULL;
+ }
+ INCREF(stubcode);
+ if (settupleitem(sc_self, STUBC, stubcode) != 0) {
+ DECREF(sc_self);
+ return NULL;
+ }
+ return sc_self;
+}
+
+
+static void
+swapcode(code, len)
+ char *code;
+ int len;
+{
+ int i = sizeof(TscOperand);
+ TscOpcode opcode;
+ TscOperand operand;
+
+ while (i < len) {
+ memcpy(&opcode, &code[i], sizeof(TscOpcode));
+ SwapOpcode(opcode);
+ memcpy(&code[i], &opcode, sizeof(TscOpcode));
+ i += sizeof(TscOpcode);
+ if (opcode & OPERAND) {
+ memcpy(&operand, &code[i], sizeof(TscOperand));
+ SwapOperand(operand);
+ memcpy(&code[i], &operand, sizeof(TscOperand));
+ i += sizeof(TscOperand);
+ }
+ }
+}
+
+object *
+sc_findstubcode(v, name)
+ object *v;
+ char *name;
+{
+ int fd, fsize;
+ char *fname, *buffer;
+ struct stat statbuf;
+ object *sc_stubcode, *ret;
+ TscOperand sc_magic;
+
+ /*
+ * Only look in the current directory for now.
+ */
+ fname = malloc(strlen(name) + 4);
+ if (fname == NULL) {
+ return err_nomem();
+ }
+ sprintf(fname, "%s.sc", name);
+ if ((fd = open(fname, O_RDONLY)) == -1) {
+ extern int errno;
+
+ if (errno == 2) {
+ /*
+ ** errno == 2 is file not found.
+ */
+ err_setstr(NameError, fname);
+ return NULL;
+ }
+ free(fname);
+ return err_errno(newstringobject(name));
+ }
+ fstat(fd, &statbuf);
+ fsize = (int)statbuf.st_size;
+ buffer = malloc(fsize);
+ if (buffer == NULL) {
+ free(fname);
+ close(fd);
+ return err_nomem();
+ }
+ if (read(fd, buffer, fsize) != fsize) {
+ close(fd);
+ free(fname);
+ return err_errno(newstringobject(name));
+ }
+ close(fd);
+ free(fname);
+ memcpy(&sc_magic, buffer, sizeof(TscOperand));
+ if (sc_magic != SC_MAGIC) {
+ SwapOperand(sc_magic);
+ if (sc_magic != SC_MAGIC) {
+ free(buffer);
+ return NULL;
+ } else {
+ swapcode(buffer, fsize);
+ }
+ }
+ sc_stubcode = newsizedstringobject( &buffer[sizeof(TscOperand)],
+ fsize - sizeof(TscOperand));
+ free(buffer);
+ if (sc_stubcode == NULL) {
+ return NULL;
+ }
+ if (dictinsert(sc_dict, name, sc_stubcode) != 0) {
+ DECREF(sc_stubcode);
+ return NULL;
+ }
+ DECREF(sc_stubcode); /* XXXX */
+ sc_stubcode = sc_makeself(v, sc_stubcode, name);
+ if (sc_stubcode == NULL) {
+ return NULL;
+ }
+ return sc_stubcode;
+}
+
+object *
+capgetattr(v, name)
+ capobject *v;
+ char *name;
+{
+ object *sc_method, *sc_stubcodemethod;
+
+ if (sc_dict == NULL) {
+ /*
+ ** For some reason the dictionary has not been
+ ** initialized. Try to find one of the built in
+ ** methods.
+ */
+ return findmethod(cap_methods, (object *)v, name);
+ }
+ sc_stubcodemethod = dictlookup(sc_dict, name);
+ if (sc_stubcodemethod != NULL) {
+ /*
+ ** There is a stubcode method in the dictionary.
+ ** Execute the stubcode interpreter with the right
+ ** arguments.
+ */
+ object *self, *ret;
+
+ self = sc_makeself((object *)v, sc_stubcodemethod, name);
+ if (self == NULL) {
+ return NULL;
+ }
+ ret = findmethod(cap_methods, self, STUBCODE);
+ DECREF(self);
+ return ret;
+ }
+ err_clear();
+ sc_method = findmethod(cap_methods, (object *)v, name);
+ if (sc_method == NULL) {
+ /*
+ ** The method is not built in and not in the
+ ** dictionary. Try to find it as a stubcode file.
+ */
+ object *self, *ret;
+
+ err_clear();
+ self = sc_findstubcode((object *)v, name);
+ if (self == NULL) {
+ return NULL;
+ }
+ ret = findmethod(cap_methods, self, STUBCODE);
+ DECREF(self);
+ return ret;
+ }
+ return sc_method;
+}
+
+int
+capcompare(v, w)
+ capobject *v, *w;
+{
+ int cmp = bcmp((char *)&v->ob_cap.cap_port,
+ (char *)&w->ob_cap, PORTSIZE);
+ if (cmp != 0)
+ return cmp;
+ return prv_number(&v->ob_cap.cap_priv) -
+ prv_number(&w->ob_cap.cap_priv);
+}
+
+static typeobject Captype = {
+ OB_HEAD_INIT(&Typetype)
+ 0,
+ "capability",
+ sizeof(capobject),
+ 0,
+ free, /*tp_dealloc*/
+ capprint, /*tp_print*/
+ capgetattr, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ capcompare, /*tp_comp
+are*/
+ caprepr, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+};
+
+
+/* Return a dictionary corresponding to capv */
+
+extern struct caplist *capv;
+
+static object *
+convertcapv()
+{
+ object *d;
+ struct caplist *c;
+ d = newdictobject();
+ if (d == NULL)
+ return NULL;
+ if (capv == NULL)
+ return d;
+ for (c = capv; c->cl_name != NULL; c++) {
+ object *v = newcapobject(c->cl_cap);
+ if (v == NULL || dictinsert(d, c->cl_name, v) != 0) {
+ DECREF(d);
+ return NULL;
+ }
+ DECREF(v);
+ }
+ return d;
+}
+
+
+/* Strongly Amoeba-specific argument handlers */
+
+static int
+getcaparg(v, a)
+ object *v;
+ capability *a;
+{
+ if (v == NULL || !is_capobject(v))
+ return err_badarg();
+ *a = ((capobject *)v) -> ob_cap;
+ return 1;
+}
+
+static int
+getstrcapargs(v, a, b)
+ object *v;
+ object **a;
+ capability *b;
+{
+ if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2)
+ return err_badarg();
+ return getstrarg(gettupleitem(v, 0), a) &&
+ getcaparg(gettupleitem(v, 1), b);
+}
+
+
+/* Amoeba methods */
+
+static object *
+amoeba_name_lookup(self, args)
+ object *self;
+ object *args;
+{
+ object *name;
+ capability cap;
+ errstat err;
+ if (!getstrarg(args, &name))
+ return NULL;
+ err = name_lookup(getstringvalue(name), &cap);
+ if (err != STD_OK)
+ return amoeba_error(err);
+ return newcapobject(&cap);
+}
+
+static object *
+amoeba_name_append(self, args)
+ object *self;
+ object *args;
+{
+ object *name;
+ capability cap;
+ errstat err;
+ if (!getstrcapargs(args, &name, &cap))
+ return NULL;
+ err = name_append(getstringvalue(name), &cap);
+ if (err != STD_OK)
+ return amoeba_error(err);
+ INCREF(None);
+ return None;
+}
+
+static object *
+amoeba_name_replace(self, args)
+ object *self;
+ object *args;
+{
+ object *name;
+ capability cap;
+ errstat err;
+ if (!getstrcapargs(args, &name, &cap))
+ return NULL;
+ err = name_replace(getstringvalue(name), &cap);
+ if (err != STD_OK)
+ return amoeba_error(err);
+ INCREF(None);
+ return None;
+}
+
+static object *
+amoeba_name_delete(self, args)
+ object *self;
+ object *args;
+{
+ object *name;
+ errstat err;
+ if (!getstrarg(args, &name))
+ return NULL;
+ err = name_delete(getstringvalue(name));
+ if (err != STD_OK)
+ return amoeba_error(err);
+ INCREF(None);
+ return None;
+}
+
+static object *
+amoeba_timeout(self, args)
+ object *self;
+ object *args;
+{
+ int i;
+ object *v;
+ interval tout;
+ if (!getintarg(args, &i))
+ return NULL;
+ tout = timeout((interval)i);
+ v = newintobject((long)tout);
+ if (v == NULL)
+ timeout(tout);
+ return v;
+}
+
+static struct methodlist amoeba_methods[] = {
+ {"name_append", amoeba_name_append},
+ {"name_delete", amoeba_name_delete},
+ {"name_lookup", amoeba_name_lookup},
+ {"name_replace", amoeba_name_replace},
+ {"timeout", amoeba_timeout},
+ {NULL, NULL} /* Sentinel */
+};
+
+/* Capability methods */
+
+static object *
+cap_b_size(self, args)
+ capobject *self;
+ object *args;
+{
+ errstat err;
+ b_fsize size;
+ if (!getnoarg(args))
+ return NULL;
+ err = b_size(&self->ob_cap, &size);
+ if (err != STD_OK)
+ return amoeba_error(err);
+ return newintobject((long)size);
+}
+
+static object *
+cap_b_read(self, args)
+ capobject *self;
+ object *args;
+{
+ errstat err;
+ char *buf;
+ object *v;
+ long offset, size;
+ b_fsize nread;
+ if (!getlonglongargs(args, &offset, &size))
+ return NULL;
+ buf = malloc((unsigned int)size);
+ if (buf == NULL) {
+ return err_nomem();
+ }
+ err = b_read(&self->ob_cap, (b_fsize)offset, buf, (b_fsize)size,
+ &nread);
+ if (err != STD_OK) {
+ free(buf);
+ return amoeba_error(err);
+ }
+ v = newsizedstringobject(buf, (int)nread);
+ free(buf);
+ return v;
+}
+
+static object *
+cap_dir_lookup(self, args)
+ capobject *self;
+ object *args;
+{
+ object *name;
+ capability cap;
+ errstat err;
+ if (!getstrarg(args, &name))
+ return NULL;
+ err = dir_lookup(&self->ob_cap, getstringvalue(name), &cap);
+ if (err != STD_OK)
+ return amoeba_error(err);
+ return newcapobject(&cap);
+}
+
+static object *
+cap_dir_append(self, args)
+ capobject *self;
+ object *args;
+{
+ object *name;
+ capability cap;
+ errstat err;
+ if (!getstrcapargs(args, &name, &cap))
+ return NULL;
+ err = dir_append(&self->ob_cap, getstringvalue(name), &cap);
+ if (err != STD_OK)
+ return amoeba_error(err);
+ INCREF(None);
+ return None;
+}
+
+static object *
+cap_dir_delete(self, args)
+ capobject *self;
+ object *args;
+{
+ object *name;
+ errstat err;
+ if (!getstrarg(args, &name))
+ return NULL;
+ err = dir_delete(&self->ob_cap, getstringvalue(name));
+ if (err != STD_OK)
+ return amoeba_error(err);
+ INCREF(None);
+ return None;
+}
+
+static object *
+cap_dir_replace(self, args)
+ capobject *self;
+ object *args;
+{
+ object *name;
+ capability cap;
+ errstat err;
+ if (!getstrcapargs(args, &name, &cap))
+ return NULL;
+ err = dir_replace(&self->ob_cap, getstringvalue(name), &cap);
+ if (err != STD_OK)
+ return amoeba_error(err);
+ INCREF(None);
+ return None;
+}
+
+static object *
+cap_dir_list(self, args)
+ capobject *self;
+ object *args;
+{
+ errstat err;
+ struct dir_open *dd;
+ object *d;
+ char *name;
+ if (!getnoarg(args))
+ return NULL;
+ if ((dd = dir_open(&self->ob_cap)) == NULL)
+ return amoeba_error(STD_COMBAD);
+ if ((d = newlistobject(0)) == NULL) {
+ dir_close(dd);
+ return NULL;
+ }
+ while ((name = dir_next(dd)) != NULL) {
+ object *v;
+ v = newstringobject(name);
+ if (v == NULL) {
+ DECREF(d);
+ d = NULL;
+ break;
+ }
+ if (addlistitem(d, v) != 0) {
+ DECREF(v);
+ DECREF(d);
+ d = NULL;
+ break;
+ }
+ DECREF(v);
+ }
+ dir_close(dd);
+ return d;
+}
+
+object *
+cap_std_info(self, args)
+ capobject *self;
+ object *args;
+{
+ char buf[256];
+ errstat err;
+ int n;
+ if (!getnoarg(args))
+ return NULL;
+ err = std_info(&self->ob_cap, buf, sizeof buf, &n);
+ if (err != STD_OK)
+ return amoeba_error(err);
+ return newsizedstringobject(buf, n);
+}
+
+object *
+cap_tod_gettime(self, args)
+ capobject *self;
+ object *args;
+{
+ header h;
+ errstat err;
+ bufsize n;
+ long sec;
+ int msec, tz, dst;
+ if (!getnoarg(args))
+ return NULL;
+ h.h_port = self->ob_cap.cap_port;
+ h.h_priv = self->ob_cap.cap_priv;
+ h.h_command = TOD_GETTIME;
+ n = trans(&h, NILBUF, 0, &h, NILBUF, 0);
+ if (ERR_STATUS(n))
+ return amoeba_error(ERR_CONVERT(n));
+ tod_decode(&h, &sec, &msec, &tz, &dst);
+ return newintobject(sec);
+}
+
+object *
+cap_tod_settime(self, args)
+ capobject *self;
+ object *args;
+{
+ header h;
+ errstat err;
+ bufsize n;
+ long sec;
+ if (!getlongarg(args, &sec))
+ return NULL;
+ h.h_port = self->ob_cap.cap_port;
+ h.h_priv = self->ob_cap.cap_priv;
+ h.h_command = TOD_SETTIME;
+ tod_encode(&h, sec, 0, 0, 0);
+ n = trans(&h, NILBUF, 0, &h, NILBUF, 0);
+ if (ERR_STATUS(n))
+ return amoeba_error(ERR_CONVERT(n));
+ INCREF(None);
+ return None;
+}
+
+static struct methodlist cap_methods[] = {
+ { STUBCODE, sc_interpreter},
+ {"b_read", cap_b_read},
+ {"b_size", cap_b_size},
+ {"dir_append", cap_dir_append},
+ {"dir_delete", cap_dir_delete},
+ {"dir_list", cap_dir_list},
+ {"dir_lookup", cap_dir_lookup},
+ {"dir_replace", cap_dir_replace},
+ {"std_info", cap_std_info},
+ {"tod_gettime", cap_tod_gettime},
+ {"tod_settime", cap_tod_settime},
+ {NULL, NULL} /* Sentinel */
+};
diff --git a/src/asa.c b/src/asa.c
new file mode 100644
index 0000000..f7f7378
--- /dev/null
+++ b/src/asa.c
@@ -0,0 +1,494 @@
+/***********************************************************
+Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The
+Netherlands.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+/* Asynchronous audio module for Silicon Graphics 4D/20 under IRIX 3.3
+ Copyright 1990 Stichting Mathematisch Centrum, Amsterdam
+ Author: Guido van Rossum, <[email protected]>
+ Last modified: [email protected], Oct 14, 1990
+
+ Callers should #include "asa.h".
+
+ This code is strongly IRIX 3.3 dependent. (Or are sproc() and
+ friends standard SYSV now?)
+
+ Caution: if you put printf's in the slave for debugging, use "-lmpc"
+ to get the semaphore version of stdio!
+
+
+ This file contains two library layers and a test program:
+
+
+ The lower layer implements a simple asynchronous execution facility,
+ built directly on the system calls sproc() and [un]blockproc().
+
+ A slave thread sits in an infinite loop waiting for work assigned to
+ it by the master thread. Work is represented by a function pointer
+ and an argument of type void*. The function returns a void* pointer
+ which is transferred back to the master when it submits the next bit
+ of work. Submitting a NULL function pointer can be used by the
+ master to wait for completion of the previous work. This lower
+ layer could be generally useful, but is currently implemented by
+ static functions, for exclusive by the asynchronous audio layer.
+
+
+ The higher layer implements an asynchronous interface to the
+ /dev/audio device on the Silicon Graphics 4D/20. It defines the
+ following functions:
+
+ int asa_init()
+ Required initialization function. The other functions will call
+ abort() when they are called before asa_init(). It creates the
+ slave process and returns a file descriptor for the audio
+ device which can be used to set the sampling rate and output
+ gain, etc. It prints a message to stderr and returns -1 if the
+ initialization failed. Calling this function more than onece is
+ harmless.
+
+ void asa_start_read(char *buf, int len)
+ Starts an asynchronous read call on the audio device. This
+ waits for completion of the previous request, if any.
+
+ void asa_start_write(char *buf, int len)
+ Starts an asynchronous write call on the audio device. This
+ waits for completion of the previous request, if any.
+
+ int asa_poll()
+ Polls whether the last asynchronous read or write request is
+ finished. Returns -1 if no request was queued, 0 if the request
+ is not yet finished, and 1 if it is finished.
+
+ int asa_wait()
+ Waits for completion if the last asynchronous read or write
+ request. It returns the result of the read or write request,
+ and sets the error code to the error code set by the request if
+ the result is -1. If no request was queued, this also returns
+ -1 but leaves the error code unchanged. Note: to get the error
+ code, don't inspect the global variable errno but call the
+ function oserror().
+
+ int asa_cancel()
+ Cancels the last asynchronous read or write request (by sending
+ the slave thread a signal for which it has a handler) then
+ returns its result and error code as asa_wait().
+
+ void asa_done()
+ Kills the slave process and closes the audio device. After
+ this, if further use of the module is required, asa_init()
+ should be called again. Calling this function when asa_init()
+ has not been called is harmless.
+
+
+ Finally, this file contains a simple test program that is compiled if
+ MAIN is defined (e.g., compile with cc -DMAIN). It makes a recording
+ and plays it back. The user must indicate begin and end of recording
+ and play-back by pressing the Return key.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/prctl.h>
+
+#include "asa.h"
+
+
+/* Asynchronous execution facility (lower layer) */
+
+
+/* Signal used to cancel requests in progress */
+#define MYSIG SIGUSR1
+
+/* Respective process IDs */
+static pid_t master_pid = -1;
+static pid_t slave_pid = -1;
+
+/* Work and result "queue" (1 element) */
+static void * (*work_func)();
+static void *work_arg;
+static void *work_result;
+
+/* Signal handler for MYSIG -- interrupts read or write system call */
+
+/*ARGSUSED*/
+static void
+handler(sig)
+ int sig;
+{
+ /* Reinstate the handler (non-BSD signal semantics) */
+ signal(sig, handler);
+}
+
+/* Subroutine to fiddle signals */
+
+static void
+dosig(sig)
+ int sig;
+{
+ if (signal(sig, SIG_IGN) != SIG_IGN)
+ signal(sig, SIG_DFL);
+}
+
+/* Slave control flow */
+
+/*ARGSUSED*/
+static void
+slave(arg)
+ void *arg;
+{
+ void * (*func)();
+ void *arg;
+ void *result;
+
+ /* Reset signal handlers that interactive programs often catch.
+ The assumption is that if the master has a handler for these
+ signals, it will be a cleanup function. The slave must die
+ from these. */
+ dosig(SIGHUP);
+ dosig(SIGQUIT);
+ dosig(SIGTERM);
+ dosig(SIGPIPE);
+
+ /* Ignore SIGINT if caught or ignored */
+ if (signal(SIGINT, SIG_IGN) == SIG_DFL)
+ signal(SIGINT, SIG_DFL);
+
+ /* Let the handler install itself */
+ handler(MYSIG);
+
+ /* Set slave_pid. This is also done in the master thread, but
+ there is a race condition whereby the slave begins execution
+ before the master has assigned the result of sproc() to
+ slave_pid. So we set it here as well -- since this sets the
+ same value it should be OK. */
+ slave_pid = getpid();
+
+ /* Set the dummy result returned by the first rendezvous */
+ result = NULL;
+
+ /* Loop forever, waiting for and executing work */
+ for (;;) {
+ /* First rendezvous: store previous result */
+ if (blockproc(slave_pid) < 0)
+ perror("slave: [result] blockproc(slave_pid)");
+ work_result = result;
+ if (unblockproc(master_pid) < 0)
+ perror("slave: [result] unblockproc(master_pid)");
+
+ /* Second rendezvous: fetch work */
+ if (blockproc(slave_pid) < 0)
+ perror("slave: [func,arg] blockproc(slave_pid)");
+ func = work_func;
+ arg = work_arg;
+ if (unblockproc(master_pid) < 0)
+ perror("slave: [func,arg] unblockproc(master_pid)");
+
+ /* Execute work, computing new result */
+ if (func == NULL) {
+ result = arg;
+ }
+ else {
+ result = (*func)(arg);
+ }
+ }
+}
+
+static int
+slave_init()
+{
+ if (slave_pid > 0)
+ return slave_pid;
+ master_pid = getpid();
+
+ /* Reset the queue, in case this is a re-init after asa_done() */
+ work_result = NULL;
+ work_func = NULL;
+ work_arg = NULL;
+
+ /* Create the slave process, sharing all segments and properties */
+ slave_pid = sproc(slave, PR_SALL, (char *)NULL);
+ if (slave_pid < 0)
+ perror("slave_init: sproc(slave, PR_SALL, NULL)");
+
+ /* Set up initial conditions---tricky!
+ Both the master and the slave start with one credit, since
+ both the result slot and the work/func slots are initially
+ free.
+ Note that we use setblockproccnt() for the master so a
+ possible indeterminate semaphore value caused by a previous
+ asa_done() at an unfortunate moment doesn't harm us.
+ */
+ setblockproccnt(master_pid, 1);
+ unblockproc(slave_pid);
+
+ return slave_pid;
+}
+
+static void
+slave_done()
+{
+ if (slave_pid > 0) {
+ if (kill(slave_pid, SIGKILL) < 0)
+ perror("slave_done: kill(slave_pid, SIGKILL)");
+ }
+ slave_pid = -1;
+}
+
+/* Queue new work and return result of previous work */
+
+static void *
+rendezvous(func, arg)
+ void * (*func)();
+ void *arg;
+{
+ void *result;
+
+ if (slave_pid <= 0)
+ abort(); /* Illegal call: not initialized properly */
+
+ /* First rendezvous: store new work */
+ if (blockproc(master_pid) < 0)
+ perror("rendezvous: [func,arg] blockproc(master_pid)");
+ work_func = func;
+ work_arg = arg;
+ if (unblockproc(slave_pid) < 0)
+ perror("rendezvous: [func,arg] unblockproc(slave_pid)");
+
+ /* Second rendezvous: fetch previous result */
+ if (blockproc(master_pid) < 0)
+ perror("rendezvous: [result] blockproc(master_pid)");
+ result = work_result;
+ if (unblockproc(slave_pid) < 0)
+ perror("rendezvous: [result] unblockproc(slave_pid)");
+
+ return result;
+}
+
+
+/* Asynchronous audio interface (higher layer) */
+
+
+int audio_fd = -1; /* File descriptor -- not initialized yet */
+
+static struct queue {
+ int func; /* 0 = read, 1 = write */
+ char *buf;
+ int len;
+ int result;
+ int error;
+} queue[2];
+
+static int qindex = 0;
+
+int
+asa_init()
+{
+ int fd;
+ char *p;
+
+ if (audio_fd >= 0)
+ return audio_fd;
+ fd = open("/dev/audio", 2);
+ if (fd < 0) {
+ perror("asa_init: Can't open /dev/audio");
+ return -1;
+ }
+ if (slave_init() < 0) {
+ perror("asa_init: Can't create slave process");
+ close(fd);
+ return -1;
+ }
+ audio_fd = fd;
+ return fd;
+}
+
+void
+asa_done()
+{
+ slave_done();
+ if (audio_fd >= 0) {
+ if (close(audio_fd) < 0)
+ perror("asa_done: close(audio_fd)");
+ }
+ audio_fd = -1;
+}
+
+static void *
+runjob(arg)
+ void *arg;
+{
+ extern int errno;
+ struct queue *q = (struct queue *)arg;
+ char *buf = q->buf;
+ int len = q->len;
+ int n = 0;
+
+ if (q->func == 0)
+ n = read(audio_fd, buf, len);
+ else
+ n = write(audio_fd, buf, len);
+ if (q->func == 0 && n >= 0) {
+ while (--len >= n && buf[len] == '\0')
+ ;
+ n = len+1;
+ }
+ q->result = n;
+ q->error = oserror();
+ return arg;
+}
+
+static void
+startjob(func, buf, len)
+ int func;
+ char *buf;
+ int len;
+{
+ struct queue *q;
+
+ q = &queue[qindex];
+ qindex = (qindex+1) & 1;
+ q->func = func;
+ q->buf = buf;
+ q->len = len;
+ (void) rendezvous(runjob, (void *)q);
+}
+
+void
+asa_start_read(buf, len)
+ char *buf;
+ int len;
+{
+ memset(buf, '\0', len);
+ startjob(0, buf, len);
+}
+
+void
+asa_start_write(buf, len)
+ char *buf;
+ int len;
+{
+ startjob(1, buf, len);
+}
+
+int
+asa_wait()
+{
+ struct queue *q;
+
+ q = (struct queue *) rendezvous((void*(*)())NULL, (void *)NULL);
+ if (q == NULL) {
+ setoserror(0);
+ return -1; /* No work was queued */
+ }
+ setoserror(q->error);
+ return q->result;
+}
+
+int
+asa_poll()
+{
+ int err;
+
+ err = prctl(PR_ISBLOCKED, slave_pid);
+ if (err < 0) {
+ perror("prctl(PR_ISBLOCKED, slave_pid)");
+ return -1;
+ }
+ else if (err == 0)
+ return 0;
+ else if (work_result == NULL) {
+ setoserror(0);
+ return -1;
+ }
+ else
+ return 1;
+}
+
+int
+asa_cancel()
+{
+ int result;
+
+ kill(slave_pid, MYSIG);
+ result = asa_wait();
+ return result;
+}
+
+
+#ifdef MAIN
+
+/* Test program */
+
+#include <sys/audio.h>
+
+main()
+{
+ static char buf[10*16*1024]; /* 10 seconds of sound at 16K/sec */
+ int n;
+ int afd;
+
+ if ((afd = asa_init()) < 0)
+ exit(1);
+ ioctl(afd, AUDIOCSETRATE, 3);
+ ioctl(afd, AUDIOCSETOUTGAIN, 0);
+ printf("Poll returns %d\n", asa_poll());
+ go("Hit enter to start recording:\n");
+ asa_start_read(buf, sizeof buf);
+ go("Hit enter to stop recording:\n");
+ /*printf("Poll returns %d\n", asa_poll());*/
+ n = asa_cancel();
+ if (n < 0)
+ perror("Read failed");
+ else {
+ printf("Got %d bytes\n", n);
+ printf("Poll returns %d\n", asa_poll());
+ go("Hit enter to start playing:\n");
+ ioctl(afd, AUDIOCSETOUTGAIN, 50);
+ asa_start_write(buf, n);
+ go("Hit enter to stop playing:\n");
+ printf("Poll returns %d\n", asa_poll());
+ n = asa_cancel();
+ if (n < 0)
+ perror("Write failed");
+ else
+ printf("Stopped at %d bytes\n", n);
+ }
+ ioctl(afd, AUDIOCSETOUTGAIN, 0);
+ asa_done();
+ exit(n < 0 ? 1 : 0);
+}
+
+go(str)
+ char *str;
+{
+ char line[100];
+
+ sleep(1);
+ fputs(str, stdout);
+ fflush(stdout);
+ fgets(line, sizeof line, stdin);
+}
+
+#endif /* MAIN */
diff --git a/src/asa.h b/src/asa.h
new file mode 100644
index 0000000..d9a7d10
--- /dev/null
+++ b/src/asa.h
@@ -0,0 +1,33 @@
+/***********************************************************
+Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The
+Netherlands.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+/* Interface for asynchronous audio module */
+
+extern int asa_init(void);
+extern void asa_done(void);
+extern void asa_start_write(char *, int);
+extern void asa_start_read(char *, int);
+extern int asa_poll(void);
+extern int asa_wait(void);
+extern int asa_cancel(void);
diff --git a/src/assert.h b/src/assert.h
new file mode 100644
index 0000000..f21225e
--- /dev/null
+++ b/src/assert.h
@@ -0,0 +1,25 @@
+/***********************************************************
+Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The
+Netherlands.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+#define assert(e) { if (!(e)) { printf("Assertion failed\n"); abort(); } }
diff --git a/src/audiomodule.c b/src/audiomodule.c
new file mode 100644
index 0000000..cca0102
--- /dev/null
+++ b/src/audiomodule.c
@@ -0,0 +1,615 @@
+/***********************************************************
+Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The
+Netherlands.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+/* Silicon Graphics audio module implementation */
+/* For SGI Personal IRIS 4D/20 under IRIX 3.3; <sys/audio.h> mentions "IP6" */
+/* Note: The set-in-gain ioctl exists but is non-functional */
+
+#include <errno.h>
+#include <sys/audio.h>
+#include "asa.h"
+
+#include "allobjects.h"
+#include "modsupport.h"
+
+static int audio_fd = -1;
+
+static int
+init()
+{
+ if (audio_fd >= 0)
+ return 1;
+ if ((audio_fd = asa_init()) >= 0)
+ return 1;
+ err_setstr(RuntimeError, "can't initialize async audio");
+ return 0;
+}
+
+
+/* POSIX methods */
+
+static object *
+audio_get_ioctl(self, args, code)
+ object *self;
+ object *args;
+ long code;
+{
+ long x;
+ if (!getnoarg(args))
+ return NULL;
+ if (!init())
+ return NULL;
+ if ((x = ioctl(audio_fd, code, (char *) NULL)) < 0) {
+ return NULL;
+ }
+ return newintobject(x);
+}
+
+static object *
+audio_set_ioctl(self, args, code)
+ object *self;
+ object *args;
+ long code;
+{
+ long x;
+ if (!getlongarg(args, &x))
+ return NULL;
+ if (!init())
+ return NULL;
+ if (ioctl(audio_fd, code, (char *) x) != 0)
+ return NULL;
+ INCREF(None);
+ return None;
+}
+
+static object *
+audio_getingain(self, args)
+ object *self;
+ object *args;
+{
+ return audio_get_ioctl(self, args, AUDIOCGETINGAIN);
+}
+
+static object *
+audio_getoutgain(self, args)
+ object *self;
+ object *args;
+{
+ return audio_get_ioctl(self, args, AUDIOCGETOUTGAIN);
+}
+
+static object *
+audio_setingain(self, args)
+ object *self;
+ object *args;
+{
+ return audio_set_ioctl(self, args, AUDIOCSETINGAIN);
+}
+
+static object *
+audio_setoutgain(self, args)
+ object *self;
+ object *args;
+{
+ return audio_set_ioctl(self, args, AUDIOCSETOUTGAIN);
+}
+
+static object *
+audio_setrate(self, args)
+ object *self;
+ object *args;
+{
+ return audio_set_ioctl(self, args, AUDIOCSETRATE);
+}
+
+static object *
+audio_setduration(self, args)
+ object *self;
+ object *args;
+{
+ return audio_set_ioctl(self, args, AUDIOCDURATION);
+}
+
+/* Compute average bias, and remove it */
+
+static void
+unbias(buf, len)
+ char *buf;
+ int len;
+{
+ register int i;
+ register int c;
+ register long bias;
+ if (len == 0)
+ return;
+ bias = 0;
+ for (i = 0; i < len; i++) {
+ c = buf[i];
+ if (c > 127)
+ c -= 256;
+ bias += c;
+ }
+ bias = (bias + len/2) / len; /* Rounded average */
+ if (bias != 0) {
+ for (i = 0; i < len; i++) {
+ buf[i] -= bias;
+ }
+ }
+}
+
+static object *
+audio_read(self, args)
+ object *self;
+ object *args;
+{
+ int c, i, n;
+ object *v;
+ char *s;
+ if (!getintarg(args, &n))
+ return NULL;
+ if (n <= 0) {
+ err_setstr(RuntimeError, "audio.read: arg <= 0");
+ return NULL;
+ }
+ if (!init())
+ return NULL;
+ v = newsizedstringobject((char *)NULL, n);
+ if (v == NULL)
+ return err_nomem();
+ s = getstringvalue(v);
+ n = read(audio_fd, s, n);
+ if (intrcheck()) {
+ DECREF(v);
+ err_set(KeyboardInterrupt);
+ return NULL;
+ }
+ /* Check for errors */
+ if (n < 0) {
+ DECREF(v);
+ return NULL;
+ }
+ /* But EOF is reported as an empty string */
+
+ unbias(s, n);
+ resizestring(&v, n);
+ return v;
+}
+
+static object *
+audio_write(self, args)
+ object *self;
+ object *args;
+{
+ int n, n2;
+ object *v;
+ if (!getstrarg(args, &v))
+ return NULL;
+ if (!init())
+ return NULL;
+ errno = 0;
+ n2 = write(audio_fd, getstringvalue(v), n = getstringsize(v));
+ if (intrcheck()) {
+ err_set(KeyboardInterrupt);
+ return NULL;
+ }
+ /* Check for other errors */
+ if (n2 != n) {
+ if (errno == 0)
+ errno = EIO;
+ return NULL;
+ }
+ INCREF(None);
+ return None;
+}
+
+/* audio.amplify(sample, f1, f2).
+ Amplify a sample by a factor changing from f1/256 to (almost) f2/256.
+ Negative factors are allowed. Sound values that are to large
+ to fit in a byte are clipped. */
+
+static object *
+audio_amplify(self, args)
+ object *self;
+ object *args;
+{
+ object *v;
+ char *s, *t;
+ int f1, f2;
+ int i, n;
+ int c;
+ if (!getstrintintarg(args, &v, &f1, &f2))
+ return NULL;
+ n = getstringsize(v);
+ s = getstringvalue(v);
+ v = newsizedstringobject((char *)NULL, n);
+ if (v == NULL)
+ return err_nomem();
+ t = getstringvalue(v);
+ for (i = 0; i < n; i++) {
+ c = s[i];
+ if (c > 127) c -= 256; /* If chars are unsigned */
+ c = c * ( f1*(n-i) + f2*i ) / ( n*256 );
+ if (c > 127) c = 127;
+ else if (c < -128) c = -128;
+ t[i] = c;
+ }
+ return v;
+}
+
+/* audio.reverse(s): return a sample backwards */
+
+static object *
+audio_reverse(self, args)
+ object *self;
+ object *args;
+{
+ object *v;
+ char *s, *t;
+ int i, n;
+ if (!getstrarg(args, &v))
+ return NULL;
+ n = getstringsize(v);
+ s = getstringvalue(v);
+ v = newsizedstringobject((char *)NULL, n);
+ if (v == NULL)
+ return err_nomem();
+ t = getstringvalue(v);
+ for (i = 0; i < n; i++) {
+ t[n-1-i] = s[i];
+ }
+ return v;
+}
+
+/* audio.add(a, b): add two samples.
+ Bytes that exceed the range are clipped.
+ If one is shorter, the rest of the longer sample is returned unchanged. */
+
+static object *
+audio_add(self, args)
+ object *self;
+ object *args;
+{
+ object *a, *b, *v;
+ char *sa, *sb, *t;
+ int i, n, na, nb, c, ca, cb;
+ if (!getstrstrarg(args, &a, &b))
+ return NULL;
+ na = getstringsize(a);
+ sa = getstringvalue(a);
+ nb = getstringsize(b);
+ sb = getstringvalue(b);
+ n = (na > nb) ? na : nb;
+ v = newsizedstringobject((char *)NULL, n);
+ if (v == NULL)
+ return err_nomem();
+ t = getstringvalue(v);
+ for (i = 0; i < n; i++) {
+ c = 0;
+ if (i < na) {
+ ca = sa[i];
+ if (ca > 127) ca = ca - 256;
+ c = c + ca;
+ }
+ if (i < nb) {
+ cb = sb[i];
+ if (cb > 127) cb = cb - 256;
+ c = c + cb;
+ }
+ if (c > 127) c = 127;
+ else if (c < -128) c = -128;
+ t[i] = c;
+ }
+ return v;
+}
+
+/* audio.chr2num(s) returns a list containing the numeric values
+ of the samples. */
+
+static object *
+audio_chr2num(self, args)
+ object *self;
+ object *args;
+{
+ object *v, *w;
+ char *s;
+ int c, i, n;
+ static object *ints[256];
+
+ /* To avoid filling memory with all those int objects, we create
+ integer objects for all the desired values and reference these. */
+ if (ints[255] == NULL) {
+ for (i = 0; i < 256; i++) {
+ if (ints[i] != NULL)
+ continue;
+ c = i;
+ if (c > 127) c -= 256;
+ ints[i] = newintobject((long)c);
+ if (ints[i] == NULL)
+ return NULL;
+ }
+ }
+
+ if (!getstrarg(args, &v))
+ return NULL;
+ n = getstringsize(v);
+ s = getstringvalue(v);
+ v = newlistobject(n);
+ if (v == NULL)
+ return err_nomem();
+ for (i = 0; i < n; i++) {
+ c = s[i] & 0xff;
+ w = ints[c];
+ INCREF(w);
+ if (setlistitem(v, i, w) != 0) {
+ DECREF(v);
+ return NULL;
+ }
+ }
+ return v;
+}
+
+/* audio.num2chr is the inverse of audio.chr2num.
+ Excess values are clipped. */
+
+static object *
+audio_num2chr(self, args)
+ object *self;
+ object *args;
+{
+ object *v, *w;
+ char *s;
+ int c, i, n;
+ if (!is_listobject(args)) {
+ err_badarg();
+ return NULL;
+ }
+ n = getlistsize(args);
+ v = newsizedstringobject((char *)NULL, n);
+ if (v == NULL)
+ return NULL;
+ s = getstringvalue(v);
+ for (i = 0; i < n; i++) {
+ w = getlistitem(args, i);
+ if (!is_intobject(w)) {
+ DECREF(v);
+ err_badarg();
+ return NULL;
+ }
+ s[i] = getintvalue(w);
+ }
+ return v;
+}
+
+static object *stdaudio_buffer = NULL;
+
+static object *
+audio_start_recording(self, args)
+ object *self;
+ object *args;
+{
+ int n;
+ object *v;
+ char *s;
+ if (!getintarg(args, &n))
+ return NULL;
+ if (stdaudio_buffer != NULL) {
+ err_setstr(RuntimeError, "audio.start_recording: device busy");
+ return NULL;
+ }
+ if (n <= 0) {
+ err_setstr(TypeError, "audio.start_recording: arg <= 0");
+ return NULL;
+ }
+ if (!init())
+ return NULL;
+ v = newsizedstringobject((char *)NULL, n);
+ if (v == NULL)
+ return err_nomem();
+ s = getstringvalue(v);
+ asa_start_read(s, n);
+ stdaudio_buffer = v;
+ INCREF(None);
+ return None;
+}
+
+static object *
+audio_poll(self, args)
+ object *self;
+ object *args;
+{
+ int n;
+ if (!getnoarg(args))
+ return NULL;
+ if (stdaudio_buffer == NULL) {
+ err_setstr(RuntimeError, "audio.poll: not busy");
+ return NULL;
+ }
+ if (!init())
+ return NULL;
+ if ((n = asa_poll()) < 0)
+ return NULL;
+ return newintobject(n);
+}
+
+static object *
+audio_wait_recording(self, args)
+ object *self;
+ object *args;
+{
+ object *v;
+ int n;
+ if (!getnoarg(args))
+ return NULL;
+ if (stdaudio_buffer == NULL) {
+ err_setstr(RuntimeError, "audio.wait_recording: not busy");
+ return NULL;
+ }
+ if (!init())
+ return NULL;
+ if ((n = asa_wait()) < 0)
+ return NULL;
+ v = stdaudio_buffer;
+ stdaudio_buffer = NULL;
+ unbias(getstringvalue(v), n);
+ resizestring(&v, n);
+ return v;
+}
+
+static object *
+audio_stop_recording(self, args)
+ object *self;
+ object *args;
+{
+ int n;
+ object *v;
+ char *s;
+ if (!getnoarg(args))
+ return NULL;
+ if (stdaudio_buffer == NULL) {
+ err_setstr(RuntimeError, "audio.stop_recording: not busy");
+ return NULL;
+ }
+ if ((n = asa_cancel()) < 0)
+ return NULL;
+ v = stdaudio_buffer;
+ stdaudio_buffer = NULL;
+ s = getstringvalue(v);
+ unbias(s, n);
+ resizestring(&v, n);
+ return v;
+}
+
+static object *
+audio_start_playing(self, args)
+ object *self;
+ object *args;
+{
+ object *v;
+ if (!getstrarg(args, &v))
+ return NULL;
+ if (stdaudio_buffer != NULL) {
+ err_setstr(RuntimeError, "audio.start_recording: device rbusy");
+ return NULL;
+ }
+ asa_start_write(getstringvalue(v), (int)getstringsize(v));
+ INCREF(v);
+ stdaudio_buffer = v;
+ INCREF(None);
+ return None;
+}
+
+static object *
+audio_wait_playing(self, args)
+ object *self;
+ object *args;
+{
+ int n;
+ if (!getnoarg(args))
+ return NULL;
+ if (stdaudio_buffer == NULL) {
+ err_setstr(RuntimeError, "audio.wait_playing: not busy");
+ return NULL;
+ }
+ if ((n = asa_wait()) < 0)
+ return NULL;
+ DECREF(stdaudio_buffer);
+ stdaudio_buffer = NULL;
+ /* XXX return newintobject((long)n); ??? */
+ INCREF(None);
+ return None;
+}
+
+static object *
+audio_stop_playing(self, args)
+ object *self;
+ object *args;
+{
+ int n;
+ if (!getnoarg(args))
+ return NULL;
+ if (stdaudio_buffer == NULL) {
+ err_setstr(RuntimeError, "audio.stop_playing: not busy");
+ return NULL;
+ }
+ if ((n = asa_cancel()) < 0)
+ return NULL;
+ DECREF(stdaudio_buffer);
+ stdaudio_buffer = NULL;
+ return newintobject((long)n);
+}
+
+static object *
+audio_audio_done(self, args)
+ object *self;
+ object *args;
+{
+ if (!getnoarg(args))
+ return NULL;
+ asa_done();
+ if (stdaudio_buffer != NULL)
+ DECREF(stdaudio_buffer);
+ stdaudio_buffer = NULL;
+ audio_fd = -1;
+ INCREF(None);
+ return None;
+}
+
+
+static struct methodlist audio_methods[] = {
+ {"getingain", audio_getingain},
+ {"getoutgain", audio_getoutgain},
+ {"setingain", audio_setingain},
+ {"setoutgain", audio_setoutgain},
+ {"setrate", audio_setrate},
+ {"setduration", audio_setduration},
+ {"read", audio_read},
+ {"write", audio_write},
+ {"amplify", audio_amplify},
+ {"reverse", audio_reverse},
+ {"add", audio_add},
+ {"chr2num", audio_chr2num},
+ {"num2chr", audio_num2chr},
+
+ /* "asa" interface: */
+
+ {"start_recording", audio_start_recording},
+ {"poll_recording", audio_poll},
+ {"wait_recording", audio_wait_recording},
+ {"stop_recording", audio_stop_recording},
+
+ {"start_playing", audio_start_playing},
+ {"poll_playing", audio_poll},
+ {"wait_playing", audio_wait_playing},
+ {"stop_playing", audio_stop_playing},
+
+ {"done", audio_audio_done},
+
+ {NULL, NULL} /* Sentinel */
+};
+
+void
+initaudio()
+{
+ initmodule("audio", audio_methods);
+}
diff --git a/src/bitset.c b/src/bitset.c
new file mode 100644
index 0000000..c08dcc7
--- /dev/null
+++ b/src/bitset.c
@@ -0,0 +1,99 @@
+/***********************************************************
+Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The
+Netherlands.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+/* Bitset primitives used by the parser generator */
+
+#include "pgenheaders.h"
+#include "bitset.h"
+
+bitset
+newbitset(nbits)
+ int nbits;
+{
+ int nbytes = NBYTES(nbits);
+ bitset ss = NEW(BYTE, nbytes);
+
+ if (ss == NULL)
+ fatal("no mem for bitset");
+
+ ss += nbytes;
+ while (--nbytes >= 0)
+ *--ss = 0;
+ return ss;
+}
+
+void
+delbitset(ss)
+ bitset ss;
+{
+ DEL(ss);
+}
+
+int
+addbit(ss, ibit)
+ bitset ss;
+ int ibit;
+{
+ int ibyte = BIT2BYTE(ibit);
+ BYTE mask = BIT2MASK(ibit);
+
+ if (ss[ibyte] & mask)
+ return 0; /* Bit already set */
+ ss[ibyte] |= mask;
+ return 1;
+}
+
+#if 0 /* Now a macro */
+int
+testbit(ss, ibit)
+ bitset ss;
+ int ibit;
+{
+ return (ss[BIT2BYTE(ibit)] & BIT2MASK(ibit)) != 0;
+}
+#endif
+
+int
+samebitset(ss1, ss2, nbits)
+ bitset ss1, ss2;
+ int nbits;
+{
+ int i;
+
+ for (i = NBYTES(nbits); --i >= 0; )
+ if (*ss1++ != *ss2++)
+ return 0;
+ return 1;
+}
+
+void
+mergebitset(ss1, ss2, nbits)
+ bitset ss1, ss2;
+ int nbits;
+{
+ int i;
+
+ for (i = NBYTES(nbits); --i >= 0; )
+ *ss1++ |= *ss2++;
+}
diff --git a/src/bitset.h b/src/bitset.h
new file mode 100644
index 0000000..5ec6882
--- /dev/null
+++ b/src/bitset.h
@@ -0,0 +1,46 @@
+/***********************************************************
+Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The
+Netherlands.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+/* Bitset interface */
+
+#define BYTE char
+
+typedef BYTE *bitset;
+
+bitset newbitset PROTO((int nbits));
+void delbitset PROTO((bitset bs));
+/* int testbit PROTO((bitset bs, int ibit)); /* Now a macro, see below */
+int addbit PROTO((bitset bs, int ibit)); /* Returns 0 if already set */
+int samebitset PROTO((bitset bs1, bitset bs2, int nbits));
+void mergebitset PROTO((bitset bs1, bitset bs2, int nbits));
+
+#define BITSPERBYTE (8*sizeof(BYTE))
+#define NBYTES(nbits) (((nbits) + BITSPERBYTE - 1) / BITSPERBYTE)
+
+#define BIT2BYTE(ibit) ((ibit) / BITSPERBYTE)
+#define BIT2SHIFT(ibit) ((ibit) % BITSPERBYTE)
+#define BIT2MASK(ibit) (1 << BIT2SHIFT(ibit))
+#define BYTE2BIT(ibyte) ((ibyte) * BITSPERBYTE)
+
+#define testbit(ss, ibit) (((ss)[BIT2BYTE(ibit)] & BIT2MASK(ibit)) != 0)
diff --git a/src/bltinmodule.c b/src/bltinmodule.c
new file mode 100644
index 0000000..151ba86
--- /dev/null
+++ b/src/bltinmodule.c
@@ -0,0 +1,559 @@
+/***********************************************************
+Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The
+Netherlands.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+/* Built-in functions */
+
+#include "allobjects.h"
+
+#include "node.h"
+#include "graminit.h"
+#include "errcode.h"
+#include "sysmodule.h"
+#include "bltinmodule.h"
+#include "import.h"
+#include "pythonrun.h"
+#include "compile.h" /* For ceval.h */
+#include "ceval.h"
+#include "modsupport.h"
+
+static object *
+builtin_abs(self, v)
+ object *self;
+ object *v;
+{
+ /* XXX This should be a method in the as_number struct in the type */
+ if (v == NULL) {
+ /* */
+ }
+ else if (is_intobject(v)) {
+ long x = getintvalue(v);
+ if (x < 0)
+ x = -x;
+ return newintobject(x);
+ }
+ else if (is_floatobject(v)) {
+ double x = getfloatvalue(v);
+ if (x < 0)
+ x = -x;
+ return newfloatobject(x);
+ }
+ err_setstr(TypeError, "abs() argument must be float or int");
+ return NULL;
+}
+
+static object *
+builtin_chr(self, v)
+ object *self;
+ object *v;
+{
+ long x;
+ char s[1];
+ if (v == NULL || !is_intobject(v)) {
+ err_setstr(TypeError, "chr() must have int argument");
+ return NULL;
+ }
+ x = getintvalue(v);
+ if (x < 0 || x >= 256) {
+ err_setstr(RuntimeError, "chr() arg not in range(256)");
+ return NULL;
+ }
+ s[0] = x;
+ return newsizedstringobject(s, 1);
+}
+
+static object *
+builtin_dir(self, v)
+ object *self;
+ object *v;
+{
+ object *d;
+ if (v == NULL) {
+ d = getlocals();
+ }
+ else {
+ if (!is_moduleobject(v)) {
+ err_setstr(TypeError,
+ "dir() argument, must be module or absent");
+ return NULL;
+ }
+ d = getmoduledict(v);
+ }
+ v = getdictkeys(d);
+ if (sortlist(v) != 0) {
+ DECREF(v);
+ v = NULL;
+ }
+ return v;
+}
+
+static object *
+builtin_divmod(self, v)
+ object *self;
+ object *v;
+{
+ object *x, *y;
+ long xi, yi, xdivy, xmody;
+ if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) {
+ err_setstr(TypeError, "divmod() requires 2 int arguments");
+ return NULL;
+ }
+ x = gettupleitem(v, 0);
+ y = gettupleitem(v, 1);
+ if (!is_intobject(x) || !is_intobject(y)) {
+ err_setstr(TypeError, "divmod() requires 2 int arguments");
+ return NULL;
+ }
+ xi = getintvalue(x);
+ yi = getintvalue(y);
+ if (yi == 0) {
+ err_setstr(TypeError, "divmod() division by zero");
+ return NULL;
+ }
+ if (yi < 0) {
+ xdivy = -xi / -yi;
+ }
+ else {
+ xdivy = xi / yi;
+ }
+ xmody = xi - xdivy*yi;
+ if (xmody < 0 && yi > 0 || xmody > 0 && yi < 0) {
+ xmody += yi;
+ xdivy -= 1;
+ }
+ v = newtupleobject(2);
+ x = newintobject(xdivy);
+ y = newintobject(xmody);
+ if (v == NULL || x == NULL || y == NULL ||
+ settupleitem(v, 0, x) != 0 ||
+ settupleitem(v, 1, y) != 0) {
+ XDECREF(v);
+ XDECREF(x);
+ XDECREF(y);
+ return NULL;
+ }
+ return v;
+}
+
+static object *
+exec_eval(v, start)
+ object *v;
+ int start;
+{
+ object *str = NULL, *globals = NULL, *locals = NULL;
+ int n;
+ if (v != NULL) {
+ if (is_stringobject(v))
+ str = v;
+ else if (is_tupleobject(v) &&
+ ((n = gettuplesize(v)) == 2 || n == 3)) {
+ str = gettupleitem(v, 0);
+ globals = gettupleitem(v, 1);
+ if (n == 3)
+ locals = gettupleitem(v, 2);
+ }
+ }
+ if (str == NULL || !is_stringobject(str) ||
+ globals != NULL && !is_dictobject(globals) ||
+ locals != NULL && !is_dictobject(locals)) {
+ err_setstr(TypeError,
+ "exec/eval arguments must be string[,dict[,dict]]");
+ return NULL;
+ }
+ return run_string(getstringvalue(str), start, globals, locals);
+}
+
+static object *
+builtin_eval(self, v)
+ object *self;
+ object *v;
+{
+ return exec_eval(v, eval_input);
+}
+
+static object *
+builtin_exec(self, v)
+ object *self;
+ object *v;
+{
+ return exec_eval(v, file_input);
+}
+
+static object *
+builtin_float(self, v)
+ object *self;
+ object *v;
+{
+ if (v == NULL) {
+ /* */
+ }
+ else if (is_floatobject(v)) {
+ INCREF(v);
+ return v;
+ }
+ else if (is_intobject(v)) {
+ long x = getintvalue(v);
+ return newfloatobject((double)x);
+ }
+ err_setstr(TypeError, "float() argument must be float or int");
+ return NULL;
+}
+
+static object *
+builtin_input(self, v)
+ object *self;
+ object *v;
+{
+ FILE *in = sysgetfile("stdin", stdin);
+ FILE *out = sysgetfile("stdout", stdout);
+ node *n;
+ int err;
+ object *m, *d;
+ flushline();
+ if (v != NULL)
+ printobject(v, out, PRINT_RAW);
+ m = add_module("__main__");
+ d = getmoduledict(m);
+ return run_file(in, "<stdin>", expr_input, d, d);
+}
+
+static object *
+builtin_int(self, v)
+ object *self;
+ object *v;
+{
+ if (v == NULL) {
+ /* */
+ }
+ else if (is_intobject(v)) {
+ INCREF(v);
+ return v;
+ }
+ else if (is_floatobject(v)) {
+ double x = getfloatvalue(v);
+ return newintobject((long)x);
+ }
+ err_setstr(TypeError, "int() argument must be float or int");
+ return NULL;
+}
+
+static object *
+builtin_len(self, v)
+ object *self;
+ object *v;
+{
+ long len;
+ typeobject *tp;
+ if (v == NULL) {
+ err_setstr(TypeError, "len() without argument");
+ return NULL;
+ }
+ tp = v->ob_type;
+ if (tp->tp_as_sequence != NULL) {
+ len = (*tp->tp_as_sequence->sq_length)(v);
+ }
+ else if (tp->tp_as_mapping != NULL) {
+ len = (*tp->tp_as_mapping->mp_length)(v);
+ }
+ else {
+ err_setstr(TypeError, "len() of unsized object");
+ return NULL;
+ }
+ return newintobject(len);
+}
+
+static object *
+min_max(v, sign)
+ object *v;
+ int sign;
+{
+ int i, n, cmp;
+ object *w, *x;
+ sequence_methods *sq;
+ if (v == NULL) {
+ err_setstr(TypeError, "min() or max() without argument");
+ return NULL;
+ }
+ sq = v->ob_type->tp_as_sequence;
+ if (sq == NULL) {
+ err_setstr(TypeError, "min() or max() of non-sequence");
+ return NULL;
+ }
+ n = (*sq->sq_length)(v);
+ if (n == 0) {
+ err_setstr(RuntimeError, "min() or max() of empty sequence");
+ return NULL;
+ }
+ w = (*sq->sq_item)(v, 0); /* Implies INCREF */
+ for (i = 1; i < n; i++) {
+ x = (*sq->sq_item)(v, i); /* Implies INCREF */
+ cmp = cmpobject(x, w);
+ if (cmp * sign > 0) {
+ DECREF(w);
+ w = x;
+ }
+ else
+ DECREF(x);
+ }
+ return w;
+}
+
+static object *
+builtin_min(self, v)
+ object *self;
+ object *v;
+{
+ return min_max(v, -1);
+}
+
+static object *
+builtin_max(self, v)
+ object *self;
+ object *v;
+{
+ return min_max(v, 1);
+}
+
+static object *
+builtin_open(self, v)
+ object *self;
+ object *v;
+{
+ object *name, *mode;
+ if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2 ||
+ !is_stringobject(name = gettupleitem(v, 0)) ||
+ !is_stringobject(mode = gettupleitem(v, 1))) {
+ err_setstr(TypeError, "open() requires 2 string arguments");
+ return NULL;
+ }
+ v = newfileobject(getstringvalue(name), getstringvalue(mode));
+ return v;
+}
+
+static object *
+builtin_ord(self, v)
+ object *self;
+ object *v;
+{
+ if (v == NULL || !is_stringobject(v)) {
+ err_setstr(TypeError, "ord() must have string argument");
+ return NULL;
+ }
+ if (getstringsize(v) != 1) {
+ err_setstr(RuntimeError, "ord() arg must have length 1");
+ return NULL;
+ }
+ return newintobject((long)(getstringvalue(v)[0] & 0xff));
+}
+
+static object *
+builtin_range(self, v)
+ object *self;
+ object *v;
+{
+ static char *errmsg = "range() requires 1-3 int arguments";
+ int i, n;
+ long ilow, ihigh, istep;
+ if (v != NULL && is_intobject(v)) {
+ ilow = 0; ihigh = getintvalue(v); istep = 1;
+ }
+ else if (v == NULL || !is_tupleobject(v)) {
+ err_setstr(TypeError, errmsg);
+ return NULL;
+ }
+ else {
+ n = gettuplesize(v);
+ if (n < 1 || n > 3) {
+ err_setstr(TypeError, errmsg);
+ return NULL;
+ }
+ for (i = 0; i < n; i++) {
+ if (!is_intobject(gettupleitem(v, i))) {
+ err_setstr(TypeError, errmsg);
+ return NULL;
+ }
+ }
+ if (n == 3) {
+ istep = getintvalue(gettupleitem(v, 2));
+ --n;
+ }
+ else
+ istep = 1;
+ ihigh = getintvalue(gettupleitem(v, --n));
+ if (n > 0)
+ ilow = getintvalue(gettupleitem(v, 0));
+ else
+ ilow = 0;
+ }
+ if (istep == 0) {
+ err_setstr(RuntimeError, "zero step for range()");
+ return NULL;
+ }
+ /* XXX ought to check overflow of subtraction */
+ if (istep > 0)
+ n = (ihigh - ilow + istep - 1) / istep;
+ else
+ n = (ihigh - ilow + istep + 1) / istep;
+ if (n < 0)
+ n = 0;
+ v = newlistobject(n);
+ if (v == NULL)
+ return NULL;
+ for (i = 0; i < n; i++) {
+ object *w = newintobject(ilow);
+ if (w == NULL) {
+ DECREF(v);
+ return NULL;
+ }
+ setlistitem(v, i, w);
+ ilow += istep;
+ }
+ return v;
+}
+
+static object *
+builtin_raw_input(self, v)
+ object *self;
+ object *v;
+{
+ FILE *in = sysgetfile("stdin", stdin);
+ FILE *out = sysgetfile("stdout", stdout);
+ char *p;
+ int err;
+ int n = 1000;
+ flushline();
+ if (v != NULL)
+ printobject(v, out, PRINT_RAW);
+ v = newsizedstringobject((char *)NULL, n);
+ if (v != NULL) {
+ if ((err = fgets_intr(getstringvalue(v), n+1, in)) != E_OK) {
+ err_input(err);
+ DECREF(v);
+ return NULL;
+ }
+ else {
+ n = strlen(getstringvalue(v));
+ if (n > 0 && getstringvalue(v)[n-1] == '\n')
+ n--;
+ resizestring(&v, n);
+ }
+ }
+ return v;
+}
+
+static object *
+builtin_reload(self, v)
+ object *self;
+ object *v;
+{
+ return reload_module(v);
+}
+
+static object *
+builtin_type(self, v)
+ object *self;
+ object *v;
+{
+ if (v == NULL) {
+ err_setstr(TypeError, "type() requres an argument");
+ return NULL;
+ }
+ v = (object *)v->ob_type;
+ INCREF(v);
+ return v;
+}
+
+static struct methodlist builtin_methods[] = {
+ {"abs", builtin_abs},
+ {"chr", builtin_chr},
+ {"dir", builtin_dir},
+ {"divmod", builtin_divmod},
+ {"eval", builtin_eval},
+ {"exec", builtin_exec},
+ {"float", builtin_float},
+ {"input", builtin_input},
+ {"int", builtin_int},
+ {"len", builtin_len},
+ {"max", builtin_max},
+ {"min", builtin_min},
+ {"open", builtin_open}, /* XXX move to OS module */
+ {"ord", builtin_ord},
+ {"range", builtin_range},
+ {"raw_input", builtin_raw_input},
+ {"reload", builtin_reload},
+ {"type", builtin_type},
+ {NULL, NULL},
+};
+
+static object *builtin_dict;
+
+object *
+getbuiltin(name)
+ char *name;
+{
+ return dictlookup(builtin_dict, name);
+}
+
+/* Predefined exceptions */
+
+object *RuntimeError;
+object *EOFError;
+object *TypeError;
+object *MemoryError;
+object *NameError;
+object *SystemError;
+object *KeyboardInterrupt;
+
+static object *
+newstdexception(name, message)
+ char *name, *message;
+{
+ object *v = newstringobject(message);
+ if (v == NULL || dictinsert(builtin_dict, name, v) != 0)
+ fatal("no mem for new standard exception");
+ return v;
+}
+
+static void
+initerrors()
+{
+ RuntimeError = newstdexception("RuntimeError", "run-time error");
+ EOFError = newstdexception("EOFError", "end-of-file read");
+ TypeError = newstdexception("TypeError", "type error");
+ MemoryError = newstdexception("MemoryError", "out of memory");
+ NameError = newstdexception("NameError", "undefined name");
+ SystemError = newstdexception("SystemError", "system error");
+ KeyboardInterrupt =
+ newstdexception("KeyboardInterrupt", "keyboard interrupt");
+}
+
+void
+initbuiltin()
+{
+ object *m;
+ m = initmodule("builtin", builtin_methods);
+ builtin_dict = getmoduledict(m);
+ INCREF(builtin_dict);
+ initerrors();
+ (void) dictinsert(builtin_dict, "None", None);
+}
diff --git a/src/bltinmodule.h b/src/bltinmodule.h
new file mode 100644
index 0000000..fe16907
--- /dev/null
+++ b/src/bltinmodule.h
@@ -0,0 +1,27 @@
+/***********************************************************
+Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The
+Netherlands.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+/* Built-in module interface */
+
+extern object *getbuiltin PROTO((char *));
diff --git a/src/ceval.c b/src/ceval.c
new file mode 100644
index 0000000..6876208
--- /dev/null
+++ b/src/ceval.c
@@ -0,0 +1,1436 @@
+/***********************************************************
+Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The
+Netherlands.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+/* Execute compiled code */
+
+#include "allobjects.h"
+
+#include "import.h"
+#include "sysmodule.h"
+#include "compile.h"
+#include "frameobject.h"
+#include "ceval.h"
+#include "opcode.h"
+#include "bltinmodule.h"
+#include "traceback.h"
+
+#ifndef NDEBUG
+#define TRACE
+#endif
+
+#ifdef TRACE
+static int
+prtrace(v, str)
+ object *v;
+ char *str;
+{
+ printf("%s ", str);
+ printobject(v, stdout, 0);
+ printf("\n");
+}
+#endif
+
+static frameobject *current_frame;
+
+object *
+getlocals()
+{
+ if (current_frame == NULL)
+ return NULL;
+ else
+ return current_frame->f_locals;
+}
+
+object *
+getglobals()
+{
+ if (current_frame == NULL)
+ return NULL;
+ else
+ return current_frame->f_globals;
+}
+
+void
+printtraceback(fp)
+ FILE *fp;
+{
+ object *v = tb_fetch();
+ if (v != NULL) {
+ fprintf(fp, "Stack backtrace (innermost last):\n");
+ tb_print(v, fp);
+ DECREF(v);
+ }
+}
+
+
+/* XXX Mixing "print ...," and direct file I/O on stdin/stdout
+ XXX has some bad consequences. The needspace flag should
+ XXX really be part of the file object. */
+
+static int needspace;
+
+void
+flushline()
+{
+ FILE *fp = sysgetfile("stdout", stdout);
+ if (needspace) {
+ fprintf(fp, "\n");
+ needspace = 0;
+ }
+}
+
+
+/* Test a value used as condition, e.g., in a for or if statement */
+
+static int
+testbool(v)
+ object *v;
+{
+ if (is_intobject(v))
+ return getintvalue(v) != 0;
+ if (is_floatobject(v))
+ return getfloatvalue(v) != 0.0;
+ if (v->ob_type->tp_as_sequence != NULL)
+ return (*v->ob_type->tp_as_sequence->sq_length)(v) != 0;
+ if (v->ob_type->tp_as_mapping != NULL)
+ return (*v->ob_type->tp_as_mapping->mp_length)(v) != 0;
+ if (v == None)
+ return 0;
+ /* All other objects are 'true' */
+ return 1;
+}
+
+static object *
+add(v, w)
+ object *v, *w;
+{
+ if (v->ob_type->tp_as_number != NULL)
+ v = (*v->ob_type->tp_as_number->nb_add)(v, w);
+ else if (v->ob_type->tp_as_sequence != NULL)
+ v = (*v->ob_type->tp_as_sequence->sq_concat)(v, w);
+ else {
+ err_setstr(TypeError, "+ not supported by operands");
+ return NULL;
+ }
+ return v;
+}
+
+static object *
+sub(v, w)
+ object *v, *w;
+{
+ if (v->ob_type->tp_as_number != NULL)
+ return (*v->ob_type->tp_as_number->nb_subtract)(v, w);
+ err_setstr(TypeError, "bad operand type(s) for -");
+ return NULL;
+}
+
+static object *
+mul(v, w)
+ object *v, *w;
+{
+ typeobject *tp;
+ if (is_intobject(v) && w->ob_type->tp_as_sequence != NULL) {
+ /* int*sequence -- swap v and w */
+ object *tmp = v;
+ v = w;
+ w = tmp;
+ }
+ tp = v->ob_type;
+ if (tp->tp_as_number != NULL)
+ return (*tp->tp_as_number->nb_multiply)(v, w);
+ if (tp->tp_as_sequence != NULL) {
+ if (!is_intobject(w)) {
+ err_setstr(TypeError,
+ "can't multiply sequence with non-int");
+ return NULL;
+ }
+ if (tp->tp_as_sequence->sq_repeat == NULL) {
+ err_setstr(TypeError, "sequence does not support *");
+ return NULL;
+ }
+ return (*tp->tp_as_sequence->sq_repeat)
+ (v, (int)getintvalue(w));
+ }
+ err_setstr(TypeError, "bad operand type(s) for *");
+ return NULL;
+}
+
+static object *
+divide(v, w)
+ object *v, *w;
+{
+ if (v->ob_type->tp_as_number != NULL)
+ return (*v->ob_type->tp_as_number->nb_divide)(v, w);
+ err_setstr(TypeError, "bad operand type(s) for /");
+ return NULL;
+}
+
+static object *
+rem(v, w)
+ object *v, *w;
+{
+ if (v->ob_type->tp_as_number != NULL)
+ return (*v->ob_type->tp_as_number->nb_remainder)(v, w);
+ err_setstr(TypeError, "bad operand type(s) for %");
+ return NULL;
+}
+
+static object *
+neg(v)
+ object *v;
+{
+ if (v->ob_type->tp_as_number != NULL)
+ return (*v->ob_type->tp_as_number->nb_negative)(v);
+ err_setstr(TypeError, "bad operand type(s) for unary -");
+ return NULL;
+}
+
+static object *
+pos(v)
+ object *v;
+{
+ if (v->ob_type->tp_as_number != NULL)
+ return (*v->ob_type->tp_as_number->nb_positive)(v);
+ err_setstr(TypeError, "bad operand type(s) for unary +");
+ return NULL;
+}
+
+static object *
+not(v)
+ object *v;
+{
+ int outcome = testbool(v);
+ object *w = outcome == 0 ? True : False;
+ INCREF(w);
+ return w;
+}
+
+static object *
+call_builtin(func, arg)
+ object *func;
+ object *arg;
+{
+ if (is_methodobject(func)) {
+ method meth = getmethod(func);
+ object *self = getself(func);
+ return (*meth)(self, arg);
+ }
+ if (is_classobject(func)) {
+ if (arg != NULL) {
+ err_setstr(TypeError,
+ "classobject() allows no arguments");
+ return NULL;
+ }
+ return newclassmemberobject(func);
+ }
+ err_setstr(TypeError, "call of non-function");
+ return NULL;
+}
+
+static object *
+call_function(func, arg)
+ object *func;
+ object *arg;
+{
+ object *newarg = NULL;
+ object *newlocals, *newglobals;
+ object *co, *v;
+
+ if (is_classmethodobject(func)) {
+ object *self = classmethodgetself(func);
+ func = classmethodgetfunc(func);
+ if (arg == NULL) {
+ arg = self;
+ }
+ else {
+ newarg = newtupleobject(2);
+ if (newarg == NULL)
+ return NULL;
+ INCREF(self);
+ INCREF(arg);
+ settupleitem(newarg, 0, self);
+ settupleitem(newarg, 1, arg);
+ arg = newarg;
+ }
+ }
+ else {
+ if (!is_funcobject(func)) {
+ err_setstr(TypeError, "call of non-function");
+ return NULL;
+ }
+ }
+
+ co = getfunccode(func);
+ if (co == NULL) {
+ XDECREF(newarg);
+ return NULL;
+ }
+ if (!is_codeobject(co)) {
+ fprintf(stderr, "XXX Bad code\n");
+ abort();
+ }
+ newlocals = newdictobject();
+ if (newlocals == NULL) {
+ XDECREF(newarg);
+ return NULL;
+ }
+
+ newglobals = getfuncglobals(func);
+ INCREF(newglobals);
+
+ v = eval_code((codeobject *)co, newglobals, newlocals, arg);
+
+ DECREF(newlocals);
+ DECREF(newglobals);
+
+ XDECREF(newarg);
+
+ return v;
+}
+
+static object *
+apply_subscript(v, w)
+ object *v, *w;
+{
+ typeobject *tp = v->ob_type;
+ if (tp->tp_as_sequence == NULL && tp->tp_as_mapping == NULL) {
+ err_setstr(TypeError, "unsubscriptable object");
+ return NULL;
+ }
+ if (tp->tp_as_sequence != NULL) {
+ int i;
+ if (!is_intobject(w)) {
+ err_setstr(TypeError, "sequence subscript not int");
+ return NULL;
+ }
+ i = getintvalue(w);
+ return (*tp->tp_as_sequence->sq_item)(v, i);
+ }
+ return (*tp->tp_as_mapping->mp_subscript)(v, w);
+}
+
+static object *
+loop_subscript(v, w)
+ object *v, *w;
+{
+ sequence_methods *sq = v->ob_type->tp_as_sequence;
+ int i, n;
+ if (sq == NULL) {
+ err_setstr(TypeError, "loop over non-sequence");
+ return NULL;
+ }
+ i = getintvalue(w);
+ n = (*sq->sq_length)(v);
+ if (i >= n)
+ return NULL; /* End of loop */
+ return (*sq->sq_item)(v, i);
+}
+
+static int
+slice_index(v, isize, pi)
+ object *v;
+ int isize;
+ int *pi;
+{
+ if (v != NULL) {
+ if (!is_intobject(v)) {
+ err_setstr(TypeError, "slice index must be int");
+ return -1;
+ }
+ *pi = getintvalue(v);
+ if (*pi < 0)
+ *pi += isize;
+ }
+ return 0;
+}
+
+static object *
+apply_slice(u, v, w) /* return u[v:w] */
+ object *u, *v, *w;
+{
+ typeobject *tp = u->ob_type;
+ int ilow, ihigh, isize;
+ if (tp->tp_as_sequence == NULL) {
+ err_setstr(TypeError, "only sequences can be sliced");
+ return NULL;
+ }
+ ilow = 0;
+ isize = ihigh = (*tp->tp_as_sequence->sq_length)(u);
+ if (slice_index(v, isize, &ilow) != 0)
+ return NULL;
+ if (slice_index(w, isize, &ihigh) != 0)
+ return NULL;
+ return (*tp->tp_as_sequence->sq_slice)(u, ilow, ihigh);
+}
+
+static int
+assign_subscript(w, key, v) /* w[key] = v */
+ object *w;
+ object *key;
+ object *v;
+{
+ typeobject *tp = w->ob_type;
+ sequence_methods *sq;
+ mapping_methods *mp;
+ int (*func)();
+ if ((sq = tp->tp_as_sequence) != NULL &&
+ (func = sq->sq_ass_item) != NULL) {
+ if (!is_intobject(key)) {
+ err_setstr(TypeError,
+ "sequence subscript must be integer");
+ return -1;
+ }
+ else
+ return (*func)(w, (int)getintvalue(key), v);
+ }
+ else if ((mp = tp->tp_as_mapping) != NULL &&
+ (func = mp->mp_ass_subscript) != NULL) {
+ return (*func)(w, key, v);
+ }
+ else {
+ err_setstr(TypeError,
+ "can't assign to this subscripted object");
+ return -1;
+ }
+}
+
+static int
+assign_slice(u, v, w, x) /* u[v:w] = x */
+ object *u, *v, *w, *x;
+{
+ sequence_methods *sq = u->ob_type->tp_as_sequence;
+ int ilow, ihigh, isize;
+ if (sq == NULL) {
+ err_setstr(TypeError, "assign to slice of non-sequence");
+ return -1;
+ }
+ if (sq == NULL || sq->sq_ass_slice == NULL) {
+ err_setstr(TypeError, "unassignable slice");
+ return -1;
+ }
+ ilow = 0;
+ isize = ihigh = (*sq->sq_length)(u);
+ if (slice_index(v, isize, &ilow) != 0)
+ return -1;
+ if (slice_index(w, isize, &ihigh) != 0)
+ return -1;
+ return (*sq->sq_ass_slice)(u, ilow, ihigh, x);
+}
+
+static int
+cmp_exception(err, v)
+ object *err, *v;
+{
+ if (is_tupleobject(v)) {
+ int i, n;
+ n = gettuplesize(v);
+ for (i = 0; i < n; i++) {
+ if (err == gettupleitem(v, i))
+ return 1;
+ }
+ return 0;
+ }
+ return err == v;
+}
+
+static int
+cmp_member(v, w)
+ object *v, *w;
+{
+ int i, n, cmp;
+ object *x;
+ sequence_methods *sq;
+ /* Special case for char in string */
+ if (is_stringobject(w)) {
+ register char *s, *end;
+ register char c;
+ if (!is_stringobject(v) || getstringsize(v) != 1) {
+ err_setstr(TypeError,
+ "string member test needs char left operand");
+ return -1;
+ }
+ c = getstringvalue(v)[0];
+ s = getstringvalue(w);
+ end = s + getstringsize(w);
+ while (s < end) {
+ if (c == *s++)
+ return 1;
+ }
+ return 0;
+ }
+ sq = w->ob_type->tp_as_sequence;
+ if (sq == NULL) {
+ err_setstr(TypeError,
+ "'in' or 'not in' needs sequence right argument");
+ return -1;
+ }
+ n = (*sq->sq_length)(w);
+ for (i = 0; i < n; i++) {
+ x = (*sq->sq_item)(w, i);
+ cmp = cmpobject(v, x);
+ XDECREF(x);
+ if (cmp == 0)
+ return 1;
+ }
+ return 0;
+}
+
+static object *
+cmp_outcome(op, v, w)
+ enum cmp_op op;
+ register object *v;
+ register object *w;
+{
+ register int cmp;
+ register int res = 0;
+ switch (op) {
+ case IS:
+ case IS_NOT:
+ res = (v == w);
+ if (op == IS_NOT)
+ res = !res;
+ break;
+ case IN:
+ case NOT_IN:
+ res = cmp_member(v, w);
+ if (res < 0)
+ return NULL;
+ if (op == NOT_IN)
+ res = !res;
+ break;
+ case EXC_MATCH:
+ res = cmp_exception(v, w);
+ break;
+ default:
+ cmp = cmpobject(v, w);
+ switch (op) {
+ case LT: res = cmp < 0; break;
+ case LE: res = cmp <= 0; break;
+ case EQ: res = cmp == 0; break;
+ case NE: res = cmp != 0; break;
+ case GT: res = cmp > 0; break;
+ case GE: res = cmp >= 0; break;
+ /* XXX no default? (res is initialized to 0 though) */
+ }
+ }
+ v = res ? True : False;
+ INCREF(v);
+ return v;
+}
+
+static int
+import_from(locals, v, name)
+ object *locals;
+ object *v;
+ char *name;
+{
+ object *w, *x;
+ w = getmoduledict(v);
+ if (name[0] == '*') {
+ int i;
+ int n = getdictsize(w);
+ for (i = 0; i < n; i++) {
+ name = getdictkey(w, i);
+ if (name == NULL || name[0] == '_')
+ continue;
+ x = dictlookup(w, name);
+ if (x == NULL) {
+ /* XXX can't happen? */
+ err_setstr(NameError, name);
+ return -1;
+ }
+ if (dictinsert(locals, name, x) != 0)
+ return -1;
+ }
+ return 0;
+ }
+ else {
+ x = dictlookup(w, name);
+ if (x == NULL) {
+ err_setstr(NameError, name);
+ return -1;
+ }
+ else
+ return dictinsert(locals, name, x);
+ }
+}
+
+static object *
+build_class(v, w)
+ object *v; /* None or tuple containing base classes */
+ object *w; /* dictionary */
+{
+ if (is_tupleobject(v)) {
+ int i;
+ for (i = gettuplesize(v); --i >= 0; ) {
+ object *x = gettupleitem(v, i);
+ if (!is_classobject(x)) {
+ err_setstr(TypeError,
+ "base is not a class object");
+ return NULL;
+ }
+ }
+ }
+ else {
+ v = NULL;
+ }
+ if (!is_dictobject(w)) {
+ err_setstr(SystemError, "build_class with non-dictionary");
+ return NULL;
+ }
+ return newclassobject(v, w);
+}
+
+
+/* Status code for main loop (reason for stack unwind) */
+
+enum why_code {
+ WHY_NOT, /* No error */
+ WHY_EXCEPTION, /* Exception occurred */
+ WHY_RERAISE, /* Exception re-raised by 'finally' */
+ WHY_RETURN, /* 'return' statement */
+ WHY_BREAK /* 'break' statement */
+};
+
+/* Interpreter main loop */
+
+object *
+eval_code(co, globals, locals, arg)
+ codeobject *co;
+ object *globals;
+ object *locals;
+ object *arg;
+{
+ register unsigned char *next_instr;
+ register int opcode; /* Current opcode */
+ register int oparg; /* Current opcode argument, if any */
+ register object **stack_pointer;
+ register enum why_code why; /* Reason for block stack unwind */
+ register int err; /* Error status -- nonzero if error */
+ register object *x; /* Result object -- NULL if error */
+ register object *v; /* Temporary objects popped off stack */
+ register object *w;
+ register object *u;
+ register object *t;
+ register frameobject *f; /* Current frame */
+ int lineno; /* Current line number */
+ object *retval; /* Return value iff why == WHY_RETURN */
+ char *name; /* Name used by some instructions */
+ FILE *fp; /* Used by print operations */
+#ifdef TRACE
+ int trace = dictlookup(globals, "__trace__") != NULL;
+#endif
+
+/* Code access macros */
+
+#define GETCONST(i) Getconst(f, i)
+#define GETNAME(i) Getname(f, i)
+#define FIRST_INSTR() (GETUSTRINGVALUE(f->f_code->co_code))
+#define INSTR_OFFSET() (next_instr - FIRST_INSTR())
+#define NEXTOP() (*next_instr++)
+#define NEXTARG() (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2])
+#define JUMPTO(x) (next_instr = FIRST_INSTR() + (x))
+#define JUMPBY(x) (next_instr += (x))
+
+/* Stack manipulation macros */
+
+#define STACK_LEVEL() (stack_pointer - f->f_valuestack)
+#define EMPTY() (STACK_LEVEL() == 0)
+#define TOP() (stack_pointer[-1])
+#define BASIC_PUSH(v) (*stack_pointer++ = (v))
+#define BASIC_POP() (*--stack_pointer)
+
+#ifdef TRACE
+#define PUSH(v) (BASIC_PUSH(v), trace && prtrace(TOP(), "push"))
+#define POP() (trace && prtrace(TOP(), "pop"), BASIC_POP())
+#else
+#define PUSH(v) BASIC_PUSH(v)
+#define POP() BASIC_POP()
+#endif
+
+ f = newframeobject(
+ current_frame, /*back*/
+ co, /*code*/
+ globals, /*globals*/
+ locals, /*locals*/
+ 50, /*nvalues*/
+ 20); /*nblocks*/
+ if (f == NULL)
+ return NULL;
+
+ current_frame = f;
+
+ next_instr = GETUSTRINGVALUE(f->f_code->co_code);
+
+ stack_pointer = f->f_valuestack;
+
+ if (arg != NULL) {
+ INCREF(arg);
+ PUSH(arg);
+ }
+
+ why = WHY_NOT;
+ err = 0;
+ x = None; /* Not a reference, just anything non-NULL */
+ lineno = -1;
+
+ for (;;) {
+ static ticker;
+
+ /* Do periodic things */
+
+ if (--ticker < 0) {
+ ticker = 10